From 6077c4154a5fa251975d9c828ed25ed893f419d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Aug 2022 17:31:26 -0700 Subject: [PATCH 001/477] #6116 bv2int bug fix --- src/sat/smt/arith_solver.h | 2 +- src/sat/smt/bv_internalize.cpp | 10 ++--- src/sat/smt/bv_solver.cpp | 70 +++++++++++++++++++++++++--------- src/sat/smt/bv_solver.h | 23 ++++++++--- 4 files changed, 76 insertions(+), 29 deletions(-) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 92d7cb120..cf21e13b8 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -66,7 +66,7 @@ namespace arith { vector> m_literals; svector> m_eqs; hint_type m_ty; - unsigned m_lit_head = 0, m_lit_tail = 0, m_eq_head = 0, m_eq_tail; + unsigned m_lit_head = 0, m_lit_tail = 0, m_eq_head = 0, m_eq_tail = 0; void reset() { m_lit_head = m_lit_tail; m_eq_head = m_eq_tail; } void add(euf::enode* a, euf::enode* b, bool is_eq) { if (m_eq_tail < m_eqs.size()) diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 04fde22f1..8199f539e 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -431,7 +431,7 @@ namespace bv { sat::literal lit = eq_internalize(n, sum); m_bv2ints.push_back(expr2enode(n)); ctx.push(push_back_vector(m_bv2ints)); - add_unit(lit); + add_unit(lit); } void solver::internalize_int2bv(app* n) { @@ -460,8 +460,8 @@ namespace bv { unsigned sz = bv.get_bv_size(n); numeral mod = power(numeral(2), sz); rhs = m_autil.mk_mod(e, m_autil.mk_int(mod)); - sat::literal eq_lit = eq_internalize(lhs, rhs); - add_unit(eq_lit); + sat::literal eq_lit = eq_internalize(lhs, rhs); + add_unit(eq_lit); expr_ref_vector n_bits(m); get_bits(n_enode, n_bits); @@ -472,8 +472,8 @@ namespace bv { rhs = m_autil.mk_mod(rhs, m_autil.mk_int(2)); rhs = mk_eq(rhs, m_autil.mk_int(1)); lhs = n_bits.get(i); - eq_lit = eq_internalize(lhs, rhs); - add_unit(eq_lit); + eq_lit = eq_internalize(lhs, rhs); + add_unit(eq_lit); } } diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 33ff829d6..7156058c7 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -216,10 +216,11 @@ namespace bv { euf::enode* bv2int_arg = bv2int->get_arg(0); for (euf::enode* p : euf::enode_parents(n1->get_root())) { if (bv.is_int2bv(p->get_expr()) && p->get_sort() == bv2int_arg->get_sort() && p->get_root() != bv2int_arg->get_root()) { - euf::enode_pair_vector eqs; - eqs.push_back({ n1, p->get_arg(0) }); - eqs.push_back({ n1, bv2int }); - ctx.propagate(p, bv2int_arg, euf::th_explain::propagate(*this, eqs, p, bv2int_arg)); + theory_var v1 = get_th_var(p); + theory_var v2 = get_th_var(bv2int_arg); + SASSERT(v1 != euf::null_theory_var); + SASSERT(v2 != euf::null_theory_var); + ctx.propagate(p, bv2int_arg, mk_bv2int_justification(v1, v2, n1, p->get_arg(0), bv2int)); break; } } @@ -379,6 +380,11 @@ namespace bv { r.push_back(b); break; } + case bv_justification::kind_t::bv2int: { + ctx.add_antecedent(c.a, c.b); + ctx.add_antecedent(c.a, c.c); + break; + } } if (!probing && ctx.use_drat()) log_drat(c); @@ -386,19 +392,26 @@ namespace bv { void solver::log_drat(bv_justification const& c) { // introduce dummy literal for equality. - sat::literal leq(s().num_vars() + 1, false); - expr_ref eq(m); - if (c.m_kind != bv_justification::kind_t::bit2ne) { + sat::literal leq1(s().num_vars() + 1, false); + sat::literal leq2(s().num_vars() + 2, false); + expr_ref eq1(m), eq2(m); + if (c.m_kind == bv_justification::kind_t::bv2int) { + eq1 = m.mk_eq(c.a->get_expr(), c.b->get_expr()); + eq2 = m.mk_eq(c.a->get_expr(), c.c->get_expr()); + ctx.set_tmp_bool_var(leq1.var(), eq1); + ctx.set_tmp_bool_var(leq2.var(), eq1); + } + else if (c.m_kind != bv_justification::kind_t::bit2ne) { expr* e1 = var2expr(c.m_v1); expr* e2 = var2expr(c.m_v2); - eq = m.mk_eq(e1, e2); - ctx.set_tmp_bool_var(leq.var(), eq); + eq1 = m.mk_eq(e1, e2); + ctx.set_tmp_bool_var(leq1.var(), eq1); } sat::literal_vector lits; switch (c.m_kind) { case bv_justification::kind_t::eq2bit: - lits.push_back(~leq); + lits.push_back(~leq1); lits.push_back(~c.m_antecedent); lits.push_back(c.m_consequent); break; @@ -407,10 +420,10 @@ namespace bv { lits.push_back(c.m_consequent); break; case bv_justification::kind_t::bit2eq: - get_antecedents(leq, c.to_index(), lits, true); + get_antecedents(leq1, c.to_index(), lits, true); for (auto& lit : lits) lit.neg(); - lits.push_back(leq); + lits.push_back(leq1); break; case bv_justification::kind_t::bit2ne: get_antecedents(c.m_consequent, c.to_index(), lits, true); @@ -418,6 +431,14 @@ namespace bv { lit.neg(); lits.push_back(c.m_consequent); break; + case bv_justification::kind_t::bv2int: + get_antecedents(leq1, c.to_index(), lits, true); + get_antecedents(leq2, c.to_index(), lits, true); + for (auto& lit : lits) + lit.neg(); + lits.push_back(leq1); + lits.push_back(leq2); + break; } ctx.get_drat().add(lits, status()); // TBD, a proper way would be to delete the lemma after use. @@ -665,7 +686,9 @@ namespace bv { return out << "bv <- v" << v1 << "[" << cidx << "] != v" << v2 << "[" << cidx << "] " << m_bits[v1][cidx] << " != " << m_bits[v2][cidx]; } case bv_justification::kind_t::ne2bit: - return out << "bv <- " << m_bits[v1] << " != " << m_bits[v2] << " @" << cidx; + return out << "bv <- " << m_bits[v1] << " != " << m_bits[v2] << " @" << cidx; + case bv_justification::kind_t::bv2int: + return out << "bv <- v" << v1 << " == v" << v2 << " <== " << ctx.bpp(c.a) << " == " << ctx.bpp(c.b) << " == " << ctx.bpp(c.c); default: UNREACHABLE(); break; @@ -818,28 +841,41 @@ namespace bv { void* mem = get_region().allocate(bv_justification::get_obj_size()); sat::constraint_base::initialize(mem, this); auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(v1, v2, c, a); - return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); + auto jst = sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); + TRACE("bv", tout << jst << " " << constraint << "\n"); + return jst; } sat::ext_justification_idx solver::mk_bit2eq_justification(theory_var v1, theory_var v2) { void* mem = get_region().allocate(bv_justification::get_obj_size()); sat::constraint_base::initialize(mem, this); auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(v1, v2); - return constraint->to_index(); + auto jst = constraint->to_index(); + return jst; } sat::justification solver::mk_bit2ne_justification(unsigned idx, sat::literal c) { void* mem = get_region().allocate(bv_justification::get_obj_size()); sat::constraint_base::initialize(mem, this); auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(idx, c); - return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); + auto jst = sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); + return jst; } sat::justification solver::mk_ne2bit_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a) { void* mem = get_region().allocate(bv_justification::get_obj_size()); sat::constraint_base::initialize(mem, this); auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(idx, v1, v2, c, a); - return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); + auto jst = sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); + return jst; + } + + sat::ext_constraint_idx solver::mk_bv2int_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c) { + void* mem = get_region().allocate(bv_justification::get_obj_size()); + sat::constraint_base::initialize(mem, this); + auto* constraint = new (sat::constraint_base::ptr2mem(mem)) bv_justification(v1, v2, a, b, c); + auto jst = constraint->to_index(); + return jst; } bool solver::assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc) { diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index b77343e30..4166ebf7b 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -51,13 +51,21 @@ namespace bv { }; struct bv_justification { - enum kind_t { eq2bit, ne2bit, bit2eq, bit2ne }; + enum kind_t { eq2bit, ne2bit, bit2eq, bit2ne, bv2int }; kind_t m_kind; - unsigned m_idx{ UINT_MAX }; - theory_var m_v1{ euf::null_theory_var }; - theory_var m_v2 { euf::null_theory_var }; - sat::literal m_consequent; - sat::literal m_antecedent; + unsigned m_idx = UINT_MAX; + theory_var m_v1 = euf::null_theory_var; + theory_var m_v2 = euf::null_theory_var; + union { + struct { + sat::literal m_consequent; + sat::literal m_antecedent; + }; + struct { + euf::enode* a, *b, *c; + }; + }; + bv_justification(theory_var v1, theory_var v2, sat::literal c, sat::literal a) : m_kind(bv_justification::kind_t::eq2bit), m_v1(v1), m_v2(v2), m_consequent(c), m_antecedent(a) {} bv_justification(theory_var v1, theory_var v2): @@ -66,6 +74,8 @@ namespace bv { m_kind(bv_justification::kind_t::bit2ne), m_idx(idx), m_consequent(c) {} bv_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a) : m_kind(bv_justification::kind_t::ne2bit), m_idx(idx), m_v1(v1), m_v2(v2), m_consequent(c), m_antecedent(a) {} + bv_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c): + m_kind(bv_justification::kind_t::bv2int), m_v1(v1), m_v2(v2), a(a), b(b), c(c) {} sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); } @@ -79,6 +89,7 @@ namespace bv { sat::ext_justification_idx mk_bit2eq_justification(theory_var v1, theory_var v2); sat::justification mk_bit2ne_justification(unsigned idx, sat::literal c); sat::justification mk_ne2bit_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a); + sat::ext_constraint_idx mk_bv2int_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c); void log_drat(bv_justification const& c); From 3011b34b3b87ca0bfe20cc7c7471dfd1d2a127a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Aug 2022 18:59:02 -0700 Subject: [PATCH 002/477] log E-matching based quantifier instantiations as hints --- src/cmd_context/extra_cmds/proof_cmds.cpp | 2 ++ src/sat/smt/bv_solver.cpp | 3 +++ src/sat/smt/euf_proof.cpp | 2 ++ src/sat/smt/q_ematch.cpp | 7 +++++-- src/sat/smt/q_solver.cpp | 24 +++++++++++++++++++++++ src/sat/smt/q_solver.h | 9 +++++++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 8d6b6ad8e..fe75acc84 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -166,6 +166,8 @@ public: } m_solver->pop(1); std::cout << "(verified-smt)\n"; + if (proof_hint) + std::cout << "(missed-hint " << mk_pp(proof_hint, m) << ")\n"; add_clause(clause); } diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 7156058c7..4a14067d1 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -442,6 +442,9 @@ namespace bv { } ctx.get_drat().add(lits, status()); // TBD, a proper way would be to delete the lemma after use. + ctx.set_tmp_bool_var(leq1.var(), nullptr); + ctx.set_tmp_bool_var(leq2.var(), nullptr); + } void solver::asserted(literal l) { diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 14671d55a..6c90b3c66 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -100,6 +100,8 @@ namespace euf { if (jst.eq_consequent().first != nullptr) lits.push_back(add_lit(jst.eq_consequent())); get_drat().add(lits, sat::status::th(m_is_redundant, jst.ext().get_id(), jst.get_pragma())); + for (unsigned i = s().num_vars(); i < nv; ++i) + set_tmp_bool_var(i, nullptr); } void solver::on_clause(unsigned n, literal const* lits, sat::status st) { diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index be9d952cd..490bce46e 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -381,9 +381,12 @@ namespace q { sat::literal_vector lits; lits.push_back(~j.m_clause.m_literal); for (unsigned i = 0; i < j.m_clause.size(); ++i) - lits.push_back(instantiate(j.m_clause, j.m_binding, j.m_clause[i])); + lits.push_back(instantiate(j.m_clause, j.m_binding, j.m_clause[i])); m_qs.log_instantiation(lits, &j); - m_qs.add_clause(lits); + euf::th_proof_hint* ph = nullptr; + if (ctx.use_drat()) + ph = q_proof_hint::mk(ctx, j.m_clause.size(), j.m_binding); + m_qs.add_clause(lits, ph); } bool ematch::flush_prop_queue() { diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index f40aa76c8..565b2536b 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -363,4 +363,28 @@ namespace q { ctx.on_instantiation(n, lits, j ? j->m_clause.num_decls() : 0, j ? j->m_binding : nullptr); } } + + q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, euf::enode* const* bindings) { + auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n)); + q_proof_hint* ph = new (mem) q_proof_hint(); + ph->m_num_bindings = n; + for (unsigned i = 0; i < n; ++i) + ph->m_bindings[i] = bindings[i]; + return ph; + } + + expr* q_proof_hint::get_hint(euf::solver& s) const { + ast_manager& m = s.get_manager(); + expr_ref_vector args(m); + sort_ref_vector sorts(m); + for (unsigned i = 0; i < m_num_bindings; ++i) { + args.push_back(m_bindings[i]->get_expr()); + sorts.push_back(args.back()->get_sort()); + } + sort* range = m.mk_proof_sort(); + func_decl* d = m.mk_func_decl(symbol("inst"), args.size(), sorts.data(), range); + expr* r = m.mk_app(d, args); + return r; + } + } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 755fc6d16..e34da020d 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -29,6 +29,15 @@ namespace euf { namespace q { + struct q_proof_hint : public euf::th_proof_hint { + unsigned m_num_bindings; + euf::enode* m_bindings[0]; + q_proof_hint() {} + static size_t get_obj_size(unsigned num_bindings) { return sizeof(q_proof_hint) + num_bindings*sizeof(euf::enode*); } + static q_proof_hint* mk(euf::solver& s, unsigned n, euf::enode* const* bindings); + expr* get_hint(euf::solver& s) const override; + }; + class solver : public euf::th_euf_solver { typedef obj_map flat_table; From d3e6ba9f98bd455239ad51bc0a2167fa64dbf72a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Aug 2022 19:09:13 -0700 Subject: [PATCH 003/477] remove union Signed-off-by: Nikolaj Bjorner --- src/sat/smt/bv_solver.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index 4166ebf7b..46948157c 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -56,15 +56,9 @@ namespace bv { unsigned m_idx = UINT_MAX; theory_var m_v1 = euf::null_theory_var; theory_var m_v2 = euf::null_theory_var; - union { - struct { - sat::literal m_consequent; - sat::literal m_antecedent; - }; - struct { - euf::enode* a, *b, *c; - }; - }; + sat::literal m_consequent; + sat::literal m_antecedent; + euf::enode* a, *b, *c; bv_justification(theory_var v1, theory_var v2, sat::literal c, sat::literal a) : m_kind(bv_justification::kind_t::eq2bit), m_v1(v1), m_v2(v2), m_consequent(c), m_antecedent(a) {} From ac5b190a72303e33bdcf07828c1002ffdc26632e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2022 08:51:53 -0700 Subject: [PATCH 004/477] track instantiations from MBQI in proof logging for new solver Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_mbi.cpp | 54 ++++++++++++++++++++++++++++++++++------ src/sat/smt/q_mbi.h | 16 ++++++------ src/sat/smt/q_solver.cpp | 13 ++++++++-- src/sat/smt/q_solver.h | 5 ++-- 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 669347d68..9f716d071 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -68,11 +68,21 @@ namespace q { } } m_max_cex += ctx.get_config().m_mbqi_max_cexs; - for (auto const& [qlit, fml, generation] : m_instantiations) { + for (auto const& [qlit, fml, inst, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ctx.mk_literal(fml); + euf::th_proof_hint* ph = nullptr; + if (!inst.empty()) { + ph = q_proof_hint::mk(ctx, inst.size(), inst.data()); + sat::literal_vector lits; + lits.push_back(~qlit); + lits.push_back(~lit); + m_qs.add_clause(lits, ph); + } + else { + m_qs.add_clause(~qlit, ~lit); + } m_qs.log_instantiation(~qlit, ~lit); - m_qs.add_clause(~qlit, ~lit); } m_instantiations.reset(); if (result != l_true) @@ -224,10 +234,31 @@ namespace q { TRACE("q", tout << "project: " << proj << "\n";); IF_VERBOSE(11, verbose_stream() << "mbi:\n" << mk_pp(q, m) << "\n" << proj << "\n"); ++m_stats.m_num_instantiations; - unsigned generation = ctx.get_max_generation(proj); - m_instantiations.push_back(instantiation_t(qlit, proj, generation)); + unsigned generation = ctx.get_max_generation(proj); + expr_ref_vector inst = extract_binding(q); + m_instantiations.push_back(instantiation_t(qlit, proj, inst, generation)); } + expr_ref_vector mbqi::extract_binding(quantifier* q) { + if (!m_defs.empty()) { + expr_safe_replace sub(m); + for (unsigned i = m_defs.size(); i-- > 0; ) { + sub(m_defs[i].term); + sub.insert(m_defs[i].var, m_defs[i].term); + } + q_body* qb = q2body(q); + expr_ref_vector inst(m); + for (expr* v : qb->vars) { + expr_ref t(m); + sub(v, t); + inst.push_back(t); + } + return inst; + } + return expr_ref_vector(m); + } + + void mbqi::add_universe_restriction(q_body& qb) { for (app* v : qb.vars) { sort* s = v->get_sort(); @@ -284,6 +315,7 @@ namespace q { expr_ref_vector fmls(qb.vbody); app_ref_vector vars(qb.vars); bool fmls_extracted = false; + m_defs.reset(); TRACE("q", tout << "Project\n"; tout << fmls << "\n"; @@ -314,16 +346,22 @@ namespace q { fmls_extracted = true; } if (!p) - continue; - if (!(*p)(*m_model, vars, fmls)) - return expr_ref(nullptr, m); + continue; + if (ctx.use_drat()) { + if (!p->project(*m_model, vars, fmls, m_defs)) + return expr_ref(m); + } + else if (!(*p)(*m_model, vars, fmls)) + return expr_ref(m); } for (app* v : vars) { expr_ref term(m); expr_ref val = (*m_model)(v); val = m_model->unfold_as_array(val); term = replace_model_value(val); - rep.insert(v, term); + rep.insert(v, term); + if (ctx.use_drat()) + m_defs.push_back(mbp::def(expr_ref(v, m), term)); eqs.push_back(m.mk_eq(v, val)); } rep(fmls); diff --git a/src/sat/smt/q_mbi.h b/src/sat/smt/q_mbi.h index c7dc4a551..2cc5655bf 100644 --- a/src/sat/smt/q_mbi.h +++ b/src/sat/smt/q_mbi.h @@ -66,15 +66,17 @@ namespace q { scoped_ptr_vector> m_values; scoped_ptr_vector m_plugins; obj_map m_q2body; - unsigned m_max_cex{ 1 }; - unsigned m_max_quick_check_rounds { 100 }; - unsigned m_max_unbounded_equalities { 10 }; - unsigned m_max_choose_candidates { 10 }; - unsigned m_generation_bound{ UINT_MAX }; - unsigned m_generation_max { UINT_MAX }; - typedef std::tuple instantiation_t; + unsigned m_max_cex = 1; + unsigned m_max_quick_check_rounds = 100; + unsigned m_max_unbounded_equalities = 10; + unsigned m_max_choose_candidates = 10; + unsigned m_generation_bound = UINT_MAX; + unsigned m_generation_max = UINT_MAX; + typedef std::tuple instantiation_t; vector m_instantiations; + vector m_defs; + expr_ref_vector extract_binding(quantifier* q); void restrict_to_universe(expr * sk, ptr_vector const & universe); // void register_value(expr* e); expr_ref replace_model_value(expr* e); diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 565b2536b..0a8ca5085 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -365,6 +365,15 @@ namespace q { } q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, euf::enode* const* bindings) { + auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n)); + q_proof_hint* ph = new (mem) q_proof_hint(); + ph->m_num_bindings = n; + for (unsigned i = 0; i < n; ++i) + ph->m_bindings[i] = bindings[i]->get_expr(); + return ph; + } + + q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, expr* const* bindings) { auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n)); q_proof_hint* ph = new (mem) q_proof_hint(); ph->m_num_bindings = n; @@ -372,13 +381,13 @@ namespace q { ph->m_bindings[i] = bindings[i]; return ph; } - + expr* q_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); expr_ref_vector args(m); sort_ref_vector sorts(m); for (unsigned i = 0; i < m_num_bindings; ++i) { - args.push_back(m_bindings[i]->get_expr()); + args.push_back(m_bindings[i]); sorts.push_back(args.back()->get_sort()); } sort* range = m.mk_proof_sort(); diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index e34da020d..ee2e47111 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -31,10 +31,11 @@ namespace q { struct q_proof_hint : public euf::th_proof_hint { unsigned m_num_bindings; - euf::enode* m_bindings[0]; + expr* m_bindings[0]; q_proof_hint() {} - static size_t get_obj_size(unsigned num_bindings) { return sizeof(q_proof_hint) + num_bindings*sizeof(euf::enode*); } + static size_t get_obj_size(unsigned num_bindings) { return sizeof(q_proof_hint) + num_bindings*sizeof(expr*); } static q_proof_hint* mk(euf::solver& s, unsigned n, euf::enode* const* bindings); + static q_proof_hint* mk(euf::solver& s, unsigned n, expr* const* bindings); expr* get_hint(euf::solver& s) const override; }; From 46383a08111609e8f4d41a2b1398bd203d1b4084 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2022 09:45:56 -0700 Subject: [PATCH 005/477] AG - unary datatypes, tester always is true. --- src/ast/rewriter/datatype_rewriter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index 97818ce82..ba0155e97 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -32,6 +32,10 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr // simplify is_cons(nil) -> false // SASSERT(num_args == 1); + if (m_util.get_datatype_num_constructors(args[0]->get_sort()) == 1) { + result = m().mk_true(); + return BR_DONE; + } if (!is_app(args[0]) || !m_util.is_constructor(to_app(args[0]))) return BR_FAILED; if (to_app(args[0])->get_decl() == m_util.get_recognizer_constructor(f)) From 61f7dc3513dcf521db60b7304b75e21edee80812 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2022 10:23:21 -0700 Subject: [PATCH 006/477] remove creation of trivial testers --- src/qe/mbp/mbp_datatypes.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qe/mbp/mbp_datatypes.cpp b/src/qe/mbp/mbp_datatypes.cpp index e40a19546..32e2b9f27 100644 --- a/src/qe/mbp/mbp_datatypes.cpp +++ b/src/qe/mbp/mbp_datatypes.cpp @@ -169,7 +169,7 @@ namespace mbp { eqs.push_back(m.mk_eq(access(c, j, acc, b), a->get_arg(j))); } } - if (!is_app_of(b, c)) { + if (!is_app_of(b, c) && dt.get_datatype_num_constructors(c->get_range()) != 1) { eqs.push_back(m.mk_app(rec, b)); } @@ -231,7 +231,7 @@ namespace mbp { } func_decl* c = to_app(l)->get_decl(); ptr_vector const& acc = *dt.get_constructor_accessors(c); - if (!is_app_of(r, c)) { + if (!is_app_of(r, c) && dt.get_datatype_num_constructors(c->get_range()) != 1) { lits.push_back(m.mk_app(dt.get_constructor_is(c), r)); } for (unsigned i = 0; i < acc.size(); ++i) { From f2afb369bdf63c8db5dffc395aa2accfb0b96f73 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2022 14:18:13 -0700 Subject: [PATCH 007/477] extend distinct check to ADT --- src/ast/datatype_decl_plugin.cpp | 22 ++++++++++++++++++++++ src/ast/datatype_decl_plugin.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 11c33d695..535500cae 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -635,6 +635,28 @@ namespace datatype { } } + bool plugin::are_distinct(app * a, app * b) const { + if (a == b) + return false; + if (is_unique_value(a) && is_unique_value(b)) + return true; + if (u().is_constructor(a) && u().is_constructor(b)) { + if (a->get_decl() != b->get_decl()) + return true; + for (unsigned i = a->get_num_args(); i-- > 0; ) { + if (!is_app(a->get_arg(i))) + continue; + if (!is_app(b->get_arg(i))) + continue; + app* _a = to_app(a->get_arg(i)); + app* _b = to_app(b->get_arg(i)); + if (m_manager->are_distinct(_a, _b)) + return true; + } + } + return false; + } + expr * plugin::get_some_value(sort * s) { SASSERT(u().is_datatype(s)); func_decl * c = u().get_non_rec_constructor(s); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 310175781..4561dfacf 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -233,6 +233,8 @@ namespace datatype { bool is_value(app* e) const override { return is_value_aux(false, e); } bool is_unique_value(app * e) const override { return is_value_aux(true, e); } + + bool are_distinct(app * a, app * b) const override; void get_op_names(svector & op_names, symbol const & logic) override; From eb2b95e5fe0ab226fa50dd91ffd5fa90f2e5a8bc Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 1 Sep 2022 15:44:22 -0700 Subject: [PATCH 008/477] spacer: trying to make C++ happy --- src/muz/spacer/spacer_expand_bnd_generalizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_expand_bnd_generalizer.cpp b/src/muz/spacer/spacer_expand_bnd_generalizer.cpp index a3e88f8d5..4f80be706 100644 --- a/src/muz/spacer/spacer_expand_bnd_generalizer.cpp +++ b/src/muz/spacer/spacer_expand_bnd_generalizer.cpp @@ -102,7 +102,7 @@ lemma_expand_bnd_generalizer::lemma_expand_bnd_generalizer(context &ctx) // remove duplicates std::sort(m_values.begin(), m_values.end()); auto last = std::unique(m_values.begin(), m_values.end()); - for (unsigned i = 0, sz = std::distance(last, m_values.end()); i < sz; ++i) + for (size_t i = 0, sz = std::distance(last, m_values.end()); i < sz; ++i) m_values.pop_back(); } From eb1ea9482edf11a7136bfeb9d5da15d26bb889e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2022 23:25:14 -0700 Subject: [PATCH 009/477] detect nested as-array in model values --- src/model/model_evaluator.cpp | 42 ++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 2d9b1ccae..6d01fdcdb 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -158,6 +158,35 @@ struct evaluator_cfg : public default_rewriter_cfg { return st; } + bool contains_as_array(expr* e) { + if (m_ar.is_as_array(e)) + return true; + if (is_var(e)) + return false; + if (is_app(e) && to_app(e)->get_num_args() == 0) + return false; + + struct has_as_array {}; + struct has_as_array_finder { + array_util& au; + has_as_array_finder(array_util& au): au(au) {} + void operator()(var* v) {} + void operator()(quantifier* q) {} + void operator()(app* a) { + if (au.is_as_array(a->get_decl())) + throw has_as_array(); + } + }; + has_as_array_finder ha(m_ar); + try { + for_each_expr(ha, e); + } + catch (has_as_array) { + return true; + } + return false; + } + br_status reduce_app_core(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = nullptr; family_id fid = f->get_family_id(); @@ -174,11 +203,17 @@ struct evaluator_cfg : public default_rewriter_cfg { #endif - if (num == 0 && (fid == null_family_id || _is_uninterp || m_ar.is_as_array(f))) { - expr * val = m_model.get_const_interp(f); + func_decl* g = nullptr; + if (num == 0 && m_ar.is_as_array(f, g)) { + auto* fi = m_model.get_func_interp(g); + if (fi && (result = fi->get_array_interp(g))) + return BR_REWRITE1; + } + if (num == 0 && (fid == null_family_id || _is_uninterp)) { + expr* val = m_model.get_const_interp(f); if (val != nullptr) { result = val; - st = m_ar.is_as_array(val) ? BR_REWRITE1 : BR_DONE; + st = contains_as_array(val) ? BR_REWRITE_FULL : BR_DONE; TRACE("model_evaluator", tout << result << "\n";); return st; } @@ -192,6 +227,7 @@ struct evaluator_cfg : public default_rewriter_cfg { result = val; return BR_DONE; } + // fall through } From e4ef1717e3a7b30fc87a4959dd80195a519721a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2022 23:26:31 -0700 Subject: [PATCH 010/477] fix variable tracking bug in explanations with literals --- src/sat/smt/euf_internalize.cpp | 2 +- src/sat/smt/euf_proof.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 8b8c7da74..96167b39f 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -167,7 +167,7 @@ namespace euf { lit = lit2; } - TRACE("euf", tout << "attach " << v << " " << mk_bounded_pp(e, m) << "\n";); + TRACE("euf", tout << "attach v" << v << " " << mk_bounded_pp(e, m) << "\n";); m_bool_var2expr.reserve(v + 1, nullptr); if (m_bool_var2expr[v] && m_egraph.find(e)) { if (m_egraph.find(e)->bool_var() != v) { diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 6c90b3c66..bcbc9439b 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -83,10 +83,11 @@ namespace euf { expr_ref_vector eqs(m); unsigned nv = s().num_vars(); auto add_lit = [&](enode_pair const& eq) { + unsigned v = nv; ++nv; eqs.push_back(m.mk_eq(eq.first->get_expr(), eq.second->get_expr())); - set_tmp_bool_var(nv, eqs.back()); - return literal(nv, false); + set_tmp_bool_var(v, eqs.back()); + return literal(v, false); }; for (auto lit : euf::th_explain::lits(jst)) From 9dca8d18ed9711ad14e12cb4176454c38bbbc355 Mon Sep 17 00:00:00 2001 From: JohnLyu2 <65240623+JohnLyu2@users.noreply.github.com> Date: Fri, 2 Sep 2022 16:36:11 -0400 Subject: [PATCH 011/477] fix negative contains bug (#6312) --- src/smt/theory_str.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 8bd6c49aa..955241efd 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -8436,6 +8436,14 @@ namespace smt { } } + bool existNegativeContains = false; + expr_ref_vector assignments(m); + ctx.get_assignments(assignments); + for (expr * a : assignments) { + expr * subterm; + if (m.is_not(a, subterm) && u.str.is_contains(subterm)) existNegativeContains = true; + } + if (!needToAssignFreeVars) { // check string-int terms @@ -8506,9 +8514,11 @@ namespace smt { // we're not done if some variable in a regex membership predicate was unassigned if (regexOK) { if (unused_internal_variables.empty()) { - TRACE("str", tout << "All variables are assigned. Done!" << std::endl;); - m_stats.m_solved_by = 2; - return FC_DONE; + if (!existNegativeContains) { + TRACE("str", tout << "All variables are assigned. Done!" << std::endl;); + m_stats.m_solved_by = 2; + return FC_DONE; + } } else { TRACE("str", tout << "Assigning decoy values to free internal variables." << std::endl;); for (auto const &var : unused_internal_variables) { @@ -8561,9 +8571,6 @@ namespace smt { } TRACE("str", tout << "arithmetic solver done in final check" << std::endl;); - expr_ref_vector assignments(m); - ctx.get_assignments(assignments); - expr_ref_vector precondition(m); expr_ref_vector cex(m); lbool model_status = fixed_length_model_construction(assignments, precondition, free_variables, candidate_model, cex); From 7e1e64d027b2d44c5b17e3ea4b8d82c002760175 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Sep 2022 17:43:57 -0700 Subject: [PATCH 012/477] fix #6313 remaining new issues --- src/qe/mbp/mbp_arith.cpp | 10 ++++++---- src/sat/smt/bv_internalize.cpp | 4 ++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index 47ee53668..79f931d50 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -183,7 +183,9 @@ namespace mbp { return c0; }; - if (a.is_mul(t, t1, t2) && is_numeral(t1, mul1)) + if (tids.contains(t)) + insert_mul(t, mul, ts); + else if (a.is_mul(t, t1, t2) && is_numeral(t1, mul1)) linearize(mbo, eval, mul * mul1, t2, c, fmls, ts, tids); else if (a.is_mul(t, t1, t2) && is_numeral(t2, mul1)) linearize(mbo, eval, mul * mul1, t1, c, fmls, ts, tids); @@ -221,6 +223,7 @@ namespace mbp { vars coeffs; rational c0 = add_def(t1, mul1, coeffs); tids.insert(t, mbo.add_mod(coeffs, c0, mul1)); + } else if (a.is_idiv(t, t1, t2) && is_numeral(t2, mul1) && mul1 > 0) { // v = t1 div mul1 @@ -278,9 +281,8 @@ namespace mbp { expr_ref var2expr(ptr_vector const& index2expr, var const& v) { expr_ref t(index2expr[v.m_id], m); - if (!v.m_coeff.is_one()) { - t = a.mk_mul(a.mk_numeral(v.m_coeff, a.is_int(t)), t); - } + if (!v.m_coeff.is_one()) + t = a.mk_mul(a.mk_numeral(v.m_coeff, a.is_int(t)), t); return t; } diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 8199f539e..6d2dc683a 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -450,6 +450,10 @@ namespace bv { * Create the axioms: * bit2bool(i,n) == ((e div 2^i) mod 2 != 0) * for i = 0,.., sz-1 + * + * Alternative axiomatization: + * e = sum bit2bool(i,n)*2^i + 2^n * (div(e, 2^n)) + * possibly term div(e,2^n) is not */ void solver::assert_int2bv_axiom(app* n) { expr* e = nullptr; From 0bdb2f16910779f02af3d401cb589c11f847743f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Sep 2022 18:03:56 -0700 Subject: [PATCH 013/477] add verbose=1 log for mbp failure --- src/qe/mbp/mbp_arith.cpp | 10 ++++++++-- src/qe/mbp/mbp_plugin.cpp | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index 79f931d50..a886a5a70 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -215,6 +215,7 @@ namespace mbp { linearize(mbo, eval, mul, t3, c, fmls, ts, tids); } else { + IF_VERBOSE(1, verbose_stream() << "mbp failed on if: " << mk_pp(t, m) << " := " << val << "\n"); throw default_exception("mbp evaluation didn't produce a truth value"); } } @@ -234,8 +235,10 @@ namespace mbp { else if (a.is_mod(t, t1, t2) && is_numeral(t2, mul1) && !mul1.is_zero()) { rational r; val = eval(t); - if (!a.is_numeral(val, r)) + if (!a.is_numeral(val, r)) { + IF_VERBOSE(1, verbose_stream() << "mbp failed on " << mk_pp(t, m) << " := " << val << "\n"); throw default_exception("mbp evaluation didn't produce an integer"); + } c += mul * r; rational c0(-r), mul0(1); @@ -335,8 +338,10 @@ namespace mbp { expr_ref val = eval(v); if (!m.inc()) return false; - if (!a.is_numeral(val, r)) + if (!a.is_numeral(val, r)) { + IF_VERBOSE(1, verbose_stream() << "mbp failed on " << mk_pp(v, m) << " := " << val << "\n"); throw default_exception("evaluation did not produce a numeral"); + } TRACE("qe", tout << mk_pp(v, m) << " " << val << "\n";); tids.insert(v, mbo.add_var(r, a.is_int(v))); } @@ -623,6 +628,7 @@ namespace mbp { expr_ref val = eval(v); if (!a.is_numeral(val, r)) { TRACE("qe", tout << eval.get_model() << "\n";); + IF_VERBOSE(1, verbose_stream() << "mbp failed on " << mk_pp(v, m) << " := " << val << "\n"); throw default_exception("mbp evaluation was only partial"); } id = mbo.add_var(r, a.is_int(v)); diff --git a/src/qe/mbp/mbp_plugin.cpp b/src/qe/mbp/mbp_plugin.cpp index 2717f65cb..2584a4ce1 100644 --- a/src/qe/mbp/mbp_plugin.cpp +++ b/src/qe/mbp/mbp_plugin.cpp @@ -246,8 +246,10 @@ namespace mbp { bool project_plugin::is_true(model_evaluator& eval, expr* e) { expr_ref val = eval(e); bool tt = m.is_true(val); - if (!tt && !m.is_false(val) && contains_uninterpreted(val)) + if (!tt && !m.is_false(val) && contains_uninterpreted(val)) { + IF_VERBOSE(1, verbose_stream() << "mbp failed on " << mk_pp(e, m) << " := " << val << "\n"); throw default_exception("could not evaluate Boolean in model"); + } SASSERT(tt || m.is_false(val)); return tt; } From 60967efd3803ddee4515ca7820da8e9e48af9386 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Sep 2022 18:39:21 -0700 Subject: [PATCH 014/477] fix wrong condition for delayed bit-blasting --- src/sat/smt/bv_delay_internalize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index 6ad10c53a..c3c457464 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -47,7 +47,7 @@ namespace bv { return true; unsigned num_vars = e->get_num_args(); for (expr* arg : *e) - if (!m.is_value(arg)) + if (m.is_value(arg)) --num_vars; if (num_vars <= 1) return true; From 85c8168af5caa17fb5c6d441c8d16b14ea573c0b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Sep 2022 22:45:50 -0700 Subject: [PATCH 015/477] use for pattern instead of iterators --- src/smt/theory_arith_core.h | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 02a9f3c68..2d18a3496 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1044,13 +1044,14 @@ namespace smt { inf_numeral const & k1(a1->get_k()); atom_kind kind1 = a1->get_atom_kind(); TRACE("mk_bound_axioms", display_atom(tout << "making bound axioms for " << a1 << " ", a1, true); tout << "\n";); + typename atoms::iterator it = occs.begin(); typename atoms::iterator end = occs.end(); - typename atoms::iterator lo_inf = end, lo_sup = end; typename atoms::iterator hi_inf = end, hi_sup = end; + for (; it != end; ++it) { - atom * a2 = *it; + atom* a2 = *it; inf_numeral const & k2(a2->get_k()); atom_kind kind2 = a2->get_atom_kind(); TRACE("mk_bound_axioms", display_atom(tout << "compare " << a2 << " ", a2, true); tout << "\n";); @@ -3010,15 +3011,12 @@ namespace smt { literal_vector & lits = m_tmp_literal_vector2; lits.reset(); lits.push_back(l); - literal_vector::const_iterator it = ante.lits().begin(); - literal_vector::const_iterator end = ante.lits().end(); - for (; it != end; ++it) - lits.push_back(~(*it)); + for (auto const& lit : ante.lits()) + lits.push_back(~lit); justification * js = nullptr; - if (proofs_enabled()) { + if (proofs_enabled()) js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.data(), ante.num_params(), ante.params("assign-bounds")); - } ctx.mk_clause(lits.size(), lits.data(), js, CLS_TH_LEMMA, nullptr); } else { @@ -3045,19 +3043,15 @@ namespace smt { int upper_idx; is_row_useful_for_bound_prop(r, lower_idx, upper_idx); - if (lower_idx >= 0) { + if (lower_idx >= 0) imply_bound_for_monomial(r, lower_idx, true); - } - else if (lower_idx == -1) { + else if (lower_idx == -1) imply_bound_for_all_monomials(r, true); - } - if (upper_idx >= 0) { + if (upper_idx >= 0) imply_bound_for_monomial(r, upper_idx, false); - } - else if (upper_idx == -1) { + else if (upper_idx == -1) imply_bound_for_all_monomials(r, false); - } // sneaking cheap eq detection in this loop propagate_cheap_eq(r_idx); From 1382cdefea3cf595cea3ca03f752277c696f741d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Sep 2022 10:04:48 -0700 Subject: [PATCH 016/477] release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index cdde16323..86707318c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -13,7 +13,27 @@ Version 4.next Version 4.11.1 ============== - add error handling to fromString method in JavaScript -- fix regression in default parameters for CDCL (Nuno Lopes) +- fix regression in default parameters for CDCL, thanks to Nuno Lopes +- fix model evaluation bugs for as-array nested under functions (data-type constructors) +- add rewrite simplifications for datatypes with a single constructor +- add "Global Guidance" capability to SPACER, thanks to Arie Gurfinkel and Hari Gorvind. + The commit logs related to Global Guidance contain detailed information. +- change proof logging format for the new core to use SMTLIB commands. + The format was so far an extension of DRAT used by SAT solvers, but not well compatible + with SMT format that is extensible. The resulting format is a mild extension of SMTLIB with + three extra commands assume, learn, del. They track input clauses, generated clauses and deleted clauses. + They are optionally augmented by proof hints. Two proof hints are used in the current version: "rup" and "farkas". + "rup" is used whent the generated clause can be justified by reverse unit propagation. "farkas" is used when + the clause can be justified by a combination of Farkas cutting planes. There is a built-in proof checker for the + format. Quantifier instantiations are also tracked as proof hints. + Other proof hints are to be added as the feature set is tested and developed. The fallback, buit-in, + self-checker uses z3 to check that the generated clause is a consequence. Note that this is generally + insufficient as generated clauses are in principle required to only be satisfiability preserving. + Proof checking and tranformation operations is overall open ended. + The log for the first commit introducing this change contains further information on the format. +- fix to re-entrancy bug in user propagator (thanks to Clemens Eisenhofer). +- handle _toExpr for quantified formulas in JS bindings + Version 4.11.0 ============== From 8e6f17ebd011a352b3e67fcec03dcd4378a1472c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Sep 2022 15:47:12 -0700 Subject: [PATCH 017/477] inc version Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- RELEASE_NOTES.md | 5 ++++- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 554da2779..b5f8ba1b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.11.1.0 LANGUAGES CXX) +project(Z3 VERSION 4.11.2.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 86707318c..b1fe88e06 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,7 +10,7 @@ Version 4.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. -Version 4.11.1 +Version 4.11.2 ============== - add error handling to fromString method in JavaScript - fix regression in default parameters for CDCL, thanks to Nuno Lopes @@ -34,6 +34,9 @@ Version 4.11.1 - fix to re-entrancy bug in user propagator (thanks to Clemens Eisenhofer). - handle _toExpr for quantified formulas in JS bindings +Version 4.11.1 +============== +- skipped Version 4.11.0 ============== diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 9aff9d427..78ecf8b5a 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 11, 1, 0) # express a default build version or pick up ci build version + set_version(4, 11, 2, 0) # express a default build version or pick up ci build version # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e68f38ee9..3d69b0ef2 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,7 +1,7 @@ variables: Major: '4' Minor: '11' - Patch: '1' + Patch: '2' AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.DefinitionName) diff --git a/scripts/release.yml b/scripts/release.yml index 99438fbb9..ac0a951af 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.11.1' + ReleaseVersion: '4.11.2' stages: From b9ddb11701c4b6c68676fb6f938d664c59855855 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 4 Sep 2022 11:57:35 +0100 Subject: [PATCH 018/477] add static love --- src/api/api_parsers.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index ec594dcd3..31ae28f47 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -124,7 +124,7 @@ extern "C" { Z3_CATCH; } - Z3_ast_vector Z3_parser_context_parse_stream(Z3_context c, scoped_ptr& ctx, bool owned, std::istream& is) { + static Z3_ast_vector Z3_parser_context_parse_stream(Z3_context c, scoped_ptr& ctx, bool owned, std::istream& is) { Z3_TRY; Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); @@ -163,6 +163,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + static Z3_ast_vector parse_smtlib2_stream(bool exec, Z3_context c, std::istream& is, unsigned num_sorts, Z3_symbol const _sort_names[], @@ -257,6 +258,4 @@ extern "C" { RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); Z3_CATCH_RETURN(mk_c(c)->mk_external_string(ous.str())); } - - -}; +} From b49ffb8a87782b1119fe6e088d51ec5afb802813 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Sep 2022 22:52:23 -0700 Subject: [PATCH 019/477] indentation --- src/sat/smt/arith_proof_checker.h | 132 +++++++++++++++++------------- src/sat/smt/bv_internalize.cpp | 48 ++++++----- 2 files changed, 97 insertions(+), 83 deletions(-) diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index d067303a5..1a8a8df27 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -41,16 +41,19 @@ namespace arith { m_coeff = 0; } }; - + ast_manager& m; - arith_util a; + arith_util a; vector> m_todo; - bool m_strict = false; - row m_ineq; - row m_conseq; - vector m_eqs; - vector m_ineqs; - vector m_diseqs; + bool m_strict = false; + row m_ineq; + row m_conseq; + vector m_eqs; + vector m_ineqs; + vector m_diseqs; + symbol m_farkas; + symbol m_implied_eq; + symbol m_bound; void add(row& r, expr* v, rational const& coeff) { rational coeff1; @@ -147,6 +150,8 @@ namespace arith { m_todo.push_back({coeff*coeff1, e2}); else if (a.is_mul(e, e1, e2) && a.is_uminus(e1, e3) && a.is_numeral(e3, coeff1)) m_todo.push_back({-coeff*coeff1, e2}); + else if (a.is_mul(e, e1, e2) && a.is_uminus(e2, e3) && a.is_numeral(e3, coeff1)) + m_todo.push_back({ -coeff * coeff1, e1 }); else if (a.is_mul(e, e1, e2) && a.is_numeral(e2, coeff1)) m_todo.push_back({coeff*coeff1, e1}); else if (a.is_add(e)) @@ -309,10 +314,14 @@ namespace arith { rows.push_back(row()); return rows.back(); } - public: - proof_checker(ast_manager& m): m(m), a(m) {} + proof_checker(ast_manager& m): + m(m), + a(m), + m_farkas("farkas"), + m_implied_eq("implied-eq"), + m_bound("bound") {} ~proof_checker() override {} @@ -328,7 +337,8 @@ namespace arith { bool add_ineq(rational const& coeff, expr* e, bool sign) { if (!m_diseqs.empty()) return add_literal(fresh(m_ineqs), abs(coeff), e, sign); - return add_literal(m_ineq, abs(coeff), e, sign); + else + return add_literal(m_ineq, abs(coeff), e, sign); } bool add_conseq(rational const& coeff, expr* e, bool sign) { @@ -374,60 +384,66 @@ namespace arith { else pos.mark(e, true); - if (jst->get_name() == symbol("farkas")) { - bool even = true; - rational coeff; - expr* x, *y; - for (expr* arg : *jst) { - if (even) { - if (!a.is_numeral(arg, coeff)) { - IF_VERBOSE(0, verbose_stream() << "not numeral " << mk_pp(jst, m) << "\n"); - return false; - } - } - else { - bool sign = m.is_not(arg, arg); - if (a.is_le(arg) || a.is_lt(arg) || a.is_ge(arg) || a.is_gt(arg)) - add_ineq(coeff, arg, sign); - else if (m.is_eq(arg, x, y)) { - if (sign) - add_diseq(x, y); - else - add_eq(x, y); - } - else - return false; - - if (sign && !pos.is_marked(arg)) { - units.push_back(m.mk_not(arg)); - pos.mark(arg, false); - } - else if (!sign && !neg.is_marked(arg)) { - units.push_back(arg); - neg.mark(arg, false); - } - - } - even = !even; - } - if (check_farkas()) { - return true; - } - - IF_VERBOSE(0, verbose_stream() << "did not check farkas\n" << mk_pp(jst, m) << "\n"; display(verbose_stream()); ); + if (jst->get_name() != m_farkas && + jst->get_name() != m_bound && + jst->get_name() != m_implied_eq) { + IF_VERBOSE(0, verbose_stream() << "unhandled inference " << mk_pp(jst, m) << "\n"); return false; } + bool is_bound = jst->get_name() == m_bound; + bool even = true; + rational coeff; + expr* x, * y; + unsigned j = 0; + for (expr* arg : *jst) { + if (even) { + if (!a.is_numeral(arg, coeff)) { + IF_VERBOSE(0, verbose_stream() << "not numeral " << mk_pp(jst, m) << "\n"); + return false; + } + } + else { + bool sign = m.is_not(arg, arg); + if (a.is_le(arg) || a.is_lt(arg) || a.is_ge(arg) || a.is_gt(arg)) { + if (is_bound && j + 1 == jst->get_num_args()) + add_conseq(coeff, arg, sign); + else + add_ineq(coeff, arg, sign); + } + else if (m.is_eq(arg, x, y)) { + if (sign) + add_diseq(x, y); + else + add_eq(x, y); + } + else { + IF_VERBOSE(0, verbose_stream() << "not a recognized arithmetical relation " << mk_pp(arg, m) << "\n"); + return false; + } - // todo: rules for bounds and implied-by - - IF_VERBOSE(0, verbose_stream() << "did not check " << mk_pp(jst, m) << "\n"); + if (sign && !pos.is_marked(arg)) { + units.push_back(m.mk_not(arg)); + pos.mark(arg, false); + } + else if (!sign && !neg.is_marked(arg)) { + units.push_back(arg); + neg.mark(arg, false); + } + } + even = !even; + ++j; + } + if (check()) + return true; + + IF_VERBOSE(0, verbose_stream() << "did not check condition\n" << mk_pp(jst, m) << "\n"; display(verbose_stream()); ); return false; } void register_plugins(euf::proof_checker& pc) override { - pc.register_plugin(symbol("farkas"), this); - pc.register_plugin(symbol("bound"), this); - pc.register_plugin(symbol("implied-eq"), this); + pc.register_plugin(m_farkas, this); + pc.register_plugin(m_bound, this); + pc.register_plugin(m_implied_eq, this); } }; diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 6d2dc683a..4cc161829 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -308,7 +308,6 @@ namespace bv { euf::enode* n = bool_var2enode(l.var()); if (!n->is_attached_to(get_id())) mk_var(n); - set_bit_eh(v, l, idx); } @@ -453,7 +452,9 @@ namespace bv { * * Alternative axiomatization: * e = sum bit2bool(i,n)*2^i + 2^n * (div(e, 2^n)) - * possibly term div(e,2^n) is not + * possibly term div(e,2^n) is not correct with respect to adapted semantics? + * if not, use fresh variable or similar. Overall should be much beter. + * Note: based on superb question raised at workshop on 9/1/22. */ void solver::assert_int2bv_axiom(app* n) { expr* e = nullptr; @@ -534,27 +535,27 @@ namespace bv { internalize_binary(a, bin); } - void solver::internalize_interp(app* n, std::function& ibin, std::function& iun) { + void solver::internalize_interp(app* n, std::function& ibin, std::function& iun) { bv_rewriter_params p(s().params()); expr* arg1 = n->get_arg(0); expr* arg2 = n->get_arg(1); mk_bits(get_th_var(n)); - sat::literal eq_lit; + sat::literal eq_lit; if (p.hi_div0()) { eq_lit = eq_internalize(n, ibin(arg1, arg2)); - add_unit(eq_lit); - } - else { - unsigned sz = bv.get_bv_size(n); - expr_ref zero(bv.mk_numeral(0, sz), m); - sat::literal eqZ = eq_internalize(arg2, zero); - sat::literal eqU = mk_literal(iun(arg1)); - sat::literal eqI = mk_literal(ibin(arg1, arg2)); - add_clause(~eqZ, eqU); - add_clause(eqZ, eqI); - ctx.add_aux(~eqZ, eqU); - ctx.add_aux(eqZ, eqI); - } + add_unit(eq_lit); + } + else { + unsigned sz = bv.get_bv_size(n); + expr_ref zero(bv.mk_numeral(0, sz), m); + sat::literal eqZ = eq_internalize(arg2, zero); + sat::literal eqU = mk_literal(iun(arg1)); + sat::literal eqI = mk_literal(ibin(arg1, arg2)); + add_clause(~eqZ, eqU); + add_clause(eqZ, eqI); + ctx.add_aux(~eqZ, eqU); + ctx.add_aux(eqZ, eqI); + } } void solver::internalize_unary(app* n, std::function& fn) { @@ -574,11 +575,9 @@ namespace bv { init_bits(n, bits); } - void solver::internalize_binary(app* e, std::function& fn) { SASSERT(e->get_num_args() >= 1); - expr_ref_vector bits(m), new_bits(m), arg_bits(m); - + expr_ref_vector bits(m), new_bits(m), arg_bits(m); get_arg_bits(e, 0, bits); for (unsigned i = 1; i < e->get_num_args(); ++i) { arg_bits.reset(); @@ -658,7 +657,7 @@ namespace bv { conc.push_back(arg); expr_ref r(bv.mk_concat(conc), m); mk_bits(get_th_var(e)); - sat::literal eq_lit = eq_internalize(e, r); + sat::literal eq_lit = eq_internalize(e, r); add_unit(eq_lit); } @@ -667,9 +666,8 @@ namespace bv { expr* arg = nullptr; VERIFY(bv.is_bit2bool(n, arg, idx)); euf::enode* argn = expr2enode(arg); - if (!argn->is_attached_to(get_id())) { - mk_var(argn); - } + if (!argn->is_attached_to(get_id())) + mk_var(argn); theory_var v_arg = argn->get_th_var(get_id()); SASSERT(idx < get_bv_size(v_arg)); sat::literal lit = expr2literal(n); @@ -770,7 +768,7 @@ namespace bv { e1 = bv.mk_bit2bool(o1, i); e2 = bv.mk_bit2bool(o2, i); literal eq = eq_internalize(e1, e2); - add_clause(eq, ~oeq); + add_clause(eq, ~oeq); eqs.push_back(~eq); } TRACE("bv", for (auto l : eqs) tout << mk_bounded_pp(literal2expr(l), m) << " "; tout << "\n";); From 616fc2cbd5522137b78097c247feb04e266ff780 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Sep 2022 16:22:11 -0700 Subject: [PATCH 020/477] fix #6314 Signed-off-by: Nikolaj Bjorner --- src/solver/assertions/asserted_formulas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 5780ef227..5dec90ba7 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -732,7 +732,7 @@ void asserted_formulas::bv_size_reduce_fn::simplify(justified_expr const& j, exp auto check_reduce = [&](expr* a, expr* b) { if (bv.is_extract(a, lo, hi, x) && lo > 0 && hi + 1 == bv.get_bv_size(x) && bv.is_numeral(b, r) && r == 0) { // insert x -> x[0,lo-1] ++ n into sub - new_term = bv.mk_concat(bv.mk_extract(lo - 1, 0, x), b); + new_term = bv.mk_concat(b, bv.mk_extract(lo - 1, 0, x)); m_sub.insert(x, new_term); n = j.get_fml(); return true; From 8dc8de8ccd4baae90bcbab7c41fe2403cab51502 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Sep 2022 03:09:18 -0700 Subject: [PATCH 021/477] lazy multiplier experiment this update provides a use case for and allows testing incremental multiplier compilation. --- src/sat/smt/bv_delay_internalize.cpp | 52 ++++++++++++++++++++++++++++ src/sat/smt/bv_solver.h | 11 ++++++ 2 files changed, 63 insertions(+) diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index c3c457464..0082efdd7 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -72,6 +72,55 @@ namespace bv { return expr_ref(bv.mk_numeral(val, get_bv_size(v)), m); } + /** + \brief expose the multiplication circuit lazily. + It adds clauses for multiplier output one by one to enforce + the semantics of multiplier semantics. + */ + + bool solver::check_lazy_mul(app* e, expr* arg_value, expr* mul_value) { + SASSERT(e->get_num_args() >= 2); + expr_ref_vector args(m), new_args(m), new_out(m); + lazy_mul* lz = nullptr; + rational v0, v1; + unsigned sz, diff = 0; + VERIFY(bv.is_numeral(arg_value, v0, sz)); + VERIFY(bv.is_numeral(mul_value, v1)); + for (diff = 0; diff < sz; ++diff) + if (v0.get_bit(diff) != v1.get_bit(diff)) + break; + SASSERT(diff < sz); + auto set_bits = [&](unsigned j, expr_ref_vector& bits) { + bits.reset(); + for (unsigned i = 0; i < sz; ++i) + bits.push_back(bv.mk_bit2bool(e->get_arg(0), j)); + }; + if (!m_lazymul.find(e, lz)) { + set_bits(0, args); + for (unsigned j = 1; j < e->get_num_args(); ++j) { + new_out.reset(); + set_bits(j, new_args); + m_bb.mk_multiplier(sz, args.data(), new_args.data(), new_out); + new_out.swap(args); + } + lz = alloc(lazy_mul, e, args); + m_lazymul.insert(e, lz); + ctx.push(new_obj_trail(lz)); + ctx.push(insert_obj_map(m_lazymul, e)); + } + if (lz->m_out.size() == lz->m_bits) + return false; + for (unsigned i = lz->m_bits; i <= diff; ++i) { + sat::literal bit1 = mk_literal(lz->m_out.get(i)); + sat::literal bit2 = mk_literal(bv.mk_bit2bool(e, i)); + add_equiv(bit1, bit2); + } + ctx.push(value_trail(lz->m_bits)); + IF_VERBOSE(1, verbose_stream() << "expand lazy mul " << mk_pp(e, m) << " to " << diff << "\n"); + lz->m_bits = diff; + return false; + } + bool solver::check_mul(app* e) { SASSERT(e->get_num_args() >= 2); expr_ref_vector args(m); @@ -96,6 +145,9 @@ namespace bv { if (!check_mul_invertibility(e, args, r1)) return false; + if (!check_lazy_mul(e, r1, r2)) + return false; + // Some other possible approaches: // algebraic rules: // x*(y+z), and there are nodes for x*y or x*z -> x*(y+z) = x*y + x*z diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index 46948157c..2c8fb4ae9 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -26,6 +26,15 @@ namespace euf { namespace bv { + struct lazy_mul { + expr_ref_vector m_out; + unsigned m_bits; + lazy_mul(app* a, expr_ref_vector& out): + m_out(out), + m_bits(0) { + } + }; + class solver : public euf::th_euf_solver { typedef rational numeral; typedef euf::theory_var theory_var; @@ -215,6 +224,7 @@ namespace bv { unsigned m_prop_queue_head = 0; sat::literal m_true = sat::null_literal; euf::enode_vector m_bv2ints; + obj_map m_lazymul; // internalize void insert_bv2a(bool_var bv, atom * a) { m_bool_var2atom.setx(bv, a, 0); } @@ -280,6 +290,7 @@ namespace bv { bool m_cheap_axioms{ true }; bool should_bit_blast(app * n); bool check_delay_internalized(expr* e); + bool check_lazy_mul(app* e, expr* mul_value, expr* arg_value); bool check_mul(app* e); bool check_mul_invertibility(app* n, expr_ref_vector const& arg_values, expr* value); bool check_mul_zero(app* n, expr_ref_vector const& arg_values, expr* value1, expr* value2); From fcc6e6c899bb5d3d7cd26563bcfbac08e22ae49e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Sep 2022 03:17:13 -0700 Subject: [PATCH 022/477] doc bug --- src/sat/smt/bv_delay_internalize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index 0082efdd7..4100aea8e 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -75,7 +75,7 @@ namespace bv { /** \brief expose the multiplication circuit lazily. It adds clauses for multiplier output one by one to enforce - the semantics of multiplier semantics. + the semantics of multipliers. */ bool solver::check_lazy_mul(app* e, expr* arg_value, expr* mul_value) { From 6a61efbf99a9b15b95d524f9fe8555c1350c53c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Sep 2022 13:35:53 -0700 Subject: [PATCH 023/477] add missing override Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index fe75acc84..505b0a5ed 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -198,13 +198,13 @@ public: m_proof_hint.reset(); } - void end_learned() { + void end_learned() override { m_checker.check(m_lits, m_proof_hint); m_lits.reset(); m_proof_hint.reset(); } - void end_deleted() { + void end_deleted() override { m_lits.reset(); m_proof_hint.reset(); } From 9717dadd9f7a823e5a90bc704d935d8c466e44af Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 5 Sep 2022 21:40:02 +0100 Subject: [PATCH 024/477] Use glibc's malloc_usable_size when available (#6321) --- src/util/memory_manager.cpp | 120 +++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 67f5b82b3..85d673f7c 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -13,6 +13,11 @@ Copyright (c) 2015 Microsoft Corporation #include "util/error_codes.h" #include "util/debug.h" #include "util/scoped_timer.h" +#ifdef __GLIBC__ +# include +# define HAS_MALLOC_USABLE_SIZE +#endif + // The following two function are automatically generated by the mk_make.py script. // The script collects ADD_INITIALIZER and ADD_FINALIZER commands in the .h files. // For example, rational.h contains @@ -215,7 +220,7 @@ void * memory::allocate(char const* file, int line, char const* obj, size_t s) { } #endif -#if !defined(SINGLE_THREAD) +#ifndef SINGLE_THREAD // ================================== // ================================== // THREAD LOCAL VERSION @@ -258,9 +263,14 @@ static void synchronize_counters(bool allocating) { } void memory::deallocate(void * p) { +#ifdef HAS_MALLOC_USABLE_SIZE + size_t sz = malloc_usable_size(p); + void * real_p = p; +#else size_t * sz_p = reinterpret_cast(p) - 1; size_t sz = *sz_p; void * real_p = reinterpret_cast(sz_p); +#endif g_memory_thread_alloc_size -= sz; free(real_p); if (g_memory_thread_alloc_size < -SYNCH_THRESHOLD) { @@ -269,28 +279,41 @@ void memory::deallocate(void * p) { } void * memory::allocate(size_t s) { +#ifndef HAS_MALLOC_USABLE_SIZE s = s + sizeof(size_t); // we allocate an extra field! - void * r = malloc(s); - if (r == nullptr) { - throw_out_of_memory(); - return nullptr; - } - *(static_cast(r)) = s; +#endif g_memory_thread_alloc_size += s; g_memory_thread_alloc_count += 1; if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) { synchronize_counters(true); } - + void * r = malloc(s); + if (r == nullptr) { + throw_out_of_memory(); + return nullptr; + } +#ifdef HAS_MALLOC_USABLE_SIZE + g_memory_thread_alloc_size += malloc_usable_size(r) - s; + return r; +#else + *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field +#endif } void* memory::reallocate(void *p, size_t s) { +#ifdef HAS_MALLOC_USABLE_SIZE + size_t sz = malloc_usable_size(p); + void * real_p = p; + // We may be lucky and malloc gave us enough space + if (sz >= s) + return p; +#else size_t *sz_p = reinterpret_cast(p)-1; size_t sz = *sz_p; void *real_p = reinterpret_cast(sz_p); s = s + sizeof(size_t); // we allocate an extra field! - +#endif g_memory_thread_alloc_size += s - sz; g_memory_thread_alloc_count += 1; if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) { @@ -302,74 +325,97 @@ void* memory::reallocate(void *p, size_t s) { throw_out_of_memory(); return nullptr; } +#ifdef HAS_MALLOC_USABLE_SIZE + g_memory_thread_alloc_size += malloc_usable_size(r) - s; + return r; +#else *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field +#endif } #else // ================================== // ================================== -// NO THREAD LOCAL VERSION +// SINGLE-THREAD MODE // ================================== // ================================== -// allocate & deallocate without using thread local storage +// allocate & deallocate without locking void memory::deallocate(void * p) { +#ifdef HAS_MALLOC_USABLE_SIZE + size_t sz = malloc_usable_size(p); + void * real_p = p; +#else size_t * sz_p = reinterpret_cast(p) - 1; size_t sz = *sz_p; void * real_p = reinterpret_cast(sz_p); - { - lock_guard lock(*g_memory_mux); - g_memory_alloc_size -= sz; - } +#endif + g_memory_alloc_size -= sz; free(real_p); } void * memory::allocate(size_t s) { +#ifndef HAS_MALLOC_USABLE_SIZE s = s + sizeof(size_t); // we allocate an extra field! - { - lock_guard lock(*g_memory_mux); - g_memory_alloc_size += s; - g_memory_alloc_count += 1; - if (g_memory_alloc_size > g_memory_max_used_size) - g_memory_max_used_size = g_memory_alloc_size; - if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size) - throw_out_of_memory(); - if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count) - throw_alloc_counts_exceeded(); - } +#endif + g_memory_alloc_size += s; + g_memory_alloc_count += 1; + if (g_memory_alloc_size > g_memory_max_used_size) + g_memory_max_used_size = g_memory_alloc_size; + if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size) + throw_out_of_memory(); + if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count) + throw_alloc_counts_exceeded(); + void * r = malloc(s); if (r == nullptr) { throw_out_of_memory(); return nullptr; } +#ifdef HAS_MALLOC_USABLE_SIZE + g_memory_alloc_size += malloc_usable_size(r) - s; + return r; +#else *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field +#endif } void* memory::reallocate(void *p, size_t s) { +#ifdef HAS_MALLOC_USABLE_SIZE + size_t sz = malloc_usable_size(p); + void * real_p = p; + // We may be lucky and malloc gave us enough space + if (sz >= s) + return p; +#else size_t * sz_p = reinterpret_cast(p) - 1; size_t sz = *sz_p; void * real_p = reinterpret_cast(sz_p); s = s + sizeof(size_t); // we allocate an extra field! - { - lock_guard lock(*g_memory_mux); - g_memory_alloc_size += s - sz; - g_memory_alloc_count += 1; - if (g_memory_alloc_size > g_memory_max_used_size) - g_memory_max_used_size = g_memory_alloc_size; - if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size) - throw_out_of_memory(); - if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count) - throw_alloc_counts_exceeded(); - } +#endif + g_memory_alloc_size += s - sz; + g_memory_alloc_count += 1; + if (g_memory_alloc_size > g_memory_max_used_size) + g_memory_max_used_size = g_memory_alloc_size; + if (g_memory_max_size != 0 && g_memory_alloc_size > g_memory_max_size) + throw_out_of_memory(); + if (g_memory_max_alloc_count != 0 && g_memory_alloc_count > g_memory_max_alloc_count) + throw_alloc_counts_exceeded(); + void *r = realloc(real_p, s); if (r == nullptr) { throw_out_of_memory(); return nullptr; } +#ifdef HAS_MALLOC_USABLE_SIZE + g_memory_alloc_size += malloc_usable_size(r) - s; + return r; +#else *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field +#endif } #endif From 9732169b040f7f85c5b11854e5ed30bff5ca013c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Sep 2022 13:44:16 -0700 Subject: [PATCH 025/477] #6320 --- src/ast/ast.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f60512e63..38f4dcf05 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -3027,11 +3027,23 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro found_complement = true; } } + // patch to deal with lambdas introduced during search. + // lambdas can occur in terms both internalized and in raw form. + if (!found_complement && !is_or(f1) && num_proofs == 2) { + args.push_back(proofs[0]); + args.push_back(proofs[1]); + args.push_back(mk_false()); + found_complement = true; + } + if (!found_complement) { args.append(num_proofs, (expr**)proofs); CTRACE("mk_unit_resolution_bug", !is_or(f1), tout << mk_ll_pp(f1, *this) << "\n"; for (unsigned i = 1; i < num_proofs; ++i) tout << mk_pp(proofs[i], *this) << "\n"; + tout << "facts\n"; + for (unsigned i = 0; i < num_proofs; ++i) + tout << mk_pp(get_fact(proofs[i]), *this) << "\n"; ); SASSERT(is_or(f1)); ptr_buffer new_lits; From adf6e98cdfca7450670fff1a237790de44daf900 Mon Sep 17 00:00:00 2001 From: Thomas Pani Date: Wed, 7 Sep 2022 00:29:12 +0200 Subject: [PATCH 026/477] Handle `_out(STRING)` parameters in Java API (#6325) --- scripts/update_api.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/update_api.py b/scripts/update_api.py index 37b8a31af..41a9face5 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -776,6 +776,13 @@ def mk_java(java_src, java_dir, package_name): java_wrapper.write(' jfieldID fid = jenv->GetFieldID(mc, "value", "I");\n') java_wrapper.write(' jenv->SetIntField(a%s, fid, (jint) _a%s);\n' % (i, i)) java_wrapper.write(' }\n') + elif param_type(param) == STRING: + java_wrapper.write(' {\n') + java_wrapper.write(' jclass mc = jenv->GetObjectClass(a%s);\n' % i) + java_wrapper.write(' jfieldID fid = jenv->GetFieldID(mc, "value", "Ljava/lang/String;");') + java_wrapper.write(' jstring fval = jenv->NewStringUTF(_a%s);\n' % i) + java_wrapper.write(' jenv->SetObjectField(a%s, fid, fval);\n' % i) + java_wrapper.write(' }\n') else: java_wrapper.write(' {\n') java_wrapper.write(' jclass mc = jenv->GetObjectClass(a%s);\n' % i) From 5322d4f24154b37d1e13e04731a42aa7b077ae13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Sep 2022 23:48:05 -0700 Subject: [PATCH 027/477] fix #6326 --- examples/c/test_capi.c | 23 +++++++++++++++++++++++ src/api/api_arith.cpp | 22 +++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index a6fcbdb22..6e6bf84fe 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2946,6 +2946,28 @@ void mk_model_example() { Z3_del_context(ctx); } +void divides_example() +{ + Z3_context ctx; + Z3_solver s; + Z3_ast x, number; + Z3_ast c; + + ctx = mk_context(); + s = mk_solver(ctx); + + x = mk_int_var(ctx, "x"); + number = mk_int(ctx, 2); + + c = Z3_mk_divides(ctx, number, x); + Z3_solver_assert(ctx, s, c); + + check2(ctx, s, Z3_L_TRUE); + + del_solver(ctx, s); + Z3_del_context(ctx); +} + /**@}*/ /**@}*/ @@ -2955,6 +2977,7 @@ int main() { #ifdef LOG_Z3_CALLS Z3_open_log("z3.log"); #endif + divides_example(); display_version(); simple_example(); demorgan(); diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 57f96dd6d..9671dbc26 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -22,6 +22,8 @@ Revision History: #include "ast/arith_decl_plugin.h" #include "math/polynomial/algebraic_numbers.h" +#include + #define MK_ARITH_OP(NAME, OP) MK_NARY(NAME, mk_c(c)->get_arith_fid(), OP, SKIP) #define MK_BINARY_ARITH_OP(NAME, OP) MK_BINARY(NAME, mk_c(c)->get_arith_fid(), OP, SKIP) #define MK_ARITH_PRED(NAME, OP) MK_BINARY(NAME, mk_c(c)->get_arith_fid(), OP, SKIP) @@ -88,7 +90,25 @@ extern "C" { MK_ARITH_PRED(Z3_mk_gt, OP_GT); MK_ARITH_PRED(Z3_mk_le, OP_LE); MK_ARITH_PRED(Z3_mk_ge, OP_GE); - MK_ARITH_PRED(Z3_mk_divides, OP_IDIVIDES); + + Z3_ast Z3_API Z3_mk_divides(Z3_context c, Z3_ast n1, Z3_ast n2) { + Z3_TRY; + LOG_Z3_mk_divides(c, n1, n2); + RESET_ERROR_CODE(); + rational val; + if (!is_expr(n1) || !mk_c(c)->autil().is_numeral(to_expr(n1), val) || !val.is_unsigned()) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + RETURN_Z3(nullptr); + } + parameter p(val.get_unsigned()); + expr* arg = to_expr(n2); + expr* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), OP_IDIVIDES, 1, &p, 1, &arg); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(nullptr); + } + MK_UNARY(Z3_mk_int2real, mk_c(c)->get_arith_fid(), OP_TO_REAL, SKIP); MK_UNARY(Z3_mk_real2int, mk_c(c)->get_arith_fid(), OP_TO_INT, SKIP); MK_UNARY(Z3_mk_is_int, mk_c(c)->get_arith_fid(), OP_IS_INT, SKIP); From 55d5af00cc5c1f46f17cb90cdce94fcb6f0ef012 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Sep 2022 00:04:57 -0700 Subject: [PATCH 028/477] disable bv delay until it is debugged #6324 regression introduced when filter for when to apply delay was fixed, but then it exercises delay tactic that isn't tested. --- src/sat/smt/bv_delay_internalize.cpp | 10 ++++++---- src/smt/params/smt_params_helper.pyg | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index 4100aea8e..7047ad2cb 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -145,9 +145,12 @@ namespace bv { if (!check_mul_invertibility(e, args, r1)) return false; +#if 0 + // unsound? + if (!check_lazy_mul(e, r1, r2)) return false; - +#endif // Some other possible approaches: // algebraic rules: // x*(y+z), and there are nodes for x*y or x*z -> x*(y+z) = x*y + x*z @@ -229,18 +232,17 @@ namespace bv { bool solver::check_mul_zero(app* n, expr_ref_vector const& arg_values, expr* mul_value, expr* arg_value) { SASSERT(mul_value != arg_value); SASSERT(!(bv.is_zero(mul_value) && bv.is_zero(arg_value))); - if (bv.is_zero(arg_value)) { + if (bv.is_zero(arg_value) && false) { unsigned sz = n->get_num_args(); expr_ref_vector args(m, sz, n->get_args()); for (unsigned i = 0; i < sz && !s().inconsistent(); ++i) { - args[i] = arg_value; expr_ref r(m.mk_app(n->get_decl(), args), m); set_delay_internalize(r, internalize_mode::init_bits_only_i); // do not bit-blast this multiplier. args[i] = n->get_arg(i); add_unit(eq_internalize(r, arg_value)); } - IF_VERBOSE(2, verbose_stream() << "delay internalize @" << s().scope_lvl() << "\n"); + IF_VERBOSE(2, verbose_stream() << "delay internalize @" << s().scope_lvl() << " " << mk_pp(n, m) << "\n"); return false; } if (bv.is_zero(mul_value)) { diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index d32517a23..f856689eb 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -48,7 +48,7 @@ def_module_params(module_name='smt', ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('bv.watch_diseq', BOOL, False, 'use watch lists instead of eager axioms for bit-vectors'), - ('bv.delay', BOOL, True, 'delay internalize expensive bit-vector operations'), + ('bv.delay', BOOL, False, 'delay internalize expensive bit-vector operations'), ('bv.eq_axioms', BOOL, True, 'enable redundant equality axioms for bit-vectors'), ('bv.size_reduce', BOOL, False, 'turn assertions that set the upper bits of a bit-vector to constants into a substitution that replaces the bit-vector with constant bits. Useful for minimizing circuits as many input bits to circuits are constant'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), From 25b5b985e6f025e5467ea6376410d9e8f32c5359 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Wed, 7 Sep 2022 18:02:06 +0200 Subject: [PATCH 029/477] Missing overload for conflict (#6329) --- src/api/c++/z3++.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8d3a70b8b..0275a22e1 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -4314,6 +4314,16 @@ namespace z3 { Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq); } + void conflict(expr_vector const& fixed, expr_vector const& lhs, expr_vector const& rhs) { + assert(cb); + assert(lhs.size() == rhs.size()); + expr conseq = ctx().bool_val(false); + array _fixed(fixed); + array _lhs(lhs); + array _rhs(rhs); + Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq); + } + void propagate(expr_vector const& fixed, expr const& conseq) { assert(cb); assert((Z3_context)conseq.ctx() == (Z3_context)ctx()); From 058ed3de56256aacab0be7d664310e5909a55acb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Sep 2022 12:37:18 -0700 Subject: [PATCH 030/477] fix #6331 --- src/smt/theory_bv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index b4290a198..a01fdd483 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1502,11 +1502,11 @@ namespace smt { // int2bv(bv2int(x)) = x when int2bv(bv2int(x)) has same sort as x enode* n1 = get_enode(r1); auto propagate_bv2int = [&](enode* bv2int) { - enode* bv2int_arg = bv2int->get_arg(0); + enode* bv2int_arg = get_arg(bv2int, 0); for (enode* p : enode::parents(n1->get_root())) { if (m_util.is_int2bv(p->get_expr()) && p->get_root() != bv2int_arg->get_root() && p->get_sort() == bv2int_arg->get_sort()) { enode_pair_vector eqs; - eqs.push_back({n1, p->get_arg(0) }); + eqs.push_back({n1, get_arg(p, 0) }); eqs.push_back({n1, bv2int}); justification * js = ctx.mk_justification( ext_theory_eq_propagation_justification(get_id(), ctx, 0, nullptr, eqs.size(), eqs.data(), p, bv2int_arg)); From 660bdc33e34f1c3109c42d800339e94730d9dd98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Sep 2022 08:18:30 -0700 Subject: [PATCH 031/477] fix #6330 --- src/smt/theory_array_full.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 4311ef32c..5de571255 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -604,6 +604,14 @@ namespace smt { for (unsigned i = 0; i < lam->get_num_decls(); ++i) args.push_back(mk_epsilon(lam->get_decl_sort(i)).first); expr_ref val(mk_select(args), m); + ctx.get_rewriter()(val); + if (has_quantifiers(val)) { + expr_ref fn(m.mk_fresh_const("lambda-body", m.mk_bool_sort()), m); + expr_ref eq(m.mk_eq(fn, val), m); + ctx.assert_expr(eq); + ctx.internalize_assertions(); + val = fn; + } ctx.internalize(def, false); ctx.internalize(val.get(), false); return try_assign_eq(val.get(), def); From 0629353fdc36f7f97d5f219c202bdf19877f96a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2022 16:02:11 -0700 Subject: [PATCH 032/477] add match for foldli --- src/ast/ast.h | 7 +++++++ src/ast/seq_decl_plugin.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/ast/ast.h b/src/ast/ast.h index d8eb072e3..512501226 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -531,6 +531,13 @@ public: #endif }; +#define MATCH_QUATARY(_MATCHER_) \ + bool _MATCHER_(expr const* n, expr*& a1, expr*& a2, expr *& a3, expr *& a4) const { \ + if (_MATCHER_(n) && to_app(n)->get_num_args() == 4) { \ + a1 = to_app(n)->get_arg(0); a2 = to_app(n)->get_arg(1); a3 = to_app(n)->get_arg(2); a4 = to_app(n)->get_arg(3); return true; } \ + return false; \ + } + #define MATCH_TERNARY(_MATCHER_) \ bool _MATCHER_(expr const* n, expr*& a1, expr*& a2, expr *& a3) const { \ if (_MATCHER_(n) && to_app(n)->get_num_args() == 3) { \ diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 30b4a9fb3..c6550d33a 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -403,6 +403,7 @@ public: MATCH_BINARY(is_map); MATCH_TERNARY(is_mapi); MATCH_TERNARY(is_foldl); + MATCH_QUATARY(is_foldli); MATCH_BINARY(is_last_index); MATCH_TERNARY(is_replace); MATCH_TERNARY(is_replace_re); From 4a652a4c0c088bd69cb7ea1ce0b45fdfd95c53ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2022 16:02:58 -0700 Subject: [PATCH 033/477] relax giveup condition for as-array when it occurs only in beta redex positions. --- src/smt/theory_array_full.cpp | 15 +++++++++++++-- src/smt/theory_array_full.h | 2 ++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 5de571255..360d34cd4 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -330,7 +330,8 @@ namespace smt { // Even if there was, as-array on interpreted // functions will be incomplete. // The instantiation operations are still sound to include. - found_unsupported_op(n); + m_as_array.push_back(node); + ctx.push_trail(push_back_vector(m_as_array)); instantiate_default_as_array_axiom(node); } else if (is_array_ext(n)) { @@ -815,12 +816,22 @@ namespace smt { if (r == FC_DONE && m_bapa) { r = m_bapa->final_check(); } - bool should_giveup = m_found_unsupported_op || has_propagate_up_trail(); + bool should_giveup = m_found_unsupported_op || has_propagate_up_trail() || has_non_beta_as_array(); if (r == FC_DONE && should_giveup) r = FC_GIVEUP; return r; } + bool theory_array_full::has_non_beta_as_array() { + for (enode* n : m_as_array) { + for (enode* p : n->get_parents()) + if (!is_beta_redex(p, n)) + return true; + } + return false; + } + + bool theory_array_full::instantiate_parent_stores_default(theory_var v) { SASSERT(v != null_theory_var); TRACE("array", tout << "v" << v << "\n";); diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 09a6daaec..210426e10 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -85,6 +85,8 @@ namespace smt { bool has_large_domain(app* array_term); bool has_unitary_domain(app* array_term); std::pair mk_epsilon(sort* s); + enode_vector m_as_array; + bool has_non_beta_as_array(); bool instantiate_select_const_axiom(enode* select, enode* cnst); bool instantiate_select_as_array_axiom(enode* select, enode* arr); From 831152547211a4d21d5c1bc3dff2a5a991e26bb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2022 16:03:24 -0700 Subject: [PATCH 034/477] map and fold cannot be treated as variables --- src/ast/rewriter/seq_eq_solver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ast/rewriter/seq_eq_solver.cpp b/src/ast/rewriter/seq_eq_solver.cpp index ca96512f0..6d8734bc9 100644 --- a/src/ast/rewriter/seq_eq_solver.cpp +++ b/src/ast/rewriter/seq_eq_solver.cpp @@ -438,6 +438,10 @@ namespace seq { !seq.str.is_unit(a) && !seq.str.is_itos(a) && !seq.str.is_nth_i(a) && + !seq.str.is_map(a) && + !seq.str.is_mapi(a) && + !seq.str.is_foldl(a) && + !seq.str.is_foldli(a) && !m.is_ite(a); } From 6df711254b39190fdb726058626b32026b338d67 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2022 16:03:52 -0700 Subject: [PATCH 035/477] fix type error when mapping over the empty sequence --- src/ast/rewriter/seq_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 4f70b7933..eed36af81 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -2068,7 +2068,7 @@ br_status seq_rewriter::mk_seq_replace_all(expr* a, expr* b, expr* c, expr_ref& */ br_status seq_rewriter::mk_seq_map(expr* f, expr* seqA, expr_ref& result) { if (str().is_empty(seqA)) { - result = str().mk_empty(get_array_range(f->get_sort())); + result = str().mk_empty(str().mk_seq(get_array_range(f->get_sort()))); return BR_DONE; } expr* a, *s1, *s2; @@ -2087,7 +2087,7 @@ br_status seq_rewriter::mk_seq_map(expr* f, expr* seqA, expr_ref& result) { br_status seq_rewriter::mk_seq_mapi(expr* f, expr* i, expr* seqA, expr_ref& result) { if (str().is_empty(seqA)) { - result = str().mk_empty(get_array_range(f->get_sort())); + result = str().mk_empty(str().mk_seq(get_array_range(f->get_sort()))); return BR_DONE; } expr* a, *s1, *s2; From 3900c03b72720d4283adce274f903692558c2b51 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 05:43:33 -0700 Subject: [PATCH 036/477] make error message more descriptive --- src/ast/array_decl_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 975eaa07a..5e9356865 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -122,7 +122,7 @@ bool array_decl_plugin::is_array_sort(sort* s) const { func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * domain) { if (arity != 1) { - m_manager->raise_exception("invalid const array definition, invalid domain size"); + m_manager->raise_exception("invalid const array definition, expected one argument"); return nullptr; } if (!is_array_sort(s)) { From 7a55bd568730df527b742d4ea9adcf07dc6f11a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 05:44:11 -0700 Subject: [PATCH 037/477] beta redex check is used in array theory to filter out safe as-arrays --- src/smt/smt_context.h | 4 ++-- src/smt/theory_array_full.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index f91878632..2fb888bc3 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -777,8 +777,6 @@ namespace smt { bool has_lambda(); - bool is_beta_redex(enode* p, enode* n) const; - void internalize_lambda(quantifier * q); void internalize_formula_core(app * n, bool gate_ctx); @@ -1035,6 +1033,8 @@ namespace smt { bool is_shared(enode * n) const; + bool is_beta_redex(enode* p, enode* n) const; + void assign_eq(enode * lhs, enode * rhs, eq_justification const & js) { push_eq(lhs, rhs, js); } diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 360d34cd4..d72eb4c06 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -825,8 +825,10 @@ namespace smt { bool theory_array_full::has_non_beta_as_array() { for (enode* n : m_as_array) { for (enode* p : n->get_parents()) - if (!is_beta_redex(p, n)) + if (!ctx.is_beta_redex(p, n)) { + TRACE("array", tout << "not a beta redex " << enode_pp(p, ctx) << "\n"); return true; + } } return false; } From 53611f47df768c6018fbd1e357ba9d5d473c221b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 05:48:17 -0700 Subject: [PATCH 038/477] modify clauses used by not-contains The literal "emp" can be true in the current assignment, in which case the clause cnt or emp or ~postf is true and does not contribute to propagation. This saves, potentially, for generating lemmas for postf. Add a lemma a = "" or |s| >= idx when a = tail(s, idx) The lemma ensures that length bounding on s is enforced (the branch that expands not-contains for long sequences s is closed). --- src/ast/rewriter/seq_axioms.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index 930abe4e6..de0030fc9 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -1258,9 +1258,12 @@ namespace seq { expr_ref emp = mk_eq_empty(a); expr_ref cnt = expr_ref(e, m); add_clause(cnt, ~pref); - add_clause(cnt, ~postf); + add_clause(cnt, emp, ~postf); add_clause(~emp, mk_eq_empty(tail)); add_clause(emp, mk_eq(a, seq.str.mk_concat(head, tail))); + expr* s, *idx; + if (m_sk.is_tail(tail, s, idx)) + add_clause(emp, mk_ge_e(mk_len(s), idx)); } expr_ref axioms::length_limit(expr* s, unsigned k) { From 809838fedeedbba84545a5e4bbc84c1ffdd8f977 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 11:32:18 -0700 Subject: [PATCH 039/477] solve for fold, expand rewrites under fold/map Occurrences of map and fold are interpreted. They are defined when the seq argument is expanded into a finite concatenation. The ensure this expansion takes place, each fold/map term is registered and defined through rewrites when the seq argument simplifies. --- src/smt/theory_seq.cpp | 102 +++++++++++++++++++++++++++++++++-------- src/smt/theory_seq.h | 2 + 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index de6742ec8..040171d82 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -418,6 +418,10 @@ final_check_status theory_seq::final_check_eh() { TRACEFIN("fixed_length"); return FC_CONTINUE; } + if (solve_recfuns()) { + TRACEFIN("solve_recfun"); + return FC_CONTINUE; + } if (m_unhandled_expr) { TRACEFIN("give_up"); TRACE("seq", tout << "unhandled: " << mk_pp(m_unhandled_expr, m) << "\n";); @@ -642,11 +646,9 @@ bool theory_seq::check_extensionality() { \brief check negated contains constraints. */ bool theory_seq::check_contains() { - for (unsigned i = 0; !ctx.inconsistent() && i < m_ncs.size(); ++i) { - if (solve_nc(i)) { + for (unsigned i = 0; !ctx.inconsistent() && i < m_ncs.size(); ++i) + if (solve_nc(i)) m_ncs.erase_and_swap(i--); - } - } return m_new_propagation || ctx.inconsistent(); } @@ -809,9 +811,9 @@ void theory_seq::set_conflict(enode_pair_vector const& eqs, literal_vector const } bool theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { - if (n1->get_root() == n2->get_root()) { + if (n1->get_root() == n2->get_root()) return false; - } + literal_vector lits; enode_pair_vector eqs; linearize(dep, eqs, lits); @@ -985,9 +987,8 @@ bool theory_seq::is_var(expr* a) const { bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { - if (l == r) { + if (l == r) return false; - } m_new_solution = true; m_rep.update(l, r, deps); enode* n1 = ensure_enode(l); @@ -1000,11 +1001,11 @@ bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { } bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { - unsigned idx; - expr* s; - if (m_util.str.is_empty(l)) { + if (m_util.str.is_empty(l)) std::swap(l, r); - } + + unsigned idx; + expr* s = nullptr; rational hi; if (m_sk.is_tail_u(l, s, idx) && has_length(s) && m_util.str.is_empty(r) && !upper_bound(s, hi)) { propagate_lit(deps, 0, nullptr, m_ax.mk_le(mk_len(s), idx+1)); @@ -1240,12 +1241,31 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { return false; } - +/** + * solve for fold/map (recursive function that depends on a sequence) + * Assumption: the Seq argument of fold/map expands into a concatentation of units + * The assumption is enforced by tracking the length of the seq argument. + * This is ensured in relevant_eh. + * Under the assumption, evern occurrence of fold/map gets simplified by expanding + * arguments. +*/ +bool theory_seq::solve_recfuns() { + for (unsigned i = 0; i < m_recfuns.size() && !ctx.inconsistent(); ++i) { + expr* t = m_recfuns[i]; + dependency* dep = nullptr; + expr_ref r(m); + if (canonize(t, dep, r) && r != t) { + add_solution(t, r, dep); + m_recfuns.erase_and_swap(i--); + } + } + return m_new_propagation || ctx.inconsistent(); +} bool theory_seq::solve_nc(unsigned idx) { nc const& n = m_ncs[idx]; - literal len_gt = n.len_gt(); + literal len_gt = n.len_gt(); expr_ref c(m); expr* a = nullptr, *b = nullptr; VERIFY(m_util.str.is_contains(n.contains(), a, b)); @@ -1263,10 +1283,12 @@ bool theory_seq::solve_nc(unsigned idx) { m_new_propagation = true; return false; case l_false: - break; + if (!m_sk.is_tail(a)) + add_length_limit(a, m_max_unfolding_depth, true); + m_ax.unroll_not_contains(n.contains()); + return true; } - m_ax.unroll_not_contains(n.contains()); - return true; + return false; } theory_seq::cell* theory_seq::mk_cell(cell* p, expr* e, dependency* d) { @@ -1456,7 +1478,7 @@ bool theory_seq::internalize_term(app* term) { mk_var(ctx.get_enode(term)); return true; } - + if (m.is_bool(term) && (m_util.str.is_in_re(term) || m_sk.is_skolem(term))) { bool_var bv = ctx.mk_bool_var(term); @@ -2500,8 +2522,8 @@ bool theory_seq::expand1(expr* e0, dependency*& eqs, expr_ref& result) { dependency* deps = nullptr; expr* e = m_rep.find(e0, deps); - expr* e1, *e2, *e3; - expr_ref arg1(m), arg2(m); + expr* e1, *e2, *e3, *e4; + expr_ref arg1(m), arg2(m), arg3(m), arg4(m); if (m_util.str.is_concat(e, e1, e2)) { arg1 = try_expand(e1, deps); arg2 = try_expand(e2, deps); @@ -2546,6 +2568,30 @@ bool theory_seq::expand1(expr* e0, dependency*& eqs, expr_ref& result) { if (!arg1 || !arg2) return true; result = m_util.str.mk_index(arg1, arg2, e3); } + else if (m_util.str.is_map(e, e1, e2)) { + arg2 = try_expand(e2, deps); + if (!arg2) return true; + result = m_util.str.mk_map(e1, arg2); + ctx.get_rewriter()(result); + } + else if (m_util.str.is_mapi(e, e1, e2, e3)) { + arg3 = try_expand(e3, deps); + if (!arg3) return true; + result = m_util.str.mk_mapi(e1, e2, arg3); + ctx.get_rewriter()(result); + } + else if (m_util.str.is_foldl(e, e1, e2, e3)) { + arg3 = try_expand(e3, deps); + if (!arg3) return true; + result = m_util.str.mk_foldl(e1, e2, arg3); + ctx.get_rewriter()(result); + } + else if (m_util.str.is_foldli(e, e1, e2, e3, e4)) { + arg4 = try_expand(e4, deps); + if (!arg4) return true; + result = m_util.str.mk_foldli(e1, e2, e3, arg4); + ctx.get_rewriter()(result); + } #if 0 else if (m_util.str.is_nth_i(e, e1, e2)) { arg1 = try_expand(e1, deps); @@ -2890,6 +2936,11 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4, liter void theory_seq::add_axiom(literal_vector & lits) { TRACE("seq", ctx.display_literals_verbose(tout << "assert " << lits << " :", lits) << "\n";); + + for (literal lit : lits) + if (ctx.get_assignment(lit) == l_true) + return; + for (literal lit : lits) ctx.mark_as_relevant(lit); @@ -3164,6 +3215,7 @@ void theory_seq::push_scope_eh() { m_nqs.push_scope(); m_ncs.push_scope(); m_lts.push_scope(); + m_recfuns.push_scope(); m_regex.push_scope(); } @@ -3177,6 +3229,7 @@ void theory_seq::pop_scope_eh(unsigned num_scopes) { m_nqs.pop_scope(num_scopes); m_ncs.pop_scope(num_scopes); m_lts.pop_scope(num_scopes); + m_recfuns.pop_scope(num_scopes); m_regex.pop_scope(num_scopes); m_rewrite.reset(); if (ctx.get_base_level() > ctx.get_scope_level() - num_scopes) { @@ -3214,6 +3267,15 @@ void theory_seq::relevant_eh(app* n) { add_int_string(n); } + expr* fn, *acc, *i, *s; + if (m_util.str.is_foldl(n, fn, acc, s) || + m_util.str.is_foldli(n, fn, i, acc, s) || + m_util.str.is_map(n, fn, s) || + m_util.str.is_mapi(n, fn, i, s)) { + add_length_to_eqc(s); + m_recfuns.push_back(n); + } + if (m_util.str.is_ubv2s(n)) add_ubv_string(n); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 48acb6ad8..49213dbd4 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -328,6 +328,7 @@ namespace smt { scoped_vector m_nqs; // set of current disequalities. scoped_vector m_ncs; // set of non-contains constraints. scoped_vector m_lts; // set of asserted str.<, str.<= literals + scoped_vector m_recfuns; // set of recursive functions that are defined by unfolding seq argument (map/fold) bool m_lts_checked; unsigned m_eq_id; th_union_find m_find; @@ -484,6 +485,7 @@ namespace smt { bool solve_nqs(unsigned i); bool solve_ne(unsigned i); bool solve_nc(unsigned i); + bool solve_recfuns(); bool check_ne_literals(unsigned idx, unsigned& num_undef_lits); bool propagate_ne2lit(unsigned idx); bool propagate_ne2eq(unsigned idx); From 3c8c80bbaccfdc7ecc17a128abe63896cb2fa0df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Sep 2022 12:33:28 -0700 Subject: [PATCH 040/477] fix #6336 --- src/ast/fpa/fpa2bv_converter.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 8c1ff40cd..18baba57c 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3431,8 +3431,14 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args } else { expr_ref ll(m); - ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1))); - ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz-1))); + ll = bv1; + if (bv_sz > 1) + ll = m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz - 1)); + ll = m_bv_util.mk_sign_extend(3, ll); + if (bv_sz > 1) + ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz - 1))); + else + ul = m_bv_util.mk_numeral(0, 4); ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz + 3)))); pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); in_range = m.mk_and(m.mk_not(ovfl), From edeeded4eaa0aaf6b98f32113b4a0531ed2bc8d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 18:59:00 -0700 Subject: [PATCH 041/477] remove DecRefQueue, use Z3_enable_concurrent_dec_ref (#6332) The notion of reference counted contexts never worked. The reference count to a context only ends up being 0 if the GC kicks in and disposes the various z3 objects. A call to Dispose on Context should free up all resources associated with that context. In exchange none of the resources are allowed any other operation than DecRef. The invocations of DecRef are protected by a lock and test on the context that the native pointer associated with the context is non-zero. Dispose sets the native pointer to zero. Z3_enable_concurrent_dec_ref ensures that: - calls to decref are thread safe. Other threads can operate on the context without interference. The Z3_context ensures that - z3objects allocated, but not disposed during the lifetime of Z3_context are freed when Z3_context is deleted (it triggers a debug warning, but this is now benign). --- src/api/dotnet/AST.cs | 35 +++----- src/api/dotnet/ASTMap.cs | 25 ++---- src/api/dotnet/ASTVector.cs | 24 ++---- src/api/dotnet/ApplyResult.cs | 25 ++---- src/api/dotnet/Context.cs | 146 +++------------------------------- src/api/dotnet/Fixedpoint.cs | 25 ++---- src/api/dotnet/FuncInterp.cs | 50 +++--------- src/api/dotnet/Goal.cs | 27 ++----- src/api/dotnet/Model.cs | 27 ++----- src/api/dotnet/Optimize.cs | 25 ++---- src/api/dotnet/ParamDescrs.cs | 27 ++----- src/api/dotnet/Params.cs | 27 ++----- src/api/dotnet/Probe.cs | 25 ++---- src/api/dotnet/Solver.cs | 25 ++---- src/api/dotnet/Statistics.cs | 27 ++----- src/api/dotnet/Tactic.cs | 28 ++----- src/api/dotnet/Z3Object.cs | 6 -- 17 files changed, 114 insertions(+), 460 deletions(-) diff --git a/src/api/dotnet/AST.cs b/src/api/dotnet/AST.cs index 0afff2c42..48a7175eb 100644 --- a/src/api/dotnet/AST.cs +++ b/src/api/dotnet/AST.cs @@ -208,37 +208,22 @@ namespace Microsoft.Z3 internal AST(Context ctx) : base(ctx) { Debug.Assert(ctx != null); } internal AST(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - // Console.WriteLine("AST IncRef()"); - if (Context == null || o == IntPtr.Zero) - return; - Context.AST_DRQ.IncAndClear(Context, o); - base.IncRef(o); + if (Context != null && o != IntPtr.Zero) + Native.Z3_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - // Console.WriteLine("AST DecRef()"); - if (Context == null || o == IntPtr.Zero) - return; - Context.AST_DRQ.Add(o); - base.DecRef(o); + if (Context != null && o != IntPtr.Zero) + { + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_dec_ref(Context.nCtx, o); + } + } } internal static AST Create(Context ctx, IntPtr obj) diff --git a/src/api/dotnet/ASTMap.cs b/src/api/dotnet/ASTMap.cs index 0dde04411..ad3c47106 100644 --- a/src/api/dotnet/ASTMap.cs +++ b/src/api/dotnet/ASTMap.cs @@ -125,31 +125,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_ast_map_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_ast_map_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.ASTMap_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_ast_map_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.ASTMap_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_ast_map_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/ASTVector.cs b/src/api/dotnet/ASTVector.cs index fcfa6bd65..777d7d56c 100644 --- a/src/api/dotnet/ASTVector.cs +++ b/src/api/dotnet/ASTVector.cs @@ -233,31 +233,19 @@ namespace Microsoft.Z3 internal ASTVector(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } internal ASTVector(Context ctx) : base(ctx, Native.Z3_mk_ast_vector(ctx.nCtx)) { Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_ast_vector_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_ast_vector_dec_ref(ctx.nCtx, obj); - } - }; internal override void IncRef(IntPtr o) { - Context.ASTVector_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_ast_vector_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.ASTVector_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_ast_vector_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/ApplyResult.cs b/src/api/dotnet/ApplyResult.cs index 342bf3216..728fde3d5 100644 --- a/src/api/dotnet/ApplyResult.cs +++ b/src/api/dotnet/ApplyResult.cs @@ -67,31 +67,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_apply_result_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_apply_result_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.ApplyResult_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_apply_result_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.ApplyResult_DRQ.Add(o); - base.DecRef(o); + lock(Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_apply_result_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index af982b2d4..5aabcbc39 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -75,6 +75,7 @@ namespace Microsoft.Z3 foreach (KeyValuePair kv in settings) Native.Z3_set_param_value(cfg, kv.Key, kv.Value); m_ctx = Native.Z3_mk_context_rc(cfg); + Native.Z3_enable_concurrent_dec_ref(m_ctx); Native.Z3_del_config(cfg); InitContext(); } @@ -4852,123 +4853,9 @@ namespace Microsoft.Z3 private void ObjectInvariant() { - Debug.Assert(m_AST_DRQ != null); - Debug.Assert(m_ASTMap_DRQ != null); - Debug.Assert(m_ASTVector_DRQ != null); - Debug.Assert(m_ApplyResult_DRQ != null); - Debug.Assert(m_FuncEntry_DRQ != null); - Debug.Assert(m_FuncInterp_DRQ != null); - Debug.Assert(m_Goal_DRQ != null); - Debug.Assert(m_Model_DRQ != null); - Debug.Assert(m_Params_DRQ != null); - Debug.Assert(m_ParamDescrs_DRQ != null); - Debug.Assert(m_Probe_DRQ != null); - Debug.Assert(m_Solver_DRQ != null); - Debug.Assert(m_Statistics_DRQ != null); - Debug.Assert(m_Tactic_DRQ != null); - Debug.Assert(m_Fixedpoint_DRQ != null); - Debug.Assert(m_Optimize_DRQ != null); + // none } - readonly private AST.DecRefQueue m_AST_DRQ = new AST.DecRefQueue(); - readonly private ASTMap.DecRefQueue m_ASTMap_DRQ = new ASTMap.DecRefQueue(10); - readonly private ASTVector.DecRefQueue m_ASTVector_DRQ = new ASTVector.DecRefQueue(10); - readonly private ApplyResult.DecRefQueue m_ApplyResult_DRQ = new ApplyResult.DecRefQueue(10); - readonly private FuncInterp.Entry.DecRefQueue m_FuncEntry_DRQ = new FuncInterp.Entry.DecRefQueue(10); - readonly private FuncInterp.DecRefQueue m_FuncInterp_DRQ = new FuncInterp.DecRefQueue(10); - readonly private Goal.DecRefQueue m_Goal_DRQ = new Goal.DecRefQueue(10); - readonly private Model.DecRefQueue m_Model_DRQ = new Model.DecRefQueue(10); - readonly private Params.DecRefQueue m_Params_DRQ = new Params.DecRefQueue(10); - readonly private ParamDescrs.DecRefQueue m_ParamDescrs_DRQ = new ParamDescrs.DecRefQueue(10); - readonly private Probe.DecRefQueue m_Probe_DRQ = new Probe.DecRefQueue(10); - readonly private Solver.DecRefQueue m_Solver_DRQ = new Solver.DecRefQueue(10); - readonly private Statistics.DecRefQueue m_Statistics_DRQ = new Statistics.DecRefQueue(10); - readonly private Tactic.DecRefQueue m_Tactic_DRQ = new Tactic.DecRefQueue(10); - readonly private Fixedpoint.DecRefQueue m_Fixedpoint_DRQ = new Fixedpoint.DecRefQueue(10); - readonly private Optimize.DecRefQueue m_Optimize_DRQ = new Optimize.DecRefQueue(10); - - /// - /// AST DRQ - /// - public IDecRefQueue AST_DRQ { get { return m_AST_DRQ; } } - - /// - /// ASTMap DRQ - /// - public IDecRefQueue ASTMap_DRQ { get { return m_ASTMap_DRQ; } } - - /// - /// ASTVector DRQ - /// - public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } } - - /// - /// ApplyResult DRQ - /// - public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } } - - /// - /// FuncEntry DRQ - /// - public IDecRefQueue FuncEntry_DRQ { get { return m_FuncEntry_DRQ; } } - - /// - /// FuncInterp DRQ - /// - public IDecRefQueue FuncInterp_DRQ { get { return m_FuncInterp_DRQ; } } - - /// - /// Goal DRQ - /// - public IDecRefQueue Goal_DRQ { get { return m_Goal_DRQ; } } - - /// - /// Model DRQ - /// - public IDecRefQueue Model_DRQ { get { return m_Model_DRQ; } } - - /// - /// Params DRQ - /// - public IDecRefQueue Params_DRQ { get { return m_Params_DRQ; } } - - /// - /// ParamDescrs DRQ - /// - public IDecRefQueue ParamDescrs_DRQ { get { return m_ParamDescrs_DRQ; } } - - /// - /// Probe DRQ - /// - public IDecRefQueue Probe_DRQ { get { return m_Probe_DRQ; } } - - /// - /// Solver DRQ - /// - public IDecRefQueue Solver_DRQ { get { return m_Solver_DRQ; } } - - /// - /// Statistics DRQ - /// - public IDecRefQueue Statistics_DRQ { get { return m_Statistics_DRQ; } } - - /// - /// Tactic DRQ - /// - public IDecRefQueue Tactic_DRQ { get { return m_Tactic_DRQ; } } - - /// - /// FixedPoint DRQ - /// - public IDecRefQueue Fixedpoint_DRQ { get { return m_Fixedpoint_DRQ; } } - - /// - /// Optimize DRQ - /// - public IDecRefQueue Optimize_DRQ { get { return m_Fixedpoint_DRQ; } } - - internal long refCount = 0; - /// /// Finalizer. /// @@ -4984,22 +4871,6 @@ namespace Microsoft.Z3 public void Dispose() { // Console.WriteLine("Context Dispose from " + System.Threading.Thread.CurrentThread.ManagedThreadId); - AST_DRQ.Clear(this); - ASTMap_DRQ.Clear(this); - ASTVector_DRQ.Clear(this); - ApplyResult_DRQ.Clear(this); - FuncEntry_DRQ.Clear(this); - FuncInterp_DRQ.Clear(this); - Goal_DRQ.Clear(this); - Model_DRQ.Clear(this); - Params_DRQ.Clear(this); - ParamDescrs_DRQ.Clear(this); - Probe_DRQ.Clear(this); - Solver_DRQ.Clear(this); - Statistics_DRQ.Clear(this); - Tactic_DRQ.Clear(this); - Fixedpoint_DRQ.Clear(this); - Optimize_DRQ.Clear(this); if (m_boolSort != null) m_boolSort.Dispose(); if (m_intSort != null) m_intSort.Dispose(); @@ -5011,13 +4882,16 @@ namespace Microsoft.Z3 m_realSort = null; m_stringSort = null; m_charSort = null; - if (refCount == 0 && m_ctx != IntPtr.Zero) + if (m_ctx != IntPtr.Zero) { - m_n_err_handler = null; IntPtr ctx = m_ctx; - m_ctx = IntPtr.Zero; - if (!is_external) - Native.Z3_del_context(ctx); + lock (this) + { + m_n_err_handler = null; + m_ctx = IntPtr.Zero; + } + if (!is_external) + Native.Z3_del_context(ctx); } else GC.ReRegisterForFinalize(this); diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index 15560d829..2edae1e2a 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -318,31 +318,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_fixedpoint_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_fixedpoint_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.Fixedpoint_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_fixedpoint_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Fixedpoint_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_fixedpoint_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/FuncInterp.cs b/src/api/dotnet/FuncInterp.cs index 6924049d3..fec6eab95 100644 --- a/src/api/dotnet/FuncInterp.cs +++ b/src/api/dotnet/FuncInterp.cs @@ -85,31 +85,18 @@ namespace Microsoft.Z3 #region Internal internal Entry(Context ctx, IntPtr obj) : base(ctx, obj) { Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_func_entry_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_func_entry_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.FuncEntry_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_func_entry_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.FuncEntry_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_func_entry_dec_ref(Context.nCtx, o); + } } #endregion }; @@ -190,31 +177,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_func_interp_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_func_interp_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.FuncInterp_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_func_interp_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.FuncInterp_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_func_interp_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index c096c0755..8183c7a79 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -252,33 +252,20 @@ namespace Microsoft.Z3 : base(ctx, Native.Z3_mk_goal(ctx.nCtx, (byte)(models ? 1 : 0), (byte)(unsatCores ? 1 : 0), (byte)(proofs ? 1 : 0))) { Debug.Assert(ctx != null); - } - - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_goal_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_goal_dec_ref(ctx.nCtx, obj); - } - }; + } internal override void IncRef(IntPtr o) { - Context.Goal_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_goal_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Goal_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_goal_dec_ref(Context.nCtx, o); + } } #endregion diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index c35c0a727..343b2beee 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -302,33 +302,20 @@ namespace Microsoft.Z3 : base(ctx, obj) { Debug.Assert(ctx != null); - } - - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_model_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_model_dec_ref(ctx.nCtx, obj); - } - }; + } internal override void IncRef(IntPtr o) { - Context.Model_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_model_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Model_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_model_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index ecd5e8e82..0694faabe 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -440,31 +440,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_optimize_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_optimize_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.Optimize_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_optimize_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Optimize_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_optimize_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/ParamDescrs.cs b/src/api/dotnet/ParamDescrs.cs index fbfb9cd16..1975037e3 100644 --- a/src/api/dotnet/ParamDescrs.cs +++ b/src/api/dotnet/ParamDescrs.cs @@ -91,33 +91,20 @@ namespace Microsoft.Z3 : base(ctx, obj) { Debug.Assert(ctx != null); - } - - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_param_descrs_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_param_descrs_dec_ref(ctx.nCtx, obj); - } - }; + } internal override void IncRef(IntPtr o) { - Context.ParamDescrs_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_param_descrs_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.ParamDescrs_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_param_descrs_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index e5926934a..64dd34968 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -147,33 +147,20 @@ namespace Microsoft.Z3 : base(ctx, Native.Z3_mk_params(ctx.nCtx)) { Debug.Assert(ctx != null); - } - - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_params_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_params_dec_ref(ctx.nCtx, obj); - } - }; + } internal override void IncRef(IntPtr o) { - Context.Params_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_params_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Params_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_params_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Probe.cs b/src/api/dotnet/Probe.cs index 5cdee79a2..e0457c2fe 100644 --- a/src/api/dotnet/Probe.cs +++ b/src/api/dotnet/Probe.cs @@ -70,31 +70,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_probe_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_probe_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.Probe_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_probe_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Probe_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_probe_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 52f2ad993..00b5117ea 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -538,31 +538,18 @@ namespace Microsoft.Z3 this.BacktrackLevel = uint.MaxValue; } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_solver_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_solver_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.Solver_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_solver_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Solver_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_solver_dec_ref(Context.nCtx, o); + } } private Status lboolToStatus(Z3_lbool r) diff --git a/src/api/dotnet/Statistics.cs b/src/api/dotnet/Statistics.cs index f6d72e0c7..1811951a2 100644 --- a/src/api/dotnet/Statistics.cs +++ b/src/api/dotnet/Statistics.cs @@ -19,8 +19,6 @@ Notes: using System; using System.Diagnostics; - - namespace Microsoft.Z3 { @@ -189,31 +187,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_stats_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_stats_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.Statistics_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_stats_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Statistics_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_stats_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Tactic.cs b/src/api/dotnet/Tactic.cs index 96b6da170..d87b8bc48 100644 --- a/src/api/dotnet/Tactic.cs +++ b/src/api/dotnet/Tactic.cs @@ -107,34 +107,18 @@ namespace Microsoft.Z3 Debug.Assert(ctx != null); } - /// - /// DecRefQueue - /// - internal class DecRefQueue : IDecRefQueue - { - public DecRefQueue() : base() { } - public DecRefQueue(uint move_limit) : base(move_limit) { } - internal override void IncRef(Context ctx, IntPtr obj) - { - Native.Z3_tactic_inc_ref(ctx.nCtx, obj); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Native.Z3_tactic_dec_ref(ctx.nCtx, obj); - } - }; - internal override void IncRef(IntPtr o) { - Context.Tactic_DRQ.IncAndClear(Context, o); - base.IncRef(o); + Native.Z3_tactic_inc_ref(Context.nCtx, o); } internal override void DecRef(IntPtr o) { - Context.Tactic_DRQ.Add(o); - base.DecRef(o); + lock (Context) + { + if (Context.nCtx != IntPtr.Zero) + Native.Z3_tactic_dec_ref(Context.nCtx, o); + } } #endregion } diff --git a/src/api/dotnet/Z3Object.cs b/src/api/dotnet/Z3Object.cs index 432885b66..1affa9d17 100644 --- a/src/api/dotnet/Z3Object.cs +++ b/src/api/dotnet/Z3Object.cs @@ -52,8 +52,6 @@ namespace Microsoft.Z3 if (m_ctx != null) { - if (Interlocked.Decrement(ref m_ctx.refCount) == 0) - GC.ReRegisterForFinalize(m_ctx); m_ctx = null; } @@ -76,16 +74,12 @@ namespace Microsoft.Z3 internal Z3Object(Context ctx) { Debug.Assert(ctx != null); - - Interlocked.Increment(ref ctx.refCount); m_ctx = ctx; } internal Z3Object(Context ctx, IntPtr obj) { Debug.Assert(ctx != null); - - Interlocked.Increment(ref ctx.refCount); m_ctx = ctx; IncRef(obj); m_n_obj = obj; From ff679e0fcebb8ce4591669cf7b283dee739cdb65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 19:02:37 -0700 Subject: [PATCH 042/477] increment version number --- CMakeLists.txt | 2 +- examples/dotnet/CMakeLists.txt | 4 ++-- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5f8ba1b6..2cd54eded 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.11.2.0 LANGUAGES CXX) +project(Z3 VERSION 4.11.3.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt index b07ae4219..c3773af7b 100644 --- a/examples/dotnet/CMakeLists.txt +++ b/examples/dotnet/CMakeLists.txt @@ -24,9 +24,9 @@ if(UNIX AND NOT APPLE) add_custom_target( z3_dotnet_test_manual_copy_assembly_hack ALL - COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${PROJECT_BINARY_DIR}/dotnet/netcoreapp2.0/ + COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${PROJECT_BINARY_DIR}/dotnet/netcoreapp3.1/ # hack the libz3 entry in deps so it's easy enough for dotnet to reach it... - COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${PROJECT_BINARY_DIR}/dotnet/netcoreapp2.0/dotnet.deps.json + COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${PROJECT_BINARY_DIR}/dotnet/netcoreapp3.1/dotnet.deps.json ) add_dependencies(z3_dotnet_test_manual_copy_assembly_hack BUILD_dotnet) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 78ecf8b5a..697793b3f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 11, 2, 0) # express a default build version or pick up ci build version + set_version(4, 11, 3, 0) # express a default build version or pick up ci build version # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 3d69b0ef2..ed7c9cb12 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,7 +1,7 @@ variables: Major: '4' Minor: '11' - Patch: '2' + Patch: '3' AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.DefinitionName) diff --git a/scripts/release.yml b/scripts/release.yml index ac0a951af..c48457c1c 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.11.2' + ReleaseVersion: '4.11.3' stages: From a5ad1097072e63e110c4d72dd9eec15c9a40ec4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2022 19:06:23 -0700 Subject: [PATCH 043/477] suppress debug warnings when concurrent dec-ref is enabled. The contract with the client is that it doesn't invoke methods on auxiliary objects after the context is deleted. The client is not required to decrement reference counts Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index a16341955..6d9af74a0 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -153,7 +153,7 @@ namespace api { flush_objects(); for (auto& kv : m_allocated_objects) { api::object* val = kv.m_value; - DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", kv.m_key, typeid(*val).name());); + DEBUG_CODE(if (!m_concurrent_dec_ref) warning_msg("Uncollected memory: %d: %s", kv.m_key, typeid(*val).name());); dealloc(val); } if (m_params.owns_manager()) From 9b7c66ea7b93e49318b79afd8eb554fb246b8c15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Sep 2022 08:41:43 -0700 Subject: [PATCH 044/477] revert update to netcoreapp version Signed-off-by: Nikolaj Bjorner --- examples/dotnet/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/dotnet/CMakeLists.txt b/examples/dotnet/CMakeLists.txt index c3773af7b..b07ae4219 100644 --- a/examples/dotnet/CMakeLists.txt +++ b/examples/dotnet/CMakeLists.txt @@ -24,9 +24,9 @@ if(UNIX AND NOT APPLE) add_custom_target( z3_dotnet_test_manual_copy_assembly_hack ALL - COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${PROJECT_BINARY_DIR}/dotnet/netcoreapp3.1/ + COMMAND ${CMAKE_COMMAND} -E copy ${z3_dotnet_test_manual_copy_deps} ${PROJECT_BINARY_DIR}/dotnet/netcoreapp2.0/ # hack the libz3 entry in deps so it's easy enough for dotnet to reach it... - COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${PROJECT_BINARY_DIR}/dotnet/netcoreapp3.1/dotnet.deps.json + COMMAND sed \"s/runtimes\\/.*libz3\\.so/libz3.so/\" -i ${PROJECT_BINARY_DIR}/dotnet/netcoreapp2.0/dotnet.deps.json ) add_dependencies(z3_dotnet_test_manual_copy_assembly_hack BUILD_dotnet) From c30b8842470203b1ae7ca02d08afdb0ad58f2a48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Sep 2022 11:01:24 -0700 Subject: [PATCH 045/477] fix #6340 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_array_full.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index d72eb4c06..120e12418 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -607,7 +607,7 @@ namespace smt { expr_ref val(mk_select(args), m); ctx.get_rewriter()(val); if (has_quantifiers(val)) { - expr_ref fn(m.mk_fresh_const("lambda-body", m.mk_bool_sort()), m); + expr_ref fn(m.mk_fresh_const("lambda-body", val->get_sort()), m); expr_ref eq(m.mk_eq(fn, val), m); ctx.assert_expr(eq); ctx.internalize_assertions(); From fd5448d26b00b6672ce90985ada529808ccdd429 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Sep 2022 17:01:45 -0700 Subject: [PATCH 046/477] fix #6340 - again Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 5 +++-- src/smt/smt_context.h | 9 +++++---- src/smt/smt_internalizer.cpp | 8 ++++++-- src/smt/theory_array_base.cpp | 2 ++ 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index b4f6a2309..bc8f9ea64 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3198,14 +3198,15 @@ namespace smt { void context::internalize_assertions() { if (get_cancel_flag()) return; + if (m_internalizing_assertions) return; + flet _internalizing(m_internalizing_assertions, true); TRACE("internalize_assertions", tout << "internalize_assertions()...\n";); timeit tt(get_verbosity_level() >= 100, "smt.preprocessing"); reduce_assertions(); if (get_cancel_flag()) return; if (!m_asserted_formulas.inconsistent()) { - unsigned sz = m_asserted_formulas.get_num_formulas(); unsigned qhead = m_asserted_formulas.get_qhead(); - while (qhead < sz) { + while (qhead < m_asserted_formulas.get_num_formulas()) { if (get_cancel_flag()) { m_asserted_formulas.commit(qhead); return; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 2fb888bc3..7ca2e1c63 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -107,11 +107,12 @@ namespace smt { ptr_vector m_justifications; - unsigned m_final_check_idx; // circular counter used for implementing fairness + unsigned m_final_check_idx = 0; // circular counter used for implementing fairness - bool m_is_auxiliary { false }; // used to prevent unwanted information from being logged. - class parallel* m_par { nullptr }; - unsigned m_par_index { 0 }; + bool m_is_auxiliary = false; // used to prevent unwanted information from being logged. + class parallel* m_par = nullptr; + unsigned m_par_index = 0; + bool m_internalizing_assertions = false; // ----------------------------------- // diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index d86594f0f..d87a4f971 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -615,11 +615,15 @@ namespace smt { bool context::has_lambda() { for (auto const & [n, q] : m_lambdas) { - if (n->get_class_size() != 1) + if (n->get_class_size() != 1) { + TRACE("context", tout << "class size " << n->get_class_size() << " " << enode_pp(n, *this) << "\n"); return true; + } for (enode* p : enode::parents(n)) - if (!is_beta_redex(p, n)) + if (!is_beta_redex(p, n)) { + TRACE("context", tout << "not a beta redex " << enode_pp(p, *this) << "\n"); return true; + } } return false; } diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index e71630fa4..a05fbc68d 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -498,6 +498,8 @@ namespace smt { return p->get_arg(0)->get_root() == n->get_root(); if (is_map(p)) return true; + if (is_store(p)) + return true; return false; } From a6a5985f8ecc42bd8fffc40b97557a79489666ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Sep 2022 17:19:48 -0700 Subject: [PATCH 047/477] fix #6341 Signed-off-by: Nikolaj Bjorner --- src/math/lp/nla_grobner.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/math/lp/nla_grobner.cpp b/src/math/lp/nla_grobner.cpp index 51604fb47..974c48d14 100644 --- a/src/math/lp/nla_grobner.cpp +++ b/src/math/lp/nla_grobner.cpp @@ -45,14 +45,19 @@ namespace nla { if (is_conflicting()) return; - if (propagate_bounds()) - return; + try { + if (propagate_bounds()) + return; - if (propagate_eqs()) - return; + if (propagate_eqs()) + return; - if (propagate_factorization()) - return; + if (propagate_factorization()) + return; + } + catch (...) { + + } if (quota > 1) quota--; From 34969b71ee246e7b7e1c3b13dd782ba19c630bcd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Sep 2022 19:58:32 -0700 Subject: [PATCH 048/477] #6340 again - reduce new assertions in fresh iteration Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 42 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index bc8f9ea64..e318d4771 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3202,26 +3202,34 @@ namespace smt { flet _internalizing(m_internalizing_assertions, true); TRACE("internalize_assertions", tout << "internalize_assertions()...\n";); timeit tt(get_verbosity_level() >= 100, "smt.preprocessing"); - reduce_assertions(); - if (get_cancel_flag()) return; - if (!m_asserted_formulas.inconsistent()) { - unsigned qhead = m_asserted_formulas.get_qhead(); - while (qhead < m_asserted_formulas.get_num_formulas()) { - if (get_cancel_flag()) { - m_asserted_formulas.commit(qhead); - return; + unsigned qhead = 0; + do { + reduce_assertions(); + if (get_cancel_flag()) + return; + qhead = m_asserted_formulas.get_qhead(); + if (!m_asserted_formulas.inconsistent()) { + unsigned sz = m_asserted_formulas.get_num_formulas(); + while (qhead < sz) { + if (get_cancel_flag()) { + m_asserted_formulas.commit(qhead); + return; + } + expr * f = m_asserted_formulas.get_formula(qhead); + proof * pr = m_asserted_formulas.get_formula_proof(qhead); + SASSERT(!pr || f == m.get_fact(pr)); + internalize_assertion(f, pr, 0); + qhead++; } - expr * f = m_asserted_formulas.get_formula(qhead); - proof * pr = m_asserted_formulas.get_formula_proof(qhead); - SASSERT(!pr || f == m.get_fact(pr)); - internalize_assertion(f, pr, 0); - qhead++; + m_asserted_formulas.commit(); + } + if (m_asserted_formulas.inconsistent() && !inconsistent()) { + asserted_inconsistent(); + break; } - m_asserted_formulas.commit(); - } - if (m_asserted_formulas.inconsistent() && !inconsistent()) { - asserted_inconsistent(); } + while (qhead < m_asserted_formulas.get_num_formulas()); + TRACE("internalize_assertions", tout << "after internalize_assertions()...\n"; tout << "inconsistent: " << inconsistent() << "\n";); TRACE("after_internalize_assertions", display(tout);); From 16ef89905d8b5702347021271bdd071d5bf80277 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 14 Sep 2022 11:50:53 +0100 Subject: [PATCH 049/477] fix infinite loop in internalize --- src/api/api_stats.cpp | 2 +- src/smt/smt_context.cpp | 35 +++++++++++++++++------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index c90850404..a3b8bacf0 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -28,7 +28,7 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; to_stats_ref(s).display_smt2(buffer); - std::string result = buffer.str(); + std::string result = std::move(buffer).str(); // Hack for removing the trailing '\n' SASSERT(result.size() > 0); result.resize(result.size()-1); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index e318d4771..1bae0ef86 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3207,26 +3207,25 @@ namespace smt { reduce_assertions(); if (get_cancel_flag()) return; - qhead = m_asserted_formulas.get_qhead(); - if (!m_asserted_formulas.inconsistent()) { - unsigned sz = m_asserted_formulas.get_num_formulas(); - while (qhead < sz) { - if (get_cancel_flag()) { - m_asserted_formulas.commit(qhead); - return; - } - expr * f = m_asserted_formulas.get_formula(qhead); - proof * pr = m_asserted_formulas.get_formula_proof(qhead); - SASSERT(!pr || f == m.get_fact(pr)); - internalize_assertion(f, pr, 0); - qhead++; - } - m_asserted_formulas.commit(); - } - if (m_asserted_formulas.inconsistent() && !inconsistent()) { - asserted_inconsistent(); + if (m_asserted_formulas.inconsistent()) { + if (!inconsistent()) + asserted_inconsistent(); break; } + qhead = m_asserted_formulas.get_qhead(); + unsigned sz = m_asserted_formulas.get_num_formulas(); + while (qhead < sz) { + if (get_cancel_flag()) { + m_asserted_formulas.commit(qhead); + return; + } + expr * f = m_asserted_formulas.get_formula(qhead); + proof * pr = m_asserted_formulas.get_formula_proof(qhead); + SASSERT(!pr || f == m.get_fact(pr)); + internalize_assertion(f, pr, 0); + ++qhead; + } + m_asserted_formulas.commit(); } while (qhead < m_asserted_formulas.get_num_formulas()); From c47ca341b7d05aec8d5260ee181c78c4c958bf13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Sep 2022 10:17:00 -0700 Subject: [PATCH 050/477] fix #6343 The bug was that axiom generation was not enabled on last_index, so no axioms got created to constrain last-index. With default settings the solver is now very slow on this example. It is related to that the smallest size of a satisfying assignment is above 24. Pending a good heuristic to find initial seeds and increments for iterative deepening, I am adding another parameter smt.seq.min_unfolding that when set to 30 helps for this example. --- src/ast/rewriter/seq_axioms.cpp | 2 ++ src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_seq_params.cpp | 1 + src/smt/params/theory_seq_params.h | 1 + src/smt/theory_seq.cpp | 2 ++ 5 files changed, 7 insertions(+) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index de0030fc9..c7dde763f 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -509,6 +509,8 @@ namespace seq { } /** + i = last_indexof(t, s): + !contains(t, s) => i = -1 |t| = 0 => |s| = 0 or i = -1 |t| = 0 & |s| = 0 => i = 0 diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index f856689eb..8dfcf5d3b 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -107,6 +107,7 @@ def_module_params(module_name='smt', ('seq.split_w_len', BOOL, True, 'enable splitting guided by length constraints'), ('seq.validate', BOOL, False, 'enable self-validation of theory axioms created by seq theory'), ('seq.max_unfolding', UINT, 1000000000, 'maximal unfolding depth for checking string equations and regular expressions'), + ('seq.min_unfolding', UINT, 1, 'initial bound for strings whose lengths are bounded by iterative deepening. Set this to a higher value if there are only models with larger string lengths'), ('str.strong_arrangements', BOOL, True, 'assert equivalences instead of implications when generating string arrangement axioms'), ('str.aggressive_length_testing', BOOL, False, 'prioritize testing concrete length values over generating more options'), ('str.aggressive_value_testing', BOOL, False, 'prioritize testing concrete string constant values over generating more options'), diff --git a/src/smt/params/theory_seq_params.cpp b/src/smt/params/theory_seq_params.cpp index 196faf387..290b2631d 100644 --- a/src/smt/params/theory_seq_params.cpp +++ b/src/smt/params/theory_seq_params.cpp @@ -22,4 +22,5 @@ void theory_seq_params::updt_params(params_ref const & _p) { m_split_w_len = p.seq_split_w_len(); m_seq_validate = p.seq_validate(); m_seq_max_unfolding = p.seq_max_unfolding(); + m_seq_min_unfolding = p.seq_min_unfolding(); } diff --git a/src/smt/params/theory_seq_params.h b/src/smt/params/theory_seq_params.h index 845411039..f964088eb 100644 --- a/src/smt/params/theory_seq_params.h +++ b/src/smt/params/theory_seq_params.h @@ -25,6 +25,7 @@ struct theory_seq_params { bool m_split_w_len = false; bool m_seq_validate = false; unsigned m_seq_max_unfolding = UINT_MAX/4; + unsigned m_seq_min_unfolding = 1; theory_seq_params(params_ref const & p = params_ref()) { updt_params(p); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 040171d82..5712d1d41 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -304,6 +304,7 @@ void theory_seq::init() { m_ax.add_axiom5 = add_ax; m_ax.mk_eq_empty2 = mk_eq_emp; m_arith_value.init(&ctx); + m_max_unfolding_depth = ctx.get_fparams().m_seq_min_unfolding; } #define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(20, verbose_stream() << s << "\n"); } @@ -3256,6 +3257,7 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_from_code(n) || m_util.str.is_to_code(n) || m_util.str.is_unit(n) || + m_util.str.is_last_index(n) || m_util.str.is_length(n) || /* m_util.str.is_replace_all(n) || uncomment to enable axiomatization */ m_util.str.is_le(n)) { From af258d172022e4b8d9781749104f1de0fd5ee05f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Sep 2022 07:38:02 -0700 Subject: [PATCH 051/477] add method for accessing i'th domain sort in array #6344 --- src/api/api_array.cpp | 23 ++++++++++++----------- src/api/java/ArraySort.java | 12 ++++++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index 7aa3a87bf..cb254dbdd 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -294,14 +294,19 @@ extern "C" { return Z3_mk_store(c, set, elem, Z3_mk_false(c)); } + static bool is_array_sort(Z3_context c, Z3_sort t) { + return + to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && + to_sort(t)->get_decl_kind() == ARRAY_SORT; + } + Z3_sort Z3_API Z3_get_array_sort_domain(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_array_sort_domain(c, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t, nullptr); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && - to_sort(t)->get_decl_kind() == ARRAY_SORT) { - Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(0).get_ast()); + if (is_array_sort(c, t)) { + Z3_sort r = of_sort(get_array_domain(to_sort(t), 0)); RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); @@ -314,10 +319,8 @@ extern "C" { LOG_Z3_get_array_sort_domain_n(c, t, idx); RESET_ERROR_CODE(); CHECK_VALID_AST(t, nullptr); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && - to_sort(t)->get_decl_kind() == ARRAY_SORT && - get_array_arity(to_sort(t)) > idx) { - Z3_sort r = reinterpret_cast(get_array_domain(to_sort(t), idx)); + if (is_array_sort(c, t) && get_array_arity(to_sort(t)) > idx) { + Z3_sort r = of_sort(get_array_domain(to_sort(t), idx)); RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); @@ -330,10 +333,8 @@ extern "C" { LOG_Z3_get_array_sort_range(c, t); RESET_ERROR_CODE(); CHECK_VALID_AST(t, nullptr); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && - to_sort(t)->get_decl_kind() == ARRAY_SORT) { - unsigned n = to_sort(t)->get_num_parameters(); - Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(n-1).get_ast()); + if (is_array_sort(c, t)) { + Z3_sort r = of_sort(get_array_range(to_sort(t))); RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); diff --git a/src/api/java/ArraySort.java b/src/api/java/ArraySort.java index 30f4178fa..3d3ef3041 100644 --- a/src/api/java/ArraySort.java +++ b/src/api/java/ArraySort.java @@ -35,6 +35,18 @@ public class ArraySort extends Sort Native.getArraySortDomain(getContext().nCtx(), getNativeObject())); } + /** + * The domain of a multi-dimensional array sort. + * @throws Z3Exception + * @throws Z3Exception on error + * @return a sort + **/ + public D getDomain(int idx) + { + return (D) Sort.create(getContext(), + Native.getArraySortDomainN(getContext().nCtx(), getNativeObject(), idx)); + } + /** * The range of the array sort. * @throws Z3Exception From 088898834caca29168f95f558d460648f3fe8899 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Sep 2022 07:41:00 -0700 Subject: [PATCH 052/477] filter length limits to be non-skolems and under concat/""/unit --- src/ast/rewriter/seq_skolem.cpp | 18 ++++++++++++++++++ src/ast/rewriter/seq_skolem.h | 15 ++++++++++----- src/smt/theory_seq.cpp | 17 +++++++++++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/seq_skolem.cpp b/src/ast/rewriter/seq_skolem.cpp index c2e948216..96b3df3ed 100644 --- a/src/ast/rewriter/seq_skolem.cpp +++ b/src/ast/rewriter/seq_skolem.cpp @@ -26,10 +26,14 @@ skolem::skolem(ast_manager& m, th_rewriter& rw): m_suffix = "seq.s.prefix"; m_accept = "aut.accept"; m_tail = "seq.tail"; + m_left = "seq.left"; + m_right = "seq.right"; m_seq_first = "seq.first"; m_seq_last = "seq.last"; m_indexof_left = "seq.idx.l"; m_indexof_right = "seq.idx.r"; + m_lindexof_left = "seq.lidx.l"; + m_lindexof_right = "seq.lidx.r"; m_aut_step = "aut.step"; m_pre = "seq.pre"; // (seq.pre s l): prefix of string s of length l m_post = "seq.post"; // (seq.post s l): suffix of string s of length k, based on extract starting at index i of length l @@ -155,6 +159,20 @@ bool skolem::is_tail(expr* e, expr*& s, expr*& idx) const { return is_tail(e) && (s = to_app(e)->get_arg(0), idx = to_app(e)->get_arg(1), true); } +bool skolem::is_left_or_right(expr* e, expr*& x, expr*& y, expr*& z) { + if (!is_skolem(m_left, e) && !is_skolem(m_right, e)) + return false; + x = nullptr; + y = nullptr; + z = nullptr; + unsigned sz = to_app(e)->get_num_args(); + if (sz > 0) x = to_app(e)->get_arg(0); + if (sz > 1) y = to_app(e)->get_arg(1); + if (sz > 2) z = to_app(e)->get_arg(2); + return true; +} + + bool skolem::is_eq(expr* e, expr*& a, expr*& b) const { return is_skolem(m_eq, e) && (a = to_app(e)->get_arg(0), b = to_app(e)->get_arg(1), true); } diff --git a/src/ast/rewriter/seq_skolem.h b/src/ast/rewriter/seq_skolem.h index 088a00eeb..4b828abf6 100644 --- a/src/ast/rewriter/seq_skolem.h +++ b/src/ast/rewriter/seq_skolem.h @@ -32,8 +32,10 @@ namespace seq { symbol m_prefix, m_suffix; symbol m_tail; + symbol m_left, m_right; symbol m_seq_first, m_seq_last; - symbol m_indexof_left, m_indexof_right; // inverse of indexof: (indexof_left s t) + s + (indexof_right s t) = t, for s in t. + symbol m_indexof_left, m_indexof_right; // inverse of indexof: (indexof_left s t) + s + (indexof_right s t) = t, for s in t. + symbol m_lindexof_left, m_lindexof_right; // inverse of indexof: (indexof_left s t) + s + (indexof_right s t) = t, for s in t. symbol m_aut_step; // regex unfolding state symbol m_accept; // regex symbol m_is_empty; // regex emptiness check @@ -81,8 +83,8 @@ namespace seq { expr_ref mk_indexof_right(expr* t, expr* s, expr* offset = nullptr) { return mk(m_indexof_right, t, s, offset); } expr_ref mk_contains_left(expr* t, expr* s, expr* offset = nullptr) { return mk("seq.cnt.l", t, s, offset); } expr_ref mk_contains_right(expr* t, expr* s, expr* offset = nullptr) { return mk("seq.cnt.r", t, s, offset); } - expr_ref mk_last_indexof_left(expr* t, expr* s, expr* offset = nullptr) { return mk("seq.lidx.l", t, s, offset); } - expr_ref mk_last_indexof_right(expr* t, expr* s, expr* offset = nullptr) { return mk("seq.lidx.r", t, s, offset); } + expr_ref mk_last_indexof_left(expr* t, expr* s, expr* offset = nullptr) { return mk(m_lindexof_left, t, s, offset); } + expr_ref mk_last_indexof_right(expr* t, expr* s, expr* offset = nullptr) { return mk(m_lindexof_right, t, s, offset); } expr_ref mk_tail(expr* s, expr* i) { return mk(m_tail, s, i); } expr_ref mk_post(expr* s, expr* i) { return mk(m_post, s, i); } @@ -100,8 +102,8 @@ namespace seq { expr_ref mk_digit2int(expr* ch) { return mk(symbol("seq.digit2int"), ch, nullptr, nullptr, nullptr, a.mk_int()); } expr_ref mk_digit2bv(expr* ch, sort* bv_sort); expr_ref mk_ubv2ch(expr* b) { return mk(symbol("seq.ubv2ch"), b, nullptr, nullptr, nullptr, seq.mk_char_sort()); } - expr_ref mk_left(expr* x, expr* y, expr* z = nullptr) { return mk("seq.left", x, y, z); } - expr_ref mk_right(expr* x, expr* y, expr* z = nullptr) { return mk("seq.right", x, y, z); } + expr_ref mk_left(expr* x, expr* y, expr* z = nullptr) { return mk(m_left, x, y, z); } + expr_ref mk_right(expr* x, expr* y, expr* z = nullptr) { return mk(m_right, x, y, z); } expr_ref mk_max_unfolding_depth(unsigned d); expr_ref mk_length_limit(expr* e, unsigned d); @@ -117,6 +119,8 @@ namespace seq { bool is_seq_first(expr* e) const { return is_skolem(m_seq_first, e); } bool is_indexof_left(expr* e) const { return is_skolem(m_indexof_left, e); } bool is_indexof_right(expr* e) const { return is_skolem(m_indexof_right, e); } + bool is_last_indexof_left(expr* e) const { return is_skolem(m_lindexof_left, e); } + bool is_last_indexof_right(expr* e) const { return is_skolem(m_lindexof_right, e); } bool is_indexof_left(expr* e, expr*& x, expr*& y) const { return is_indexof_left(e) && (x = to_app(e)->get_arg(0), y = to_app(e)->get_arg(1), true); } @@ -124,6 +128,7 @@ namespace seq { return is_indexof_right(e) && (x = to_app(e)->get_arg(0), y = to_app(e)->get_arg(1), true); } + bool is_left_or_right(expr* e, expr*& x, expr*& y, expr*& z); bool is_step(expr* e) const { return is_skolem(m_aut_step, e); } bool is_step(expr* e, expr*& s, expr*& idx, expr*& re, expr*& i, expr*& j, expr*& t) const; bool is_accept(expr* acc) const { return is_skolem(m_accept, acc); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 5712d1d41..7b0955518 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1538,10 +1538,23 @@ void theory_seq::add_length(expr* l) { Add length limit restrictions to sequence s. */ void theory_seq::add_length_limit(expr* s, unsigned k, bool is_searching) { - if (m_sk.is_indexof_left(s)) + if (m_util.str.is_concat(s)) { + for (expr* e : *to_app(s)) + add_length_limit(e, k, is_searching); return; - if (m_sk.is_indexof_right(s)) + } + if (m_util.str.is_unit(s)) return; + if (m_util.str.is_empty(s)) + return; + + if (m_sk.is_skolem(s)) { + for (expr* e : *to_app(s)) + if (m_util.is_seq(e) || m_sk.is_skolem(e)) + add_length_limit(e, k, is_searching); + return; + } + expr_ref lim_e = m_ax.add_length_limit(s, k); unsigned k0 = 0; if (m_length_limit_map.find(s, k0)) { From bd4db4c41f88919da6f8fdb0a718717c9ee2d8d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:17:47 -0700 Subject: [PATCH 053/477] add option to rewrite and for arithmetic simplification --- src/ast/rewriter/arith_rewriter.cpp | 25 +++++++++++++++++++++++++ src/ast/rewriter/arith_rewriter.h | 2 ++ src/ast/rewriter/bool_rewriter.cpp | 20 ++++++++++---------- src/ast/rewriter/th_rewriter.cpp | 5 +++++ src/model/model_evaluator.cpp | 5 +++++ 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 35b45295f..cdf09d7f3 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -706,6 +706,31 @@ br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result return st; } +br_status arith_rewriter::mk_and_core(unsigned n, expr* const* args, expr_ref& result) { + if (n <= 1) + return BR_FAILED; + expr* x, * y, * z, * u; + rational a, b; + if (m_util.is_le(args[0], x, y) && m_util.is_numeral(x, a)) { + expr* arg0 = args[0]; + ptr_buffer rest; + for (unsigned i = 1; i < n; ++i) { + if (m_util.is_le(args[i], z, u) && u == y && m_util.is_numeral(z, b)) { + if (b > a) + arg0 = args[i]; + } + else + rest.push_back(args[i]); + } + if (rest.size() < n - 1) { + rest.push_back(arg0); + result = m().mk_and(rest); + return BR_REWRITE1; + } + } + return BR_FAILED; +} + bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) { expr* x = nullptr, *y = nullptr, *z = nullptr, *u = nullptr; rational p, k, l; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 19a8363a0..c80226d0c 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -149,6 +149,8 @@ public: br_status mk_abs_core(expr * arg, expr_ref & result); + br_status mk_and_core(unsigned n, expr* const* args, expr_ref& result); + br_status mk_div_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_idiv_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_idivides(unsigned k, expr * arg, expr_ref & result); diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 1e58db340..fb2b0795b 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -175,7 +175,7 @@ br_status bool_rewriter::mk_flat_and_core(unsigned num_args, expr * const * args } if (mk_nflat_and_core(flat_args.size(), flat_args.data(), result) == BR_FAILED) result = m().mk_and(flat_args); - return BR_DONE; + return BR_REWRITE1; } return mk_nflat_and_core(num_args, args, result); } @@ -874,7 +874,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re expr_ref tmp(m()); mk_not(c, tmp); mk_and(tmp, e, result); - return BR_DONE; + return BR_REWRITE1; } } if (m().is_true(e) && m_elim_ite) { @@ -885,11 +885,11 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re } if (m().is_false(e) && m_elim_ite) { mk_and(c, t, result); - return BR_DONE; + return BR_REWRITE1; } if (c == e && m_elim_ite) { mk_and(c, t, result); - return BR_DONE; + return BR_REWRITE1; } if (c == t && m_elim_ite) { mk_or(c, e, result); @@ -912,13 +912,13 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re expr_ref a(m()); mk_and(c, t2, a); result = m().mk_not(m().mk_eq(t1, a)); - return BR_REWRITE2; + return BR_REWRITE3; } if (m().is_not(t, t1) && m().is_eq(t1, t2, t1) && e == t1) { expr_ref a(m()); mk_and(c, t2, a); result = m().mk_eq(t1, a); - return BR_REWRITE2; + return BR_REWRITE3; } #endif @@ -931,14 +931,14 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re expr_ref new_c(m()); mk_and(c, not_c2, new_c); result = m().mk_ite(new_c, to_app(t)->get_arg(2), e); - return BR_REWRITE1; + return BR_REWRITE2; } // (ite c1 (ite c2 t1 t2) t2) ==> (ite (and c1 c2) t1 t2) if (e == to_app(t)->get_arg(2)) { expr_ref new_c(m()); mk_and(c, to_app(t)->get_arg(0), new_c); result = m().mk_ite(new_c, to_app(t)->get_arg(1), e); - return BR_REWRITE1; + return BR_REWRITE2; } @@ -955,7 +955,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re expr_ref new_c(m()); mk_or(and1, and2, new_c); result = m().mk_ite(new_c, to_app(t)->get_arg(1), to_app(t)->get_arg(2)); - return BR_REWRITE1; + return BR_REWRITE3; } // (ite c1 (ite c2 t1 t2) (ite c3 t2 t1)) ==> (ite (or (and c1 c2) (and (not c1) (not c3))) t1 t2) @@ -972,7 +972,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re expr_ref new_c(m()); mk_or(and1, and2, new_c); result = m().mk_ite(new_c, to_app(t)->get_arg(1), to_app(t)->get_arg(2)); - return BR_REWRITE1; + return BR_REWRITE3; } } } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index c69534b08..aa02ab009 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -215,6 +215,11 @@ struct th_rewriter_cfg : public default_rewriter_cfg { if (st != BR_FAILED) return st; } + if (false && k == OP_AND) { + st = m_a_rw.mk_and_core(num, args, result); + if (st != BR_FAILED) + return st; + } if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) && to_app(args[0])->get_family_id() == m_seq_rw.get_fid()) { st = m_seq_rw.mk_eq_core(args[0], args[1], result); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 6d01fdcdb..843345a46 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -262,6 +262,11 @@ struct evaluator_cfg : public default_rewriter_cfg { if (st != BR_FAILED) return st; } + if (k == OP_AND) { + st = m_a_rw.mk_and_core(num, args, result); + if (st != BR_FAILED) + return st; + } return m_b_rw.mk_app_core(f, num, args, result); } if (fid == m_a_rw.get_fid()) From 9a987237d5e647e243feaa5bd832d9f2e1fc5094 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:18:33 -0700 Subject: [PATCH 054/477] don't rename uint_set but keep the original name --- src/sat/sat_lookahead.h | 2 +- src/util/sat_literal.h | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index a50d3ed37..784293461 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -353,7 +353,7 @@ namespace sat { candidate(bool_var v, double r): m_var(v), m_rating(r) {} }; svector m_candidates; - uint_set m_select_lookahead_vars; + tracked_uint_set m_select_lookahead_vars; double get_rating(bool_var v) const { return m_rating[v]; } double get_rating(literal l) const { return get_rating(l.var()); } diff --git a/src/util/sat_literal.h b/src/util/sat_literal.h index 920b0528b..aeb23bddd 100644 --- a/src/util/sat_literal.h +++ b/src/util/sat_literal.h @@ -110,12 +110,10 @@ namespace sat { inline void negate(literal_vector& ls) { for (unsigned i = 0; i < ls.size(); ++i) ls[i].neg(); } - typedef tracked_uint_set uint_set; - - typedef uint_set bool_var_set; + typedef tracked_uint_set bool_var_set; class literal_set { - uint_set m_set; + tracked_uint_set m_set; public: literal_set(literal_vector const& v) { for (unsigned i = 0; i < v.size(); ++i) insert(v[i]); @@ -141,9 +139,9 @@ namespace sat { void reset() { m_set.reset(); } void finalize() { m_set.finalize(); } class iterator { - uint_set::iterator m_it; + tracked_uint_set::iterator m_it; public: - iterator(uint_set::iterator it):m_it(it) {} + iterator(tracked_uint_set::iterator it):m_it(it) {} literal operator*() const { return to_literal(*m_it); } iterator& operator++() { ++m_it; return *this; } iterator operator++(int) { iterator tmp = *this; ++m_it; return tmp; } From c11bd79484b9c7b31abe2752315955df42f093f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:18:58 -0700 Subject: [PATCH 055/477] add assertions --- src/sat/sat_solver.cpp | 43 +++++++++++++++++++++++------------------- src/sat/sat_solver.h | 1 + 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 6a5f15567..7370ed266 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -428,9 +428,8 @@ namespace sat { } ++m_stats.m_non_learned_generation; - if (!m_searching) { - m_mc.add_clause(num_lits, lits); - } + if (!m_searching) + m_mc.add_clause(num_lits, lits); } @@ -945,6 +944,7 @@ namespace sat { void solver::assign_core(literal l, justification j) { SASSERT(value(l) == l_undef); + SASSERT(!m_trail.contains(l) && !m_trail.contains(~l)); TRACE("sat_assign_core", tout << l << " " << j << "\n";); if (j.level() == 0) { if (m_config.m_drat) @@ -3654,11 +3654,14 @@ namespace sat { } } m_trail.shrink(old_sz); + DEBUG_CODE(for (literal l : m_trail) SASSERT(lvl(l.var()) <= new_lvl);); m_qhead = m_trail.size(); if (!m_replay_assign.empty()) IF_VERBOSE(20, verbose_stream() << "replay assign: " << m_replay_assign.size() << "\n"); CTRACE("sat", !m_replay_assign.empty(), tout << "replay-assign: " << m_replay_assign << "\n";); for (unsigned i = m_replay_assign.size(); i-- > 0; ) { literal lit = m_replay_assign[i]; + SASSERT(value(lit) == l_true); + SASSERT(!m_trail.contains(lit) && !m_trail.contains(~lit)); m_trail.push_back(lit); } @@ -3709,11 +3712,11 @@ namespace sat { // void solver::user_push() { - pop_to_base_level(); m_free_var_freeze.push_back(m_free_vars); m_free_vars.reset(); // resetting free_vars forces new variables to be assigned above new_v bool_var new_v = mk_var(true, false); + SASSERT(new_v + 1 == m_justification.size()); // there are no active variables that have higher values literal lit = literal(new_v, false); m_user_scope_literals.push_back(lit); m_cut_simplifier = nullptr; // for simplicity, wipe it out @@ -3724,13 +3727,13 @@ namespace sat { void solver::user_pop(unsigned num_scopes) { unsigned old_sz = m_user_scope_literals.size() - num_scopes; - bool_var max_var = m_user_scope_literals[old_sz].var(); + bool_var max_var = m_user_scope_literals[old_sz].var(); m_user_scope_literals.shrink(old_sz); pop_to_base_level(); if (m_ext) m_ext->user_pop(num_scopes); - + gc_vars(max_var); TRACE("sat", display(tout);); @@ -3743,7 +3746,7 @@ namespace sat { m_free_vars.append(m_free_var_freeze[old_sz]); m_free_var_freeze.shrink(old_sz); scoped_suspend_rlimit _sp(m_rlimit); - propagate(false); + propagate(false); } void solver::pop_to_base_level() { @@ -4832,20 +4835,22 @@ namespace sat { return true; } + void solver::init_ts(unsigned n, svector& v, unsigned& ts) { + if (v.empty()) + ts = 0; + + ts++; + if (ts == 0) { + ts = 1; + v.reset(); + } + while (v.size() < n) + v.push_back(0); + } + void solver::init_visited() { - if (m_visited.empty()) { - m_visited_ts = 0; - } - m_visited_ts++; - if (m_visited_ts == 0) { - m_visited_ts = 1; - m_visited.reset(); - } - while (m_visited.size() < 2*num_vars()) { - m_visited.push_back(0); - } + init_ts(2 * num_vars(), m_visited, m_visited_ts); } - }; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 3228bcf60..0b01b777c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -343,6 +343,7 @@ namespace sat { void push_reinit_stack(clause & c); void push_reinit_stack(literal l1, literal l2); + void init_ts(unsigned n, svector& v, unsigned& ts); void init_visited(); void mark_visited(literal l) { m_visited[l.index()] = m_visited_ts; } void mark_visited(bool_var v) { mark_visited(literal(v, false)); } From d479bd9c53cf33b45c1852c7b9ee84d7f99b125e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:19:07 -0700 Subject: [PATCH 056/477] formatting --- src/sat/sat_solver/inc_sat_solver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 57531ef8a..981d91072 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -596,10 +596,10 @@ public: void convert_internalized() { m_solver.pop_to_base_level(); - if (!is_internalized() && m_fmls_head > 0) { - internalize_formulas(); - } - if (!is_internalized() || m_internalized_converted) return; + if (!is_internalized() && m_fmls_head > 0) + internalize_formulas(); + if (!is_internalized() || m_internalized_converted) + return; sat2goal s2g; m_cached_mc = nullptr; goal g(m, false, true, false); From 0b9c9cbbcece6d399b0c17c9060d93c0580dc6d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:20:37 -0700 Subject: [PATCH 057/477] add a queue head to delay propagation delay propagation on each disequality/equality should suffice once. It adds relevant inequalities to ensure the arithmetic solver is coherent about disequalities. --- src/sat/smt/arith_solver.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 27de68f3b..cec3f49e7 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -385,20 +385,16 @@ namespace arith { TRACE("arith", tout << b << "\n";); lp::constraint_index ci = b.get_constraint(is_true); lp().activate(ci); - if (is_infeasible()) { + if (is_infeasible()) return; - } lp::lconstraint_kind k = bound2constraint_kind(b.is_int(), b.get_bound_kind(), is_true); - if (k == lp::LT || k == lp::LE) { + if (k == lp::LT || k == lp::LE) ++m_stats.m_assert_lower; - } - else { + else ++m_stats.m_assert_upper; - } inf_rational value = b.get_value(is_true); - if (propagate_eqs() && value.is_rational()) { + if (propagate_eqs() && value.is_rational()) propagate_eqs(b.tv(), ci, k, b, value.get_rational()); - } #if 0 if (propagation_mode() != BP_NONE) lp().mark_rows_for_bound_prop(b.tv().id()); @@ -1118,16 +1114,23 @@ namespace arith { } bool solver::check_delayed_eqs() { - for (auto p : m_delayed_eqs) { + bool found_diseq = false; + if (m_delayed_eqs_qhead == m_delayed_eqs.size()) + return true; + force_push(); + ctx.push(value_trail(m_delayed_eqs_qhead)); + for (; m_delayed_eqs_qhead < m_delayed_eqs.size(); ++ m_delayed_eqs_qhead) { + auto p = m_delayed_eqs[m_delayed_eqs_qhead]; auto const& e = p.first; if (p.second) new_eq_eh(e); else if (is_eq(e.v1(), e.v2())) { mk_diseq_axiom(e); - return false; + found_diseq = true; + break; } - } - return true; + } + return !found_diseq; } lbool solver::check_lia() { From 2b4ba5e170ba71446f69b3d1696a9246f7c1afc4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:21:06 -0700 Subject: [PATCH 058/477] updated header file for arithmetic solver --- src/sat/smt/arith_solver.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index cf21e13b8..a1c89af76 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -218,6 +218,7 @@ namespace arith { svector m_equalities; // asserted rows corresponding to equalities. svector m_definitions; // asserted rows corresponding to definitions svector> m_delayed_eqs; + unsigned m_delayed_eqs_qhead = 0; literal_vector m_asserted; expr* m_not_handled{ nullptr }; From e54635e0ed8cd237e6e085b2aa45368a8a98d348 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:21:49 -0700 Subject: [PATCH 059/477] rename statistics to something more meaningful: instantiations from MBQI are tagged with mbi --- src/sat/smt/q_mbi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 9f716d071..f2caa2a3e 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -635,8 +635,8 @@ namespace q { void mbqi::collect_statistics(statistics& st) const { if (m_solver) m_solver->collect_statistics(st); - st.update("q-num-instantiations", m_stats.m_num_instantiations); - st.update("q-num-checks", m_stats.m_num_checks); + st.update("q mbi instantiations", m_stats.m_num_instantiations); + st.update("q mbi num checks", m_stats.m_num_checks); } } From 13f43ea107bf901f5d535045d79933bf7f89b513 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Sep 2022 17:22:44 -0700 Subject: [PATCH 060/477] bug fix for #6319 literals that are replayed need to be registered with respective theories, otherwise, they will not propagate with the theories (the enode have to be attached with relevant theory variables). --- src/sat/smt/euf_solver.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index dcb919d65..2cd6c1024 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -616,15 +616,17 @@ namespace euf { else lit = si.internalize(e, false); VERIFY(lit.var() == v); - if (!m_egraph.find(e) && (!m.is_iff(e) && !m.is_or(e) && !m.is_and(e) && !m.is_not(e))) { + if (!m_egraph.find(e) && !m.is_iff(e) && !m.is_or(e) && !m.is_and(e) && !m.is_not(e) && !m.is_implies(e) && !m.is_xor(e)) { ptr_buffer args; if (is_app(e)) for (expr* arg : *to_app(e)) args.push_back(e_internalize(arg)); + internalize(e, true); if (!m_egraph.find(e)) mk_enode(e, args.size(), args.data()); } - attach_lit(lit, e); + else + attach_lit(lit, e); } if (relevancy_enabled()) @@ -863,7 +865,13 @@ namespace euf { out << "bool-vars\n"; for (unsigned v : m_var_trail) { expr* e = m_bool_var2expr[v]; - out << v << (is_relevant(v)?"":"n") << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1) << "\n"; + out << v << (is_relevant(v)?"":"n") << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1); + euf::enode* n = m_egraph.find(e); + if (n) { + for (auto const& th : enode_th_vars(n)) + out << " " << m_id2solver[th.get_id()]->name(); + } + out << "\n"; } for (auto* e : m_solvers) e->display(out); From d6d34a8962bf33de661f0fd0d47873cbde849930 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Sep 2022 02:32:04 -0700 Subject: [PATCH 061/477] #6319 --- src/sat/smt/euf_solver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 2cd6c1024..806509e4a 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -488,7 +488,8 @@ namespace euf { }; if (merge_shared_bools()) cont = true; - for (auto* e : m_solvers) { + for (unsigned i = 0; i < m_solvers.size(); ++i) { + auto* e = m_solvers[i]; if (!m.inc()) return sat::check_result::CR_GIVEUP; if (e == m_qsolver) From fce4d2ad9075586e778dc01d4ae649af9c48ccd2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Sep 2022 03:07:51 -0700 Subject: [PATCH 062/477] #6319 --- src/sat/smt/euf_internalize.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 96167b39f..609f5296b 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -264,7 +264,11 @@ namespace euf { sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id()); if (sz <= 1) return; - if (sz <= distinct_max_args) { + sort* srt = e->get_arg(0)->get_sort(); + auto sort_sz = srt->get_num_elements(); + if (sort_sz.is_finite() && sort_sz.size() <= sz) + s().add_clause(0, nullptr, st); + else if (sz <= distinct_max_args) { for (unsigned i = 0; i < sz; ++i) { for (unsigned j = i + 1; j < sz; ++j) { expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr()); @@ -274,8 +278,7 @@ namespace euf { } } else { - // dist-f(x_1) = v_1 & ... & dist-f(x_n) = v_n - sort* srt = e->get_arg(0)->get_sort(); + // dist-f(x_1) = v_1 & ... & dist-f(x_n) = v_n SASSERT(!m.is_bool(srt)); sort_ref u(m.mk_fresh_sort("distinct-elems"), m); func_decl_ref f(m.mk_fresh_func_decl("dist-f", "", 1, &srt, u), m); From f4bea58852e094bb3ab5a72e6c0a71cec0e7969d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Sep 2022 03:19:47 -0700 Subject: [PATCH 063/477] #6319 ensure unknown when a lambda is not in beta redex --- src/sat/smt/array_axioms.cpp | 12 ++++++++++++ src/sat/smt/array_internalize.cpp | 2 ++ src/sat/smt/array_solver.cpp | 4 +++- src/sat/smt/array_solver.h | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index e824b01ad..a2e5200de 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -700,6 +700,18 @@ namespace array { n->unmark1(); } + bool solver::check_lambdas() { + unsigned num_vars = get_num_vars(); + for (unsigned i = 0; i < num_vars; i++) { + auto* n = var2enode(i); + if (a.is_as_array(n->get_expr()) || is_lambda(n->get_expr())) + for (euf::enode* p : euf::enode_parents(n)) + if (!ctx.is_beta_redex(p, n)) + return false; + } + return true; + } + bool solver::is_shared_arg(euf::enode* r) { SASSERT(r->is_root()); for (euf::enode* n : euf::enode_parents(r)) { diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 68dea4d63..bd01f52da 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -252,6 +252,8 @@ namespace array { return p->get_arg(0)->get_root() == n->get_root(); if (a.is_map(p->get_expr())) return true; + if (a.is_store(p->get_expr())) + return true; return false; } diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index eb8986098..2481e337a 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -108,7 +108,9 @@ namespace array { if (m_delay_qhead < m_axiom_trail.size()) return sat::check_result::CR_CONTINUE; - + if (!check_lambdas()) + return sat::check_result::CR_GIVEUP; + // validate_check(); return sat::check_result::CR_DONE; } diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index f2b4fb565..fbff2afb6 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -218,6 +218,7 @@ namespace array { bool should_prop_upward(var_data const& d) const; bool can_beta_reduce(euf::enode* n) const { return can_beta_reduce(n->get_expr()); } bool can_beta_reduce(expr* e) const; + bool check_lambdas(); var_data& get_var_data(euf::enode* n) { return get_var_data(n->get_th_var(get_id())); } var_data& get_var_data(theory_var v) { return *m_var_data[v]; } From 9118a93e44a0c33d2a7c427d1ad15c7ecf99f6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jack=C2=B7Boos=C2=B7Yu?= <47264268+JackBoosY@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:36:54 +0000 Subject: [PATCH 064/477] [document] Add vcpkg instruction step (#6345) --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 2d75c73d6..39b0a3e78 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,19 @@ Z3 has a build system using CMake. Read the [README-CMake.md](README-CMake.md) file for details. It is recommended for most build tasks, except for building OCaml bindings. +## Building Z3 using vcpkg + +vcpkg is a full platform package manager, you can easily install libzmq with vcpkg. + +Execute: + +```bash +git clone https://github.com/microsoft/vcpkg.git +./bootstrap-vcpkg.bat # For powershell +./bootstrap-vcpkg.sh # For bash +./vcpkg install z3 +``` + ## Dependencies Z3 itself has few dependencies. It uses C++ runtime libraries, including pthreads for multi-threading. It is optionally possible to use GMP for multi-precision integers, but Z3 contains its own self-contained From 7caf6a682bbd700a0db522380c4fe1f3f1610942 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Sep 2022 20:10:20 -0700 Subject: [PATCH 065/477] #6319 resolve for unsat core when using assumptions --- src/sat/sat_solver.cpp | 30 ++++++++++++++---------------- src/sat/smt/array_axioms.cpp | 5 +++++ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7370ed266..5222201c9 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -940,6 +940,7 @@ namespace sat { m_inconsistent = true; m_conflict = c; m_not_l = not_l; + TRACE("sat", display(display_justification(tout << "conflict " << not_l << " ", c) << "\n")); } void solver::assign_core(literal l, justification j) { @@ -1803,24 +1804,21 @@ namespace sat { void solver::init_assumptions(unsigned num_lits, literal const* lits) { - if (num_lits == 0 && m_user_scope_literals.empty()) { - return; - } + if (num_lits == 0 && m_user_scope_literals.empty()) + return; SASSERT(at_base_lvl()); reset_assumptions(); push(); propagate(false); - if (inconsistent()) { - return; - } + if (inconsistent()) + return; TRACE("sat", tout << literal_vector(num_lits, lits) << "\n"; - if (!m_user_scope_literals.empty()) { - tout << "user literals: " << m_user_scope_literals << "\n"; - } + if (!m_user_scope_literals.empty()) + tout << "user literals: " << m_user_scope_literals << "\n"; m_mc.display(tout); ); @@ -1897,13 +1895,11 @@ namespace sat { tout << "consistent: " << !inconsistent() << "\n"; for (literal a : m_assumptions) { index_set s; - if (m_antecedents.find(a.var(), s)) { - tout << a << ": "; display_index_set(tout, s) << "\n"; - } - } - for (literal lit : m_user_scope_literals) { - tout << "user " << lit << "\n"; + if (m_antecedents.find(a.var(), s)) + tout << a << ": "; display_index_set(tout, s) << "\n"; } + for (literal lit : m_user_scope_literals) + tout << "user " << lit << "\n"; ); } } @@ -2419,7 +2415,9 @@ namespace sat { m_conflict_lvl = get_max_lvl(m_not_l, m_conflict, unique_max); justification js = m_conflict; - if (m_conflict_lvl <= 1 && (!m_assumptions.empty() || !m_user_scope_literals.empty())) { + if (m_conflict_lvl <= 1 && (!m_assumptions.empty() || + !m_ext_assumption_set.empty() || + !m_user_scope_literals.empty())) { TRACE("sat", tout << "unsat core\n";); resolve_conflict_for_unsat_core(); return l_false; diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index a2e5200de..2c08b3e69 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -700,6 +700,11 @@ namespace array { n->unmark1(); } + /** + * \brief check that lambda expressions are beta redexes. + * The array solver is not a decision procedure for lambdas that do not occur in beta + * redexes. + */ bool solver::check_lambdas() { unsigned num_vars = get_num_vars(); for (unsigned i = 0; i < num_vars; i++) { From 20250b200f472006e51d6d6bca3dec49821d5d51 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Sep 2022 20:31:36 -0700 Subject: [PATCH 066/477] #6319 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_internalize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 609f5296b..c8ae2a7c6 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -266,7 +266,7 @@ namespace euf { return; sort* srt = e->get_arg(0)->get_sort(); auto sort_sz = srt->get_num_elements(); - if (sort_sz.is_finite() && sort_sz.size() <= sz) + if (sort_sz.is_finite() && sort_sz.size() < sz) s().add_clause(0, nullptr, st); else if (sz <= distinct_max_args) { for (unsigned i = 0; i < sz; ++i) { From 4518f4fe02dcad10a88e7020262cf660563881a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Sep 2022 20:31:55 -0700 Subject: [PATCH 067/477] fix #6352 Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 535500cae..041d6740a 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -904,18 +904,16 @@ namespace datatype { bool util::is_well_founded(unsigned num_types, sort* const* sorts) { buffer well_founded(num_types, false); obj_map sort2id; - for (unsigned i = 0; i < num_types; ++i) { + for (unsigned i = 0; i < num_types; ++i) sort2id.insert(sorts[i], i); - } unsigned num_well_founded = 0, id = 0; bool changed; ptr_vector subsorts; do { changed = false; for (unsigned tid = 0; tid < num_types; tid++) { - if (well_founded[tid]) { + if (well_founded[tid]) continue; - } sort* s = sorts[tid]; def const& d = get_def(s); for (constructor const* c : d) { @@ -923,9 +921,12 @@ namespace datatype { subsorts.reset(); get_subsorts(a->range(), subsorts); for (sort* srt : subsorts) { - if (sort2id.find(srt, id) && !well_founded[id]) { - goto next_constructor; + if (sort2id.find(srt, id)) { + if (!well_founded[id]) + goto next_constructor; } + else if (is_datatype(srt)) + break; } } changed = true; From 42945de240e25efb51c1c78b9591894c7075eb4c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Sep 2022 12:09:31 -0700 Subject: [PATCH 068/477] #6319 align use of optsmt and the new core (they should not be used together) --- src/opt/opt_context.cpp | 36 ++++++++++++++++++++++++++++-------- src/opt/opt_context.h | 1 + 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8c4ec6ed9..bc41e0c6d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -697,10 +697,25 @@ namespace opt { } } + /** + * Set the solver to the SAT core. + * It requres: + * - either EUF is enabled or the query is finite domain. + * - it is a MaxSAT query because linear optimiation is not exposed over the EUF core. + * - opt_solver relies on features from the legacy core. + * - the MaxSAT engine does not depend on old core features (branch and bound solver for MaxSAT) + * - proofs are not enabled + * Relaxation of these filters are possible by adding functionality to the new core. + * - Pareto optimizaiton might already be possible with EUF = true + * - optsmt needs to be disetangled from the legacy core + */ void context::update_solver() { sat_params p(m_params); if (!p.euf() && (!m_enable_sat || !probe_fd())) return; + + if (!is_maxsat_query()) + return; if (m_maxsat_engine != symbol("maxres") && m_maxsat_engine != symbol("rc2") && @@ -755,24 +770,29 @@ namespace opt { } }; + bool context::is_maxsat_query() { + for (objective& obj : m_objectives) + if (obj.m_type != O_MAXSMT) + return false; + return true; + } + bool context::probe_fd() { expr_fast_mark1 visited; is_fd proc(m); - try { + if (!is_maxsat_query()) + return false; + try { for (objective& obj : m_objectives) { - if (obj.m_type != O_MAXSMT) return false; maxsmt& ms = *m_maxsmts.find(obj.m_id); - for (unsigned j = 0; j < ms.size(); ++j) { + for (unsigned j = 0; j < ms.size(); ++j) quick_for_each_expr(proc, visited, ms[j]); - } } unsigned sz = get_solver().get_num_assertions(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < sz; i++) quick_for_each_expr(proc, visited, get_solver().get_assertion(i)); - } - for (expr* f : m_hard_constraints) { + for (expr* f : m_hard_constraints) quick_for_each_expr(proc, visited, f); - } } catch (const is_fd::found_fd &) { return false; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 49cc6adcd..8b0e8eab1 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -330,6 +330,7 @@ namespace opt { struct is_fd; bool probe_fd(); + bool is_maxsat_query(); struct is_propositional_fn; bool is_propositional(expr* e); From 58fad41dfa34df10b69b0b5969f84e9db61f3d5f Mon Sep 17 00:00:00 2001 From: Peter Bruch <582627+ptr1120@users.noreply.github.com> Date: Thu, 22 Sep 2022 20:25:17 +0200 Subject: [PATCH 069/477] Dotnet Api: Fix infinite finalization of Context (#6361) * Dotnet Api: suppress GC finalization of dotnet context in favor of re-registering finalization * Dotnet Api: enable concurrent dec-ref even if context is created without parameters. * Dotnet Api: removed dead code. --- src/api/dotnet/CMakeLists.txt | 2 - src/api/dotnet/Context.cs | 6 +- src/api/dotnet/Deprecated.cs | 35 ----------- src/api/dotnet/IDecRefQueue.cs | 103 --------------------------------- src/api/dotnet/Z3Object.cs | 9 +-- 5 files changed, 6 insertions(+), 149 deletions(-) delete mode 100644 src/api/dotnet/Deprecated.cs delete mode 100644 src/api/dotnet/IDecRefQueue.cs diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 82abfbf09..b2ba590ce 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -59,7 +59,6 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE Context.cs DatatypeExpr.cs DatatypeSort.cs - Deprecated.cs EnumSort.cs Expr.cs FiniteDomainExpr.cs @@ -76,7 +75,6 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE FuncInterp.cs Global.cs Goal.cs - IDecRefQueue.cs IntExpr.cs IntNum.cs IntSort.cs diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 5aabcbc39..80b5a95f1 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -42,6 +42,7 @@ namespace Microsoft.Z3 lock (creation_lock) { m_ctx = Native.Z3_mk_context_rc(IntPtr.Zero); + Native.Z3_enable_concurrent_dec_ref(m_ctx); InitContext(); } } @@ -4794,7 +4795,6 @@ namespace Microsoft.Z3 PrintMode = Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT; m_n_err_handler = new Native.Z3_error_handler(NativeErrorHandler); // keep reference so it doesn't get collected. Native.Z3_set_error_handler(m_ctx, m_n_err_handler); - GC.SuppressFinalize(this); } internal void CheckContextMatch(Z3Object other) @@ -4893,8 +4893,8 @@ namespace Microsoft.Z3 if (!is_external) Native.Z3_del_context(ctx); } - else - GC.ReRegisterForFinalize(this); + + GC.SuppressFinalize(this); } diff --git a/src/api/dotnet/Deprecated.cs b/src/api/dotnet/Deprecated.cs deleted file mode 100644 index 64255cea2..000000000 --- a/src/api/dotnet/Deprecated.cs +++ /dev/null @@ -1,35 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - Deprecated.cs - -Abstract: - - Expose deprecated features for use from the managed API - those who use them for experiments. - -Author: - - Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - ---*/ -using System.Diagnostics; -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace Microsoft.Z3 -{ - /// - /// The main interaction with Z3 happens via the Context. - /// - public class Deprecated - { - - - } -} \ No newline at end of file diff --git a/src/api/dotnet/IDecRefQueue.cs b/src/api/dotnet/IDecRefQueue.cs deleted file mode 100644 index 8af0973d6..000000000 --- a/src/api/dotnet/IDecRefQueue.cs +++ /dev/null @@ -1,103 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - DecRefQueue.cs - -Abstract: - - Z3 Managed API: DecRef Queues - -Author: - - Christoph Wintersteiger (cwinter) 2012-03-16 - -Notes: - ---*/ - -using System.Diagnostics; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Threading; - -namespace Microsoft.Z3 -{ - /// - /// DecRefQueue interface - /// - public abstract class IDecRefQueue - { - #region Object invariant - - private void ObjectInvariant() - { - Debug.Assert(this.m_queue != null); - } - - #endregion - - readonly private Object m_lock = new Object(); - readonly private List m_queue = new List(); - private uint m_move_limit; - - internal IDecRefQueue(uint move_limit = 1024) - { - m_move_limit = move_limit; - } - - /// - /// Sets the limit on numbers of objects that are kept back at GC collection. - /// - /// - public void SetLimit(uint l) { m_move_limit = l; } - - internal abstract void IncRef(Context ctx, IntPtr obj); - internal abstract void DecRef(Context ctx, IntPtr obj); - - internal void IncAndClear(Context ctx, IntPtr o) - { - Debug.Assert(ctx != null); - - IncRef(ctx, o); - if (m_queue.Count >= m_move_limit) Clear(ctx); - } - - internal void Add(IntPtr o) - { - if (o == IntPtr.Zero) return; - - lock (m_lock) - { - m_queue.Add(o); - } - } - - internal void Clear(Context ctx) - { - Debug.Assert(ctx != null); - - lock (m_lock) - { - foreach (IntPtr o in m_queue) - DecRef(ctx, o); - m_queue.Clear(); - } - } - } - - abstract class DecRefQueueContracts : IDecRefQueue - { - internal override void IncRef(Context ctx, IntPtr obj) - { - Debug.Assert(ctx != null); - } - - internal override void DecRef(Context ctx, IntPtr obj) - { - Debug.Assert(ctx != null); - } - } -} diff --git a/src/api/dotnet/Z3Object.cs b/src/api/dotnet/Z3Object.cs index 1affa9d17..4295ef054 100644 --- a/src/api/dotnet/Z3Object.cs +++ b/src/api/dotnet/Z3Object.cs @@ -50,10 +50,7 @@ namespace Microsoft.Z3 m_n_obj = IntPtr.Zero; } - if (m_ctx != null) - { - m_ctx = null; - } + m_ctx = null; GC.SuppressFinalize(this); } @@ -81,8 +78,8 @@ namespace Microsoft.Z3 { Debug.Assert(ctx != null); m_ctx = ctx; - IncRef(obj); m_n_obj = obj; + IncRef(obj); } internal virtual void IncRef(IntPtr o) { } @@ -103,7 +100,7 @@ namespace Microsoft.Z3 internal static IntPtr GetNativeObject(Z3Object s) { - if (s == null) return new IntPtr(); + if (s == null) return IntPtr.Zero; return s.NativeObject; } From a67fe054d54d1fdd4a73dbcee9c56a27db239f92 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Thu, 22 Sep 2022 20:26:08 +0200 Subject: [PATCH 070/477] Memory leak in .NET user-propagator (#6360) The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically --- src/api/dotnet/UserPropagator.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/UserPropagator.cs b/src/api/dotnet/UserPropagator.cs index 9b4fbc9b7..b9cd4dc39 100644 --- a/src/api/dotnet/UserPropagator.cs +++ b/src/api/dotnet/UserPropagator.cs @@ -37,7 +37,7 @@ namespace Microsoft.Z3 /// /// Propagator context for .Net /// - public class UserPropagator + public class UserPropagator : IDisposable { /// /// Delegate type for fixed callback @@ -205,10 +205,20 @@ namespace Microsoft.Z3 } /// - /// Release provate memory. + /// Release private memory. /// ~UserPropagator() { + Dispose(); + } + + /// + /// Must be called. The object will not be garbage collected automatically even if the context is disposed + /// + public virtual void Dispose() + { + if (!gch.IsAllocated) + return; gch.Free(); if (solver == null) ctx.Dispose(); From 00cf5ed4c72bd0de62422ffacd0a891368e048c5 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 22 Sep 2022 22:03:59 +0200 Subject: [PATCH 071/477] GitHub Workflows security hardening (#6353) * build: harden wasm-release.yml permissions Signed-off-by: Alex * build: harden wasm.yml permissions Signed-off-by: Alex --- .github/workflows/wasm-release.yml | 3 +++ .github/workflows/wasm.yml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index 255de7dc5..c34571784 100644 --- a/.github/workflows/wasm-release.yml +++ b/.github/workflows/wasm-release.yml @@ -12,6 +12,9 @@ defaults: env: EM_VERSION: 3.1.15 +permissions: + contents: read # to fetch code (actions/checkout) + jobs: publish: name: Publish diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index bd76c8033..418438635 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -12,6 +12,9 @@ defaults: env: EM_VERSION: 3.1.15 +permissions: + contents: read # to fetch code (actions/checkout) + jobs: check: name: Check From b0d0c36b11e81e0b917d91b8762bbfa6abc77991 Mon Sep 17 00:00:00 2001 From: gmh5225 <2315157@qq.com> Date: Fri, 23 Sep 2022 04:55:40 +0800 Subject: [PATCH 072/477] Add option 'MSVC_STATIC' (#6358) * Add option 'MSVC_STATIC' * Update CMakeLists.txt * Update CMakeLists.txt * Upload msvc-static-build.yml --- .github/workflows/msvc-static-build.yml | 20 ++++++++++++++++++++ CMakeLists.txt | 1 + src/CMakeLists.txt | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .github/workflows/msvc-static-build.yml diff --git a/.github/workflows/msvc-static-build.yml b/.github/workflows/msvc-static-build.yml new file mode 100644 index 000000000..81fb9c45a --- /dev/null +++ b/.github/workflows/msvc-static-build.yml @@ -0,0 +1,20 @@ +name: MSVC Static Build + +on: + push: + pull_request: + +jobs: + build: + runs-on: windows-2019 + env: + BUILD_TYPE: Release + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + + - name: Build + run: | + cmake -B build -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DZ3_BUILD_LIBZ3_SHARED=OFF -DZ3_BUILD_LIBZ3_MSVC_STATIC=ON + cmake --build build --config ${{ env.BUILD_TYPE }} --parallel + diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cd54eded..7093e679f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,6 +304,7 @@ endif() # Option to control what type of library we build ################################################################################ option(Z3_BUILD_LIBZ3_SHARED "Build libz3 as a shared library if true, otherwise build a static library" ON) +option(Z3_BUILD_LIBZ3_MSVC_STATIC "Build libz3 as a statically-linked runtime library" OFF) ################################################################################ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5be29c950..56c1d65cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,6 +115,27 @@ if (Z3_BUILD_LIBZ3_SHARED) else() set(lib_type "STATIC") endif() +# Enable static msvc runtime. +if (MSVC AND Z3_BUILD_LIBZ3_MSVC_STATIC) + set(CompilerFlags + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO + ) + foreach(CompilerFlag ${CompilerFlags}) + string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") + string(REPLACE "/MDd" "/MTd" ${CompilerFlag} "${${CompilerFlag}}") + set(${CompilerFlag} "${${CompilerFlag}}" CACHE STRING "msvc compiler flags" FORCE) + message("MSVC flags: ${CompilerFlag}:${${CompilerFlag}}") + endforeach() +endif(MSVC) add_library(libz3 ${lib_type} ${object_files}) target_include_directories(libz3 INTERFACE $ From c24d445886360b117f226fea438311103a9e6331 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Sep 2022 17:05:00 -0500 Subject: [PATCH 073/477] fix #6355 conversion from AIG to expressions should always use the optimized conversion function. the aig-tactic should throttle regarding output bloat from AIG. If the expression after AIG simpification, for whatever reason, is bloated the rewrite does not take place. --- src/tactic/aig/aig.cpp | 54 +++++++++++----------------- src/tactic/aig/aig_tactic.cpp | 46 ++++++++++++++++-------- src/tactic/smtlogics/qfbv_tactic.cpp | 8 +---- 3 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index b689a53e2..433120b48 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -18,7 +18,8 @@ Notes: --*/ #include "tactic/aig/aig.h" #include "tactic/goal.h" -#include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_util.h" #define USE_TWO_LEVEL_RULES #define FIRST_NODE_ID (UINT_MAX/2) @@ -431,13 +432,8 @@ struct aig_manager::imp { expr2aig(imp & _m):m(_m) {} ~expr2aig() { - obj_map::iterator it = m_cache.begin(); - obj_map::iterator end = m_cache.end(); - for (; it != end; ++it) { - TRACE("expr2aig", tout << "dec-ref: "; m.display_ref(tout, it->m_value); - tout << " ref-count: " << ref_count(it->m_value) << "\n";); - m.dec_ref(it->m_value); - } + for (auto& [k,v] : m_cache) + m.dec_ref(v); restore_result_stack(0); } @@ -447,7 +443,7 @@ struct aig_manager::imp { } void cache_result(expr * t, aig_lit const & r) { - TRACE("expr2aig", tout << "caching:\n" << mk_ismt2_pp(t, m.m()) << "\n---> "; m.display_ref(tout, r); tout << "\n";); + TRACE("expr2aig", tout << "caching:\n" << mk_bounded_pp(t, m.m()) << "\n---> "; m.display_ref(tout, r); tout << "\n";); SASSERT(!m_cache.contains(t)); m.inc_ref(r); m_cache.insert(t, r); @@ -1009,33 +1005,34 @@ struct aig_manager::imp { r = invert(r); } - void operator()(aig_lit const & l, expr_ref & r) { - naive(l, r); - } - - void operator()(aig_lit const & l, goal & g) { - g.reset(); + void not_naive(aig_lit const& l, expr_ref & r) { sbuffer roots; + expr_ref_vector rs(r.m()); roots.push_back(l); while (!roots.empty()) { aig_lit n = roots.back(); roots.pop_back(); if (n.is_inverted()) { - g.assert_expr(invert(process_root(n.ptr())), nullptr, nullptr); + rs.push_back(invert(process_root(n.ptr()))); continue; } aig * p = n.ptr(); if (m.is_ite(p)) { - g.assert_expr(process_root(p), nullptr, nullptr); + rs.push_back(process_root(p)); continue; } if (is_var(p)) { - g.assert_expr(m.var2expr(p), nullptr, nullptr); + rs.push_back(m.var2expr(p)); continue; } roots.push_back(left(p)); roots.push_back(right(p)); } + r = ::mk_and(rs); + } + + void operator()(aig_lit const & l, expr_ref & r) { + not_naive(l, r); } }; @@ -1534,18 +1531,14 @@ public: } SASSERT(ref_count(r) >= 1); } - catch (const aig_exception & ex) { - dec_ref(r); - throw ex; - } + catch (const aig_exception & ex) { + dec_ref(r); + throw ex; + } dec_ref_result(r); return r; } - void to_formula(aig_lit const & r, goal & g) { - aig2expr proc(*this); - proc(r, g); - } void to_formula(aig_lit const & r, expr_ref & result) { aig2expr proc(*this); @@ -1581,7 +1574,7 @@ public: qhead++; display_ref(out, n); out << ": "; if (is_var(n)) { - out << mk_ismt2_pp(m_var2exprs[n->m_id], m()) << "\n"; + out << mk_bounded_pp(m_var2exprs[n->m_id], m()) << "\n"; } else { display_ref(out, n->m_children[0]); @@ -1607,7 +1600,7 @@ public: if (r.is_inverted()) out << "(not "; if (is_var(r)) { - out << mk_ismt2_pp(var2expr(r.ptr()), m()); + out << mk_bounded_pp(var2expr(r.ptr()), m()); } else { out << "aig" << to_idx(r.ptr()); @@ -1738,11 +1731,6 @@ void aig_manager::max_sharing(aig_ref & r) { r = aig_ref(*this, m_imp->max_sharing(aig_lit(r))); } -void aig_manager::to_formula(aig_ref const & r, goal & g) { - SASSERT(!g.proofs_enabled()); - SASSERT(!g.unsat_core_enabled()); - return m_imp->to_formula(aig_lit(r), g); -} void aig_manager::to_formula(aig_ref const & r, expr_ref & res) { return m_imp->to_formula(aig_lit(r), res); diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index 5ffc0dc20..9c5390c16 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -16,6 +16,9 @@ Author: Notes: --*/ +#include "ast/ast_util.h" +#include "ast/ast_ll_pp.h" +#include "ast/for_each_expr.h" #include "tactic/tactical.h" #include "tactic/aig/aig.h" @@ -24,7 +27,6 @@ class aig_manager; class aig_tactic : public tactic { unsigned long long m_max_memory; bool m_aig_gate_encoding; - bool m_aig_per_assertion; aig_manager * m_aig_manager; struct mk_aig_manager { @@ -52,40 +54,54 @@ public: aig_tactic * t = alloc(aig_tactic); t->m_max_memory = m_max_memory; t->m_aig_gate_encoding = m_aig_gate_encoding; - t->m_aig_per_assertion = m_aig_per_assertion; return t; } void updt_params(params_ref const & p) override { m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_aig_gate_encoding = p.get_bool("aig_default_gate_encoding", true); - m_aig_per_assertion = p.get_bool("aig_per_assertion", true); } void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); - r.insert("aig_per_assertion", CPK_BOOL, "(default: true) process one assertion at a time."); } void operator()(goal_ref const & g) { + ast_manager& m = g->m(); + mk_aig_manager mk(*this, m); - mk_aig_manager mk(*this, g->m()); - if (m_aig_per_assertion) { - for (unsigned i = 0; i < g->size(); i++) { + expr_ref_vector nodeps(m); + + for (unsigned i = 0; i < g->size(); i++) { + expr_dependency * ed = g->dep(i); + if (!ed) { + nodeps.push_back(g->form(i)); + g->update(i, m.mk_true()); + } + else { aig_ref r = m_aig_manager->mk_aig(g->form(i)); m_aig_manager->max_sharing(r); - expr_ref new_f(g->m()); + expr_ref new_f(m); m_aig_manager->to_formula(r, new_f); - expr_dependency * ed = g->dep(i); - g->update(i, new_f, nullptr, ed); + unsigned old_sz = get_num_exprs(g->form(i)); + unsigned new_sz = get_num_exprs(new_f); + if (new_sz <= 1.2*old_sz) + g->update(i, new_f, nullptr, ed); } } - else { - fail_if_unsat_core_generation("aig", g); - aig_ref r = m_aig_manager->mk_aig(*(g.get())); - g->reset(); // save memory + + if (!nodeps.empty()) { + expr_ref conj(::mk_and(nodeps)); + aig_ref r = m_aig_manager->mk_aig(conj); m_aig_manager->max_sharing(r); - m_aig_manager->to_formula(r, *(g.get())); + expr_ref new_f(m); + m_aig_manager->to_formula(r, new_f); + unsigned old_sz = get_num_exprs(conj); + unsigned new_sz = get_num_exprs(new_f); + + if (new_sz > 1.2*old_sz) + new_f = conj; + g->assert_expr(new_f); } } diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index af20eae3e..b242d86cf 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -90,9 +90,6 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat params_ref solver_p; solver_p.set_bool("preprocess", false); // preprocessor of smt::context is not needed. - params_ref big_aig_p; - big_aig_p.set_bool("aig_per_assertion", false); - tactic* preamble_st = mk_qfbv_preamble(m, p); tactic * st = main_p(and_then(preamble_st, // If the user sets HI_DIV0=false, then the formula may contain uninterpreted function @@ -107,10 +104,7 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat and_then(using_params(and_then(mk_simplify_tactic(m), mk_solve_eqs_tactic(m)), local_ctx_p), - if_no_proofs(cond(mk_produce_unsat_cores_probe(), - mk_aig_tactic(), - using_params(mk_aig_tactic(), - big_aig_p))))), + if_no_proofs(mk_aig_tactic()))), sat), smt)))); From 4c6d7158cbc05665a6d10bede1ffb81269b4db8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Sep 2022 17:05:27 -0500 Subject: [PATCH 074/477] extended debugging for sat.euf --- src/sat/smt/arith_solver.cpp | 3 +-- src/sat/smt/euf_solver.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index cec3f49e7..c5730c19c 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -612,8 +612,7 @@ namespace arith { verbose_stream() << eval << " " << value << " " << ctx.bpp(n) << "\n"; verbose_stream() << n->bool_var() << " " << n->value() << " " << get_phase(n->bool_var()) << " " << ctx.bpp(n) << "\n"; verbose_stream() << *b << "\n";); - IF_VERBOSE(0, ctx.display(verbose_stream())); - IF_VERBOSE(0, verbose_stream() << mdl << "\n"); + IF_VERBOSE(0, ctx.display_validation_failure(verbose_stream(), mdl, n)); UNREACHABLE(); } } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 91b348e50..089c896cb 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -160,7 +160,6 @@ namespace euf { void collect_dependencies(user_sort& us, deps_t& deps); void values2model(deps_t const& deps, model_ref& mdl); void validate_model(model& mdl); - void display_validation_failure(std::ostream& out, model& mdl, enode* n); // solving void propagate_literals(); @@ -409,6 +408,7 @@ namespace euf { obj_map const& values2root(); void model_updated(model_ref& mdl); expr* node2value(enode* n) const; + void display_validation_failure(std::ostream& out, model& mdl, enode* n); // diagnostics func_decl_ref_vector const& unhandled_functions() { return m_unhandled_functions; } From de74e342c649e7ca253385a5b24b13530a6ab4c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 13:19:55 -0500 Subject: [PATCH 075/477] #5261 --- src/shell/dimacs_frontend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index a5d562440..092e01acf 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -75,7 +75,7 @@ static void display_model(sat::solver const & s) { case l_true: std::cout << i << " "; break; } } - std::cout << "\n"; + std::cout << " 0\n"; } static void display_core(sat::solver const& s, vector const& tracking_clauses) { From 3d9512b93c765f873770a69c654513f89318a72b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 13:49:20 -0500 Subject: [PATCH 076/477] fix #6363 --- src/ast/macros/macro_util.cpp | 38 +++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 8a4036730..70803b361 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -923,7 +923,7 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, TRACE("macro_util", tout << "Candidate check for: " << mk_ismt2_pp(atom, m_manager) << std::endl;); - if (m_manager.is_eq(atom, lhs, rhs)) { + auto insert_quasi = [&](expr* lhs, expr* rhs) { if (is_quasi_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs) && @@ -931,22 +931,30 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, expr_ref cond(m_manager); get_rest_clause_as_cond(atom, cond); insert_quasi_macro(to_app(lhs), num_decls, rhs, cond, false, true, false, r); + return true; } - else if (is_hint_atom(lhs, rhs)) { - insert_quasi_macro(to_app(lhs), num_decls, rhs, nullptr, false, true, true, r); - } + return false; + }; - if (is_quasi_macro_head(rhs, num_decls) && - !is_forbidden(to_app(rhs)->get_decl()) && - !occurs(to_app(rhs)->get_decl(), lhs) && - !rest_contains_decl(to_app(rhs)->get_decl(), atom)) { - expr_ref cond(m_manager); - get_rest_clause_as_cond(atom, cond); - insert_quasi_macro(to_app(rhs), num_decls, lhs, cond, false, true, false, r); - } - else if (is_hint_atom(rhs, lhs)) { - insert_quasi_macro(to_app(rhs), num_decls, lhs, nullptr, false, true, true, r); - } + auto insert_hint = [&](expr* lhs, expr* rhs) { + if (is_hint_atom(lhs, rhs)) + insert_quasi_macro(to_app(lhs), num_decls, rhs, nullptr, false, true, true, r); + }; + + if (m_manager.is_eq(atom, lhs, rhs)) { + if (!insert_quasi(lhs, rhs)) + insert_hint(lhs, rhs); + if (!insert_quasi(rhs, lhs)) + insert_hint(rhs, lhs); + } + expr* atom2; + if (m_manager.is_not(atom, atom2) && m_manager.is_eq(atom2, lhs, rhs) && m_manager.is_bool(lhs)) { + expr_ref nlhs(m_manager.mk_not(lhs), m_manager); + expr_ref nrhs(m_manager.mk_not(rhs), m_manager); + if (!insert_quasi(lhs, nrhs)) + insert_hint(lhs, nrhs); + if (!insert_quasi(rhs, nlhs)) + insert_hint(rhs, nlhs); } collect_arith_macro_candidates(atom, num_decls, r); From 79b43574424caadc740945e8d774911680bd55bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 14:31:48 -0500 Subject: [PATCH 077/477] #6363 --- src/ast/macros/macro_util.cpp | 140 +++++++++++++++++----------------- src/ast/macros/macro_util.h | 2 +- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 70803b361..a28d9c608 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -28,7 +28,7 @@ Revision History: #include "ast/rewriter/bool_rewriter.h" macro_util::macro_util(ast_manager & m): - m_manager(m), + m(m), m_bv(m), m_arith(m), m_arith_rw(m), @@ -176,7 +176,7 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const { */ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { expr * lhs = nullptr, * rhs = nullptr; - if (m_manager.is_eq(n, lhs, rhs) && + if (m.is_eq(n, lhs, rhs) && is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs)) { @@ -184,13 +184,13 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he def = rhs; return true; } - if (m_manager.is_not(n, lhs) && m_manager.is_eq(lhs, lhs, rhs) && - m_manager.is_bool(lhs) && + if (m.is_not(n, lhs) && m.is_eq(lhs, lhs, rhs) && + m.is_bool(lhs) && is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs)) { head = to_app(lhs); - def = m_manager.mk_not(rhs); + def = m.mk_not(rhs); return true; } return false; @@ -216,7 +216,7 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he */ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { expr * lhs = nullptr, * rhs = nullptr; - if (m_manager.is_eq(n, lhs, rhs) && + if (m.is_eq(n, lhs, rhs) && is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && !occurs(to_app(rhs)->get_decl(), lhs)) { @@ -224,13 +224,13 @@ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & h def = lhs; return true; } - if (m_manager.is_not(n, n) && m_manager.is_eq(n, lhs, rhs) && - m_manager.is_bool(lhs) && + if (m.is_not(n, n) && m.is_eq(n, lhs, rhs) && + m.is_bool(lhs) && is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && !occurs(to_app(rhs)->get_decl(), lhs)) { head = to_app(rhs); - def = m_manager.mk_not(lhs); + def = m.mk_not(lhs); return true; } return false; @@ -262,7 +262,7 @@ bool macro_util::poly_contains_head(expr * n, func_decl * f, expr * exception) c bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const { // TODO: obsolete... we should move to collect_arith_macro_candidates - if (!m_manager.is_eq(n) && !m_arith.is_le(n) && !m_arith.is_ge(n)) + if (!m.is_eq(n) && !m_arith.is_le(n) && !m_arith.is_ge(n)) return false; expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); @@ -306,7 +306,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex if (h == nullptr) return false; head = to_app(h); - expr_ref tmp(m_manager); + expr_ref tmp(m); tmp = m_arith.mk_add(args.size(), args.data()); if (inv) mk_sub(tmp, rhs, def); @@ -321,12 +321,12 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex */ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t) { expr* lhs = nullptr, *rhs = nullptr; - if (!m_manager.is_eq(n, lhs, rhs)) + if (!m.is_eq(n, lhs, rhs)) return false; if (!is_ground(lhs) && !is_ground(rhs)) return false; sort * s = lhs->get_sort(); - if (m_manager.is_uninterp(s)) + if (m.is_uninterp(s)) return false; sort_size sz = s->get_num_elements(); if (sz.is_finite() && sz.size() == 1) @@ -351,11 +351,11 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, ap bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) { if (!is_forall(n)) return false; - TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";); + TRACE("macro_util", tout << "processing: " << mk_pp(n, m) << "\n";); expr * body = to_quantifier(n)->get_expr(); unsigned num_decls = to_quantifier(n)->get_num_decls(); expr * lhs, *rhs; - if (!m_manager.is_iff(body, lhs, rhs)) + if (!m.is_iff(body, lhs, rhs)) return false; if (is_pseudo_head(lhs, num_decls, head, t) && !is_forbidden(head->get_decl()) && @@ -466,14 +466,14 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decl continue; } } - var * new_var = m_manager.mk_var(next_var_idx, arg->get_sort()); + var * new_var = m.mk_var(next_var_idx, arg->get_sort()); next_var_idx++; - expr * new_cond = m_manager.mk_eq(new_var, arg); + expr * new_cond = m.mk_eq(new_var, arg); new_args.push_back(new_var); new_conds.push_back(new_cond); } - bool_rewriter(m_manager).mk_and(new_conds.size(), new_conds.data(), cond); - head = m_manager.mk_app(qhead->get_decl(), new_args.size(), new_args.data()); + bool_rewriter(m).mk_and(new_conds.size(), new_conds.data(), cond); + head = m.mk_app(qhead->get_decl(), new_args.size(), new_args.data()); num_decls = next_var_idx; } @@ -485,7 +485,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" << mk_pp(def, m_manager) << "\n";); + TRACE("macro_util", tout << mk_pp(head, m) << "\n" << mk_pp(def, m) << "\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)); @@ -503,20 +503,20 @@ void macro_util::mk_macro_interpretation(app * head, unsigned num_decls, expr * f(x_3, x_2) --> f(x_0, x_1) */ void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const { - expr_ref_buffer var_mapping(m_manager); + expr_ref_buffer var_mapping(m); var_mapping.resize(num_decls); bool changed = false; unsigned num_args = head->get_num_args(); TRACE("macro_util", - tout << "head: " << mk_pp(head, m_manager) << "\n"; - tout << "applying substitution to:\n" << mk_bounded_pp(t, m_manager) << "\n";); + tout << "head: " << mk_pp(head, m) << "\n"; + tout << "applying substitution to:\n" << mk_bounded_pp(t, m) << "\n";); for (unsigned i = 0; i < num_args; i++) { var * v = to_var(head->get_arg(i)); unsigned vi = v->get_idx(); SASSERT(vi < num_decls); if (vi != i) { changed = true; - var_ref new_var(m_manager.mk_var(i, v->get_sort()), m_manager); + var_ref new_var(m.mk_var(i, v->get_sort()), m); var_mapping.setx(num_decls - vi - 1, new_var); } else @@ -525,13 +525,13 @@ void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_r if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. - var_subst subst(m_manager, true); + var_subst subst(m, true); TRACE("macro_util", - tout << "head: " << mk_pp(head, m_manager) << "\n"; - tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; + tout << "head: " << mk_pp(head, m) << "\n"; + tout << "applying substitution to:\n" << mk_ll_pp(t, m) << "\nsubstitution:\n"; for (unsigned i = 0; i < var_mapping.size(); i++) { if (var_mapping[i] != 0) - tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager); + tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m); }); norm_t = subst(t, var_mapping.size(), var_mapping.data()); } @@ -642,8 +642,8 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned & num_decls, app_r is_hint_head(head, vars) must also return true */ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { - TRACE("macro_util", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; - if (exception) tout << mk_pp(exception, m_manager); else tout << ""; + TRACE("macro_util", tout << "is_poly_hint n:\n" << mk_pp(n, m) << "\nhead:\n" << mk_pp(head, m) << "\nexception:\n"; + if (exception) tout << mk_pp(exception, m); else tout << ""; tout << "\n";); ptr_buffer vars; if (!is_hint_head(head, vars)) { @@ -664,7 +664,7 @@ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; if (arg != exception && (occurs(f, arg) || !vars_of_is_subset(arg, vars))) { - TRACE("macro_util", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";); + TRACE("macro_util", tout << "failed because of:\n" << mk_pp(arg, m) << "\n";); return false; } } @@ -710,36 +710,36 @@ void macro_util::macro_candidates::insert(func_decl * f, expr * def, expr * cond // ----------------------------- void macro_util::insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { - expr_ref norm_def(m_manager); - expr_ref norm_cond(m_manager); + expr_ref norm_def(m); + expr_ref norm_cond(m); normalize_expr(head, num_decls, def, norm_def); if (cond != nullptr) normalize_expr(head, num_decls, cond, norm_cond); else if (!hint) - norm_cond = m_manager.mk_true(); + norm_cond = m.mk_true(); SASSERT(!hint || norm_cond.get() == 0); r.insert(head->get_decl(), norm_def.get(), norm_cond.get(), ineq, satisfy_atom, hint); } void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { - TRACE("macro_util", tout << expr_ref(head, m_manager) << "\n";); + TRACE("macro_util", tout << expr_ref(head, m) << "\n";); if (!is_macro_head(head, head->get_num_args())) { - app_ref new_head(m_manager); - expr_ref extra_cond(m_manager); - expr_ref new_cond(m_manager); + app_ref new_head(m); + expr_ref extra_cond(m); + expr_ref new_cond(m); if (!hint) { quasi_macro_head_to_macro_head(head, num_decls, new_head, extra_cond); if (cond == nullptr) new_cond = extra_cond; else - bool_rewriter(m_manager).mk_and(cond, extra_cond, new_cond); + bool_rewriter(m).mk_and(cond, extra_cond, new_cond); } else { - hint_to_macro_head(m_manager, head, num_decls, new_head); + hint_to_macro_head(m, head, num_decls, new_head); TRACE("macro_util", - tout << "hint macro head: " << mk_ismt2_pp(new_head, m_manager) << std::endl; - tout << "hint macro def: " << mk_ismt2_pp(def, m_manager) << std::endl; ); + tout << "hint macro head: " << mk_ismt2_pp(new_head, m) << std::endl; + tout << "hint macro def: " << mk_ismt2_pp(def, m) << std::endl; ); } insert_macro(new_head, num_decls, def, new_cond, ineq, satisfy_atom, hint, r); } @@ -751,10 +751,10 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, bool macro_util::rest_contains_decl(func_decl * f, expr * except_lit) { if (m_curr_clause == nullptr) return false; - SASSERT(is_clause(m_manager, m_curr_clause)); - unsigned num_lits = get_clause_num_literals(m_manager, m_curr_clause); + SASSERT(is_clause(m, m_curr_clause)); + unsigned num_lits = get_clause_num_literals(m, m_curr_clause); for (unsigned i = 0; i < num_lits; i++) { - expr * l = get_clause_literal(m_manager, m_curr_clause, i); + expr * l = get_clause_literal(m, m_curr_clause, i); if (l != except_lit && occurs(f, l)) return true; } @@ -764,20 +764,20 @@ bool macro_util::rest_contains_decl(func_decl * f, expr * except_lit) { void macro_util::get_rest_clause_as_cond(expr * except_lit, expr_ref & extra_cond) { if (m_curr_clause == nullptr) return; - SASSERT(is_clause(m_manager, m_curr_clause)); - expr_ref_buffer neg_other_lits(m_manager); - unsigned num_lits = get_clause_num_literals(m_manager, m_curr_clause); + SASSERT(is_clause(m, m_curr_clause)); + expr_ref_buffer neg_other_lits(m); + unsigned num_lits = get_clause_num_literals(m, m_curr_clause); for (unsigned i = 0; i < num_lits; i++) { - expr * l = get_clause_literal(m_manager, m_curr_clause, i); + expr * l = get_clause_literal(m, m_curr_clause, i); if (l != except_lit) { - expr_ref neg_l(m_manager); - bool_rewriter(m_manager).mk_not(l, neg_l); + expr_ref neg_l(m); + bool_rewriter(m).mk_not(l, neg_l); neg_other_lits.push_back(neg_l); } } if (neg_other_lits.empty()) return; - bool_rewriter(m_manager).mk_and(neg_other_lits.size(), neg_other_lits.data(), extra_cond); + bool_rewriter(m).mk_and(neg_other_lits.size(), neg_other_lits.data(), extra_cond); } void macro_util::collect_poly_args(expr * n, expr * exception, ptr_buffer & args) { @@ -800,14 +800,14 @@ void macro_util::collect_poly_args(expr * n, expr * exception, ptr_buffer } void macro_util::add_arith_macro_candidate(app * head, unsigned num_decls, expr * def, expr * atom, bool ineq, bool hint, macro_candidates & r) { - expr_ref cond(m_manager); + expr_ref cond(m); if (!hint) get_rest_clause_as_cond(atom, cond); insert_quasi_macro(head, num_decls, def, cond, ineq, true, hint, r); } void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * atom, unsigned num_decls, bool is_ineq, macro_candidates & r) { - if (!is_add(lhs) && m_manager.is_eq(atom)) // this case is a simple macro. + if (!is_add(lhs) && m.is_eq(atom)) // this case is a simple macro. return; ptr_buffer args; unsigned lhs_num_args; @@ -837,9 +837,9 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a if (_is_arith_macro || _is_poly_hint) { collect_poly_args(lhs, arg, args); - expr_ref rest(m_manager); + expr_ref rest(m); mk_add(args.size(), args.data(), arg->get_sort(), rest); - expr_ref def(m_manager); + expr_ref def(m); mk_sub(rhs, rest, def); // If is_poly_hint, rhs may contain variables that do not occur in to_app(arg). // So, we should re-check. @@ -858,9 +858,9 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a if (_is_arith_macro || _is_poly_hint) { collect_poly_args(lhs, arg, args); - expr_ref rest(m_manager); + expr_ref rest(m); mk_add(args.size(), args.data(), arg->get_sort(), rest); - expr_ref def(m_manager); + expr_ref def(m); mk_sub(rest, rhs, def); // If is_poly_hint, rhs may contain variables that do not occur in to_app(neg_arg). // So, we should re-check. @@ -872,12 +872,12 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a } void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r) { - TRACE("macro_util", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";); - if (!m_manager.is_eq(atom) && !is_le_ge(atom)) + TRACE("macro_util", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m) << "\n";); + if (!m.is_eq(atom) && !is_le_ge(atom)) return; expr * lhs = to_app(atom)->get_arg(0); expr * rhs = to_app(atom)->get_arg(1); - bool is_ineq = !m_manager.is_eq(atom); + bool is_ineq = !m.is_eq(atom); collect_arith_macro_candidates(lhs, rhs, atom, num_decls, is_ineq, r); collect_arith_macro_candidates(rhs, lhs, atom, num_decls, is_ineq, r); } @@ -921,14 +921,14 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) { expr* lhs, *rhs; - TRACE("macro_util", tout << "Candidate check for: " << mk_ismt2_pp(atom, m_manager) << std::endl;); + TRACE("macro_util", tout << "Candidate check for: " << mk_ismt2_pp(atom, m) << std::endl;); auto insert_quasi = [&](expr* lhs, expr* rhs) { if (is_quasi_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs) && !rest_contains_decl(to_app(lhs)->get_decl(), atom)) { - expr_ref cond(m_manager); + expr_ref cond(m); get_rest_clause_as_cond(atom, cond); insert_quasi_macro(to_app(lhs), num_decls, rhs, cond, false, true, false, r); return true; @@ -941,16 +941,16 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, insert_quasi_macro(to_app(lhs), num_decls, rhs, nullptr, false, true, true, r); }; - if (m_manager.is_eq(atom, lhs, rhs)) { + if (m.is_eq(atom, lhs, rhs)) { if (!insert_quasi(lhs, rhs)) insert_hint(lhs, rhs); if (!insert_quasi(rhs, lhs)) insert_hint(rhs, lhs); } expr* atom2; - if (m_manager.is_not(atom, atom2) && m_manager.is_eq(atom2, lhs, rhs) && m_manager.is_bool(lhs)) { - expr_ref nlhs(m_manager.mk_not(lhs), m_manager); - expr_ref nrhs(m_manager.mk_not(rhs), m_manager); + if (m.is_not(atom, atom2) && m.is_eq(atom2, lhs, rhs) && m.is_bool(lhs)) { + expr_ref nlhs(m.mk_not(lhs), m); + expr_ref nrhs(m.mk_not(rhs), m); if (!insert_quasi(lhs, nrhs)) insert_hint(lhs, nrhs); if (!insert_quasi(rhs, nlhs)) @@ -973,11 +973,11 @@ void macro_util::collect_macro_candidates(quantifier * q, macro_candidates & r) return; unsigned num_decls = q->get_num_decls(); SASSERT(m_curr_clause == 0); - if (is_clause(m_manager, n)) { + if (is_clause(m, n)) { m_curr_clause = n; - unsigned num_lits = get_clause_num_literals(m_manager, n); + unsigned num_lits = get_clause_num_literals(m, n); for (unsigned i = 0; i < num_lits; i++) - collect_macro_candidates_core(get_clause_literal(m_manager, n, i), num_decls, r); + collect_macro_candidates_core(get_clause_literal(m, n, i), num_decls, r); m_curr_clause = nullptr; } else { diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index 17b409c12..b714bd9e5 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -56,7 +56,7 @@ public: }; private: - ast_manager & m_manager; + ast_manager & m; bv_util m_bv; arith_util m_arith; mutable arith_rewriter m_arith_rw; From c41b6da6bbbd2305abbda89d40760bca516ce234 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 14:47:48 -0500 Subject: [PATCH 078/477] #6319 using a queue for disequality propagaiton was a regression: values of numerals can change along the same stack so prior passing the filter does not mean it passes later. --- src/sat/smt/arith_solver.cpp | 7 +++---- src/sat/smt/arith_solver.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index c5730c19c..7d3578dc5 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1114,12 +1114,11 @@ namespace arith { bool solver::check_delayed_eqs() { bool found_diseq = false; - if (m_delayed_eqs_qhead == m_delayed_eqs.size()) + if (m_delayed_eqs.empty()) return true; force_push(); - ctx.push(value_trail(m_delayed_eqs_qhead)); - for (; m_delayed_eqs_qhead < m_delayed_eqs.size(); ++ m_delayed_eqs_qhead) { - auto p = m_delayed_eqs[m_delayed_eqs_qhead]; + for (unsigned i; i < m_delayed_eqs.size(); ++i) { + auto p = m_delayed_eqs[i]; auto const& e = p.first; if (p.second) new_eq_eh(e); diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index a1c89af76..cf21e13b8 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -218,7 +218,6 @@ namespace arith { svector m_equalities; // asserted rows corresponding to equalities. svector m_definitions; // asserted rows corresponding to definitions svector> m_delayed_eqs; - unsigned m_delayed_eqs_qhead = 0; literal_vector m_asserted; expr* m_not_handled{ nullptr }; From 622687528344411b60fef18c49c8c77fcbe29380 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 15:51:26 -0500 Subject: [PATCH 079/477] fix regression with uninitialized variable --- src/sat/smt/arith_internalize.cpp | 2 ++ src/sat/smt/arith_solver.cpp | 8 +------- src/sat/smt/arith_solver.h | 5 +---- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 09352e147..30eab0b53 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -98,6 +98,7 @@ namespace arith { void solver::found_underspecified(expr* n) { if (a.is_underspecified(n)) { TRACE("arith", tout << "Unhandled: " << mk_pp(n, m) << "\n";); + ctx.push(push_back_vector(m_underspecified)); m_underspecified.push_back(to_app(n)); } expr* e = nullptr, * x = nullptr, * y = nullptr; @@ -243,6 +244,7 @@ namespace arith { mk_abs_axiom(t); else if (a.is_idiv(n, n1, n2)) { if (!a.is_numeral(n2, r) || r.is_zero()) found_underspecified(n); + ctx.push(push_back_vector(m_idiv_terms)); m_idiv_terms.push_back(n); app_ref mod(a.mk_mod(n1, n2), m); internalize(mod, m_is_redundant); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 7d3578dc5..883773988 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -681,10 +681,7 @@ namespace arith { scope& sc = m_scopes.back(); sc.m_bounds_lim = m_bounds_trail.size(); sc.m_asserted_qhead = m_asserted_qhead; - sc.m_idiv_lim = m_idiv_terms.size(); sc.m_asserted_lim = m_asserted.size(); - sc.m_not_handled = m_not_handled; - sc.m_underspecified_lim = m_underspecified.size(); lp().push(); if (m_nla) m_nla->push(); @@ -696,11 +693,8 @@ namespace arith { TRACE("arith", tout << "pop " << num_scopes << "\n";); unsigned old_size = m_scopes.size() - num_scopes; del_bounds(m_scopes[old_size].m_bounds_lim); - m_idiv_terms.shrink(m_scopes[old_size].m_idiv_lim); m_asserted.shrink(m_scopes[old_size].m_asserted_lim); m_asserted_qhead = m_scopes[old_size].m_asserted_qhead; - m_underspecified.shrink(m_scopes[old_size].m_underspecified_lim); - m_not_handled = m_scopes[old_size].m_not_handled; m_scopes.resize(old_size); lp().pop(num_scopes); m_new_bounds.reset(); @@ -1117,7 +1111,7 @@ namespace arith { if (m_delayed_eqs.empty()) return true; force_push(); - for (unsigned i; i < m_delayed_eqs.size(); ++i) { + for (unsigned i = 0; i < m_delayed_eqs.size(); ++i) { auto p = m_delayed_eqs[i]; auto const& e = p.first; if (p.second) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index cf21e13b8..83c91ac05 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -105,11 +105,8 @@ namespace arith { struct scope { unsigned m_bounds_lim; - unsigned m_idiv_lim; unsigned m_asserted_qhead; unsigned m_asserted_lim; - unsigned m_underspecified_lim; - expr* m_not_handled; }; class resource_limit : public lp::lp_resource_limit { @@ -220,7 +217,7 @@ namespace arith { svector> m_delayed_eqs; literal_vector m_asserted; - expr* m_not_handled{ nullptr }; + expr* m_not_handled = nullptr; ptr_vector m_underspecified; ptr_vector m_idiv_terms; vector > m_use_list; // bounds where variables are used. From 1f150ecd5230808d660949d665ba49aee696890e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 22:22:34 -0500 Subject: [PATCH 080/477] #6319 #6319 - fix incompleteness in propagation of default to all array terms in the equivalence class. Fix bug with q_mbi where domain restrictions are not using values because the current model does not evaluate certain bound variables to values. Set model completion when adding these bound variables to the model to ensure their values are not missed. Add better propagation of diagnostics when tactics and the new solver return unknown. The reason for unknown can now be traced to what theory was culprit (currently no additional information) --- src/CMakeLists.txt | 2 +- src/sat/sat_extension.h | 2 ++ src/sat/sat_solver.cpp | 2 +- src/sat/smt/arith_solver.cpp | 1 - src/sat/smt/array_internalize.cpp | 2 +- src/sat/smt/array_model.cpp | 13 ++++++++++--- src/sat/smt/array_solver.cpp | 9 +++++++-- src/sat/smt/array_solver.h | 5 +++-- src/sat/smt/euf_model.cpp | 12 +++++++++++- src/sat/smt/euf_solver.cpp | 9 ++++++--- src/sat/smt/euf_solver.h | 2 ++ src/sat/smt/q_mbi.cpp | 20 ++++++++++++++------ src/sat/tactic/sat_tactic.cpp | 2 ++ src/solver/solver2tactic.cpp | 1 + src/tactic/goal.h | 5 +++++ src/tactic/tactic.cpp | 7 ++++--- 16 files changed, 70 insertions(+), 24 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56c1d65cd..b96638944 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,7 +135,7 @@ if (MSVC AND Z3_BUILD_LIBZ3_MSVC_STATIC) set(${CompilerFlag} "${${CompilerFlag}}" CACHE STRING "msvc compiler flags" FORCE) message("MSVC flags: ${CompilerFlag}:${${CompilerFlag}}") endforeach() -endif(MSVC) +endif() add_library(libz3 ${lib_type} ${object_files}) target_include_directories(libz3 INTERFACE $ diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index ffcb95587..8730a2c2e 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -132,6 +132,8 @@ namespace sat { return false; } virtual bool is_pb() { return false; } + + virtual std::string reason_unknown() { return "unknown"; } }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5222201c9..59503fb00 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1357,7 +1357,6 @@ namespace sat { return is_sat; } catch (const abort_solver &) { - m_reason_unknown = "sat.giveup"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort giveup\")\n";); return l_undef; } @@ -1778,6 +1777,7 @@ namespace sat { case check_result::CR_CONTINUE: break; case check_result::CR_GIVEUP: + m_reason_unknown = m_ext->reason_unknown(); throw abort_solver(); } return l_undef; diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 883773988..87e159b87 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -686,7 +686,6 @@ namespace arith { if (m_nla) m_nla->push(); th_euf_solver::push_core(); - } void solver::pop_core(unsigned num_scopes) { diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index bd01f52da..4df4f3a50 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -122,7 +122,7 @@ namespace array { ctx.push(push_back_vector(m_minmaxdiffs)); break; case OP_ARRAY_DEFAULT: - add_parent_default(find(n->get_arg(0)), n); + add_parent_default(find(n->get_arg(0))); break; case OP_ARRAY_MAP: case OP_SET_UNION: diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index 8b56ff3ae..aa986d87f 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -69,14 +69,21 @@ namespace array { values.set(n->get_expr_id(), n->get_expr()); return; } - + theory_var v = get_th_var(n); + euf::enode* d = get_default(v); + + if (a.is_const(n->get_expr())) { + expr* val = values.get(d->get_root_id()); + SASSERT(val); + values.set(n->get_expr_id(), a.mk_const_array(n->get_sort(), val)); + return; + } + 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); mdl.register_decl(f, fi); - theory_var v = get_th_var(n); - euf::enode* d = get_default(v); if (d && !fi->get_else()) fi->set_else(values.get(d->get_root_id())); diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index 2481e337a..1c4b95abe 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -172,6 +172,10 @@ namespace array { add_parent_select(v1, select); if (is_lambda(e1) || is_lambda(e2)) push_axiom(congruence_axiom(n1, n2)); + if (d1.m_has_default && !d2.m_has_default) + add_parent_default(v2); + if (!d1.m_has_default && d2.m_has_default) + add_parent_default(v1); } void solver::add_parent_select(theory_var v_child, euf::enode* select) { @@ -206,9 +210,10 @@ namespace array { propagate_select_axioms(d, lambda); } - void solver::add_parent_default(theory_var v, euf::enode* def) { - SASSERT(a.is_default(def->get_expr())); + void solver::add_parent_default(theory_var v) { auto& d = get_var_data(find(v)); + ctx.push(value_trail(d.m_has_default)); + d.m_has_default = true; for (euf::enode* lambda : d.m_lambdas) push_axiom(default_axiom(lambda)); if (should_prop_upward(d)) diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index fbff2afb6..5c2708842 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -50,7 +50,8 @@ namespace array { // void log_drat(array_justification const& c); struct var_data { - bool m_prop_upward{ false }; + bool m_prop_upward = false ; + bool m_has_default = false; euf::enode_vector m_lambdas; // equivalent nodes that have beta reduction properties euf::enode_vector m_parent_lambdas; // parents that have beta reduction properties euf::enode_vector m_parent_selects; // parents that use array in select position @@ -202,7 +203,7 @@ namespace array { // solving void add_parent_select(theory_var v_child, euf::enode* select); - void add_parent_default(theory_var v_child, euf::enode* def); + void add_parent_default(theory_var v_child); void add_lambda(theory_var v, euf::enode* lambda); void add_parent_lambda(theory_var v_child, euf::enode* lambda); diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 4b7745dd7..c22c46322 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -296,7 +296,17 @@ namespace euf { expr_ref sval(m); th_rewriter rw(m); rw(val, sval); - out << bpp(r) << " := " << sval << " " << mdl(r->get_root()->get_expr()) << "\n"; + expr_ref mval = mdl(r->get_root()->get_expr()); + if (mval != sval) { + out << bpp(r) << " :=\neval: " << sval << "\nmval: " << mval << "\n"; + continue; + } + if (!m.is_bool(val)) + continue; + auto bval = s().value(r->bool_var()); + bool tt = l_true == bval; + if (tt != m.is_true(sval)) + out << bpp(r) << " :=\neval: " << sval << "\nmval: " << bval << "\n"; } for (euf::enode* r : nodes) r->unmark1(); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 806509e4a..c30fdbf89 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -166,8 +166,9 @@ namespace euf { IF_VERBOSE(0, verbose_stream() << mk_pp(f, m) << " not handled\n"); } - void solver::init_search() { + void solver::init_search() { TRACE("before_search", s().display(tout);); + m_reason_unknown.clear(); for (auto* s : m_solvers) s->init_search(); } @@ -482,7 +483,7 @@ namespace euf { auto apply_solver = [&](th_solver* e) { switch (e->check()) { case sat::check_result::CR_CONTINUE: cont = true; break; - case sat::check_result::CR_GIVEUP: give_up = true; break; + case sat::check_result::CR_GIVEUP: m_reason_unknown = "incomplete theory " + e->name().str(); TRACE("euf", tout << "give up " << e->name() << "\n"); give_up = true; break; default: break; } }; @@ -490,8 +491,10 @@ namespace euf { cont = true; for (unsigned i = 0; i < m_solvers.size(); ++i) { auto* e = m_solvers[i]; - if (!m.inc()) + if (!m.inc()) { + m_reason_unknown = "canceled"; return sat::check_result::CR_GIVEUP; + } if (e == m_qsolver) continue; apply_solver(e); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 089c896cb..d19e0acac 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -105,6 +105,7 @@ namespace euf { user_solver::solver* m_user_propagator = nullptr; th_solver* m_qsolver = nullptr; unsigned m_generation = 0; + std::string m_reason_unknown; mutable ptr_vector m_todo; ptr_vector m_bool_var2expr; @@ -290,6 +291,7 @@ namespace euf { bool should_research(sat::literal_vector const& core) override; void add_assumptions(sat::literal_set& assumptions) override; bool tracking_assumptions() override; + std::string reason_unknown() override { return m_reason_unknown; } void propagate(literal lit, ext_justification_idx idx); bool propagate(enode* a, enode* b, ext_justification_idx idx); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index f2caa2a3e..a87be2dee 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -198,6 +198,7 @@ namespace q { expr_ref_vector eqs(m); add_domain_bounds(mdl, qb); auto proj = solver_project(mdl, qb, eqs, false); + CTRACE("q", !proj, tout << "could not project " << qb.mbody << " " << eqs << "\n" << mdl); if (!proj) return false; add_instantiation(q, proj); @@ -339,8 +340,10 @@ namespace q { fmls.append(qb.domain_eqs); eliminate_nested_vars(fmls, qb); for (expr* e : fmls) - if (!m_model->is_true(e)) + if (!m_model->is_true(e)) { + TRACE("q", tout << "not true: " << mk_pp(e, m) << " := " << (*m_model)(e) << "\n"); return expr_ref(nullptr, m); + } mbp::project_plugin proj(m); proj.extract_literals(*m_model, vars, fmls); fmls_extracted = true; @@ -348,8 +351,9 @@ namespace q { if (!p) continue; if (ctx.use_drat()) { - if (!p->project(*m_model, vars, fmls, m_defs)) - return expr_ref(m); + if (!p->project(*m_model, vars, fmls, m_defs)) + return expr_ref(m); + } else if (!(*p)(*m_model, vars, fmls)) return expr_ref(m); @@ -430,8 +434,11 @@ namespace q { void mbqi::add_domain_bounds(model& mdl, q_body& qb) { qb.domain_eqs.reset(); m_model->reset_eval_cache(); - for (app* v : qb.vars) - m_model->register_decl(v->get_decl(), mdl(v)); + { + model::scoped_model_completion _sc(mdl, true); + for (app* v : qb.vars) + m_model->register_decl(v->get_decl(), mdl(v)); + } ctx.model_updated(m_model); if (qb.var_args.empty()) return; @@ -440,7 +447,8 @@ namespace q { expr_ref _term = subst(t, qb.vars); app_ref term(to_app(_term), m); expr_ref value = (*m_model)(term->get_arg(idx)); - m_model_fixer.invert_arg(term, idx, value, qb.domain_eqs); + if (m.is_value(value)) + m_model_fixer.invert_arg(term, idx, value, qb.domain_eqs); } } diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 892a88f89..562fa431e 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -74,6 +74,8 @@ class sat_tactic : public tactic { TRACE("sat", tout << "result of checking: " << r << " "; if (r == l_undef) tout << m_solver->get_reason_unknown(); tout << "\n"; if (m_goal2sat.has_interpreted_funs()) tout << "has interpreted\n";); + if (r == l_undef) + g->set_reason_unknown(m_solver->get_reason_unknown()); if (r == l_false) { expr_dependency * lcore = nullptr; if (produce_core) { diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 389ee124b..81d21f959 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -164,6 +164,7 @@ public: in->assert_expr(local_solver->get_assertion(i)); } } + in->set_reason_unknown(local_solver->reason_unknown()); result.push_back(in.get()); break; } diff --git a/src/tactic/goal.h b/src/tactic/goal.h index f32e4a66b..5e7e0b2fe 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -55,6 +55,7 @@ protected: proof_converter_ref m_pc; dependency_converter_ref m_dc; unsigned m_ref_count; + std::string m_reason_unknown; expr_array m_forms; expr_array m_proofs; expr_dependency_array m_dependencies; @@ -159,6 +160,8 @@ public: void set(model_converter* m) { m_mc = m; } void set(proof_converter* p) { m_pc = p; } + void set_reason_unknown(std::string const& reason_unknown) { m_reason_unknown = reason_unknown; } + std::string const& get_reason_unknown() { return m_reason_unknown; } bool is_cnf() const; goal * translate(ast_translation & translator) const; @@ -176,6 +179,8 @@ template inline bool is_decided_sat(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided_sat(); } template inline bool is_decided_unsat(GoalCollection const & c) { return c.size() == 1 && c[0]->is_decided_unsat(); } +template +inline std::string get_reason_unknown(GoalCollection const & c) { return c.size() == 1 ? c[0]->get_reason_unknown() : std::string("unknown"); } template void for_each_expr_at(ForEachProc& proc, goal const & s) { diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index cc0ab8f5e..b1609ed85 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -184,8 +184,7 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p if (r.size() > 0) { pr = r[0]->pr(0); CTRACE("tactic", pr, tout << pr << "\n";); - } - + } if (is_decided_sat(r)) { model_converter_ref mc = r[0]->mc(); @@ -217,7 +216,9 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p if (mc) (*mc)(labels); } - reason_unknown = "incomplete"; + reason_unknown = get_reason_unknown(r); + if (reason_unknown.empty()) + reason_unknown = "unknown"; return l_undef; } } From 3dfff3d7a1fc013b5d6ab1cac1a4c0f3d88d97a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Sep 2022 22:48:54 -0700 Subject: [PATCH 081/477] tracing for fpa --- src/sat/smt/fpa_solver.cpp | 41 +++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 55e41fea4..4a5795953 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -47,20 +47,18 @@ namespace fpa { expr_ref solver::convert(expr* e) { expr_ref res(m); expr* ccnv; - TRACE("t_fpa", tout << "converting " << mk_ismt2_pp(e, m) << std::endl;); + TRACE("t_fpa", tout << "converting " << mk_ismt2_pp(e, m) << "\n";); if (m_conversions.find(e, ccnv)) { res = ccnv; - TRACE("t_fpa_detail", tout << "cached:" << std::endl; - tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << - mk_ismt2_pp(res, m) << std::endl;); + TRACE("t_fpa_detail", tout << "cached:" << "\n"; + tout << mk_ismt2_pp(e, m) << "\n" << " -> " << "\n" << mk_ismt2_pp(res, m) << "\n";); } else { res = m_rw.convert(m_th_rw, e); - TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; - tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << - mk_ismt2_pp(res, m) << std::endl;); + TRACE("t_fpa_detail", tout << "converted; caching:" << "\n"; + tout << mk_ismt2_pp(e, m) << "\n" << " -> " << "\n" << mk_ismt2_pp(res, m) << "\n";); m_conversions.insert(e, res); m.inc_ref(e); @@ -257,26 +255,23 @@ namespace fpa { } void solver::ensure_equality_relation(theory_var x, theory_var y) { + fpa_util& fu = m_fpa_util; enode* e_x = var2enode(x); enode* e_y = var2enode(y); - - TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl; - tout << mk_ismt2_pp(e_x->get_expr(), m) << std::endl << " = " << std::endl << - mk_ismt2_pp(e_y->get_expr(), m) << std::endl;); - - fpa_util& fu = m_fpa_util; - expr* xe = e_x->get_expr(); expr* ye = e_y->get_expr(); if (fu.is_bvwrap(xe) || fu.is_bvwrap(ye)) return; + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n"; + tout << mk_ismt2_pp(xe, m) << "\n" << " = " << "\n" << mk_ismt2_pp(ye, m) << "\n";); + expr_ref xc = convert(xe); expr_ref yc = convert(ye); - TRACE("t_fpa_detail", tout << "xc = " << mk_ismt2_pp(xc, m) << std::endl << - "yc = " << mk_ismt2_pp(yc, m) << std::endl;); + TRACE("t_fpa_detail", tout << "xc = " << mk_ismt2_pp(xc, m) << "\n" << + "yc = " << mk_ismt2_pp(yc, m) << "\n";); expr_ref c(m); @@ -390,9 +385,9 @@ namespace fpa { for (enode* n : ctx.get_egraph().nodes()) { theory_var v = n->get_th_var(m_fpa_util.get_family_id()); if (v != -1) { - if (first) out << "fpa theory variables:" << std::endl; + if (first) out << "fpa theory variables:" << "\n"; out << v << " -> " << - mk_ismt2_pp(n->get_expr(), m) << std::endl; + mk_ismt2_pp(n->get_expr(), m) << "\n"; first = false; } } @@ -400,24 +395,24 @@ namespace fpa { if (first) return out; - out << "bv theory variables:" << std::endl; + out << "bv theory variables:" << "\n"; for (enode* n : ctx.get_egraph().nodes()) { theory_var v = n->get_th_var(m_bv_util.get_family_id()); if (v != -1) out << v << " -> " << - mk_ismt2_pp(n->get_expr(), m) << std::endl; + mk_ismt2_pp(n->get_expr(), m) << "\n"; } - out << "arith theory variables:" << std::endl; + out << "arith theory variables:" << "\n"; for (enode* n : ctx.get_egraph().nodes()) { theory_var v = n->get_th_var(m_arith_util.get_family_id()); if (v != -1) out << v << " -> " << - mk_ismt2_pp(n->get_expr(), m) << std::endl; + mk_ismt2_pp(n->get_expr(), m) << "\n"; } out << "equivalence classes:\n"; for (enode* n : ctx.get_egraph().nodes()) { expr* e = n->get_expr(); - out << n->get_root_id() << " --> " << mk_ismt2_pp(e, m) << std::endl; + out << n->get_root_id() << " --> " << mk_ismt2_pp(e, m) << "\n"; } return out; } From 5ca53f37c00fa5aa7bbc713250092c3d9183ae3e Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Sat, 24 Sep 2022 18:54:14 +0200 Subject: [PATCH 082/477] Throw an exception if the variable in decide-callback is already assigned (#6362) * Memory leak in .NET user-propagator The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically * Throw an exception if variable passed to decide is already assigned instead of running in an assertion violation --- src/smt/theory_user_propagator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index b8efea851..7bbf9d925 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -249,7 +249,11 @@ void theory_user_propagator::decide(bool_var& var, bool& is_pos) { // get unassigned variable from enode var = enode_to_bool(new_enode, new_bit); - + + if (var == null_bool_var) + // selected variable is already assigned + throw default_exception("expression in \"decide\" is already assigned"); + // in case the callback did not decide on a truth value -> let Z3 decide is_pos = ctx.guess(var, phase); } From b3c2169838e12ea9c5da8d5a4c35faf8eb7dd412 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Sep 2022 09:55:15 -0700 Subject: [PATCH 083/477] Update msvc-static-build.yml --- .github/workflows/msvc-static-build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/msvc-static-build.yml b/.github/workflows/msvc-static-build.yml index 81fb9c45a..461752279 100644 --- a/.github/workflows/msvc-static-build.yml +++ b/.github/workflows/msvc-static-build.yml @@ -1,5 +1,8 @@ name: MSVC Static Build +permissions: + contents: read # to fetch code (actions/checkout) + on: push: pull_request: From aadb1a2d446834d8e1fcdbcfd501513ac6eb5981 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Sep 2022 09:56:45 -0700 Subject: [PATCH 084/477] Update msvc-static-build.yml move "permissions" to same location as wasm actions --- .github/workflows/msvc-static-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/msvc-static-build.yml b/.github/workflows/msvc-static-build.yml index 461752279..2db222161 100644 --- a/.github/workflows/msvc-static-build.yml +++ b/.github/workflows/msvc-static-build.yml @@ -1,12 +1,12 @@ name: MSVC Static Build - -permissions: - contents: read # to fetch code (actions/checkout) on: push: pull_request: +permissions: + contents: read # to fetch code (actions/checkout) + jobs: build: runs-on: windows-2019 From 6f2fde87d1a58469cbc7f5a357aa9cab7cc7c3b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Sep 2022 14:40:30 -0700 Subject: [PATCH 085/477] move has-default up before merge of parents Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_solver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index 1c4b95abe..f66c2a183 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -164,6 +164,10 @@ namespace array { auto& d2 = get_var_data(v2); if (d2.m_prop_upward && !d1.m_prop_upward) set_prop_upward(v1); + if (d1.m_has_default && !d2.m_has_default) + add_parent_default(v2); + if (!d1.m_has_default && d2.m_has_default) + add_parent_default(v1); for (euf::enode* lambda : d2.m_lambdas) add_lambda(v1, lambda); for (euf::enode* lambda : d2.m_parent_lambdas) @@ -172,10 +176,6 @@ namespace array { add_parent_select(v1, select); if (is_lambda(e1) || is_lambda(e2)) push_axiom(congruence_axiom(n1, n2)); - if (d1.m_has_default && !d2.m_has_default) - add_parent_default(v2); - if (!d1.m_has_default && d2.m_has_default) - add_parent_default(v1); } void solver::add_parent_select(theory_var v_child, euf::enode* select) { From 9be8fc7857024c8888695c0ec3814b6750a83a36 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Sep 2022 14:26:20 -0700 Subject: [PATCH 086/477] Add EUF (congruence closure) proof hints and checker to the new core EUF proofs are checked modulo union-find. Equalities are added to to union-find if they are assumptions or if they can be derived using congruence closure. The congruence closure assumptions are added as proof-hints. Note that this proof format does not track equality inferences, symmetry and transitivity. Instead they are handled by assuming a union-find based checker. --- src/ast/euf/euf_egraph.cpp | 47 +++++---- src/ast/euf/euf_egraph.h | 19 +++- src/ast/euf/euf_justification.h | 24 ++++- src/sat/smt/bv_solver.cpp | 6 +- src/sat/smt/euf_proof.cpp | 53 +++++++++- src/sat/smt/euf_proof_checker.cpp | 162 +++++++++++++++++++++++++++++- src/sat/smt/euf_solver.cpp | 33 +++--- src/sat/smt/euf_solver.h | 19 +++- src/sat/smt/q_ematch.cpp | 6 +- src/sat/smt/q_ematch.h | 1 + src/sat/smt/user_solver.cpp | 2 +- 11 files changed, 315 insertions(+), 57 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 3820d2592..30dd1d720 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -126,7 +126,7 @@ namespace euf { if (n2 == n) update_children(n); else - merge(n, n2, justification::congruence(comm)); + merge(n, n2, justification::congruence(comm, m_congruence_timestamp++)); } return n; } @@ -554,7 +554,7 @@ namespace euf { force_push(); for (unsigned i = 0; i < m_to_merge.size() && m.limit().inc() && !inconsistent(); ++i) { auto const& w = m_to_merge[i]; - merge(w.a, w.b, justification::congruence(w.commutativity)); + merge(w.a, w.b, justification::congruence(w.commutativity, m_congruence_timestamp++)); } m_to_merge.reset(); return @@ -707,25 +707,28 @@ namespace euf { } template - void egraph::explain(ptr_vector& justifications) { + void egraph::explain(ptr_vector& justifications, cc_justification* cc) { SASSERT(m_inconsistent); push_todo(m_n1); push_todo(m_n2); - explain_eq(justifications, m_n1, m_n2, m_justification); - explain_todo(justifications); + explain_eq(justifications, cc, m_n1, m_n2, m_justification); + explain_todo(justifications, cc); } template - void egraph::explain_eq(ptr_vector& justifications, enode* a, enode* b, justification const& j) { + void egraph::explain_eq(ptr_vector& justifications, cc_justification* cc, enode* a, enode* b, justification const& j) { + TRACE("euf_verbose", tout << "explain-eq: " << bpp(a) << " == " << bpp(b) << " jst: " << j << "\n";); if (j.is_external()) justifications.push_back(j.ext()); else if (j.is_congruence()) push_congruence(a, b, j.is_commutative()); + if (cc && j.is_congruence()) + cc->push_back(std::tuple(a, b, j.timestamp(), j.is_commutative())); } template - void egraph::explain_eq(ptr_vector& justifications, enode* a, enode* b) { + void egraph::explain_eq(ptr_vector& justifications, cc_justification* cc, enode* a, enode* b) { SASSERT(a->get_root() == b->get_root()); enode* lca = find_lca(a, b); @@ -734,27 +737,27 @@ namespace euf { push_to_lca(b, lca); if (m_used_eq) m_used_eq(a->get_expr(), b->get_expr(), lca->get_expr()); - explain_todo(justifications); + explain_todo(justifications, cc); } template - unsigned egraph::explain_diseq(ptr_vector& justifications, enode* a, enode* b) { + unsigned egraph::explain_diseq(ptr_vector& justifications, cc_justification* cc, enode* a, enode* b) { enode* ra = a->get_root(), * rb = b->get_root(); SASSERT(ra != rb); if (ra->interpreted() && rb->interpreted()) { - explain_eq(justifications, a, ra); - explain_eq(justifications, b, rb); + explain_eq(justifications, cc, a, ra); + explain_eq(justifications, cc, b, rb); return sat::null_bool_var; } enode* r = tmp_eq(ra, rb); SASSERT(r && r->get_root()->value() == l_false); - explain_eq(justifications, r, r->get_root()); + explain_eq(justifications, cc, r, r->get_root()); return r->get_root()->bool_var(); } template - void egraph::explain_todo(ptr_vector& justifications) { + void egraph::explain_todo(ptr_vector& justifications, cc_justification* cc) { for (unsigned i = 0; i < m_todo.size(); ++i) { enode* n = m_todo[i]; if (n->is_marked1()) @@ -762,7 +765,7 @@ namespace euf { if (n->m_target) { n->mark1(); CTRACE("euf_verbose", m_display_justification, n->m_justification.display(tout << n->get_expr_id() << " = " << n->m_target->get_expr_id() << " ", m_display_justification) << "\n";); - explain_eq(justifications, n, n->m_target, n->m_justification); + explain_eq(justifications, cc, n, n->m_target, n->m_justification); } else if (!n->is_marked1() && n->value() != l_undef) { n->mark1(); @@ -890,15 +893,15 @@ namespace euf { } } -template void euf::egraph::explain(ptr_vector& justifications); -template void euf::egraph::explain_todo(ptr_vector& justifications); -template void euf::egraph::explain_eq(ptr_vector& justifications, enode* a, enode* b); -template unsigned euf::egraph::explain_diseq(ptr_vector& justifications, enode* a, enode* b); +template void euf::egraph::explain(ptr_vector& justifications, cc_justification*); +template void euf::egraph::explain_todo(ptr_vector& justifications, cc_justification*); +template void euf::egraph::explain_eq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); +template unsigned euf::egraph::explain_diseq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); -template void euf::egraph::explain(ptr_vector& justifications); -template void euf::egraph::explain_todo(ptr_vector& justifications); -template void euf::egraph::explain_eq(ptr_vector& justifications, enode* a, enode* b); -template unsigned euf::egraph::explain_diseq(ptr_vector& justifications, enode* a, enode* b); +template void euf::egraph::explain(ptr_vector& justifications, cc_justification*); +template void euf::egraph::explain_todo(ptr_vector& justifications, cc_justification*); +template void euf::egraph::explain_eq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); +template unsigned euf::egraph::explain_diseq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index 55f94f0f2..c0d7f03d8 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -72,6 +72,13 @@ namespace euf { th_eq(theory_id id, theory_var v1, theory_var v2, expr* eq) : m_id(id), m_v1(v1), m_v2(v2), m_eq(eq), m_root(nullptr) {} }; + + // cc_justification contains the uses of congruence closure + // It is the only information collected from justifications in order to + // reconstruct EUF proofs. Transitivity, Symmetry of equality are not + // tracked. + typedef std::tuple cc_justification_record; + typedef svector cc_justification; class egraph { @@ -186,6 +193,8 @@ namespace euf { stats m_stats; bool m_uses_congruence = false; bool m_default_relevant = true; + uint64_t m_congruence_timestamp = 0; + std::vector> m_on_merge; std::function m_on_make; std::function m_used_eq; @@ -226,10 +235,10 @@ namespace euf { void erase_from_table(enode* p); template - void explain_eq(ptr_vector& justifications, enode* a, enode* b, justification const& j); + void explain_eq(ptr_vector& justifications, cc_justification* cc, enode* a, enode* b, justification const& j); template - void explain_todo(ptr_vector& justifications); + void explain_todo(ptr_vector& justifications, cc_justification* cc); std::ostream& display(std::ostream& out, unsigned max_args, enode* n) const; @@ -306,11 +315,11 @@ namespace euf { void end_explain(); bool uses_congruence() const { return m_uses_congruence; } template - void explain(ptr_vector& justifications); + void explain(ptr_vector& justifications, cc_justification* cc); template - void explain_eq(ptr_vector& justifications, enode* a, enode* b); + void explain_eq(ptr_vector& justifications, cc_justification* cc, enode* a, enode* b); template - unsigned explain_diseq(ptr_vector& justifications, enode* a, enode* b); + unsigned explain_diseq(ptr_vector& justifications, cc_justification* cc, enode* a, enode* b); enode_vector const& nodes() const { return m_nodes; } ast_manager& get_manager() { return m; } diff --git a/src/ast/euf/euf_justification.h b/src/ast/euf/euf_justification.h index 2241ff0b6..57b532e3b 100644 --- a/src/ast/euf/euf_justification.h +++ b/src/ast/euf/euf_justification.h @@ -13,6 +13,11 @@ Author: Nikolaj Bjorner (nbjorner) 2020-08-23 +Notes: + +- congruence closure justifications are given a timestamp so it is easy to sort them. + See the longer descriptoin in euf_proof_checker.cpp + --*/ #pragma once @@ -27,11 +32,15 @@ namespace euf { }; kind_t m_kind; bool m_comm; - void* m_external; - justification(bool comm): + union { + void* m_external; + uint64_t m_timestamp; + }; + + justification(bool comm, uint64_t ts): m_kind(kind_t::congruence_t), m_comm(comm), - m_external(nullptr) + m_timestamp(ts) {} justification(void* ext): @@ -48,12 +57,13 @@ namespace euf { {} static justification axiom() { return justification(); } - static justification congruence(bool c) { return justification(c); } + static justification congruence(bool c, uint64_t ts) { return justification(c, ts); } static justification external(void* ext) { return justification(ext); } bool is_external() const { return m_kind == kind_t::external_t; } bool is_congruence() const { return m_kind == kind_t::congruence_t; } bool is_commutative() const { return m_comm; } + uint64_t timestamp() const { SASSERT(is_congruence()); return m_timestamp; } template T* ext() const { SASSERT(is_external()); return static_cast(m_external); } @@ -64,7 +74,7 @@ namespace euf { case kind_t::axiom_t: return axiom(); case kind_t::congruence_t: - return congruence(m_comm); + return congruence(m_comm, m_timestamp); default: UNREACHABLE(); return axiom(); @@ -90,4 +100,8 @@ namespace euf { return out; } }; + + inline std::ostream& operator<<(std::ostream& out, justification const& j) { + return j.display(out, nullptr); + } } diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 4a14067d1..8ef2c5cd5 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -313,7 +313,7 @@ namespace bv { case bv_justification::kind_t::eq2bit: SASSERT(s().value(c.m_antecedent) == l_true); r.push_back(c.m_antecedent); - ctx.add_antecedent(var2enode(c.m_v1), var2enode(c.m_v2)); + ctx.add_antecedent(probing, var2enode(c.m_v1), var2enode(c.m_v2)); break; case bv_justification::kind_t::ne2bit: { r.push_back(c.m_antecedent); @@ -381,8 +381,8 @@ namespace bv { break; } case bv_justification::kind_t::bv2int: { - ctx.add_antecedent(c.a, c.b); - ctx.add_antecedent(c.a, c.c); + ctx.add_antecedent(probing, c.a, c.b); + ctx.add_antecedent(probing, c.a, c.c); break; } } diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index bcbc9439b..bf8aad44b 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -46,7 +46,7 @@ namespace euf { * so it isn't necessarily an axiom over EUF, * We will here leave it to the EUF checker to perform resolution steps. */ - void solver::log_antecedents(literal l, literal_vector const& r) { + void solver::log_antecedents(literal l, literal_vector const& r, eq_proof_hint* hint) { TRACE("euf", log_antecedents(tout, l, r);); if (!use_drat()) return; @@ -55,7 +55,7 @@ namespace euf { lits.push_back(~lit); if (l != sat::null_literal) lits.push_back(l); - get_drat().add(lits, sat::status::th(true, get_id())); + get_drat().add(lits, sat::status::th(true, get_id(), hint)); } void solver::log_antecedents(std::ostream& out, literal l, literal_vector const& r) { @@ -74,6 +74,55 @@ namespace euf { } } + eq_proof_hint* solver::mk_hint(literal lit, literal_vector const& r) { + if (!use_drat()) + return nullptr; + push(value_trail(m_lit_tail)); + push(value_trail(m_cc_tail)); + push(restore_size_trail(m_eq_proof_literals)); + if (lit != sat::null_literal) + m_eq_proof_literals.push_back(~lit); + m_eq_proof_literals.append(r); + m_lit_head = m_lit_tail; + m_cc_head = m_cc_tail; + m_lit_tail = m_eq_proof_literals.size(); + m_cc_tail = m_explain_cc.size(); + return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); + } + + expr* eq_proof_hint::get_hint(euf::solver& s) const { + ast_manager& m = s.get_manager(); + func_decl_ref cc(m); + sort* proof = m.mk_proof_sort(); + ptr_buffer sorts; + expr_ref_vector args(m); + if (m_cc_head < m_cc_tail) { + sort* sorts[2] = { m.mk_bool_sort(), m.mk_bool_sort() }; + cc = m.mk_func_decl(symbol("cc"), 2, sorts, proof); + } + auto cc_proof = [&](bool comm, expr* eq) { + return m.mk_app(cc, m.mk_bool_val(comm), eq); + }; + auto compare_ts = [](cc_justification_record const& a, + cc_justification_record const& b) { + auto const& [_1, _2, ta, _3] = a; + auto const& [_4, _5, tb, _6] = b; + return ta < tb; + }; + for (unsigned i = m_lit_head; i < m_lit_tail; ++i) + args.push_back(s.literal2expr(s.m_eq_proof_literals[i])); + std::sort(s.m_explain_cc.data() + m_cc_head, s.m_explain_cc.data() + m_cc_tail, compare_ts); + for (unsigned i = m_cc_head; i < m_cc_tail; ++i) { + auto const& [a, b, ts, comm] = s.m_explain_cc[i]; + args.push_back(cc_proof(comm, m.mk_eq(a->get_expr(), b->get_expr()))); + } + for (auto * arg : args) + sorts.push_back(arg->get_sort()); + + func_decl* f = m.mk_func_decl(symbol("euf"), sorts.size(), sorts.data(), proof); + return m.mk_app(f, args); + } + void solver::set_tmp_bool_var(bool_var b, expr* e) { m_bool_var2expr.setx(b, e, nullptr); } diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 41f627914..3ddafd00b 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -15,18 +15,178 @@ Author: --*/ +#include "util/union_find.h" #include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_proof_checker.h" namespace euf { + /** + * The equality proof checker checks congruence proofs. + * A congruence claim comprises + * - a set of equality and diseqality literals that are + * unsatisfiable modulo equality reasoning. + * - a list of congruence claims that are used for equality reasoning. + * Congruence claims are expressions of the form + * (cc uses_commutativity (= a b)) + * where uses_commutativity is true or false + * If uses commutativity is true, then a, b are (the same) binary functions + * a := f(x,y), b := f(z,u), such that x = u and y = z are consequences from + * the current equalities. + * If uses_commtativity is false, then a, b are the same n-ary expressions + * each argument position i, a_i == b_i follows from current equalities. + * If the arguments are equal according to the current equalities, then the equality + * a = b is added as a consequence. + * + * The congruence claims can be justified from the equalities in the literals. + * To be more precise, the congruence claims are justified in the they appear. + * The congruence closure algorithm (egraph) uses timestamps to record a timestamp + * when a congruence was inferred. Proof generation ensures that the congruence premises + * are sorted by the timestamp such that a congruence that depends on an earlier congruence + * appears later in the sorted order. + * + * Equality justifications are checked using union-find. + * We use union-find instead of fine-grained equality proofs (symmetry and transitivity + * of equality) assuming that it is both cheap and simple to establish a certified + * union-find checker. + */ + + class eq_proof_checker : public proof_checker_plugin { + ast_manager& m; + basic_union_find m_uf; + svector> m_expr2id; + svector> m_diseqs; + unsigned m_ts = 0; + + void merge(expr* x, expr* y) { + m_uf.merge(expr2id(x), expr2id(y)); + IF_VERBOSE(10, verbose_stream() << "merge " << mk_bounded_pp(x, m) << " == " << mk_bounded_pp(y, m) << "\n"); + } + + bool are_equal(expr* x, expr* y) { + return m_uf.find(expr2id(x)) == m_uf.find(expr2id(y)); + } + + bool congruence(bool comm, app* x, app* y) { + if (x->get_decl() != y->get_decl()) + return false; + if (x->get_num_args() != y->get_num_args()) + return false; + if (comm) { + if (x->get_num_args() != 2) + return false; + if (!are_equal(x->get_arg(0), y->get_arg(1))) + return false; + if (!are_equal(y->get_arg(0), x->get_arg(1))) + return false; + merge(x, y); + } + else { + for (unsigned i = 0; i < x->get_num_args(); ++i) + if (!are_equal(x->get_arg(i), y->get_arg(i))) + return false; + merge(x, y); + } + IF_VERBOSE(10, verbose_stream() << "cc " << mk_bounded_pp(x, m) << " == " << mk_bounded_pp(y, m) << "\n"); + return true; + } + + void reset() { + ++m_ts; + if (m_ts == 0) { + m_expr2id.reset(); + ++m_ts; + } + m_uf.reset(); + m_diseqs.reset(); + } + + unsigned expr2id(expr* e) { + auto [ts, id] = m_expr2id.get(e->get_id(), {0,0}); + if (ts != m_ts) { + id = m_uf.mk_var(); + m_expr2id.setx(e->get_id(), {m_ts, id}, {0,0}); + } + return id; + } + + + public: + eq_proof_checker(ast_manager& m): m(m) {} + + ~eq_proof_checker() override {} + + bool check(expr_ref_vector const& clause, app* jst, expr_ref_vector& units) override { + IF_VERBOSE(10, verbose_stream() << clause << "\n" << mk_pp(jst, m) << "\n"); + reset(); + expr_mark pos, neg; + expr* x, *y; + for (expr* e : clause) + if (m.is_not(e, e)) + neg.mark(e, true); + else + pos.mark(e, true); + + for (expr* arg : *jst) { + if (m.is_bool(arg)) { + bool sign = m.is_not(arg, arg); + if (sign && !pos.is_marked(arg)) + units.push_back(m.mk_not(arg)); + else if (!sign & !neg.is_marked(arg)) + units.push_back(arg); + if (m.is_eq(arg, x, y)) { + if (sign) + m_diseqs.push_back({x, y}); + else + merge(x, y); + } + else + IF_VERBOSE(0, verbose_stream() << "TODO " << mk_pp(arg, m) << " " << sign << "\n"); + } + else if (m.is_proof(arg)) { + if (!is_app(arg)) + return false; + app* a = to_app(arg); + if (a->get_num_args() != 2) + return false; + if (a->get_name() != symbol("cc")) + return false; + if (!m.is_eq(a->get_arg(1), x, y)) + return false; + if (!is_app(x) || !is_app(y)) + return false; + if (!congruence(m.is_true(a->get_arg(0)), to_app(x), to_app(y))) { + IF_VERBOSE(0, verbose_stream() << "not congruent " << mk_pp(a, m) << "\n"); + return false; + } + } + else { + IF_VERBOSE(0, verbose_stream() << "unrecognized argument " << mk_pp(arg, m) << "\n"); + return false; + } + } + for (auto const& [a, b] : m_diseqs) + if (are_equal(a, b)) + return true; + return false; + } + + void register_plugins(proof_checker& pc) override { + pc.register_plugin(symbol("euf"), this); + } + + }; + proof_checker::proof_checker(ast_manager& m): m(m) { arith::proof_checker* apc = alloc(arith::proof_checker, m); + eq_proof_checker* epc = alloc(eq_proof_checker, m); m_plugins.push_back(apc); + m_plugins.push_back(epc); apc->register_plugins(*this); - (void)m; + epc->register_plugins(*this); } proof_checker::~proof_checker() {} diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index c30fdbf89..2e6b07e51 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -202,6 +202,8 @@ namespace euf { void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) { m_egraph.begin_explain(); m_explain.reset(); + if (use_drat() && !probing) + push(restore_size_trail(m_explain_cc, m_explain_cc.size())); auto* ext = sat::constraint_base::to_extension(idx); if (ext == this) get_antecedents(l, constraint::from_idx(idx), r, probing); @@ -220,33 +222,35 @@ namespace euf { } } m_egraph.end_explain(); + eq_proof_hint* hint = (use_drat() && !probing) ? mk_hint(l, r) : nullptr; unsigned j = 0; for (sat::literal lit : r) if (s().lvl(lit) > 0) r[j++] = lit; r.shrink(j); - TRACE("euf", tout << "explain " << l << " <- " << r << " " << probing << "\n";); + CTRACE("euf", probing, tout << "explain " << l << " <- " << r << "\n"); DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true);); if (!probing) - log_antecedents(l, r); + log_antecedents(l, r, hint); } void solver::get_antecedents(literal l, th_explain& jst, literal_vector& r, bool probing) { for (auto lit : euf::th_explain::lits(jst)) r.push_back(lit); for (auto eq : euf::th_explain::eqs(jst)) - add_antecedent(eq.first, eq.second); - + add_antecedent(probing, eq.first, eq.second); + if (!probing && use_drat()) log_justification(l, jst); } - void solver::add_antecedent(enode* a, enode* b) { - m_egraph.explain_eq(m_explain, a, b); + void solver::add_antecedent(bool probing, enode* a, enode* b) { + cc_justification* cc = (!probing && use_drat()) ? &m_explain_cc : nullptr; + m_egraph.explain_eq(m_explain, cc, a, b); } - void solver::add_diseq_antecedent(ptr_vector& ex, enode* a, enode* b) { - sat::bool_var v = get_egraph().explain_diseq(ex, a, b); + void solver::add_diseq_antecedent(ptr_vector& ex, cc_justification* cc, enode* a, enode* b) { + sat::bool_var v = get_egraph().explain_diseq(ex, cc, a, b); SASSERT(v == sat::null_bool_var || s().value(v) == l_false); if (v != sat::null_bool_var) ex.push_back(to_ptr(sat::literal(v, true))); @@ -262,14 +266,17 @@ namespace euf { void solver::get_antecedents(literal l, constraint& j, literal_vector& r, bool probing) { expr* e = nullptr; euf::enode* n = nullptr; + cc_justification* cc = nullptr; if (!probing && !m_drating) init_ackerman(); - + if (!probing && use_drat()) + cc = &m_explain_cc; + switch (j.kind()) { case constraint::kind_t::conflict: SASSERT(m_egraph.inconsistent()); - m_egraph.explain(m_explain); + m_egraph.explain(m_explain, cc); break; case constraint::kind_t::eq: e = m_bool_var2expr[l.var()]; @@ -277,14 +284,14 @@ namespace euf { SASSERT(n); SASSERT(n->is_equality()); SASSERT(!l.sign()); - m_egraph.explain_eq(m_explain, n->get_arg(0), n->get_arg(1)); + m_egraph.explain_eq(m_explain, cc, n->get_arg(0), n->get_arg(1)); break; case constraint::kind_t::lit: e = m_bool_var2expr[l.var()]; n = m_egraph.find(e); SASSERT(n); SASSERT(m.is_bool(n->get_expr())); - m_egraph.explain_eq(m_explain, n, (l.sign() ? mk_false() : mk_true())); + m_egraph.explain_eq(m_explain, cc, n, (l.sign() ? mk_false() : mk_true())); break; default: IF_VERBOSE(0, verbose_stream() << (unsigned)j.kind() << "\n"); @@ -423,7 +430,7 @@ namespace euf { m_egraph.begin_explain(); m_explain.reset(); - m_egraph.explain_eq(m_explain, e.child(), e.root()); + m_egraph.explain_eq(m_explain, nullptr, e.child(), e.root()); m_egraph.end_explain(); if (m_egraph.uses_congruence()) return false; diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index d19e0acac..f4867d841 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -60,9 +60,18 @@ namespace euf { std::ostream& display(std::ostream& out) const; }; + class eq_proof_hint : public th_proof_hint { + unsigned m_lit_head, m_lit_tail, m_cc_head, m_cc_tail; + public: + eq_proof_hint(unsigned lh, unsigned lt, unsigned ch, unsigned ct): + m_lit_head(lh), m_lit_tail(lt), m_cc_head(ch), m_cc_tail(ct) {} + expr* get_hint(euf::solver& s) const override; + }; + class solver : public sat::extension, public th_internalizer, public th_decompile, public sat::clause_eh { typedef top_sort deps_t; friend class ackerman; + friend class eq_proof_hint; class user_sort; struct stats { unsigned m_ackerman; @@ -110,6 +119,7 @@ namespace euf { ptr_vector m_bool_var2expr; ptr_vector m_explain; + euf::cc_justification m_explain_cc; unsigned m_num_scopes = 0; unsigned_vector m_var_trail; svector m_scopes; @@ -172,8 +182,11 @@ namespace euf { // proofs void log_antecedents(std::ostream& out, literal l, literal_vector const& r); - void log_antecedents(literal l, literal_vector const& r); + void log_antecedents(literal l, literal_vector const& r, eq_proof_hint* hint); void log_justification(literal l, th_explain const& jst); + literal_vector m_eq_proof_literals; + unsigned m_lit_head = 0, m_lit_tail = 0, m_cc_head = 0, m_cc_tail = 0; + eq_proof_hint* mk_hint(literal lit, literal_vector const& r); bool m_proof_initialized = false; void init_proof(); @@ -307,8 +320,8 @@ namespace euf { void get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) override; void get_antecedents(literal l, th_explain& jst, literal_vector& r, bool probing); - void add_antecedent(enode* a, enode* b); - void add_diseq_antecedent(ptr_vector& ex, enode* a, enode* b); + void add_antecedent(bool probing, enode* a, enode* b); + void add_diseq_antecedent(ptr_vector& ex, cc_justification* cc, enode* a, enode* b); void add_explain(size_t* p) { m_explain.push_back(p); } void reset_explain() { m_explain.reset(); } void set_eliminated(bool_var v) override; diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 490bce46e..a4093cdb7 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -113,14 +113,16 @@ namespace q { if (idx != UINT_MAX) lit = c[idx]; m_explain.reset(); + m_explain_cc.reset(); ctx.get_egraph().begin_explain(); ctx.reset_explain(); + euf::cc_justification* cc = ctx.use_drat() ? &m_explain_cc : nullptr; for (auto const& [a, b] : m_evidence) { SASSERT(a->get_root() == b->get_root() || ctx.get_egraph().are_diseq(a, b)); if (a->get_root() == b->get_root()) - ctx.get_egraph().explain_eq(m_explain, a, b); + ctx.get_egraph().explain_eq(m_explain, cc, a, b); else - ctx.add_diseq_antecedent(m_explain, a, b); + ctx.add_diseq_antecedent(m_explain, cc, a, b); } ctx.get_egraph().end_explain(); diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index ef933a3a8..834c8740d 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -96,6 +96,7 @@ namespace q { binding* alloc_binding(clause& c, app* pat, euf::enode* const* _binding, unsigned max_generation, unsigned min_top, unsigned max_top); ptr_vector m_explain; + euf::cc_justification m_explain_cc; sat::ext_justification_idx mk_justification(unsigned idx, clause& c, euf::enode* const* b); void ensure_ground_enodes(expr* e); diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 494e69e55..5c98a6fac 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -207,7 +207,7 @@ namespace user_solver { for (unsigned id : prop.m_ids) r.append(m_id2justification[id]); for (auto const& p : prop.m_eqs) - ctx.add_antecedent(expr2enode(p.first), expr2enode(p.second)); + ctx.add_antecedent(probing, expr2enode(p.first), expr2enode(p.second)); } /* From d7b9cc70d003ae9ad75062c89293be6f05fc3b99 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Sep 2022 18:03:16 -0700 Subject: [PATCH 087/477] smc Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_mbi.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index a87be2dee..8be75f03c 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -355,8 +355,10 @@ namespace q { return expr_ref(m); } - else if (!(*p)(*m_model, vars, fmls)) + else if (!(*p)(*m_model, vars, fmls)) { + TRACE("q", tout << "theory projection failed\n"); return expr_ref(m); + } } for (app* v : vars) { expr_ref term(m); @@ -581,6 +583,7 @@ namespace q { binding.reset(); auto const& nodes = ctx.get_egraph().nodes(); m_model->reset_eval_cache(); + model::scoped_model_completion _sc(*m_model, true); for (unsigned j = 0; j < offsets.size(); ++j) { unsigned offset = offsets[j]; binding.push_back(nodes[offset]->get_expr()); From 7b982a812eabf6e0a6ccccdf5fd1b157887dcf32 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Sep 2022 18:09:32 -0700 Subject: [PATCH 088/477] fix build Signed-off-by: Nikolaj Bjorner --- src/test/egraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/egraph.cpp b/src/test/egraph.cpp index a3c61abad..a3e70a77f 100644 --- a/src/test/egraph.cpp +++ b/src/test/egraph.cpp @@ -124,7 +124,7 @@ static void test3() { SASSERT(g.inconsistent()); ptr_vector js; g.begin_explain(); - g.explain(js); + g.explain(js, nullptr); g.end_explain(); for (int* j : js) std::cout << "conflict: " << *j << "\n"; From 9782d4a730174f406f710a7420822b11d3a3cdc4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Sep 2022 05:04:02 -0700 Subject: [PATCH 089/477] #5261 Signed-off-by: Nikolaj Bjorner --- src/shell/dimacs_frontend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 092e01acf..12dedb64f 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -75,7 +75,7 @@ static void display_model(sat::solver const & s) { case l_true: std::cout << i << " "; break; } } - std::cout << " 0\n"; + std::cout << "0\n"; } static void display_core(sat::solver const& s, vector const& tracking_clauses) { From 107981f099f478cb278d5b4c2c9181515e8c6769 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Sep 2022 10:40:43 -0700 Subject: [PATCH 090/477] update proof formats for new core - update proof format for quantifier instantiation to track original literals - update proof replay tools with ability to extract proof object The formats and features are subject to heavy revisions. Example ``` (set-option :sat.euf true) (set-option :sat.smt.proof eufproof.smt2) (declare-fun f (Int) Int) (declare-const x Int) (assert (or (= (f (f (f x))) x) (= (f (f x)) x))) (assert (not (= (f (f (f (f (f (f x)))))) x))) (check-sat) ``` eufproof.smt2 is: ``` (declare-fun x () Int) (declare-fun f (Int) Int) (define-const $24 Int (f x)) (define-const $25 Int (f $24)) (define-const $26 Int (f $25)) (define-const $27 Bool (= $26 x)) (define-const $28 Bool (= $25 x)) (assume $27 $28) (define-const $30 Int (f $26)) (define-const $31 Int (f $30)) (define-const $32 Int (f $31)) (define-const $33 Bool (= $32 x)) (assume (not $33)) (declare-fun rup () Proof) (infer (not $33) rup) (declare-fun euf (Bool Bool Proof Proof Proof Proof) Proof) (declare-fun cc (Bool) Proof) (define-const $42 Bool (= $32 $30)) (define-const $43 Proof (cc $42)) (define-const $40 Bool (= $31 $24)) (define-const $41 Proof (cc $40)) (define-const $38 Bool (= $30 $25)) (define-const $39 Proof (cc $38)) (define-const $36 Bool (= $24 $26)) (define-const $37 Proof (cc $36)) (define-const $34 Bool (not $33)) (define-const $44 Proof (euf $34 $28 $37 $39 $41 $43)) (infer (not $28) $33 $44) (infer (not $28) rup) (infer $27 rup) (declare-fun euf (Bool Bool Proof Proof Proof) Proof) (define-const $49 Bool (= $32 $26)) (define-const $50 Proof (cc $49)) (define-const $47 Bool (= $31 $25)) (define-const $48 Proof (cc $47)) (define-const $45 Bool (= $24 $30)) (define-const $46 Proof (cc $45)) (define-const $51 Proof (euf $34 $27 $46 $48 $50)) (infer $33 $51) (infer rup) ``` Example of inspecting proof from Python: ``` from z3 import * def parse(file): s = Solver() set_option("solver.proof.save", True) set_option("solver.proof.check", False) s.from_file(file) for step in s.proof().children(): print(step) parse("../eufproof.smt2") ``` Proof checking (self-validation) is on by default. Proof saving is off by default. You can use the proof logs and the proof terms to retrieve quantifier instantiations from the new core. The self-checker contains a few built-in tuned checkers but falls back to self-checking inferred clauses using SMT. --- src/api/api_parsers.cpp | 4 + src/api/api_solver.cpp | 10 ++- src/ast/ast.cpp | 10 +-- src/cmd_context/basic_cmds.cpp | 4 +- src/cmd_context/cmd_context.cpp | 2 + src/cmd_context/cmd_context.h | 5 +- src/cmd_context/extra_cmds/proof_cmds.cpp | 83 ++++++++++++++++--- src/muz/spacer/spacer_iuc_solver.h | 5 +- src/opt/opt_context.cpp | 2 +- src/opt/opt_context.h | 3 +- src/opt/opt_solver.cpp | 2 +- src/opt/opt_solver.h | 2 +- src/params/solver_params.pyg | 2 + src/sat/sat_solver/inc_sat_solver.cpp | 5 +- src/sat/smt/arith_axioms.cpp | 47 ++++++----- src/sat/smt/arith_diagnostics.cpp | 10 +++ src/sat/smt/arith_proof_checker.h | 10 +-- src/sat/smt/arith_solver.h | 2 + src/sat/smt/euf_proof.cpp | 26 +++--- src/sat/smt/euf_proof_checker.cpp | 44 ++++++++-- src/sat/smt/euf_solver.h | 2 +- src/sat/smt/q_ematch.cpp | 2 +- src/sat/smt/q_mbi.cpp | 17 +--- src/sat/smt/q_solver.cpp | 45 ++++++---- src/sat/smt/q_solver.h | 19 +++-- src/sat/smt/sat_th.cpp | 15 ++-- src/sat/smt/sat_th.h | 5 +- src/smt/smt_solver.cpp | 2 +- src/solver/check_sat_result.cpp | 13 ++- src/solver/check_sat_result.h | 18 ++-- src/solver/combined_solver.cpp | 9 +- src/solver/solver.h | 2 +- src/solver/solver_na2as.cpp | 2 +- src/solver/solver_na2as.h | 1 - src/solver/solver_pool.cpp | 4 +- src/solver/tactic2solver.cpp | 6 +- .../fd_solver/bounded_int2bv_solver.cpp | 2 +- src/tactic/fd_solver/enum2bv_solver.cpp | 2 +- src/tactic/fd_solver/pb2bv_solver.cpp | 2 +- src/tactic/fd_solver/smtfd_solver.cpp | 2 +- 40 files changed, 295 insertions(+), 153 deletions(-) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 31ae28f47..00fe1cd8b 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -27,6 +27,7 @@ Revision History: #include "solver/solver_na2as.h" #include "muz/fp/dl_cmds.h" #include "opt/opt_cmds.h" +#include "cmd_context/extra_cmds/proof_cmds.h" @@ -42,6 +43,7 @@ extern "C" { ast_manager& m = c.m(); ctx = alloc(cmd_context, false, &(m)); install_dl_cmds(*ctx.get()); + install_proof_cmds(*ctx.get()); install_opt_cmds(*ctx.get()); install_smt2_extra_cmds(*ctx.get()); ctx->register_plist(); @@ -175,6 +177,7 @@ extern "C" { ast_manager& m = mk_c(c)->m(); scoped_ptr ctx = alloc(cmd_context, false, &(m)); install_dl_cmds(*ctx.get()); + install_proof_cmds(*ctx.get()); install_opt_cmds(*ctx.get()); install_smt2_extra_cmds(*ctx.get()); ctx->register_plist(); @@ -233,6 +236,7 @@ extern "C" { auto* ctx = alloc(cmd_context, false, &(mk_c(c)->m())); mk_c(c)->cmd() = ctx; install_dl_cmds(*ctx); + install_proof_cmds(*ctx); install_opt_cmds(*ctx); install_smt2_extra_cmds(*ctx); ctx->register_plist(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index a56ca3d3c..5048f39fe 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -43,6 +43,7 @@ Revision History: #include "sat/sat_solver.h" #include "sat/tactic/goal2sat.h" #include "sat/tactic/sat2goal.h" +#include "cmd_context/extra_cmds/proof_cmds.h" extern "C" { @@ -257,8 +258,10 @@ extern "C" { void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) { auto& solver = *to_solver(s); - if (!solver.m_cmd_context) + if (!solver.m_cmd_context) { solver.m_cmd_context = alloc(cmd_context, false, &(mk_c(c)->m())); + install_proof_cmds(*solver.m_cmd_context); + } auto& ctx = solver.m_cmd_context; ctx->set_ignore_check(true); std::stringstream errstrm; @@ -270,6 +273,7 @@ extern "C" { return; } + bool initialized = to_solver(s)->m_solver.get() != nullptr; if (!initialized) init_solver(c, s); @@ -277,6 +281,10 @@ extern "C" { to_solver(s)->assert_expr(e); ctx->reset_tracked_assertions(); to_solver_ref(s)->set_model_converter(ctx->get_model_converter()); + auto* ctx_s = ctx->get_solver(); + if (ctx_s && ctx_s->get_proof()) + to_solver_ref(s)->set_proof(ctx_s->get_proof()); + } static void solver_from_dimacs_stream(Z3_context c, Z3_solver s, std::istream& is) { diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 38f4dcf05..f9bdc3414 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -856,11 +856,11 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren case PR_MODUS_PONENS_OEQ: return mk_proof_decl("mp~", k, 2, m_mp_oeq_decl); case PR_TH_LEMMA: return mk_proof_decl("th-lemma", k, num_parents, m_th_lemma_decls); case PR_HYPER_RESOLVE: return mk_proof_decl("hyper-res", k, num_parents, m_hyper_res_decl0); - case PR_ASSUMPTION_ADD: return mk_proof_decl("add-assume", k, num_parents, m_assumption_add_decl); - case PR_LEMMA_ADD: return mk_proof_decl("add-lemma", k, num_parents, m_lemma_add_decl); - case PR_TH_ASSUMPTION_ADD: return mk_proof_decl("add-th-assume", k, num_parents, m_th_assumption_add_decl); - case PR_TH_LEMMA_ADD: return mk_proof_decl("add-th-lemma", k, num_parents, m_th_lemma_add_decl); - case PR_REDUNDANT_DEL: return mk_proof_decl("del-redundant", k, num_parents, m_redundant_del_decl); + case PR_ASSUMPTION_ADD: return mk_proof_decl("assume", k, num_parents, m_assumption_add_decl); + case PR_LEMMA_ADD: return mk_proof_decl("infer", k, num_parents, m_lemma_add_decl); + case PR_TH_ASSUMPTION_ADD: return mk_proof_decl("th-assume", k, num_parents, m_th_assumption_add_decl); + case PR_TH_LEMMA_ADD: return mk_proof_decl("th-lemma", k, num_parents, m_th_lemma_add_decl); + case PR_REDUNDANT_DEL: return mk_proof_decl("del", k, num_parents, m_redundant_del_decl); case PR_CLAUSE_TRAIL: return mk_proof_decl("proof-trail", k, num_parents, false); default: UNREACHABLE(); diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index b17bc3641..a2757d955 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -177,10 +177,10 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", { if (!ctx.has_manager()) throw cmd_exception("proof is not available"); - if (ctx.ignore_check()) - return; expr_ref pr(ctx.m()); auto* chsr = ctx.get_check_sat_result(); + if (!chsr && ctx.ignore_check()) + return; if (!chsr) throw cmd_exception("proof is not available"); pr = chsr->get_proof(); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 97ae0fbc1..0c38f2e4a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -604,6 +604,8 @@ void cmd_context::global_params_updated() { if (m_opt) { get_opt()->updt_params(gparams::get_module("opt")); } + if (m_proof_cmds) + m_proof_cmds->updt_params(gparams::get_module("solver")); } void cmd_context::set_produce_models(bool f) { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 512e367ef..61e3b2ecc 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -96,8 +96,9 @@ public: virtual ~proof_cmds() {} virtual void add_literal(expr* e) = 0; virtual void end_assumption() = 0; - virtual void end_learned() = 0; + virtual void end_infer() = 0; virtual void end_deleted() = 0; + virtual void updt_params(params_ref const& p) = 0; }; @@ -159,6 +160,7 @@ struct builtin_decl { class opt_wrapper : public check_sat_result { public: + opt_wrapper(ast_manager& m): check_sat_result(m) {} virtual bool empty() = 0; virtual void push() = 0; virtual void pop(unsigned n) = 0; @@ -411,6 +413,7 @@ public: sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; } proof_cmds* get_proof_cmds() { return m_proof_cmds.get(); } + solver* get_solver() { return m_solver.get(); } void set_proof_cmds(proof_cmds* pc) { m_proof_cmds = pc; } void set_solver_factory(solver_factory * s); diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 505b0a5ed..03cb3f95c 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -47,6 +47,7 @@ Proof checker for clauses created during search. #include "sat/sat_drat.h" #include "sat/smt/euf_proof_checker.h" #include "cmd_context/cmd_context.h" +#include "params/solver_params.hpp" #include class smt_checker { @@ -166,8 +167,6 @@ public: } m_solver->pop(1); std::cout << "(verified-smt)\n"; - if (proof_hint) - std::cout << "(missed-hint " << mk_pp(proof_hint, m) << ")\n"; add_clause(clause); } @@ -175,15 +174,59 @@ public: add_clause(clause); m_solver->assert_expr(mk_or(clause)); } + + void del(expr_ref_vector const& clause) { + + } + +}; + + +class proof_saver { + cmd_context& ctx; + ast_manager& m; +public: + proof_saver(cmd_context& ctx):ctx(ctx), m(ctx.m()) { + auto* s = ctx.get_solver(); + if (!s) + ctx.set_solver_factory(mk_smt_strategic_solver_factory()); + if (!ctx.get_check_sat_result()) + ctx.set_check_sat_result(ctx.get_solver()); + } + + void assume(expr_ref_vector const& clause) { + ctx.get_solver()->log_inference(m.mk_assumption_add(nullptr, mk_or(clause))); + } + + void del(expr_ref_vector const& clause) { + ctx.get_solver()->log_inference(m.mk_redundant_del(mk_or(clause))); + } + + void infer(expr_ref_vector const& clause, app* hint) { + ctx.get_solver()->log_inference(m.mk_lemma_add(hint, mk_or(clause))); + } + }; class proof_cmds_imp : public proof_cmds { + cmd_context& ctx; ast_manager& m; expr_ref_vector m_lits; app_ref m_proof_hint; - smt_checker m_checker; + bool m_check = true; + bool m_save = false; + bool m_trim = false; + scoped_ptr m_checker; + scoped_ptr m_saver; + + smt_checker& checker() { if (!m_checker) m_checker = alloc(smt_checker, m); return *m_checker; } + proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; } + + public: - proof_cmds_imp(ast_manager& m): m(m), m_lits(m), m_proof_hint(m), m_checker(m) {} + proof_cmds_imp(cmd_context& ctx): ctx(ctx), m(ctx.m()), m_lits(m), m_proof_hint(m) { + updt_params(gparams::get_module("solver")); + } void add_literal(expr* e) override { if (m.is_proof(e)) @@ -193,27 +236,43 @@ public: } void end_assumption() override { - m_checker.assume(m_lits); + if (m_check) + checker().assume(m_lits); + if (m_save) + saver().assume(m_lits); m_lits.reset(); m_proof_hint.reset(); } - void end_learned() override { - m_checker.check(m_lits, m_proof_hint); + void end_infer() override { + if (m_check) + checker().check(m_lits, m_proof_hint); + if (m_save) + saver().infer(m_lits, m_proof_hint); m_lits.reset(); m_proof_hint.reset(); } void end_deleted() override { + if (m_check) + checker().del(m_lits); + if (m_save) + saver().del(m_lits); m_lits.reset(); m_proof_hint.reset(); } + + void updt_params(params_ref const& p) { + solver_params sp(p); + m_check = sp.proof_check(); + m_save = sp.proof_save(); + } }; static proof_cmds& get(cmd_context& ctx) { if (!ctx.get_proof_cmds()) - ctx.set_proof_cmds(alloc(proof_cmds_imp, ctx.m())); + ctx.set_proof_cmds(alloc(proof_cmds_imp, ctx)); return *ctx.get_proof_cmds(); } @@ -248,9 +307,9 @@ public: }; // learned/redundant clause -class learn_cmd : public cmd { +class infer_cmd : public cmd { public: - learn_cmd():cmd("learn") {} + infer_cmd():cmd("infer") {} char const* get_usage() const override { return "+"; } char const* get_descr(cmd_context& ctx) const override { return "proof command for learned (redundant) clauses"; } unsigned get_arity() const override { return VAR_ARITY; } @@ -259,11 +318,11 @@ public: void failure_cleanup(cmd_context & ctx) override {} cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR; } void set_next_arg(cmd_context & ctx, expr * arg) override { get(ctx).add_literal(arg); } - void execute(cmd_context& ctx) override { get(ctx).end_learned(); } + void execute(cmd_context& ctx) override { get(ctx).end_infer(); } }; void install_proof_cmds(cmd_context & ctx) { ctx.insert(alloc(del_cmd)); - ctx.insert(alloc(learn_cmd)); + ctx.insert(alloc(infer_cmd)); ctx.insert(alloc(assume_cmd)); } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 8b75adf88..be1a3879b 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -42,7 +42,6 @@ private: }; friend struct def_manager; - ast_manager& m; solver& m_solver; app_ref_vector m_proxies; unsigned m_num_proxies; @@ -72,7 +71,7 @@ public: iuc_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool old_hyp_reducer, bool split_literals = false) : - m(solver.get_manager()), + solver(m), m_solver(solver), m_proxies(m), m_num_proxies(0), @@ -150,7 +149,7 @@ public: void get_unsat_core(expr_ref_vector &r) override; void get_model_core(model_ref &m) override {m_solver.get_model(m);} - proof *get_proof() override {return m_solver.get_proof();} + proof *get_proof_core() override {return m_solver.get_proof_core();} std::string reason_unknown() const override { return m_solver.reason_unknown(); } void set_reason_unknown(char const* msg) override { m_solver.set_reason_unknown(msg); } void get_labels(svector &r) override { m_solver.get_labels(r); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index bc41e0c6d..ba31d74cf 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -124,7 +124,7 @@ namespace opt { } context::context(ast_manager& m): - m(m), + opt_wrapper(m), m_arith(m), m_bv(m), m_hard_constraints(m), diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 8b0e8eab1..a93400592 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -164,7 +164,6 @@ namespace opt { unsigned get_index(symbol const& id) { return m_indices[id]; } }; - ast_manager& m; on_model_t m_on_model_ctx; std::function m_on_model_eh; bool m_calling_on_model = false; @@ -226,7 +225,7 @@ namespace opt { void get_box_model(model_ref& _m, unsigned index) override; void fix_model(model_ref& _m) override; void collect_statistics(statistics& stats) const override; - proof* get_proof() override { return nullptr; } + proof* get_proof_core() override { return nullptr; } void get_labels(svector & r) override; void get_unsat_core(expr_ref_vector & r) override; std::string reason_unknown() const override; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 01975464a..64bf389bf 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -365,7 +365,7 @@ namespace opt { m = m_last_model.get(); } - proof * opt_solver::get_proof() { + proof * opt_solver::get_proof_core() { return m_context.get_proof(); } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index e71287400..bd83f06c8 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -97,7 +97,7 @@ namespace opt { lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override; void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & _m) override; - proof * get_proof() override; + proof * get_proof_core() override; std::string reason_unknown() const override; void set_reason_unknown(char const* msg) override; void get_labels(svector & r) override; diff --git a/src/params/solver_params.pyg b/src/params/solver_params.pyg index b475d368d..6e33ca6d7 100644 --- a/src/params/solver_params.pyg +++ b/src/params/solver_params.pyg @@ -8,5 +8,7 @@ def_module_params('solver', ('lemmas2console', BOOL, False, 'print lemmas during search'), ('instantiations2console', BOOL, False, 'print quantifier instantiations to the console'), ('axioms2files', BOOL, False, 'print negated theory axioms to separate files during search'), + ('proof.check', BOOL, True, 'check proof logs'), + ('proof.save', BOOL, False, 'save proof log into a proof object that can be extracted using (get-proof)'), )) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 981d91072..5c1859258 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -48,7 +48,6 @@ Notes: // incremental SAT solver. class inc_sat_solver : public solver { - ast_manager& m; mutable sat::solver m_solver; stacked_value m_has_uninterpreted; goal2sat m_goal2sat; @@ -87,7 +86,7 @@ class inc_sat_solver : public solver { bool is_internalized() const { return m_fmls_head == m_fmls.size(); } public: inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode): - m(m), + solver(m), m_solver(p, m.limit()), m_has_uninterpreted(false), m_fmls(m), @@ -405,7 +404,7 @@ public: return result; } - proof * get_proof() override { + proof * get_proof_core() override { return nullptr; } diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index 4d1afb4cc..2b02015e0 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -251,6 +251,17 @@ namespace arith { if (hi_sup != end) mk_bound_axiom(b, *hi_sup); } + void solver::add_farkas_clause(sat::literal l1, sat::literal l2) { + arith_proof_hint* bound_params = nullptr; + if (ctx.use_drat()) { + m_arith_hint.set_type(ctx, hint_type::farkas_h); + m_arith_hint.add_lit(rational(1), ~l1); + m_arith_hint.add_lit(rational(1), ~l2); + bound_params = m_arith_hint.mk(ctx); + } + add_clause(l1, l2, bound_params); + } + void solver::mk_bound_axiom(api_bound& b1, api_bound& b2) { literal l1(b1.get_lit()); literal l2(b2.get_lit()); @@ -263,55 +274,45 @@ namespace arith { if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); - auto bin_clause = [&](sat::literal l1, sat::literal l2) { - arith_proof_hint* bound_params = nullptr; - if (ctx.use_drat()) { - m_arith_hint.set_type(ctx, hint_type::farkas_h); - m_arith_hint.add_lit(rational(1), ~l1); - m_arith_hint.add_lit(rational(1), ~l2); - bound_params = m_arith_hint.mk(ctx); - } - add_clause(l1, l2, bound_params); - }; if (kind1 == lp_api::lower_t) { if (kind2 == lp_api::lower_t) { if (k2 <= k1) - bin_clause(~l1, l2); + add_farkas_clause(~l1, l2); else - bin_clause(l1, ~l2); + add_farkas_clause(l1, ~l2); } else if (k1 <= k2) // k1 <= k2, k1 <= x or x <= k2 - bin_clause(l1, l2); + add_farkas_clause(l1, l2); else { // k1 > hi_inf, k1 <= x => ~(x <= hi_inf) - bin_clause(~l1, ~l2); + add_farkas_clause(~l1, ~l2); if (v_is_int && k1 == k2 + rational(1)) // k1 <= x or x <= k1-1 - bin_clause(l1, l2); + add_farkas_clause(l1, l2); } } else if (kind2 == lp_api::lower_t) { if (k1 >= k2) // k1 >= lo_inf, k1 >= x or lo_inf <= x - bin_clause(l1, l2); + add_farkas_clause(l1, l2); else { // k1 < k2, k2 <= x => ~(x <= k1) - bin_clause(~l1, ~l2); + add_farkas_clause(~l1, ~l2); if (v_is_int && k1 == k2 - rational(1)) // x <= k1 or k1+l <= x - bin_clause(l1, l2); + add_farkas_clause(l1, l2); } } else { // kind1 == A_UPPER, kind2 == A_UPPER if (k1 >= k2) // k1 >= k2, x <= k2 => x <= k1 - bin_clause(l1, ~l2); + add_farkas_clause(l1, ~l2); else // k1 <= hi_sup , x <= k1 => x <= hi_sup - bin_clause(~l1, l2); + add_farkas_clause(~l1, l2); } } @@ -421,9 +422,9 @@ namespace arith { ge = mk_literal(a.mk_ge(diff, zero)); } ++m_stats.m_assert_diseq; - add_clause(~eq, le); - add_clause(~eq, ge); - add_clause(~le, ~ge, eq); + add_farkas_clause(~eq, le); + add_farkas_clause(~eq, ge); + add_clause(~le, ~ge, eq, explain_triangle_eq(le, ge, eq)); } diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 3c3235df1..cba691319 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -133,6 +133,16 @@ namespace arith { return m_arith_hint.mk(ctx); } + arith_proof_hint const* solver::explain_triangle_eq(sat::literal le, sat::literal ge, sat::literal eq) { + if (!ctx.use_drat()) + return nullptr; + m_arith_hint.set_type(ctx, hint_type::implied_eq_h); + m_arith_hint.add_lit(rational(1), le); + m_arith_hint.add_lit(rational(1), ge); + m_arith_hint.add_lit(rational(1), ~eq); + return m_arith_hint.mk(ctx); + } + expr* arith_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); family_id fid = m.get_family_id("arith"); diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index 1a8a8df27..56e4cf1f8 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -383,14 +383,13 @@ namespace arith { neg.mark(e, true); else pos.mark(e, true); - - if (jst->get_name() != m_farkas && - jst->get_name() != m_bound && - jst->get_name() != m_implied_eq) { + bool is_bound = jst->get_name() == m_bound; + bool is_implied_eq = jst->get_name() == m_implied_eq; + bool is_farkas = jst->get_name() == m_farkas; + if (!is_farkas && !is_bound && !is_implied_eq) { IF_VERBOSE(0, verbose_stream() << "unhandled inference " << mk_pp(jst, m) << "\n"); return false; } - bool is_bound = jst->get_name() == m_bound; bool even = true; rational coeff; expr* x, * y; @@ -436,7 +435,6 @@ namespace arith { if (check()) return true; - IF_VERBOSE(0, verbose_stream() << "did not check condition\n" << mk_pp(jst, m) << "\n"; display(verbose_stream()); ); return false; } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 83c91ac05..2142874d5 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -322,6 +322,7 @@ namespace arith { void mk_bound_axiom(api_bound& b1, api_bound& b2); void mk_power0_axioms(app* t, app* n); void flush_bound_axioms(); + void add_farkas_clause(sat::literal l1, sat::literal l2); // bounds struct compare_bounds { @@ -473,6 +474,7 @@ namespace arith { arith_proof_hint const* explain(hint_type ty, sat::literal lit = sat::null_literal); arith_proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b); + arith_proof_hint const* explain_triangle_eq(sat::literal le, sat::literal ge, sat::literal eq); void explain_assumptions(); diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index bf8aad44b..99bc99d48 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -92,16 +92,20 @@ namespace euf { expr* eq_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); - func_decl_ref cc(m); + func_decl_ref cc(m), cc_comm(m); sort* proof = m.mk_proof_sort(); ptr_buffer sorts; expr_ref_vector args(m); if (m_cc_head < m_cc_tail) { - sort* sorts[2] = { m.mk_bool_sort(), m.mk_bool_sort() }; - cc = m.mk_func_decl(symbol("cc"), 2, sorts, proof); + sort* sorts[1] = { m.mk_bool_sort() }; + cc_comm = m.mk_func_decl(symbol("comm"), 1, sorts, proof); + cc = m.mk_func_decl(symbol("cc"), 1, sorts, proof); } auto cc_proof = [&](bool comm, expr* eq) { - return m.mk_app(cc, m.mk_bool_val(comm), eq); + if (comm) + return m.mk_app(cc_comm, eq); + else + return m.mk_app(cc, eq); }; auto compare_ts = [](cc_justification_record const& a, cc_justification_record const& b) { @@ -168,11 +172,11 @@ namespace euf { if (!visit_clause(out, n, lits)) return; if (st.is_asserted()) - display_redundant(out, n, lits, status2proof_hint(st)); + display_inferred(out, n, lits, status2proof_hint(st)); else if (st.is_deleted()) display_deleted(out, n, lits); else if (st.is_redundant()) - display_redundant(out, n, lits, status2proof_hint(st)); + display_inferred(out, n, lits, status2proof_hint(st)); else if (st.is_input()) display_assume(out, n, lits); else @@ -228,10 +232,12 @@ namespace euf { display_literals(out << "(assume", n, lits) << ")\n"; } - void solver::display_redundant(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint) { - if (proof_hint) - visit_expr(out, proof_hint); - display_hint(display_literals(out << "(learn", n, lits), proof_hint) << ")\n"; + void solver::display_inferred(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint) { + expr_ref hint(proof_hint, m); + if (!hint) + hint = m.mk_const(symbol("smt"), m.mk_proof_sort()); + visit_expr(out, hint); + display_hint(display_literals(out << "(infer", n, lits), hint) << ")\n"; } void solver::display_deleted(std::ostream& out, unsigned n, literal const* lits) { diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 3ddafd00b..d0a4e4ab1 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -20,6 +20,7 @@ Author: #include "ast/ast_ll_pp.h" #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_proof_checker.h" +#include namespace euf { @@ -57,6 +58,7 @@ namespace euf { ast_manager& m; basic_union_find m_uf; svector> m_expr2id; + ptr_vector m_id2expr; svector> m_diseqs; unsigned m_ts = 0; @@ -108,10 +110,10 @@ namespace euf { if (ts != m_ts) { id = m_uf.mk_var(); m_expr2id.setx(e->get_id(), {m_ts, id}, {0,0}); + m_id2expr.setx(id, e, nullptr); } return id; - } - + } public: eq_proof_checker(ast_manager& m): m(m) {} @@ -149,15 +151,17 @@ namespace euf { if (!is_app(arg)) return false; app* a = to_app(arg); - if (a->get_num_args() != 2) + if (a->get_num_args() != 1) return false; - if (a->get_name() != symbol("cc")) + if (!m.is_eq(a->get_arg(0), x, y)) return false; - if (!m.is_eq(a->get_arg(1), x, y)) + bool is_cc = a->get_name() == symbol("cc"); + bool is_comm = a->get_name() == symbol("comm"); + if (!is_cc && !is_comm) return false; if (!is_app(x) || !is_app(y)) return false; - if (!congruence(m.is_true(a->get_arg(0)), to_app(x), to_app(y))) { + if (!congruence(!is_cc, to_app(x), to_app(y))) { IF_VERBOSE(0, verbose_stream() << "not congruent " << mk_pp(a, m) << "\n"); return false; } @@ -167,9 +171,27 @@ namespace euf { return false; } } + // check if a disequality is violated. for (auto const& [a, b] : m_diseqs) if (are_equal(a, b)) - return true; + return true; + + // check if some equivalence class contains two distinct values. + for (unsigned v = 0; v < m_uf.get_num_vars(); ++v) { + if (v != m_uf.find(v)) + continue; + unsigned r = v; + expr* val = nullptr; + do { + expr* e = m_id2expr[v]; + if (val && m.are_distinct(e, val)) + return true; + if (m.is_value(e)) + val = e; + v = m_uf.next(v); + } + while (r != v); + } return false; } @@ -201,8 +223,12 @@ namespace euf { units.reset(); app* a = to_app(e); proof_checker_plugin* p = nullptr; - if (m_map.find(a->get_decl()->get_name(), p)) - return p->check(clause, a, units); + if (!m_map.find(a->get_decl()->get_name(), p)) + return false; + if (p->check(clause, a, units)) + return true; + + std::cout << "(missed-hint " << mk_pp(e, m) << ")\n"; return false; } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index f4867d841..b5d65205c 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -197,7 +197,7 @@ namespace euf { void on_proof(unsigned n, literal const* lits, sat::status st); std::ostream& display_literals(std::ostream& out, unsigned n, sat::literal const* lits); void display_assume(std::ostream& out, unsigned n, literal const* lits); - void display_redundant(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint); + void display_inferred(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint); void display_deleted(std::ostream& out, unsigned n, literal const* lits); std::ostream& display_hint(std::ostream& out, expr* proof_hint); expr_ref status2proof_hint(sat::status st); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index a4093cdb7..4a834d355 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -387,7 +387,7 @@ namespace q { m_qs.log_instantiation(lits, &j); euf::th_proof_hint* ph = nullptr; if (ctx.use_drat()) - ph = q_proof_hint::mk(ctx, j.m_clause.size(), j.m_binding); + ph = q_proof_hint::mk(ctx, lits, j.m_clause.size(), j.m_binding); m_qs.add_clause(lits, ph); } diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 8be75f03c..0802f71c9 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -70,19 +70,10 @@ namespace q { m_max_cex += ctx.get_config().m_mbqi_max_cexs; for (auto const& [qlit, fml, inst, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); - sat::literal lit = ctx.mk_literal(fml); - euf::th_proof_hint* ph = nullptr; - if (!inst.empty()) { - ph = q_proof_hint::mk(ctx, inst.size(), inst.data()); - sat::literal_vector lits; - lits.push_back(~qlit); - lits.push_back(~lit); - m_qs.add_clause(lits, ph); - } - else { - m_qs.add_clause(~qlit, ~lit); - } - m_qs.log_instantiation(~qlit, ~lit); + sat::literal lit = ~ctx.mk_literal(fml); + auto* ph = q_proof_hint::mk(ctx, ~qlit, lit, inst.size(), inst.data()); + m_qs.add_clause(~qlit, lit, ph); + m_qs.log_instantiation(~qlit, lit); } m_instantiations.reset(); if (result != l_true) diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 0a8ca5085..c99311f4e 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -364,36 +364,49 @@ namespace q { } } - q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, euf::enode* const* bindings) { - auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n)); - q_proof_hint* ph = new (mem) q_proof_hint(); - ph->m_num_bindings = n; + q_proof_hint* q_proof_hint::mk(euf::solver& s, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings) { + auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, lits.size())); + q_proof_hint* ph = new (mem) q_proof_hint(n, lits.size()); for (unsigned i = 0; i < n; ++i) ph->m_bindings[i] = bindings[i]->get_expr(); + for (unsigned i = 0; i < lits.size(); ++i) + ph->m_literals[i] = lits[i]; return ph; } - q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned n, expr* const* bindings) { - auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n)); - q_proof_hint* ph = new (mem) q_proof_hint(); - ph->m_num_bindings = n; + q_proof_hint* q_proof_hint::mk(euf::solver& s, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings) { + auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, 2)); + q_proof_hint* ph = new (mem) q_proof_hint(n, 2); for (unsigned i = 0; i < n; ++i) ph->m_bindings[i] = bindings[i]; + ph->m_literals[0] = l1; + ph->m_literals[1] = l2; return ph; } expr* q_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); expr_ref_vector args(m); - sort_ref_vector sorts(m); - for (unsigned i = 0; i < m_num_bindings; ++i) { - args.push_back(m_bindings[i]); - sorts.push_back(args.back()->get_sort()); - } + ptr_buffer sorts; + expr_ref binding(m); sort* range = m.mk_proof_sort(); - func_decl* d = m.mk_func_decl(symbol("inst"), args.size(), sorts.data(), range); - expr* r = m.mk_app(d, args); - return r; + func_decl* d; + for (unsigned i = 0; i < m_num_bindings; ++i) + args.push_back(m_bindings[i]); + for (expr* arg : args) + sorts.push_back(arg->get_sort()); + d = m.mk_func_decl(symbol("bind"), args.size(), sorts.data(), range); + binding = m.mk_app(d, args); + args.reset(); + sorts.reset(); + for (unsigned i = 0; i < m_num_literals; ++i) + args.push_back(s.literal2expr(~m_literals[i])); + args.push_back(binding); + for (expr* arg : args) + sorts.push_back(arg->get_sort()); + + d = m.mk_func_decl(symbol("inst"), args.size(), sorts.data(), range); + return m.mk_app(d, args); } } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index ee2e47111..3a95a00be 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -30,12 +30,19 @@ namespace euf { namespace q { struct q_proof_hint : public euf::th_proof_hint { - unsigned m_num_bindings; - expr* m_bindings[0]; - q_proof_hint() {} - static size_t get_obj_size(unsigned num_bindings) { return sizeof(q_proof_hint) + num_bindings*sizeof(expr*); } - static q_proof_hint* mk(euf::solver& s, unsigned n, euf::enode* const* bindings); - static q_proof_hint* mk(euf::solver& s, unsigned n, expr* const* bindings); + unsigned m_num_bindings; + unsigned m_num_literals; + sat::literal* m_literals; + expr* m_bindings[0]; + + q_proof_hint(unsigned b, unsigned l) { + m_num_bindings = b; + m_num_literals = l; + m_literals = reinterpret_cast(m_bindings + m_num_bindings); + } + static size_t get_obj_size(unsigned num_bindings, unsigned num_lits) { return sizeof(q_proof_hint) + num_bindings*sizeof(expr*) + num_lits*sizeof(sat::literal); } + static q_proof_hint* mk(euf::solver& s, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings); + static q_proof_hint* mk(euf::solver& s, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings); expr* get_hint(euf::solver& s) const override; }; diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 3267f0940..00a23d903 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -143,20 +143,16 @@ namespace euf { is_new = true; return is_new; } - - bool th_euf_solver::add_clause(sat::literal a, sat::literal b) { - sat::literal lits[2] = { a, b }; - return add_clause(2, lits); - } - - bool th_euf_solver::add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps) { + + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps) { + SASSERT(ps); sat::literal lits[2] = { a, b }; return add_clause(2, lits, ps); } - bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c) { + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, th_proof_hint const* ps) { sat::literal lits[3] = { a, b, c }; - return add_clause(3, lits); + return add_clause(3, lits, ps); } bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d) { @@ -165,6 +161,7 @@ namespace euf { } bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps) { + //SASSERT(!ctx.use_drat() || ps); - very far from true, and isn't a requirement bool was_true = false; for (unsigned i = 0; i < n; ++i) was_true |= is_true(lits[i]); diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 8289418fc..a76b86cfd 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -160,9 +160,8 @@ namespace euf { bool add_unit(sat::literal lit); bool add_units(sat::literal_vector const& lits); bool add_clause(sat::literal lit) { return add_unit(lit); } - bool add_clause(sat::literal a, sat::literal b); - bool add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps); - bool add_clause(sat::literal a, sat::literal b, sat::literal c); + bool add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps = nullptr); + bool add_clause(sat::literal a, sat::literal b, sat::literal c, th_proof_hint const* ps = nullptr); bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d); bool add_clause(sat::literal_vector const& lits, th_proof_hint const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); } bool add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps = nullptr); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 5064ed7ef..61c6de377 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -289,7 +289,7 @@ namespace { m_context.get_model(m); } - proof * get_proof() override { + proof * get_proof_core() override { return m_context.get_proof(); } diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index d29e0f2bd..e946dd430 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -39,8 +39,19 @@ void check_sat_result::set_reason_unknown(event_handler& eh) { } } +proof* check_sat_result::get_proof() { + if (!m_log.empty() && !m_proof) { + app* last = m_log.back(); + m_log.push_back(to_app(m.get_fact(last))); + m_proof = m.mk_clause_trail(m_log.size(), m_log.data()); + } + if (m_proof) + return m_proof.get(); + return get_proof_core(); +} simple_check_sat_result::simple_check_sat_result(ast_manager & m): + check_sat_result(m), m_core(m), m_proof(m) { } @@ -66,7 +77,7 @@ void simple_check_sat_result::get_model_core(model_ref & m) { m = nullptr; } -proof * simple_check_sat_result::get_proof() { +proof * simple_check_sat_result::get_proof_core() { return m_proof; } diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 86941f590..e00b53cc9 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -39,12 +39,15 @@ Notes: */ class check_sat_result { protected: - unsigned m_ref_count; - lbool m_status; + ast_manager& m; + proof_ref_vector m_log; + proof_ref m_proof; + unsigned m_ref_count = 0; + lbool m_status = l_undef; model_converter_ref m_mc0; - double m_time; + double m_time = 0; public: - check_sat_result():m_ref_count(0), m_status(l_undef), m_time(0) {} + check_sat_result(ast_manager& m): m(m), m_log(m), m_proof(m) {} virtual ~check_sat_result() = default; void inc_ref() { m_ref_count++; } void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } @@ -59,7 +62,10 @@ public: get_model_core(m); if (m && mc0()) (*mc0())(m); } - virtual proof * get_proof() = 0; + void log_inference(proof* p) { m_log.push_back(p); } + void set_proof(proof* p) { m_proof = p; } + proof* get_proof(); + virtual proof * get_proof_core() = 0; virtual std::string reason_unknown() const = 0; virtual void set_reason_unknown(char const* msg) = 0; void set_reason_unknown(event_handler& eh); @@ -97,7 +103,7 @@ struct simple_check_sat_result : public check_sat_result { void collect_statistics(statistics & st) const override; void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & m) override; - proof * get_proof() override; + proof * get_proof_core() override; std::string reason_unknown() const override; void get_labels(svector & r) override; void set_reason_unknown(char const* msg) override { m_unknown = msg; } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 6e414816f..76e6138ab 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -115,7 +115,8 @@ private: } public: - combined_solver(solver * s1, solver * s2, params_ref const & p) { + combined_solver(solver * s1, solver * s2, params_ref const & p): + solver(s1->get_manager()) { m_solver1 = s1; m_solver2 = s2; updt_local_params(p); @@ -318,11 +319,11 @@ public: return m_solver2->get_trail(max_level); } - proof * get_proof() override { + proof * get_proof_core() override { if (m_use_solver1_results) - return m_solver1->get_proof(); + return m_solver1->get_proof_core(); else - return m_solver2->get_proof(); + return m_solver2->get_proof_core(); } std::string reason_unknown() const override { diff --git a/src/solver/solver.h b/src/solver/solver.h index 8b7d56a8c..8a4bec538 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -52,7 +52,7 @@ class solver : public check_sat_result, public user_propagator::core { params_ref m_params; symbol m_cancel_backup_file; public: - solver() {} + solver(ast_manager& m): check_sat_result(m) {} /** \brief Creates a clone of the solver. diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 4951f8833..605a32ae1 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -24,7 +24,7 @@ Notes: solver_na2as::solver_na2as(ast_manager & m): - m(m), + solver(m), m_assumptions(m) { } diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index c8340bd6e..81a58fb39 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -25,7 +25,6 @@ Notes: class solver_na2as : public solver { protected: - ast_manager & m; expr_ref_vector m_assumptions; unsigned_vector m_scopes; void restore_assumptions(unsigned old_sz); diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index bbc46c9c8..f5760bde3 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -102,10 +102,10 @@ public: } - proof * get_proof() override { + proof * get_proof_core() override { scoped_watch _t_(m_pool.m_proof_watch); if (!m_proof.get()) { - m_proof = m_base->get_proof(); + m_proof = m_base->get_proof_core(); if (m_proof) { elim_aux_assertions pc(m_pred); pc(m, m_proof, m_proof); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index b178929bd..6e34758e6 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -70,7 +70,7 @@ public: void collect_statistics(statistics & st) const override; void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & m) override; - proof * get_proof() override; + proof * get_proof_core() override; std::string reason_unknown() const override; void set_reason_unknown(char const* msg) override; void get_labels(svector & r) override {} @@ -311,9 +311,9 @@ void tactic2solver::get_model_core(model_ref & m) { } } -proof * tactic2solver::get_proof() { +proof * tactic2solver::get_proof_core() { if (m_result.get()) - return m_result->get_proof(); + return m_result->get_proof_core(); else return nullptr; } diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index bc05a3328..f7974671e 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -195,7 +195,7 @@ public: mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } - proof * get_proof() override { return m_solver->get_proof(); } + proof * get_proof_core() override { return m_solver->get_proof_core(); } std::string reason_unknown() const override { return m_solver->reason_unknown(); } void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } void get_labels(svector & r) override { m_solver->get_labels(r); } diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 5322b523d..5e05fdf31 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -120,7 +120,7 @@ public: mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } - proof * get_proof() override { return m_solver->get_proof(); } + proof * get_proof_core() override { return m_solver->get_proof_core(); } std::string reason_unknown() const override { return m_solver->reason_unknown(); } void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } void get_labels(svector & r) override { m_solver->get_labels(r); } diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index ee4a03d31..609ed173d 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -116,7 +116,7 @@ public: mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } - proof * get_proof() override { return m_solver->get_proof(); } + proof * get_proof_core() override { return m_solver->get_proof_core(); } std::string reason_unknown() const override { return m_solver->reason_unknown(); } void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } void get_labels(svector & r) override { m_solver->get_labels(r); } diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index f653e22e2..3729a2ad1 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -2075,7 +2075,7 @@ namespace smtfd { return m_fd_sat_solver->get_model_converter(); } - proof * get_proof() override { return nullptr; } + proof * get_proof_core() override { return nullptr; } std::string reason_unknown() const override { return m_reason_unknown; } void set_reason_unknown(char const* msg) override { m_reason_unknown = msg; } void get_labels(svector & r) override { } From 6eb2d2acfafc2d43243ac94c3a2848ce468af5b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Sep 2022 11:25:36 -0700 Subject: [PATCH 091/477] update dependencies for build Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 697793b3f..fa67f9340 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -82,9 +82,9 @@ def init_project_def(): add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'fd_solver', 'qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_fpa.h', 'z3_spacer.h'] - add_lib('api', ['portfolio', 'realclosure', 'opt'], - includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'qe', 'euf', 'arith_tactics'], 'cmd_context/extra_cmds') + add_lib('api', ['portfolio', 'realclosure', 'opt', 'extra_cmds'], + includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds', 'opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing', 'simplex', 'sat_smt'], exe_name='test-z3', install=False) _libz3Component = add_dll('api_dll', ['api', 'sat', 'extra_cmds'], 'api/dll', From ccda49bad5d0c033701c35c34d3d6dd79cc32dcb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2022 13:03:34 -0400 Subject: [PATCH 092/477] fix #6376 have solver throw an exception when user supplies a non-propositional assumption --- src/tactic/fd_solver/bounded_int2bv_solver.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index f7974671e..ed10f7efb 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -140,8 +140,18 @@ public: } } + void check_assumptions(unsigned num_assumptions, expr * const * assumptions) { + for (unsigned i = 0; i < num_assumptions; ++i) { + expr* arg = assumptions[i]; + m.is_not(arg, arg); + if (!is_uninterp_const(arg)) + throw default_exception("only propositional assumptions are supported for finite domains " + mk_pp(arg, m)); + } + } + lbool check_sat_core2(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); + check_assumptions(num_assumptions, assumptions); return m_solver->check_sat_core(num_assumptions, assumptions); } From b9cba825317f78b67167ccfe421cc3a3eea3d600 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2022 13:04:19 -0400 Subject: [PATCH 093/477] work on proof checking - add outline of trim routine - streamline how proof terms are checked and how residue units are extracted. --- src/ast/ast.h | 2 + src/cmd_context/extra_cmds/proof_cmds.cpp | 147 ++++++++++++++++++- src/params/solver_params.pyg | 1 + src/sat/sat_solver.h | 1 + src/sat/smt/arith_axioms.cpp | 2 +- src/sat/smt/arith_diagnostics.cpp | 14 +- src/sat/smt/arith_proof_checker.h | 134 +++++++++--------- src/sat/smt/arith_solver.h | 17 ++- src/sat/smt/euf_proof_checker.cpp | 164 ++++++++++++++++++---- src/sat/smt/euf_proof_checker.h | 11 +- 10 files changed, 384 insertions(+), 109 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 512501226..511c2cee0 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -731,6 +731,8 @@ public: unsigned get_num_args() const { return m_num_args; } expr * get_arg(unsigned idx) const { SASSERT(idx < m_num_args); return m_args[idx]; } expr * const * get_args() const { return m_args; } + std::tuple args2() const { SASSERT(m_num_args == 2); return {get_arg(0), get_arg(1)}; } + std::tuple args3() const { SASSERT(m_num_args == 3); return {get_arg(0), get_arg(1), get_arg(2)}; } unsigned get_size() const { return get_obj_size(get_num_args()); } expr * const * begin() const { return m_args; } expr * const * end() const { return m_args + m_num_args; } diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 03cb3f95c..e429358fa 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -181,6 +181,141 @@ public: }; +namespace sat { + /** + * Replay proof entierly, then walk backwards extracting reduced proof. + */ + class proof_trim { + cmd_context& ctx; + ast_manager& m; + solver s; + literal_vector m_clause; + struct hash { + unsigned operator()(literal_vector const& v) const { + return string_hash((char const*)v.begin(), v.size()*sizeof(literal), 3); + } + }; + struct eq { + bool operator()(literal_vector const& a, literal_vector const& b) const { + return a == b; + } + }; + map m_clauses; + + void mk_clause(expr_ref_vector const& clause) { + m_clause.reset(); + for (expr* arg: clause) + add_literal(arg); + std::sort(m_clause.begin(), m_clause.end()); + } + + bool_var mk_var(expr* arg) { + while (arg->get_id() >= s.num_vars()) + s.mk_var(true, true); + return arg->get_id(); + } + + void add_literal(expr* arg) { + bool sign = m.is_not(arg, arg); + m_clause.push_back(literal(mk_var(arg), sign)); + } + + + /** + Pseudo-code from Gurfinkel, Vizel, FMCAD 2014 + Input: trail (a0,d0), ..., (an,dn) = ({},bot) + Output: reduced trail - result + result = [] + C = an + for i = n to 0 do + if s.is_deleted(ai) then s.revive(ai) + else + if s.isontrail(ai) then + s.undotrailcore(ai,C) + s.delete(ai) + if ai in C then + if ai is not initial then + s.savetrail() + s.enqueue(not ai) + c = s.propagate() + s.conflictanalysiscore(c, C) + s.restoretrail() + result += [ai] + reverse(result) + + is_deleted(ai): + clause was detached + revive(ai): + attach clause ai + isontrail(ai): + some literal on the current trail in s is justified by ai + undotrailcore(ai, C): + pop the trail until dependencies on ai are gone + savetrail: + store current trail so it can be restored + enqueue(not ai): + assert negations of ai at a new decision level + conflictanalysiscore(c, C): + ? + restoretrail: + restore the trail to the position before enqueue + + + + */ + void trim() { + + } + + public: + proof_trim(cmd_context& ctx): + ctx(ctx), + m(ctx.m()), + s(gparams::get_module("sat"), m.limit()) { + + } + + void assume(expr_ref_vector const& _clause) { + mk_clause(_clause); + IF_VERBOSE(3, verbose_stream() << "add: " << m_clause << "\n"); + auto* cl = s.mk_clause(m_clause, status::redundant()); + s.propagate(false); + if (!cl) + return; + IF_VERBOSE(3, verbose_stream() << "add: " << *cl << "\n"); + auto& v = m_clauses.insert_if_not_there(m_clause, clause_vector()); + v.push_back(cl); + } + + void del(expr_ref_vector const& _clause) { + mk_clause(_clause); + IF_VERBOSE(3, verbose_stream() << "del: " << m_clause << "\n"); + if (m_clause.size() == 2) { + s.detach_bin_clause(m_clause[0], m_clause[1], true); + return; + } + auto* e = m_clauses.find_core(m_clause); + if (!e) + return; + auto& v = e->get_data().m_value; + if (!v.empty()) { + IF_VERBOSE(3, verbose_stream() << "del: " << *v.back() << "\n"); + s.detach_clause(*v.back()); + v.pop_back(); + } + } + + void infer(expr_ref_vector const& _clause, app*) { + assume(_clause); + } + + void updt_params(params_ref const& p) { + s.updt_params(p); + } + + }; +} + class proof_saver { cmd_context& ctx; @@ -218,10 +353,11 @@ class proof_cmds_imp : public proof_cmds { bool m_trim = false; scoped_ptr m_checker; scoped_ptr m_saver; + scoped_ptr m_trimmer; smt_checker& checker() { if (!m_checker) m_checker = alloc(smt_checker, m); return *m_checker; } proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; } - + sat::proof_trim& trim() { if (!m_trimmer) m_trimmer = alloc(sat::proof_trim, ctx); return *m_trimmer; } public: proof_cmds_imp(cmd_context& ctx): ctx(ctx), m(ctx.m()), m_lits(m), m_proof_hint(m) { @@ -240,6 +376,8 @@ public: checker().assume(m_lits); if (m_save) saver().assume(m_lits); + if (m_trim) + trim().assume(m_lits); m_lits.reset(); m_proof_hint.reset(); } @@ -249,6 +387,8 @@ public: checker().check(m_lits, m_proof_hint); if (m_save) saver().infer(m_lits, m_proof_hint); + if (m_trim) + trim().infer(m_lits, m_proof_hint); m_lits.reset(); m_proof_hint.reset(); } @@ -258,6 +398,8 @@ public: checker().del(m_lits); if (m_save) saver().del(m_lits); + if (m_trim) + trim().del(m_lits); m_lits.reset(); m_proof_hint.reset(); } @@ -266,6 +408,9 @@ public: solver_params sp(p); m_check = sp.proof_check(); m_save = sp.proof_save(); + m_trim = sp.proof_trim(); + if (m_trim) + trim().updt_params(p); } }; diff --git a/src/params/solver_params.pyg b/src/params/solver_params.pyg index 6e33ca6d7..9ff13864d 100644 --- a/src/params/solver_params.pyg +++ b/src/params/solver_params.pyg @@ -10,5 +10,6 @@ def_module_params('solver', ('axioms2files', BOOL, False, 'print negated theory axioms to separate files during search'), ('proof.check', BOOL, True, 'check proof logs'), ('proof.save', BOOL, False, 'save proof log into a proof object that can be extracted using (get-proof)'), + ('proof.trim', BOOL, False, 'trim and save proof into a proof object that an be extracted using (get-proof)'), )) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0b01b777c..5c413ce09 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -235,6 +235,7 @@ namespace sat { friend class aig_finder; friend class lut_finder; friend class npn3_finder; + friend class proof_trim; public: solver(params_ref const & p, reslimit& l); ~solver() override; diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index 2b02015e0..93917042e 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -424,7 +424,7 @@ namespace arith { ++m_stats.m_assert_diseq; add_farkas_clause(~eq, le); add_farkas_clause(~eq, ge); - add_clause(~le, ~ge, eq, explain_triangle_eq(le, ge, eq)); + add_clause(~le, ~ge, eq, explain_trichotomy(le, ge, eq)); } diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index cba691319..ec9b11e76 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -129,14 +129,16 @@ namespace arith { return nullptr; m_arith_hint.set_type(ctx, hint_type::implied_eq_h); explain_assumptions(); + m_arith_hint.set_num_le(1); // TODO m_arith_hint.add_diseq(a, b); return m_arith_hint.mk(ctx); } - arith_proof_hint const* solver::explain_triangle_eq(sat::literal le, sat::literal ge, sat::literal eq) { + arith_proof_hint const* solver::explain_trichotomy(sat::literal le, sat::literal ge, sat::literal eq) { if (!ctx.use_drat()) return nullptr; m_arith_hint.set_type(ctx, hint_type::implied_eq_h); + m_arith_hint.set_num_le(1); m_arith_hint.add_lit(rational(1), le); m_arith_hint.add_lit(rational(1), ge); m_arith_hint.add_lit(rational(1), ~eq); @@ -149,6 +151,9 @@ namespace arith { arith_util arith(m); solver& a = dynamic_cast(*s.fid2solver(fid)); char const* name; + expr_ref_vector args(m); + sort_ref_vector sorts(m); + switch (m_ty) { case hint_type::farkas_h: name = "farkas"; @@ -158,15 +163,14 @@ namespace arith { break; case hint_type::implied_eq_h: name = "implied-eq"; + args.push_back(arith.mk_int(m_num_le)); break; } rational lc(1); for (unsigned i = m_lit_head; i < m_lit_tail; ++i) lc = lcm(lc, denominator(a.m_arith_hint.lit(i).first)); - - expr_ref_vector args(m); - sort_ref_vector sorts(m); - for (unsigned i = m_lit_head; i < m_lit_tail; ++i) { + + for (unsigned i = m_lit_head; i < m_lit_tail; ++i) { auto const& [coeff, lit] = a.m_arith_hint.lit(i); args.push_back(arith.mk_int(abs(coeff*lc))); args.push_back(s.literal2expr(lit)); diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index 56e4cf1f8..df1dc00f1 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -18,7 +18,7 @@ Notes: The module assumes a limited repertoire of arithmetic proof rules. - farkas - inequalities, equalities and disequalities with coefficients -- implied-eq - last literal is a disequality. The literals before imply the corresponding equality. +- implied-eq - last literal is a disequality. The literals before imply the complementary equality. - bound - last literal is a bound. It is implied by prior literals. --*/ @@ -26,8 +26,10 @@ The module assumes a limited repertoire of arithmetic proof rules. #include "util/obj_pair_set.h" #include "ast/ast_trail.h" +#include "ast/ast_util.h" #include "ast/arith_decl_plugin.h" #include "sat/smt/euf_proof_checker.h" +#include namespace arith { @@ -49,8 +51,6 @@ namespace arith { row m_ineq; row m_conseq; vector m_eqs; - vector m_ineqs; - vector m_diseqs; symbol m_farkas; symbol m_implied_eq; symbol m_bound; @@ -261,26 +261,6 @@ namespace arith { return false; } - // - // checking disequalities is TBD. - // it has to select only a subset of bounds to justify each inequality. - // example - // c <= x <= c, c <= y <= c => x = y - // for the proof of x <= y use the inequalities x <= c <= y - // for the proof of y <= x use the inequalities y <= c <= x - // example - // x <= y, y <= z, z <= u, u <= x => x = z - // for the proof of x <= z use the inequalities x <= y, y <= z - // for the proof of z <= x use the inequalities z <= u, u <= x - // - // so when m_diseqs is non-empty we can't just add inequalities with Farkas coefficients - // into m_ineq, since coefficients of the usable subset vanish. - // - - bool check_diseq() { - return false; - } - std::ostream& display_row(std::ostream& out, row const& r) { bool first = true; for (auto const& [v, coeff] : r.m_coeffs) { @@ -329,16 +309,11 @@ namespace arith { m_ineq.reset(); m_conseq.reset(); m_eqs.reset(); - m_ineqs.reset(); - m_diseqs.reset(); m_strict = false; } bool add_ineq(rational const& coeff, expr* e, bool sign) { - if (!m_diseqs.empty()) - return add_literal(fresh(m_ineqs), abs(coeff), e, sign); - else - return add_literal(m_ineq, abs(coeff), e, sign); + return add_literal(m_ineq, abs(coeff), e, sign); } bool add_conseq(rational const& coeff, expr* e, bool sign) { @@ -350,20 +325,12 @@ namespace arith { linearize(r, rational(1), a); linearize(r, rational(-1), b); } - - void add_diseq(expr* a, expr* b) { - row& r = fresh(m_diseqs); - linearize(r, rational(1), a); - linearize(r, rational(-1), b); - } bool check() { - if (!m_diseqs.empty()) - return check_diseq(); - else if (!m_conseq.m_coeffs.empty()) - return check_bound(); - else + if (m_conseq.m_coeffs.empty()) return check_farkas(); + else + return check_bound(); } std::ostream& display(std::ostream& out) { @@ -375,14 +342,41 @@ namespace arith { return out; } - bool check(expr_ref_vector const& clause, app* jst, expr_ref_vector& units) override { + expr_ref_vector clause(app* jst) override { + expr_ref_vector result(m); + for (expr* arg : *jst) + if (m.is_bool(arg)) + result.push_back(mk_not(m, arg)); + return result; + } + + /** + Add implied equality as an inequality + */ + bool add_implied_ineq(bool sign, app* jst) { + unsigned n = jst->get_num_args(); + if (n < 2) + return false; + expr* arg1 = jst->get_arg(n - 2); + expr* arg2 = jst->get_arg(n - 1); + rational coeff; + if (!a.is_numeral(arg1, coeff)) + return false; + if (!m.is_not(arg2, arg2)) + return false; + if (!m.is_eq(arg2, arg1, arg2)) + return false; + if (!sign) + coeff.neg(); + auto& r = m_ineq; + linearize(r, coeff, arg1); + linearize(r, -coeff, arg2); + m_strict = true; + return true; + } + + bool check(app* jst) override { reset(); - expr_mark pos, neg; - for (expr* e : clause) - if (m.is_not(e, e)) - neg.mark(e, true); - else - pos.mark(e, true); bool is_bound = jst->get_name() == m_bound; bool is_implied_eq = jst->get_name() == m_implied_eq; bool is_farkas = jst->get_name() == m_farkas; @@ -393,25 +387,51 @@ namespace arith { bool even = true; rational coeff; expr* x, * y; - unsigned j = 0; + unsigned j = 0, num_le = 0; + + for (expr* arg : *jst) { if (even) { if (!a.is_numeral(arg, coeff)) { IF_VERBOSE(0, verbose_stream() << "not numeral " << mk_pp(jst, m) << "\n"); return false; } + if (is_implied_eq) { + is_implied_eq = false; + if (!coeff.is_unsigned()) { + IF_VERBOSE(0, verbose_stream() << "not unsigned " << mk_pp(jst, m) << "\n"); + return false; + } + num_le = coeff.get_unsigned(); + if (!add_implied_ineq(false, jst)) + return false; + ++j; + continue; + } } else { bool sign = m.is_not(arg, arg); if (a.is_le(arg) || a.is_lt(arg) || a.is_ge(arg) || a.is_gt(arg)) { if (is_bound && j + 1 == jst->get_num_args()) add_conseq(coeff, arg, sign); + else if (num_le > 0) { + add_ineq(coeff, arg, sign); + --num_le; + if (num_le == 0) { + // we processed all the first inequalities, + // check that they imply one half of the implied equality. + if (!check()) + return false; + reset(); + VERIFY(add_implied_ineq(true, jst)); + } + } else add_ineq(coeff, arg, sign); } else if (m.is_eq(arg, x, y)) { - if (sign) - add_diseq(x, y); + if (sign) + return check(); // it should be an implied equality else add_eq(x, y); } @@ -419,23 +439,11 @@ namespace arith { IF_VERBOSE(0, verbose_stream() << "not a recognized arithmetical relation " << mk_pp(arg, m) << "\n"); return false; } - - if (sign && !pos.is_marked(arg)) { - units.push_back(m.mk_not(arg)); - pos.mark(arg, false); - } - else if (!sign && !neg.is_marked(arg)) { - units.push_back(arg); - neg.mark(arg, false); - } } even = !even; ++j; } - if (check()) - return true; - - return false; + return check(); } void register_plugins(euf::proof_checker& pc) override { diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 2142874d5..4fdb57386 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -51,14 +51,15 @@ namespace arith { enum class hint_type { farkas_h, bound_h, - implied_eq_h + implied_eq_h }; struct arith_proof_hint : public euf::th_proof_hint { - hint_type m_ty; - unsigned m_lit_head, m_lit_tail, m_eq_head, m_eq_tail; - arith_proof_hint(hint_type t, unsigned lh, unsigned lt, unsigned eh, unsigned et): - m_ty(t), m_lit_head(lh), m_lit_tail(lt), m_eq_head(eh), m_eq_tail(et) {} + hint_type m_ty; + unsigned m_num_le; + unsigned m_lit_head, m_lit_tail, m_eq_head, m_eq_tail; + arith_proof_hint(hint_type t, unsigned num_le, unsigned lh, unsigned lt, unsigned eh, unsigned et): + m_ty(t), m_num_le(num_le), m_lit_head(lh), m_lit_tail(lt), m_eq_head(eh), m_eq_tail(et) {} expr* get_hint(euf::solver& s) const override; }; @@ -66,6 +67,7 @@ namespace arith { vector> m_literals; svector> m_eqs; hint_type m_ty; + unsigned m_num_le = 0; unsigned m_lit_head = 0, m_lit_tail = 0, m_eq_head = 0, m_eq_tail = 0; void reset() { m_lit_head = m_lit_tail; m_eq_head = m_eq_tail; } void add(euf::enode* a, euf::enode* b, bool is_eq) { @@ -82,6 +84,7 @@ namespace arith { m_ty = ty; reset(); } + void set_num_le(unsigned n) { m_num_le = n; } void add_eq(euf::enode* a, euf::enode* b) { add(a, b, true); } void add_diseq(euf::enode* a, euf::enode* b) { add(a, b, false); } void add_lit(rational const& coeff, literal lit) { @@ -94,7 +97,7 @@ namespace arith { std::pair const& lit(unsigned i) const { return m_literals[i]; } std::tuple const& eq(unsigned i) const { return m_eqs[i]; } arith_proof_hint* mk(euf::solver& s) { - return new (s.get_region()) arith_proof_hint(m_ty, m_lit_head, m_lit_tail, m_eq_head, m_eq_tail); + return new (s.get_region()) arith_proof_hint(m_ty, m_num_le, m_lit_head, m_lit_tail, m_eq_head, m_eq_tail); } }; @@ -474,7 +477,7 @@ namespace arith { arith_proof_hint const* explain(hint_type ty, sat::literal lit = sat::null_literal); arith_proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b); - arith_proof_hint const* explain_triangle_eq(sat::literal le, sat::literal ge, sat::literal eq); + arith_proof_hint const* explain_trichotomy(sat::literal le, sat::literal ge, sat::literal eq); void explain_assumptions(); diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index d0a4e4ab1..4774e154f 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -17,6 +17,7 @@ Author: #include "util/union_find.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" #include "ast/ast_ll_pp.h" #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_proof_checker.h" @@ -120,24 +121,23 @@ namespace euf { ~eq_proof_checker() override {} - bool check(expr_ref_vector const& clause, app* jst, expr_ref_vector& units) override { - IF_VERBOSE(10, verbose_stream() << clause << "\n" << mk_pp(jst, m) << "\n"); + expr_ref_vector clause(app* jst) override { + expr_ref_vector result(m); + for (expr* arg : *jst) + if (m.is_bool(arg)) + result.push_back(mk_not(m, arg)); + return result; + } + + bool check(app* jst) override { + IF_VERBOSE(10, verbose_stream() << mk_pp(jst, m) << "\n"); reset(); - expr_mark pos, neg; - expr* x, *y; - for (expr* e : clause) - if (m.is_not(e, e)) - neg.mark(e, true); - else - pos.mark(e, true); for (expr* arg : *jst) { - if (m.is_bool(arg)) { - bool sign = m.is_not(arg, arg); - if (sign && !pos.is_marked(arg)) - units.push_back(m.mk_not(arg)); - else if (!sign & !neg.is_marked(arg)) - units.push_back(arg); + expr* x, *y; + bool sign = m.is_not(arg, arg); + + if (m.is_bool(arg)) { if (m.is_eq(arg, x, y)) { if (sign) m_diseqs.push_back({x, y}); @@ -198,38 +198,144 @@ namespace euf { void register_plugins(proof_checker& pc) override { pc.register_plugin(symbol("euf"), this); } + }; + /** + A resolution proof term is of the form + (res pivot proof1 proof2) + The pivot occurs with opposite signs in proof1 and proof2 + */ + + class res_proof_checker : public proof_checker_plugin { + ast_manager& m; + proof_checker& pc; + + public: + res_proof_checker(ast_manager& m, proof_checker& pc): m(m), pc(pc) {} + + ~res_proof_checker() override {} + + bool check(app* jst) override { + if (jst->get_num_args() != 3) + return false; + auto [pivot, proof1, proof2] = jst->args3(); + if (!m.is_bool(pivot) || !m.is_proof(proof1) || !m.is_proof(proof2)) + return false; + expr* narg; + bool found1 = false, found2 = false, found3 = false, found4 = false; + for (expr* arg : pc.clause(proof1)) { + found1 |= arg == pivot; + found2 |= m.is_not(arg, narg) && narg == pivot; + } + if (found1 == found2) + return false; + + for (expr* arg : pc.clause(proof2)) { + found3 |= arg == pivot; + found4 |= m.is_not(arg, narg) && narg == pivot; + } + if (found3 == found4) + return false; + if (found3 == found1) + return false; + return pc.check(proof1) && pc.check(proof2); + } + + expr_ref_vector clause(app* jst) override { + expr_ref_vector result(m); + auto [pivot, proof1, proof2] = jst->args3(); + expr* narg; + auto is_pivot = [&](expr* arg) { + if (arg == pivot) + return true; + return m.is_not(arg, narg) && narg == pivot; + }; + for (expr* arg : pc.clause(proof1)) + if (!is_pivot(arg)) + result.push_back(arg); + for (expr* arg : pc.clause(proof2)) + if (!is_pivot(arg)) + result.push_back(arg); + return result; + } + + void register_plugins(proof_checker& pc) override { + pc.register_plugin(symbol("res"), this); + } }; proof_checker::proof_checker(ast_manager& m): m(m) { - arith::proof_checker* apc = alloc(arith::proof_checker, m); - eq_proof_checker* epc = alloc(eq_proof_checker, m); - m_plugins.push_back(apc); - m_plugins.push_back(epc); - apc->register_plugins(*this); - epc->register_plugins(*this); + add_plugin(alloc(arith::proof_checker, m)); + add_plugin(alloc(eq_proof_checker, m)); + add_plugin(alloc(res_proof_checker, m, *this)); } - proof_checker::~proof_checker() {} + proof_checker::~proof_checker() { + for (auto& [k, v] : m_checked_clauses) + dealloc(v); + } + + void proof_checker::add_plugin(proof_checker_plugin* p) { + m_plugins.push_back(p); + p->register_plugins(*this); + } void proof_checker::register_plugin(symbol const& rule, proof_checker_plugin* p) { m_map.insert(rule, p); } - bool proof_checker::check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units) { + bool proof_checker::check(expr* e) { + if (m_checked_clauses.contains(e)) + return true; + if (!e || !is_app(e)) return false; - units.reset(); app* a = to_app(e); proof_checker_plugin* p = nullptr; if (!m_map.find(a->get_decl()->get_name(), p)) return false; - if (p->check(clause, a, units)) - return true; - - std::cout << "(missed-hint " << mk_pp(e, m) << ")\n"; - return false; + if (!p->check(a)) { + std::cout << "(missed-hint " << mk_pp(e, m) << ")\n"; + return false; + } + return true; + } + + expr_ref_vector proof_checker::clause(expr* e) { + expr_ref_vector* rr; + if (m_checked_clauses.find(e, rr)) + return *rr; + SASSERT(is_app(e) && m_map.contains(to_app(e)->get_decl()->get_name())); + auto& r = m_map[to_app(e)->get_decl()->get_name()]->clause(to_app(e)); + m_checked_clauses.insert(e, alloc(expr_ref_vector, r)); + return r; + } + + bool proof_checker::check(expr_ref_vector const& clause1, expr* e, expr_ref_vector & units) { + if (!check(e)) + return false; + units.reset(); + expr_mark literals; + auto clause2 = clause(e); + + // check that all literals in clause1 are in clause2 + for (expr* arg : clause2) + literals.mark(arg, true); + for (expr* arg : clause1) + if (!literals.is_marked(arg)) + return false; + + // extract negated units for literals in clause2 but not in clause1 + // the literals should be rup + literals.reset(); + for (expr* arg : clause1) + literals.mark(arg, true); + for (expr* arg : clause2) + if (!literals.is_marked(arg)) + units.push_back(mk_not(m, arg)); + + return true; } } diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 464d90559..023bfae48 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -27,18 +27,23 @@ namespace euf { class proof_checker_plugin { public: virtual ~proof_checker_plugin() {} - virtual bool check(expr_ref_vector const& clause, app* jst, expr_ref_vector& units) = 0; + virtual bool check(app* jst) = 0; + virtual expr_ref_vector clause(app* jst) = 0; virtual void register_plugins(proof_checker& pc) = 0; }; class proof_checker { ast_manager& m; - scoped_ptr_vector m_plugins; - map m_map; + scoped_ptr_vector m_plugins; // plugins of proof checkers + map m_map; // symbol table of proof checkers + obj_map m_checked_clauses; // cache of previously checked proofs and their clauses. + void add_plugin(proof_checker_plugin* p); public: proof_checker(ast_manager& m); ~proof_checker(); void register_plugin(symbol const& rule, proof_checker_plugin*); + bool check(expr* jst); + expr_ref_vector clause(expr* jst); bool check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units); }; From 876ca2f1a5cce354fd03327c1ec886bfe3316ab2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2022 14:51:28 -0400 Subject: [PATCH 094/477] fix #6371 --- src/ast/rewriter/th_rewriter.cpp | 4 +++- src/cmd_context/cmd_context.cpp | 9 +++++++-- src/solver/assertions/asserted_formulas.cpp | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index aa02ab009..f7ac45ff5 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -826,7 +826,6 @@ struct th_rewriter_cfg : public default_rewriter_cfg { result = elim_unused_vars(m(), q1, params_ref()); - TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << "\n";); result_pr = nullptr; if (m().proofs_enabled()) { @@ -835,6 +834,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg { p2 = m().mk_elim_unused_vars(q1, result); result_pr = m().mk_transitivity(p1, p2); } + + TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << " " << result_pr << "\n" ;); + SASSERT(old_q->get_sort() == result->get_sort()); return true; } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 0c38f2e4a..8fb859b88 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -621,10 +621,15 @@ void cmd_context::set_produce_unsat_cores(bool f) { } void cmd_context::set_produce_proofs(bool f) { - SASSERT(!has_assertions() || m_params.m_proof == f); - if (has_manager()) + if (m_params.m_proof == f) + return; + SASSERT(!has_assertions()); + if (has_manager()) { m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED); + std::cout << m_params.m_proof << " " << f << "\n"; + } m_params.m_proof = f; + mk_solver(); } diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 5dec90ba7..630d73945 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -171,7 +171,7 @@ void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { else pr = m.mk_modus_ponens(in_pr, pr); } - TRACE("assert_expr_bug", tout << "after...\n" << r << "\n";); + TRACE("assert_expr_bug", tout << "after...\n" << r << "\n" << pr << "\n";); } m_has_quantifiers |= ::has_quantifiers(e); From ab045f0645ae3a6fb2b3acf6500d597fba3c6a6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2022 16:52:19 -0400 Subject: [PATCH 095/477] fix build Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 118 +++++++++++++++++----- src/sat/smt/euf_proof_checker.cpp | 2 +- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index e429358fa..c95e5cc18 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -190,6 +190,9 @@ namespace sat { ast_manager& m; solver s; literal_vector m_clause; + + vector> m_trail; + struct hash { unsigned operator()(literal_vector const& v) const { return string_hash((char const*)v.begin(), v.size()*sizeof(literal), 3); @@ -226,7 +229,7 @@ namespace sat { Input: trail (a0,d0), ..., (an,dn) = ({},bot) Output: reduced trail - result result = [] - C = an + C = { an } for i = n to 0 do if s.is_deleted(ai) then s.revive(ai) else @@ -260,53 +263,112 @@ namespace sat { restoretrail: restore the trail to the position before enqueue - - + */ - void trim() { + void trim() { + vector result, clauses; + clauses.push_back(literal_vector()); + for (unsigned i = m_trail.size(); i-- > 0; ) { + auto const& [cl, clp, is_add, is_initial] = m_trail[i]; + if (!is_add) { + revive(cl, clp); + continue; + } + prune_trail(cl, clp); + del(cl, clp); + if (!clauses.contains(cl)) + continue; + if (!is_initial) { + s.push(); + unsigned lvl = s.scope_lvl(); + for (auto lit : cl) + s.assign(~lit, justification(lvl)); + s.propagate(false); + SASSERT(s.inconsistent()); + conflict_analysis(clauses); + s.pop(1); + } + result.push_back(cl); + } + result.reverse(); + } + + void del(literal_vector const& cl, clause* cp) { + if (cp) + s.detach_clause(*cp); + else + del(cl); + } + + void prune_trail(literal_vector const& cl, clause* cp) { + + } + + void conflict_analysis(vector const& clauses) { } + + + void revive(literal_vector const& cl, clause* cp) { + if (cp) + s.attach_clause(*cp); + else + s.mk_clause(cl, status::redundant()); + } + + + clause* del(literal_vector const& cl) { + clause* cp = nullptr; + IF_VERBOSE(3, verbose_stream() << "del: " << cl << "\n"); + if (m_clause.size() == 2) { + s.detach_bin_clause(cl[0], cl[1], true); + return cp; + } + auto* e = m_clauses.find_core(cl); + if (!e) + return cp; + auto& v = e->get_data().m_value; + if (!v.empty()) { + cp = v.back(); + IF_VERBOSE(3, verbose_stream() << "del: " << *cp << "\n"); + s.detach_clause(*cp); + v.pop_back(); + } + return cp; + } + + void save(literal_vector const& lits, clause* cl) { + if (!cl) + return; + IF_VERBOSE(3, verbose_stream() << "add: " << *cl << "\n"); + auto& v = m_clauses.insert_if_not_there(lits, clause_vector()); + v.push_back(cl); + } public: proof_trim(cmd_context& ctx): ctx(ctx), m(ctx.m()), - s(gparams::get_module("sat"), m.limit()) { - + s(gparams::get_module("sat"), m.limit()) { } - void assume(expr_ref_vector const& _clause) { + void assume(expr_ref_vector const& _clause, bool is_initial = true) { mk_clause(_clause); IF_VERBOSE(3, verbose_stream() << "add: " << m_clause << "\n"); auto* cl = s.mk_clause(m_clause, status::redundant()); - s.propagate(false); - if (!cl) - return; - IF_VERBOSE(3, verbose_stream() << "add: " << *cl << "\n"); - auto& v = m_clauses.insert_if_not_there(m_clause, clause_vector()); - v.push_back(cl); + m_trail.push_back({ m_clause, cl, true, is_initial }); + s.propagate(false); + save(m_clause, cl); } void del(expr_ref_vector const& _clause) { mk_clause(_clause); - IF_VERBOSE(3, verbose_stream() << "del: " << m_clause << "\n"); - if (m_clause.size() == 2) { - s.detach_bin_clause(m_clause[0], m_clause[1], true); - return; - } - auto* e = m_clauses.find_core(m_clause); - if (!e) - return; - auto& v = e->get_data().m_value; - if (!v.empty()) { - IF_VERBOSE(3, verbose_stream() << "del: " << *v.back() << "\n"); - s.detach_clause(*v.back()); - v.pop_back(); - } + clause* cp = del(m_clause); + m_trail.push_back({ m_clause, cp, false, true }); } void infer(expr_ref_vector const& _clause, app*) { - assume(_clause); + assume(_clause, false); } void updt_params(params_ref const& p) { diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 4774e154f..daa775b16 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -307,7 +307,7 @@ namespace euf { if (m_checked_clauses.find(e, rr)) return *rr; SASSERT(is_app(e) && m_map.contains(to_app(e)->get_decl()->get_name())); - auto& r = m_map[to_app(e)->get_decl()->get_name()]->clause(to_app(e)); + expr_ref_vector r = m_map[to_app(e)->get_decl()->get_name()]->clause(to_app(e)); m_checked_clauses.insert(e, alloc(expr_ref_vector, r)); return r; } From 903cddcaaa40236eb64ce3745718add2d36bc9cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2022 17:10:18 -0400 Subject: [PATCH 096/477] fix build Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_iuc_solver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index be1a3879b..8bc4ef1d4 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -68,11 +68,11 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - iuc_solver(solver &solver, unsigned iuc, unsigned iuc_arith, + iuc_solver(solver &, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool old_hyp_reducer, bool split_literals = false) : solver(m), - m_solver(solver), + m_solver(s), m_proxies(m), m_num_proxies(0), m_base_defs(*this), From 47e44c5538e2be8d11abfd34e7eea3d4a310379f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 1 Oct 2022 12:17:15 +0100 Subject: [PATCH 097/477] fix build --- src/muz/spacer/spacer_iuc_solver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 8bc4ef1d4..edfc68522 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -68,7 +68,7 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - iuc_solver(solver &, unsigned iuc, unsigned iuc_arith, + iuc_solver(solver &s, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool old_hyp_reducer, bool split_literals = false) : solver(m), From 49ebca6c1c2d3296b095a0924eb7db1a1acfa453 Mon Sep 17 00:00:00 2001 From: Naxaes Date: Sat, 1 Oct 2022 15:01:36 +0200 Subject: [PATCH 098/477] Fix clang build (#6378) --- src/sat/smt/euf_proof_checker.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index daa775b16..158b850a5 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -243,7 +243,10 @@ namespace euf { expr_ref_vector clause(app* jst) override { expr_ref_vector result(m); - auto [pivot, proof1, proof2] = jst->args3(); + auto x = jst->args3(); + auto pivot = std::get<0>(x); + auto proof1 = std::get<1>(x); + auto proof2 = std::get<2>(x); expr* narg; auto is_pivot = [&](expr* arg) { if (arg == pivot) From 24ff0f2d36255eccbfd078e9212ecc1b9e7a23de Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 1 Oct 2022 21:48:27 +0100 Subject: [PATCH 099/477] attempt to fix cmake build --- src/api/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 08ea9ce29..5cc604f15 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -68,4 +68,5 @@ z3_add_component(api opt portfolio realclosure + extra_cmds ) From cffe5fe1a5e1094f1ea10f4cea08cd21a103c893 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Oct 2022 17:05:36 -0400 Subject: [PATCH 100/477] remove debug print Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 8fb859b88..1bae574d5 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -624,10 +624,8 @@ void cmd_context::set_produce_proofs(bool f) { if (m_params.m_proof == f) return; SASSERT(!has_assertions()); - if (has_manager()) { + if (has_manager()) m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED); - std::cout << m_params.m_proof << " " << f << "\n"; - } m_params.m_proof = f; mk_solver(); } From ad49dd739be8ac8c6737bc9dad0cc4b41e3cdb46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Oct 2022 17:08:02 -0400 Subject: [PATCH 101/477] initialize variables to avoid warning messages whether real or spurious Signed-off-by: Nikolaj Bjorner --- src/test/lp/lp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 04afd8f96..547985f26 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -1899,7 +1899,7 @@ void find_dir_and_file_name(std::string a, std::string & dir, std::string& fn) { void process_test_file(std::string test_dir, std::string test_file_name, argument_parser & args_parser, std::string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives); void solve_some_mps(argument_parser & args_parser) { - unsigned max_iters, time_limit; + unsigned max_iters = UINT_MAX, time_limit = UINT_MAX; get_time_limit_and_max_iters_from_parser(args_parser, time_limit); unsigned successes = 0; unsigned failures = 0; From 1eed058b98f054a7c5915feb4f404a70e685cd6c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 2 Oct 2022 21:34:17 +0100 Subject: [PATCH 102/477] use std::move --- src/math/realclosure/realclosure.cpp | 33 ++++++++++++---------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 1ff2785ae..68ed35b5d 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -506,8 +506,7 @@ namespace realclosure { m_bqim(lim, m_bqm), m_plus_inf_approx(m_bqm), m_minus_inf_approx(m_bqm) { - mpq one(1); - m_one = mk_rational(one); + m_one = mk_rational(mpq(1)); inc_ref(m_one); m_pi = nullptr; m_e = nullptr; @@ -2557,13 +2556,10 @@ namespace realclosure { return new (allocator()) rational_value(); } - /** - \brief Make a rational and swap its value with v - */ - rational_value * mk_rational_and_swap(mpq & v) { + rational_value * mk_rational(mpq && v) { SASSERT(!qm().is_zero(v)); rational_value * r = mk_rational(); - ::swap(r->m_value, v); + r->m_value = std::move(v); return r; } @@ -2585,7 +2581,7 @@ namespace realclosure { SASSERT(!bqm().is_zero(v)); scoped_mpq v_q(qm()); // v as a rational ::to_mpq(qm(), v, v_q); - return mk_rational(v_q); + return mk_rational(std::move(v_q)); } void reset_interval(value * a) { @@ -3270,7 +3266,7 @@ namespace realclosure { scoped_mpq num_z(qm()); qm().div(lcm_z, to_mpq(dens[i]), num_z); SASSERT(qm().is_int(num_z)); - m = mk_rational_and_swap(num_z); + m = mk_rational(std::move(num_z)); is_z = true; } bool found_lt_eq = false; @@ -3432,7 +3428,7 @@ namespace realclosure { scoped_mpq r(qm()); SASSERT(qm().is_int(to_mpq(a))); qm().div(to_mpq(a), b, r); - a = mk_rational_and_swap(r); + a = mk_rational(std::move(r)); } else { rational_function_value * rf = to_rational_function(a); @@ -3592,9 +3588,8 @@ namespace realclosure { r.reset(); if (sz > 1) { for (unsigned i = 1; i < sz; i++) { - mpq i_mpq(i); value_ref a_i(*this); - a_i = mk_rational_and_swap(i_mpq); + a_i = mk_rational(mpq(i)); mul(a_i, p[i], a_i); r.push_back(a_i); } @@ -3821,7 +3816,7 @@ namespace realclosure { scoped_mpz mpz_twok(qm()); qm().mul2k(mpz(1), b.k(), mpz_twok); value_ref twok(*this), twok_i(*this); - twok = mk_rational(mpz_twok); + twok = mk_rational(std::move(mpz_twok)); twok_i = twok; value_ref c(*this); c = mk_rational(b.numerator()); @@ -5061,7 +5056,7 @@ namespace realclosure { if (qm().is_zero(v)) r = nullptr; else - r = mk_rational_and_swap(v); + r = mk_rational(std::move(v)); } else { INC_DEPTH(); @@ -5090,7 +5085,7 @@ namespace realclosure { if (qm().is_zero(v)) r = nullptr; else - r = mk_rational_and_swap(v); + r = mk_rational(std::move(v)); } else { value_ref neg_b(*this); @@ -5124,7 +5119,7 @@ namespace realclosure { scoped_mpq v(qm()); qm().set(v, to_mpq(a)); qm().neg(v); - r = mk_rational_and_swap(v); + r = mk_rational(std::move(v)); } else { neg_rf(to_rational_function(a), r); @@ -5269,7 +5264,7 @@ namespace realclosure { else if (is_nz_rational(a) && is_nz_rational(b)) { scoped_mpq v(qm()); qm().mul(to_mpq(a), to_mpq(b), v); - r = mk_rational_and_swap(v); + r = mk_rational(std::move(v)); } else { INC_DEPTH(); @@ -5304,7 +5299,7 @@ namespace realclosure { else if (is_nz_rational(a) && is_nz_rational(b)) { scoped_mpq v(qm()); qm().div(to_mpq(a), to_mpq(b), v); - r = mk_rational_and_swap(v); + r = mk_rational(std::move(v)); } else { value_ref inv_b(*this); @@ -5557,7 +5552,7 @@ namespace realclosure { if (is_nz_rational(a)) { scoped_mpq v(qm()); qm().inv(to_mpq(a), v); - r = mk_rational_and_swap(v); + r = mk_rational(std::move(v)); } else { inv_rf(to_rational_function(a), r); From be3c7d7115d7fc2856cb60154d8810eb56abfc61 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 2 Oct 2022 21:44:08 +0100 Subject: [PATCH 103/477] delete dead code --- src/util/mpq.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/util/mpq.h b/src/util/mpq.h index f1afcbe50..31ffbeab8 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -32,13 +32,10 @@ public: mpq(mpq &&) noexcept = default; mpq & operator=(mpq&&) = default; mpq & operator=(mpq const&) = delete; - void swap(mpq & other) { m_num.swap(other.m_num); m_den.swap(other.m_den); } mpz const & numerator() const { return m_num; } mpz const & denominator() const { return m_den; } }; -inline void swap(mpq & m1, mpq & m2) { m1.swap(m2); } - template class mpq_manager : public mpz_manager { mpz m_tmp1; From b03d4e4fc2495cdbad256a09098bd0ed42aaa8d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Oct 2022 15:26:10 -0400 Subject: [PATCH 104/477] update solver only if there is a manager Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 1bae574d5..0de13252b 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -624,10 +624,11 @@ void cmd_context::set_produce_proofs(bool f) { if (m_params.m_proof == f) return; SASSERT(!has_assertions()); - if (has_manager()) - m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED); m_params.m_proof = f; - mk_solver(); + if (has_manager()) { + m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED); + mk_solver(); + } } From 6e05162df038ce79eddc31a0ddadd363b547f826 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Oct 2022 15:27:26 -0400 Subject: [PATCH 105/477] update solver only if there is a manager Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 0de13252b..a5c66f78b 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -627,7 +627,8 @@ void cmd_context::set_produce_proofs(bool f) { m_params.m_proof = f; if (has_manager()) { m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED); - mk_solver(); + if (m_solver_factory) + mk_solver(); } } From d22c86f9fe6b817cfcc3a085fb5fc4055db1de83 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Oct 2022 15:53:58 -0400 Subject: [PATCH 106/477] init spacer_iuc_solver properly Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_iuc_solver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index edfc68522..0d4712215 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -71,7 +71,7 @@ public: iuc_solver(solver &s, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool old_hyp_reducer, bool split_literals = false) : - solver(m), + solver(s.get_manager()), m_solver(s), m_proxies(m), m_num_proxies(0), From c1c659dc93950ffe7721cf1f9a523e6fe6c34ef5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Oct 2022 16:25:40 +0200 Subject: [PATCH 107/477] trying trim Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 247 ++++------------ src/sat/CMakeLists.txt | 1 + src/sat/sat_proof_trim.cpp | 326 ++++++++++++++++++++++ src/sat/sat_proof_trim.h | 79 ++++++ 4 files changed, 457 insertions(+), 196 deletions(-) create mode 100644 src/sat/sat_proof_trim.cpp create mode 100644 src/sat/sat_proof_trim.h diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index c95e5cc18..e464e6ecb 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -45,6 +45,7 @@ Proof checker for clauses created during search. #include "smt/smt_solver.h" #include "sat/sat_solver.h" #include "sat/sat_drat.h" +#include "sat/sat_proof_trim.h" #include "sat/smt/euf_proof_checker.h" #include "cmd_context/cmd_context.h" #include "params/solver_params.hpp" @@ -181,203 +182,57 @@ public: }; -namespace sat { - /** - * Replay proof entierly, then walk backwards extracting reduced proof. - */ - class proof_trim { - cmd_context& ctx; - ast_manager& m; - solver s; - literal_vector m_clause; - - vector> m_trail; +/** + * Replay proof entierly, then walk backwards extracting reduced proof. + */ +class proof_trim { + cmd_context& ctx; + ast_manager& m; + sat::proof_trim trim; - struct hash { - unsigned operator()(literal_vector const& v) const { - return string_hash((char const*)v.begin(), v.size()*sizeof(literal), 3); - } - }; - struct eq { - bool operator()(literal_vector const& a, literal_vector const& b) const { - return a == b; - } - }; - map m_clauses; + void mk_clause(expr_ref_vector const& clause) { + trim.init_clause(); + for (expr* arg: clause) + add_literal(arg); + } - void mk_clause(expr_ref_vector const& clause) { - m_clause.reset(); - for (expr* arg: clause) - add_literal(arg); - std::sort(m_clause.begin(), m_clause.end()); - } + sat::bool_var mk_var(expr* arg) { + while (arg->get_id() >= trim.num_vars()) + trim.mk_var(); + return arg->get_id(); + } - bool_var mk_var(expr* arg) { - while (arg->get_id() >= s.num_vars()) - s.mk_var(true, true); - return arg->get_id(); - } - - void add_literal(expr* arg) { - bool sign = m.is_not(arg, arg); - m_clause.push_back(literal(mk_var(arg), sign)); - } - - - /** - Pseudo-code from Gurfinkel, Vizel, FMCAD 2014 - Input: trail (a0,d0), ..., (an,dn) = ({},bot) - Output: reduced trail - result - result = [] - C = { an } - for i = n to 0 do - if s.is_deleted(ai) then s.revive(ai) - else - if s.isontrail(ai) then - s.undotrailcore(ai,C) - s.delete(ai) - if ai in C then - if ai is not initial then - s.savetrail() - s.enqueue(not ai) - c = s.propagate() - s.conflictanalysiscore(c, C) - s.restoretrail() - result += [ai] - reverse(result) - - is_deleted(ai): - clause was detached - revive(ai): - attach clause ai - isontrail(ai): - some literal on the current trail in s is justified by ai - undotrailcore(ai, C): - pop the trail until dependencies on ai are gone - savetrail: - store current trail so it can be restored - enqueue(not ai): - assert negations of ai at a new decision level - conflictanalysiscore(c, C): - ? - restoretrail: - restore the trail to the position before enqueue - - - */ - void trim() { - vector result, clauses; - clauses.push_back(literal_vector()); - for (unsigned i = m_trail.size(); i-- > 0; ) { - auto const& [cl, clp, is_add, is_initial] = m_trail[i]; - if (!is_add) { - revive(cl, clp); - continue; - } - prune_trail(cl, clp); - del(cl, clp); - if (!clauses.contains(cl)) - continue; - if (!is_initial) { - s.push(); - unsigned lvl = s.scope_lvl(); - for (auto lit : cl) - s.assign(~lit, justification(lvl)); - s.propagate(false); - SASSERT(s.inconsistent()); - conflict_analysis(clauses); - s.pop(1); - } - result.push_back(cl); - } - result.reverse(); - } - - void del(literal_vector const& cl, clause* cp) { - if (cp) - s.detach_clause(*cp); - else - del(cl); - } - - void prune_trail(literal_vector const& cl, clause* cp) { - - } - - void conflict_analysis(vector const& clauses) { - - } - - - void revive(literal_vector const& cl, clause* cp) { - if (cp) - s.attach_clause(*cp); - else - s.mk_clause(cl, status::redundant()); - } - - - clause* del(literal_vector const& cl) { - clause* cp = nullptr; - IF_VERBOSE(3, verbose_stream() << "del: " << cl << "\n"); - if (m_clause.size() == 2) { - s.detach_bin_clause(cl[0], cl[1], true); - return cp; - } - auto* e = m_clauses.find_core(cl); - if (!e) - return cp; - auto& v = e->get_data().m_value; - if (!v.empty()) { - cp = v.back(); - IF_VERBOSE(3, verbose_stream() << "del: " << *cp << "\n"); - s.detach_clause(*cp); - v.pop_back(); - } - return cp; - } - - void save(literal_vector const& lits, clause* cl) { - if (!cl) - return; - IF_VERBOSE(3, verbose_stream() << "add: " << *cl << "\n"); - auto& v = m_clauses.insert_if_not_there(lits, clause_vector()); - v.push_back(cl); - } - - public: - proof_trim(cmd_context& ctx): - ctx(ctx), - m(ctx.m()), - s(gparams::get_module("sat"), m.limit()) { - } - - void assume(expr_ref_vector const& _clause, bool is_initial = true) { - mk_clause(_clause); - IF_VERBOSE(3, verbose_stream() << "add: " << m_clause << "\n"); - auto* cl = s.mk_clause(m_clause, status::redundant()); - m_trail.push_back({ m_clause, cl, true, is_initial }); - s.propagate(false); - save(m_clause, cl); - } - - void del(expr_ref_vector const& _clause) { - mk_clause(_clause); - clause* cp = del(m_clause); - m_trail.push_back({ m_clause, cp, false, true }); - } - - void infer(expr_ref_vector const& _clause, app*) { - assume(_clause, false); - } - - void updt_params(params_ref const& p) { - s.updt_params(p); - } - - }; -} - + void add_literal(expr* arg) { + bool sign = m.is_not(arg, arg); + trim.add_literal(mk_var(arg), sign); + } + +public: + proof_trim(cmd_context& ctx): + ctx(ctx), + m(ctx.m()), + trim(gparams::get_module("sat"), m.limit()) { + } + + void assume(expr_ref_vector const& _clause, bool is_initial = true) { + mk_clause(_clause); + trim.assume(true); + } + + void del(expr_ref_vector const& _clause) { + mk_clause(_clause); + trim.del(); + } + + void infer(expr_ref_vector const& _clause, app*) { + mk_clause(_clause); + trim.infer(); + } + + void updt_params(params_ref const& p) { + trim.updt_params(p); + } +}; class proof_saver { cmd_context& ctx; @@ -415,11 +270,11 @@ class proof_cmds_imp : public proof_cmds { bool m_trim = false; scoped_ptr m_checker; scoped_ptr m_saver; - scoped_ptr m_trimmer; + scoped_ptr m_trimmer; smt_checker& checker() { if (!m_checker) m_checker = alloc(smt_checker, m); return *m_checker; } proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; } - sat::proof_trim& trim() { if (!m_trimmer) m_trimmer = alloc(sat::proof_trim, ctx); return *m_trimmer; } + proof_trim& trim() { if (!m_trimmer) m_trimmer = alloc(proof_trim, ctx); return *m_trimmer; } public: proof_cmds_imp(cmd_context& ctx): ctx(ctx), m(ctx.m()), m_lits(m), m_proof_hint(m) { diff --git a/src/sat/CMakeLists.txt b/src/sat/CMakeLists.txt index b16a15482..b6f6a6f94 100644 --- a/src/sat/CMakeLists.txt +++ b/src/sat/CMakeLists.txt @@ -30,6 +30,7 @@ z3_add_component(sat sat_parallel.cpp sat_prob.cpp sat_probing.cpp + sat_proof_trim.cpp sat_scc.cpp sat_simplifier.cpp sat_solver.cpp diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp new file mode 100644 index 000000000..b8ecec04e --- /dev/null +++ b/src/sat/sat_proof_trim.cpp @@ -0,0 +1,326 @@ +/*++ + Copyright (c) 2020 Microsoft Corporation + + Module Name: + + sat_proof_trim.cpp + + Abstract: + + proof replay and trim + + Author: + + Nikolaj Bjorner 2023-10-04 + + Notes: + + +--*/ + +#include "sat/sat_proof_trim.h" + +namespace sat { + + + /** + Pseudo-code from Gurfinkel, Vizel, FMCAD 2014 + Input: trail (a0,d0), ..., (an,dn) = ({},bot) + Output: reduced trail - result + result = [] + C = { an } + for i = n to 0 do + if s.is_deleted(ai) then s.revive(ai) + else + if s.isontrail(ai) then + s.undotrailcore(ai,C) + s.delete(ai) + if ai in C then + if ai is not initial then + s.savetrail() + s.enqueue(not ai) + c = s.propagate() + s.conflictanalysiscore(c, C) + s.restoretrail() + result += [ai] + reverse(result) + + is_deleted(ai): + clause was detached + revive(ai): + attach clause ai + isontrail(ai): + some literal on the current trail in s is justified by ai + undotrailcore(ai, C): + pop the trail until dependencies on ai are gone + savetrail: + store current trail so it can be restored + enqueue(not ai): + assert negations of ai at a new decision level + conflictanalysiscore(c, C): + ? + restoretrail: + restore the trail to the position before enqueue + + */ + + void proof_trim::trim() { + vector result, clauses; + clauses.push_back(literal_vector()); + for (unsigned i = m_trail.size(); i-- > 0; ) { + auto const& [cl, clp, is_add, is_initial] = m_trail[i]; + if (!is_add) { + revive(cl, clp); + continue; + } + prune_trail(cl, clp); + del(cl, clp); + if (!clauses.contains(cl)) + continue; + result.push_back(cl); + if (is_initial) + continue; + s.push(); + unsigned init_sz = s.m_trail.size(); + unsigned lvl = s.scope_lvl(); + for (auto lit : cl) + s.assign(~lit, justification(lvl)); + s.propagate(false); + SASSERT(s.inconsistent()); + conflict_analysis_core(init_sz, clauses); + s.pop(1); + } + result.reverse(); + } + + void proof_trim::del(literal_vector const& cl, clause* cp) { + if (cp) + s.detach_clause(*cp); + else + del(cl); + } + + bool proof_trim::match_clause(literal_vector const& cl, literal l1, literal l2) const { + return cl.size() == 2 && ((l1 == cl[0] && l2 == cl[1]) || (l1 == cl[1] && l2 == cl[0])); + } + + bool proof_trim::match_clause(literal_vector const& cl, literal l1, literal l2, literal l3) const { + return cl.size() == 3 && + ((l1 == cl[0] && l2 == cl[1] && l3 == cl[2]) || + (l1 == cl[0] && l2 == cl[2] && l3 == cl[1]) || + (l1 == cl[1] && l2 == cl[0] && l3 == cl[2]) || + (l1 == cl[1] && l2 == cl[2] && l3 == cl[0]) || + (l1 == cl[2] && l2 == cl[1] && l3 == cl[0]) || + (l1 == cl[2] && l2 == cl[0] && l3 == cl[1])); + } + + /** + * cl is on the trail if there is some literal l that is implied by cl + * Remove all clauses after cl that are in the cone of influence of cl. + * The coi is defined inductively: C is in coi of cl if it contains ~l + * or it contains ~l' where l' is implied by a clause in the coi of cl. + * Possible optimization: + * - check if clause contains a literal that is on implied on the trail + * if it doesn't contain any such literal, bypass the trail adjustment. + */ + + void proof_trim::prune_trail(literal_vector const& cl, clause* cp) { + m_in_clause.reset(); + m_in_coi.reset(); + + for (literal lit : cl) + m_in_clause.insert(lit.index()); + + bool on_trail = false; + unsigned j = 0; + for (unsigned i = 0; i < s.trail_size(); ++i) { + literal l = s.trail_literal(i); + if (m_in_clause.contains(l.index())) { + SASSERT(!on_trail); + on_trail = true; + m_in_coi.insert((~l).index()); + s.m_assignment[l.index()] = l_undef; + s.m_assignment[(~l).index()] = l_undef; + continue; + } + if (!on_trail) { + s.m_trail[j++] = s.m_trail[i]; + continue; + } + + auto js = s.get_justification(l); + bool in_coi = false; + if (js.is_clause()) + for (literal lit : s.get_clause(j)) + in_coi |= m_in_coi.contains(lit.index()); + else if (js.is_binary_clause()) + in_coi = m_in_coi.contains(js.get_literal().index()); + else if (js.is_ternary_clause()) + in_coi = m_in_coi.contains(js.get_literal1().index()) || m_in_coi.contains(js.get_literal2().index()); + else + UNREACHABLE(); // approach does not work for external justifications + + if (in_coi) { + m_in_coi.insert((~l).index()); + s.m_assignment[l.index()] = l_undef; + s.m_assignment[(~l).index()] = l_undef; + } + else + s.m_trail[j++] = s.m_trail[i]; + } + s.m_trail.shrink(j); + } + + + /** + The current state is in conflict. + Chase justifications for conflict to extract clauses that are in coi of conflict. + + Assume: + F | G, ~C |- [] + Let T (trail) be the extension of G, ~C that derives the empty clause. + T := G, ~C, l1:j1, l2:j2, ..., lk:jk + The goal is to extract clauses in T that are used to derive C. + - some of the literals in ~C that are not set to true already (they must be unassigned relative) + are used to derive the empty clause. + - some literals in ~C that are assigned to true may also be used to derive the empty clause. + + Example: + C = c or d or e + G = a + F = { ~a or ~b, c or d or b, ... } + T = ~b : ~a or ~b, ~c: D ~d : D , ~e : D, b : c or d or b + where D is a decision marker (justification::NONE) + The conflict depends on the first two clauses in F. + + All literals that are are used in clauses leading to the conflict are + queried for their explanation. Their explanation is added to the clauses. + + */ + void proof_trim::conflict_analysis_core(unsigned init_sz, vector& clauses) { + justification j = s.m_conflict; + literal consequent = null_literal; + unsigned idx = s.m_trail.size() - 1; + unsigned old_sz = s.m_unmark.size(); + bool_var c_var; + auto add_dependency = [&](bool_var v) { + auto j = s.m_justification[v]; + literal lit = literal(v, s.value(v) == l_false); + add_core(lit, j, clauses); + }; + + if (s.m_not_l != null_literal) { + s.process_antecedent_for_unsat_core(s.m_not_l); + add_core(s.m_not_l, s.m_justification[s.m_not_l.var()], clauses); + add_core(~s.m_not_l, j, clauses); + consequent = ~s.m_not_l; + } + while (true) { + s.process_consequent_for_unsat_core(consequent, j); + while (idx >= init_sz) { + consequent = s.m_trail[idx]; + c_var = consequent.var(); + if (s.is_marked(c_var)) + break; + --idx; + } + if (idx < init_sz) + break; + j = s.m_justification[c_var]; + --idx; + } + for (unsigned i = s.m_mark.size(); i-- > old_sz; ) + add_dependency(s.m_unmark[i]); + s.reset_unmark(old_sz); + } + + void proof_trim::add_core(literal l, justification j, vector& clauses) { + m_clause.reset(); + switch (j.get_kind()) { + case justification::NONE: + return; + case justification::BINARY: + m_clause.push_back(l); + m_clause.push_back(j.get_literal()); + break; + case justification::TERNARY: + m_clause.push_back(l); + m_clause.push_back(j.get_literal1()); + m_clause.push_back(j.get_literal2()); + break; + case justification::CLAUSE: + for (auto lit : s.get_clause(j)) + m_clause.push_back(lit); + break; + default: + UNREACHABLE(); + break; + } + std::sort(m_clause.begin(), m_clause.end()); + clauses.insert(m_clause); + } + + + void proof_trim::revive(literal_vector const& cl, clause* cp) { + if (cp) + s.attach_clause(*cp); + else + s.mk_clause(cl, status::redundant()); + } + + + clause* proof_trim::del(literal_vector const& cl) { + clause* cp = nullptr; + IF_VERBOSE(3, verbose_stream() << "del: " << cl << "\n"); + if (m_clause.size() == 2) { + s.detach_bin_clause(cl[0], cl[1], true); + return cp; + } + auto* e = m_clauses.find_core(cl); + if (!e) + return cp; + auto& v = e->get_data().m_value; + if (!v.empty()) { + cp = v.back(); + IF_VERBOSE(3, verbose_stream() << "del: " << *cp << "\n"); + s.detach_clause(*cp); + v.pop_back(); + } + return cp; + } + + void proof_trim::save(literal_vector const& lits, clause* cl) { + if (!cl) + return; + IF_VERBOSE(3, verbose_stream() << "add: " << *cl << "\n"); + auto& v = m_clauses.insert_if_not_there(lits, clause_vector()); + v.push_back(cl); + } + + + + proof_trim::proof_trim(params_ref const& p, reslimit& lim): + s(p, lim) + {} + + void proof_trim::assume(bool is_initial) { + std::sort(m_clause.begin(), m_clause.end()); + IF_VERBOSE(3, verbose_stream() << "add: " << m_clause << "\n"); + auto* cl = s.mk_clause(m_clause, status::redundant()); + m_trail.push_back({ m_clause, cl, true, is_initial }); + s.propagate(false); + save(m_clause, cl); + } + + void proof_trim::del() { + std::sort(m_clause.begin(), m_clause.end()); + clause* cp = del(m_clause); + m_trail.push_back({ m_clause, cp, false, true }); + } + + void proof_trim::infer() { + assume(false); + } + + +} diff --git a/src/sat/sat_proof_trim.h b/src/sat/sat_proof_trim.h new file mode 100644 index 000000000..c7b871df7 --- /dev/null +++ b/src/sat/sat_proof_trim.h @@ -0,0 +1,79 @@ +/*++ + Copyright (c) 2020 Microsoft Corporation + + Module Name: + + sat_trim.h + + Abstract: + + proof replay and trim + + Author: + + Nikolaj Bjorner 2023-10-04 + + Notes: + + +--*/ + +#pragma once + +#include "util/params.h" +#include "util/statistics.h" +#include "sat/sat_clause.h" +#include "sat/sat_types.h" +#include "sat/sat_solver.h" + +namespace sat { + + class proof_trim { + solver s; + literal_vector m_clause; + uint_set m_in_clause; + uint_set m_in_coi; + vector> m_trail; + + struct hash { + unsigned operator()(literal_vector const& v) const { + return string_hash((char const*)v.begin(), v.size()*sizeof(literal), 3); + } + }; + struct eq { + bool operator()(literal_vector const& a, literal_vector const& b) const { + return a == b; + } + }; + map m_clauses; + + void del(literal_vector const& cl, clause* cp); + + bool match_clause(literal_vector const& cl, literal l1, literal l2) const; + bool match_clause(literal_vector const& cl, literal l1, literal l2, literal l3) const; + + void prune_trail(literal_vector const& cl, clause* cp); + void conflict_analysis_core(unsigned init_sz, vector& clauses); + void add_core(literal l, justification j, vector& clauses); + void revive(literal_vector const& cl, clause* cp); + clause* del(literal_vector const& cl); + void save(literal_vector const& lits, clause* cl); + + public: + + proof_trim(params_ref const& p, reslimit& lim); + + bool_var mk_var() { return s.mk_var(true, true); } + void init_clause() { m_clause.reset(); } + void add_literal(bool_var v, bool sign) { m_clause.push_back(literal(v, sign)); } + unsigned num_vars() { return s.num_vars(); } + + void assume(bool is_initial = true); + void del(); + void infer(); + void updt_params(params_ref const& p) { s.updt_params(p); } + + void trim(); + + }; +} From f8ca692dee93163a630e706d5df5f484d47b6471 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Oct 2022 04:32:00 +0200 Subject: [PATCH 108/477] fixes to trim Signed-off-by: Nikolaj Bjorner --- src/sat/sat_proof_trim.cpp | 166 +++++++++++++++++-------------------- src/sat/sat_proof_trim.h | 11 ++- 2 files changed, 85 insertions(+), 92 deletions(-) diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index b8ecec04e..be581eec7 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -26,47 +26,13 @@ namespace sat { /** Pseudo-code from Gurfinkel, Vizel, FMCAD 2014 Input: trail (a0,d0), ..., (an,dn) = ({},bot) - Output: reduced trail - result - result = [] - C = { an } - for i = n to 0 do - if s.is_deleted(ai) then s.revive(ai) - else - if s.isontrail(ai) then - s.undotrailcore(ai,C) - s.delete(ai) - if ai in C then - if ai is not initial then - s.savetrail() - s.enqueue(not ai) - c = s.propagate() - s.conflictanalysiscore(c, C) - s.restoretrail() - result += [ai] - reverse(result) - - is_deleted(ai): - clause was detached - revive(ai): - attach clause ai - isontrail(ai): - some literal on the current trail in s is justified by ai - undotrailcore(ai, C): - pop the trail until dependencies on ai are gone - savetrail: - store current trail so it can be restored - enqueue(not ai): - assert negations of ai at a new decision level - conflictanalysiscore(c, C): - ? - restoretrail: - restore the trail to the position before enqueue - + Output: reduced trail - result */ - void proof_trim::trim() { - vector result, clauses; - clauses.push_back(literal_vector()); + vector proof_trim::trim() { + vector result; + m_core_literals.reset(); + m_core_literals.insert(literal_vector()); for (unsigned i = m_trail.size(); i-- > 0; ) { auto const& [cl, clp, is_add, is_initial] = m_trail[i]; if (!is_add) { @@ -75,22 +41,15 @@ namespace sat { } prune_trail(cl, clp); del(cl, clp); - if (!clauses.contains(cl)) + if (!in_core(cl, clp)) continue; result.push_back(cl); if (is_initial) continue; - s.push(); - unsigned init_sz = s.m_trail.size(); - unsigned lvl = s.scope_lvl(); - for (auto lit : cl) - s.assign(~lit, justification(lvl)); - s.propagate(false); - SASSERT(s.inconsistent()); - conflict_analysis_core(init_sz, clauses); - s.pop(1); + conflict_analysis_core(cl, clp); } result.reverse(); + return result; } void proof_trim::del(literal_vector const& cl, clause* cp) { @@ -176,14 +135,15 @@ namespace sat { The current state is in conflict. Chase justifications for conflict to extract clauses that are in coi of conflict. + Assume: F | G, ~C |- [] Let T (trail) be the extension of G, ~C that derives the empty clause. T := G, ~C, l1:j1, l2:j2, ..., lk:jk The goal is to extract clauses in T that are used to derive C. - - some of the literals in ~C that are not set to true already (they must be unassigned relative) - are used to derive the empty clause. - - some literals in ~C that are assigned to true may also be used to derive the empty clause. + This is achieved by collecting all literals from j1, j2, ... jk + and the conflict clause that are at level below ~C and using the clauses that justify those literals. + Example: C = c or d or e @@ -197,44 +157,67 @@ namespace sat { queried for their explanation. Their explanation is added to the clauses. */ - void proof_trim::conflict_analysis_core(unsigned init_sz, vector& clauses) { - justification j = s.m_conflict; - literal consequent = null_literal; - unsigned idx = s.m_trail.size() - 1; - unsigned old_sz = s.m_unmark.size(); - bool_var c_var; - auto add_dependency = [&](bool_var v) { - auto j = s.m_justification[v]; - literal lit = literal(v, s.value(v) == l_false); - add_core(lit, j, clauses); - }; - - if (s.m_not_l != null_literal) { - s.process_antecedent_for_unsat_core(s.m_not_l); - add_core(s.m_not_l, s.m_justification[s.m_not_l.var()], clauses); - add_core(~s.m_not_l, j, clauses); - consequent = ~s.m_not_l; + void proof_trim::conflict_analysis_core(literal_vector const& cl, clause* cp) { + + s.push(); + unsigned lvl = s.scope_lvl(); + for (auto lit : cl) + s.assign(~lit, justification(lvl)); + unsigned trail_size0 = s.m_trail.size(); + s.push(); + s.propagate(false); + if (!s.inconsistent()) { + s.m_qhead = 0; + s.propagate(false); } - while (true) { - s.process_consequent_for_unsat_core(consequent, j); - while (idx >= init_sz) { - consequent = s.m_trail[idx]; - c_var = consequent.var(); - if (s.is_marked(c_var)) - break; - --idx; + SASSERT(s.inconsistent()); + + auto add_dependency = [&](literal lit) { + bool_var v = lit.var(); + if (s.lvl(v) == 0) { + // inefficient for repeated insertions ? + auto j = s.m_justification[v]; + literal lit = literal(v, s.value(v) == l_false); + add_core(lit, j); } - if (idx < init_sz) + else if (s.lvl(v) == 2) + s.mark(v); + }; + + auto add_jdependency = [&](justification j) { + switch (j.get_kind()) { + case justification::BINARY: + add_dependency(j.get_literal()); break; - j = s.m_justification[c_var]; - --idx; + case justification::TERNARY: + add_dependency(j.get_literal1()); + add_dependency(j.get_literal2()); + break; + case justification::CLAUSE: + for (auto lit : s.get_clause(j)) + if (s.value(lit) == l_false) + add_dependency(lit); + break; + default: + break; + } + }; + + if (s.m_not_l != null_literal) + add_dependency(s.m_not_l); + add_jdependency(s.m_conflict); + + for (unsigned i = s.m_trail.size(); i-- > trail_size0; ) { + bool_var v = s.m_trail[i].var(); + if (!s.is_marked(v)) + continue; + s.reset_mark(v); + add_jdependency(s.m_justification[v]); } - for (unsigned i = s.m_mark.size(); i-- > old_sz; ) - add_dependency(s.m_unmark[i]); - s.reset_unmark(old_sz); + s.pop(2); } - void proof_trim::add_core(literal l, justification j, vector& clauses) { + void proof_trim::add_core(literal l, justification j) { m_clause.reset(); switch (j.get_kind()) { case justification::NONE: @@ -248,18 +231,23 @@ namespace sat { m_clause.push_back(j.get_literal1()); m_clause.push_back(j.get_literal2()); break; - case justification::CLAUSE: - for (auto lit : s.get_clause(j)) - m_clause.push_back(lit); - break; + case justification::CLAUSE: + s.get_clause(j).mark_used(); + return; default: UNREACHABLE(); break; } std::sort(m_clause.begin(), m_clause.end()); - clauses.insert(m_clause); + m_core_literals.insert(m_clause); } + bool proof_trim::in_core(literal_vector const& cl, clause* cp) const { + if (cp) + return cp->was_used(); + else + return m_core_literals.contains(cl); + } void proof_trim::revive(literal_vector const& cl, clause* cp) { if (cp) diff --git a/src/sat/sat_proof_trim.h b/src/sat/sat_proof_trim.h index c7b871df7..4199b8386 100644 --- a/src/sat/sat_proof_trim.h +++ b/src/sat/sat_proof_trim.h @@ -35,6 +35,7 @@ namespace sat { uint_set m_in_coi; vector> m_trail; + struct hash { unsigned operator()(literal_vector const& v) const { return string_hash((char const*)v.begin(), v.size()*sizeof(literal), 3); @@ -47,17 +48,21 @@ namespace sat { }; map m_clauses; + hashtable m_core_literals; + void del(literal_vector const& cl, clause* cp); bool match_clause(literal_vector const& cl, literal l1, literal l2) const; bool match_clause(literal_vector const& cl, literal l1, literal l2, literal l3) const; void prune_trail(literal_vector const& cl, clause* cp); - void conflict_analysis_core(unsigned init_sz, vector& clauses); - void add_core(literal l, justification j, vector& clauses); + void conflict_analysis_core(literal_vector const& cl, clause* cp); + void add_core(literal l, justification j); + bool in_core(literal_vector const& cl, clause* cp) const; void revive(literal_vector const& cl, clause* cp); clause* del(literal_vector const& cl); void save(literal_vector const& lits, clause* cl); + public: @@ -73,7 +78,7 @@ namespace sat { void infer(); void updt_params(params_ref const& p) { s.updt_params(p); } - void trim(); + vector trim(); }; } From 4e780d0cc84570df7e711643d471677a80c3ecc2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Oct 2022 05:43:48 +0200 Subject: [PATCH 109/477] trim Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 48 ++++++-- src/sat/sat_proof_trim.cpp | 132 +++++++++++----------- src/sat/sat_proof_trim.h | 11 +- 3 files changed, 116 insertions(+), 75 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index e464e6ecb..1e675aecc 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -189,7 +189,9 @@ class proof_trim { cmd_context& ctx; ast_manager& m; sat::proof_trim trim; - + vector m_clauses; + bool_vector m_is_infer; + void mk_clause(expr_ref_vector const& clause) { trim.init_clause(); for (expr* arg: clause) @@ -214,9 +216,11 @@ public: trim(gparams::get_module("sat"), m.limit()) { } - void assume(expr_ref_vector const& _clause, bool is_initial = true) { - mk_clause(_clause); - trim.assume(true); + void assume(expr_ref_vector const& clause) { + mk_clause(clause); + trim.assume(m_clauses.size()); + m_clauses.push_back(clause); + m_is_infer.push_back(false); } void del(expr_ref_vector const& _clause) { @@ -224,14 +228,42 @@ public: trim.del(); } - void infer(expr_ref_vector const& _clause, app*) { - mk_clause(_clause); - trim.infer(); + void infer(expr_ref_vector const& clause, app* hint) { + mk_clause(clause); + trim.infer(m_clauses.size()); + m_clauses.push_back(clause); + if (hint) + m_clauses.back().push_back(hint); + m_is_infer.push_back(true); } void updt_params(params_ref const& p) { trim.updt_params(p); - } + } + + void do_trim(std::ostream& out) { + ast_pp_util pp(m); + auto ids = trim.trim(); + for (unsigned id : ids) { + auto const& clause = m_clauses[id]; + bool is_infer = m_is_infer[id]; + for (expr* e : clause) + pp.collect(e); + pp.display_decls(out); + for (expr* e : clause) + pp.define_expr(out, e); + + if (!is_infer) + out << "(assume "; + else + out << "(infer"; + for (expr* e : clause) + pp.display_expr_def(out << " ", e); + out << ")\n"; + } + } + + }; class proof_saver { diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index be581eec7..522b91cdc 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -29,12 +29,13 @@ namespace sat { Output: reduced trail - result */ - vector proof_trim::trim() { - vector result; + unsigned_vector proof_trim::trim() { + unsigned_vector result; m_core_literals.reset(); m_core_literals.insert(literal_vector()); + m_propagated.resize(num_vars(), false); for (unsigned i = m_trail.size(); i-- > 0; ) { - auto const& [cl, clp, is_add, is_initial] = m_trail[i]; + auto const& [id, cl, clp, is_add, is_initial] = m_trail[i]; if (!is_add) { revive(cl, clp); continue; @@ -43,7 +44,7 @@ namespace sat { del(cl, clp); if (!in_core(cl, clp)) continue; - result.push_back(cl); + result.push_back(id); if (is_initial) continue; conflict_analysis_core(cl, clp); @@ -73,15 +74,15 @@ namespace sat { (l1 == cl[2] && l2 == cl[0] && l3 == cl[1])); } - /** - * cl is on the trail if there is some literal l that is implied by cl - * Remove all clauses after cl that are in the cone of influence of cl. - * The coi is defined inductively: C is in coi of cl if it contains ~l - * or it contains ~l' where l' is implied by a clause in the coi of cl. - * Possible optimization: - * - check if clause contains a literal that is on implied on the trail - * if it doesn't contain any such literal, bypass the trail adjustment. - */ + /** + * cl is on the trail if there is some literal l that is implied by cl + * Remove all clauses after cl that are in the cone of influence of cl. + * The coi is defined inductively: C is in coi of cl if it contains ~l + * or it contains ~l' where l' is implied by a clause in the coi of cl. + * Possible optimization: + * - check if clause contains a literal that is on implied on the trail + * if it doesn't contain any such literal, bypass the trail adjustment. + */ void proof_trim::prune_trail(literal_vector const& cl, clause* cp) { m_in_clause.reset(); @@ -89,6 +90,12 @@ namespace sat { for (literal lit : cl) m_in_clause.insert(lit.index()); + + auto unassign_literal = [&](literal l) { + m_in_coi.insert((~l).index()); + s.m_assignment[l.index()] = l_undef; + s.m_assignment[(~l).index()] = l_undef; + }; bool on_trail = false; unsigned j = 0; @@ -97,9 +104,7 @@ namespace sat { if (m_in_clause.contains(l.index())) { SASSERT(!on_trail); on_trail = true; - m_in_coi.insert((~l).index()); - s.m_assignment[l.index()] = l_undef; - s.m_assignment[(~l).index()] = l_undef; + unassign_literal(l); continue; } if (!on_trail) { @@ -119,11 +124,8 @@ namespace sat { else UNREACHABLE(); // approach does not work for external justifications - if (in_coi) { - m_in_coi.insert((~l).index()); - s.m_assignment[l.index()] = l_undef; - s.m_assignment[(~l).index()] = l_undef; - } + if (in_coi) + unassign_literal(l); else s.m_trail[j++] = s.m_trail[i]; } @@ -171,52 +173,59 @@ namespace sat { s.propagate(false); } SASSERT(s.inconsistent()); - - auto add_dependency = [&](literal lit) { - bool_var v = lit.var(); - if (s.lvl(v) == 0) { - // inefficient for repeated insertions ? - auto j = s.m_justification[v]; - literal lit = literal(v, s.value(v) == l_false); - add_core(lit, j); - } - else if (s.lvl(v) == 2) - s.mark(v); - }; - - auto add_jdependency = [&](justification j) { - switch (j.get_kind()) { - case justification::BINARY: - add_dependency(j.get_literal()); - break; - case justification::TERNARY: - add_dependency(j.get_literal1()); - add_dependency(j.get_literal2()); - break; - case justification::CLAUSE: - for (auto lit : s.get_clause(j)) - if (s.value(lit) == l_false) - add_dependency(lit); - break; - default: - break; - } - }; + for (unsigned i = trail_size0; i < s.m_trail.size(); ++i) + m_propagated[s.m_trail[i].var()] = true; if (s.m_not_l != null_literal) add_dependency(s.m_not_l); - add_jdependency(s.m_conflict); + add_dependency(s.m_conflict); for (unsigned i = s.m_trail.size(); i-- > trail_size0; ) { bool_var v = s.m_trail[i].var(); + m_propagated[v] = false; if (!s.is_marked(v)) continue; s.reset_mark(v); - add_jdependency(s.m_justification[v]); + add_dependency(s.get_justification(v)); } s.pop(2); } + void proof_trim::add_dependency(literal lit) { + bool_var v = lit.var(); + if (m_propagated[v]) // literal was propagated after assuming ~C + s.mark(v); + else if (s.lvl(v) == 0) { // literal depends on level 0, it is not assumed by ~C + // inefficient for repeated insertions ? + auto j = s.get_justification(v); + literal lit = literal(v, s.value(v) == l_false); + add_core(lit, j); + } + } + + void proof_trim::add_dependency(justification j) { + switch (j.get_kind()) { + case justification::BINARY: + add_dependency(j.get_literal()); + break; + case justification::TERNARY: + add_dependency(j.get_literal1()); + add_dependency(j.get_literal2()); + break; + case justification::CLAUSE: + for (auto lit : s.get_clause(j)) + if (s.value(lit) == l_false) + add_dependency(lit); + break; + case justification::EXT_JUSTIFICATION: + UNREACHABLE(); + break; + default: + break; + } + } + + void proof_trim::add_core(literal l, justification j) { m_clause.reset(); switch (j.get_kind()) { @@ -256,7 +265,6 @@ namespace sat { s.mk_clause(cl, status::redundant()); } - clause* proof_trim::del(literal_vector const& cl) { clause* cp = nullptr; IF_VERBOSE(3, verbose_stream() << "del: " << cl << "\n"); @@ -283,19 +291,17 @@ namespace sat { IF_VERBOSE(3, verbose_stream() << "add: " << *cl << "\n"); auto& v = m_clauses.insert_if_not_there(lits, clause_vector()); v.push_back(cl); - } - - + } proof_trim::proof_trim(params_ref const& p, reslimit& lim): s(p, lim) {} - void proof_trim::assume(bool is_initial) { + void proof_trim::assume(unsigned id, bool is_initial) { std::sort(m_clause.begin(), m_clause.end()); IF_VERBOSE(3, verbose_stream() << "add: " << m_clause << "\n"); auto* cl = s.mk_clause(m_clause, status::redundant()); - m_trail.push_back({ m_clause, cl, true, is_initial }); + m_trail.push_back({ id, m_clause, cl, true, is_initial }); s.propagate(false); save(m_clause, cl); } @@ -303,11 +309,11 @@ namespace sat { void proof_trim::del() { std::sort(m_clause.begin(), m_clause.end()); clause* cp = del(m_clause); - m_trail.push_back({ m_clause, cp, false, true }); + m_trail.push_back({ 0, m_clause, cp, false, true }); } - void proof_trim::infer() { - assume(false); + void proof_trim::infer(unsigned id) { + assume(id, false); } diff --git a/src/sat/sat_proof_trim.h b/src/sat/sat_proof_trim.h index 4199b8386..bf0468bc9 100644 --- a/src/sat/sat_proof_trim.h +++ b/src/sat/sat_proof_trim.h @@ -33,7 +33,7 @@ namespace sat { literal_vector m_clause; uint_set m_in_clause; uint_set m_in_coi; - vector> m_trail; + vector> m_trail; struct hash { @@ -49,6 +49,7 @@ namespace sat { map m_clauses; hashtable m_core_literals; + bool_vector m_propagated; void del(literal_vector const& cl, clause* cp); @@ -57,6 +58,8 @@ namespace sat { void prune_trail(literal_vector const& cl, clause* cp); void conflict_analysis_core(literal_vector const& cl, clause* cp); + void add_dependency(literal lit); + void add_dependency(justification j); void add_core(literal l, justification j); bool in_core(literal_vector const& cl, clause* cp) const; void revive(literal_vector const& cl, clause* cp); @@ -73,12 +76,12 @@ namespace sat { void add_literal(bool_var v, bool sign) { m_clause.push_back(literal(v, sign)); } unsigned num_vars() { return s.num_vars(); } - void assume(bool is_initial = true); + void assume(unsigned id, bool is_initial = true); void del(); - void infer(); + void infer(unsigned id); void updt_params(params_ref const& p) { s.updt_params(p); } - vector trim(); + unsigned_vector trim(); }; } From 9f78a96c1dccf982f5586735f0c2cade72252fa2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Oct 2022 18:19:03 +0200 Subject: [PATCH 110/477] wip - trim --- src/cmd_context/extra_cmds/proof_cmds.cpp | 54 +++++++++++++++++++++-- src/sat/sat_proof_trim.cpp | 45 +++++++++++++++---- src/sat/sat_solver.cpp | 16 ++++--- src/sat/sat_solver.h | 7 ++- src/smt/theory_user_propagator.cpp | 14 ++++++ 5 files changed, 114 insertions(+), 22 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 1e675aecc..1e75b1590 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -189,8 +189,10 @@ class proof_trim { cmd_context& ctx; ast_manager& m; sat::proof_trim trim; + euf::proof_checker m_checker; vector m_clauses; bool_vector m_is_infer; + symbol m_rup; void mk_clause(expr_ref_vector const& clause) { trim.init_clause(); @@ -208,12 +210,18 @@ class proof_trim { bool sign = m.is_not(arg, arg); trim.add_literal(mk_var(arg), sign); } + + bool is_rup(expr* hint) const { + return hint && is_app(hint) && to_app(hint)->get_decl()->get_name() == m_rup; + } public: proof_trim(cmd_context& ctx): ctx(ctx), m(ctx.m()), - trim(gparams::get_module("sat"), m.limit()) { + trim(gparams::get_module("sat"), m.limit()), + m_checker(m) { + m_rup = symbol("rup"); } void assume(expr_ref_vector const& clause) { @@ -227,14 +235,52 @@ public: mk_clause(_clause); trim.del(); } + + /** + * Theory axioms are treated as assumptions. + * Some literals in the theory axioms may have been removed + * because they are false at base level. To reconstruct this + * dependency rely on the proof_checker to produce the original + * clauses. Thus, trim isn't correct for theory axioms that don't + * have a way to return clauses. + * The clauses can be retrieved directly from the justification + * that is used internally, so adding clause retrieval for every + * theory axiom is possible even if there are no checkers. + * In this case, the proof_checker::check dependency should not + * be used. + */ void infer(expr_ref_vector const& clause, app* hint) { + if (hint && !is_rup(hint) && m_checker.check(hint)) { + auto clause1 = m_checker.clause(hint); + if (clause1.size() != clause.size()) { + mk_clause(clause1); + trim.assume(m_clauses.size()); + clause1.push_back(hint); + m_clauses.push_back(clause1); + m_is_infer.push_back(false); + mk_clause(clause); + trim.infer(m_clauses.size()); + m_clauses.push_back(clause); + m_clauses.back().push_back(hint); + m_is_infer.push_back(true); + if (clause.empty()) + do_trim(std::cout); + return; + } + } + mk_clause(clause); - trim.infer(m_clauses.size()); + if (is_rup(hint)) + trim.infer(m_clauses.size()); + else + trim.assume(m_clauses.size()); m_clauses.push_back(clause); if (hint) m_clauses.back().push_back(hint); - m_is_infer.push_back(true); + m_is_infer.push_back(is_rup(hint)); + if (clause.empty()) + do_trim(std::cout); } void updt_params(params_ref const& p) { @@ -254,7 +300,7 @@ public: pp.define_expr(out, e); if (!is_infer) - out << "(assume "; + out << "(assume"; else out << "(infer"; for (expr* e : clause) diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index 522b91cdc..9e1ab7c06 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -40,7 +40,10 @@ namespace sat { revive(cl, clp); continue; } + IF_VERBOSE(0, s.display(verbose_stream())); prune_trail(cl, clp); + IF_VERBOSE(0, verbose_stream() << cl << " " << in_core(cl, clp) << ": "; for (auto const& c : m_core_literals) verbose_stream() << "{" << c << "} "); + IF_VERBOSE(0, s.display(verbose_stream() << "\n")); del(cl, clp); if (!in_core(cl, clp)) continue; @@ -88,6 +91,9 @@ namespace sat { m_in_clause.reset(); m_in_coi.reset(); + if (cl.empty()) + return; + for (literal lit : cl) m_in_clause.insert(lit.index()); @@ -130,6 +136,9 @@ namespace sat { s.m_trail[j++] = s.m_trail[i]; } s.m_trail.shrink(j); + s.m_inconsistent = false; + s.m_qhead = s.m_trail.size(); + s.propagate(false); } @@ -160,24 +169,38 @@ namespace sat { */ void proof_trim::conflict_analysis_core(literal_vector const& cl, clause* cp) { - + IF_VERBOSE(3, verbose_stream() << "core " << cl << "\n"); + + if (cl.empty()) { + add_core(~s.m_not_l, s.m_conflict); + add_core(s.m_not_l, s.get_justification(s.m_not_l)); + return; + } + SASSERT(!s.inconsistent()); s.push(); unsigned lvl = s.scope_lvl(); for (auto lit : cl) s.assign(~lit, justification(lvl)); unsigned trail_size0 = s.m_trail.size(); - s.push(); s.propagate(false); if (!s.inconsistent()) { s.m_qhead = 0; s.propagate(false); } + if (!s.inconsistent()) + IF_VERBOSE(0, s.display(verbose_stream())); + SASSERT(s.inconsistent()); for (unsigned i = trail_size0; i < s.m_trail.size(); ++i) m_propagated[s.m_trail[i].var()] = true; - if (s.m_not_l != null_literal) + SASSERT(s.inconsistent()); + IF_VERBOSE(3, verbose_stream() << s.m_not_l << " " << s.m_conflict << "\n"); + if (s.m_not_l != null_literal) { + if (s.lvl(s.m_not_l) == 0) + add_core(~s.m_not_l, s.m_conflict); add_dependency(s.m_not_l); + } add_dependency(s.m_conflict); for (unsigned i = s.m_trail.size(); i-- > trail_size0; ) { @@ -188,7 +211,7 @@ namespace sat { s.reset_mark(v); add_dependency(s.get_justification(v)); } - s.pop(2); + s.pop(1); } void proof_trim::add_dependency(literal lit) { @@ -230,7 +253,8 @@ namespace sat { m_clause.reset(); switch (j.get_kind()) { case justification::NONE: - return; + m_clause.push_back(l); + break; case justification::BINARY: m_clause.push_back(l); m_clause.push_back(j.get_literal()); @@ -242,12 +266,14 @@ namespace sat { break; case justification::CLAUSE: s.get_clause(j).mark_used(); + IF_VERBOSE(3, verbose_stream() << "add core " << s.get_clause(j) << "\n"); return; default: UNREACHABLE(); break; } std::sort(m_clause.begin(), m_clause.end()); + IF_VERBOSE(3, verbose_stream() << "add core " << m_clause << "\n"); m_core_literals.insert(m_clause); } @@ -268,7 +294,7 @@ namespace sat { clause* proof_trim::del(literal_vector const& cl) { clause* cp = nullptr; IF_VERBOSE(3, verbose_stream() << "del: " << cl << "\n"); - if (m_clause.size() == 2) { + if (cl.size() == 2) { s.detach_bin_clause(cl[0], cl[1], true); return cp; } @@ -294,12 +320,13 @@ namespace sat { } proof_trim::proof_trim(params_ref const& p, reslimit& lim): - s(p, lim) - {} + s(p, lim) { + s.set_trim(); + } void proof_trim::assume(unsigned id, bool is_initial) { std::sort(m_clause.begin(), m_clause.end()); - IF_VERBOSE(3, verbose_stream() << "add: " << m_clause << "\n"); + IF_VERBOSE(3, verbose_stream() << (is_initial?"assume ":"rup ") << m_clause << "\n"); auto* cl = s.mk_clause(m_clause, status::redundant()); m_trail.push_back({ id, m_clause, cl, true, is_initial }); s.propagate(false); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 59503fb00..d10e1124d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -416,7 +416,7 @@ namespace sat { bool logged = false; if (!redundant || !st.is_sat()) { unsigned old_sz = num_lits; - bool keep = simplify_clause(num_lits, lits); + bool keep = m_trim || simplify_clause(num_lits, lits); TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";); if (!keep) { return nullptr; // clause is equivalent to true. @@ -461,16 +461,16 @@ namespace sat { m_touched[l1.var()] = m_touch_index; m_touched[l2.var()] = m_touch_index; - if (redundant && find_binary_watch(get_wlist(~l1), ~l2) && value(l1) == l_undef) { + if (redundant && !m_trim && find_binary_watch(get_wlist(~l1), ~l2) && value(l1) == l_undef) { assign_unit(l1); return; } - if (redundant && find_binary_watch(get_wlist(~l2), ~l1) && value(l2) == l_undef) { + if (redundant && !m_trim && find_binary_watch(get_wlist(~l2), ~l1) && value(l2) == l_undef) { assign_unit(l2); return; } watched* w0 = redundant ? find_binary_watch(get_wlist(~l1), l2) : nullptr; - if (w0) { + if (w0 && !m_trim) { TRACE("sat", tout << "found binary " << l1 << " " << l2 << "\n";); if (w0->is_learned() && !redundant) { w0->set_learned(false); @@ -487,9 +487,10 @@ namespace sat { if (m_config.m_drat) m_drat.add(l1, l2, st); if (propagate_bin_clause(l1, l2)) { - if (at_base_lvl()) + if (!at_base_lvl()) + push_reinit_stack(l1, l2); + else if (!m_trim) return; - push_reinit_stack(l1, l2); } else if (has_variables_to_reinit(l1, l2)) push_reinit_stack(l1, l2); @@ -950,7 +951,8 @@ namespace sat { if (j.level() == 0) { if (m_config.m_drat) drat_log_unit(l, j); - j = justification(0); // erase justification for level 0 + if (!m_trim) + j = justification(0); // erase justification for level 0 } else { VERIFY(!at_base_lvl()); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 5c413ce09..64ee209c9 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -174,6 +174,7 @@ namespace sat { literal_vector m_trail; clause_wrapper_vector m_clauses_to_reinit; std::string m_reason_unknown; + bool m_trim = false; svector m_visited; unsigned m_visited_ts; @@ -203,7 +204,7 @@ namespace sat { class lookahead* m_cuber; class i_local_search* m_local_search; - statistics m_aux_stats; + statistics m_aux_stats; void del_clauses(clause_vector& clauses); @@ -283,6 +284,8 @@ namespace sat { random_gen& rand() { return m_rand; } + void set_trim() { m_trim = true; } + protected: void reset_var(bool_var v, bool ext, bool dvar); @@ -399,7 +402,7 @@ namespace sat { } } void update_assign(literal l, justification j) { - if (j.level() == 0) + if (j.level() == 0 && !m_trim) m_justification[l.var()] = j; } void assign_unit(literal l) { assign(l, justification(0)); } diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 7bbf9d925..f19f933f2 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -323,10 +323,12 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { ctx.set_conflict(js); } else { +#if 1 for (auto& lit : m_lits) lit.neg(); for (auto const& [a,b] : m_eqs) m_lits.push_back(~mk_eq(a->get_expr(), b->get_expr(), false)); +#endif literal lit; if (has_quantifiers(prop.m_conseq)) { @@ -339,8 +341,20 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { else lit = mk_literal(prop.m_conseq); ctx.mark_as_relevant(lit); + +#if 0 + justification* js = + ctx.mk_justification( + ext_theory_propagation_justification( + get_id(), ctx, m_lits.size(), m_lits.data(), m_eqs.size(), m_eqs.data(), lit)); + + ctx.assign(lit, js); +#endif + +#if 1 m_lits.push_back(lit); ctx.mk_th_lemma(get_id(), m_lits); +#endif TRACE("user_propagate", ctx.display(tout);); } } From a792251a82c08035f5f899789fd1127efd2e394f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 6 Oct 2022 17:22:17 +0100 Subject: [PATCH 111/477] remove old compat code --- src/util/mpn.h | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/util/mpn.h b/src/util/mpn.h index 7b3b392e9..45209c269 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -54,30 +54,7 @@ public: char * to_string(mpn_digit const * a, size_t lng, char * buf, size_t lbuf) const; private: - #if defined(__LP64__) || defined(_WIN64) - class mpn_sbuffer : public sbuffer { - public: - mpn_sbuffer() : sbuffer() {} - - mpn_sbuffer(size_t nsz, const mpn_digit & elem = 0) : - sbuffer(static_cast(nsz), elem) - { - } - void resize(size_t nsz, const mpn_digit & elem = 0) { - sbuffer::resize(static_cast(nsz), elem); - } - - mpn_digit & operator[](size_t idx) { - return sbuffer::operator[](static_cast(idx)); - } - - const mpn_digit & operator[](size_t idx) const { - return sbuffer::operator[](static_cast(idx)); - } - }; - #else - typedef sbuffer mpn_sbuffer; - #endif + using mpn_sbuffer = sbuffer; static const mpn_digit zero; void display_raw(std::ostream & out, mpn_digit const * a, size_t lng) const; @@ -104,4 +81,3 @@ private: void trace(mpn_digit const * a, size_t lnga) const; void trace_nl(mpn_digit const * a, size_t lnga) const; }; - From 5c9f69829b0758d125f26a91a0b78d2194973b9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Oct 2022 09:58:04 +0200 Subject: [PATCH 112/477] fixes to trim --- src/cmd_context/extra_cmds/proof_cmds.cpp | 17 +++-- src/sat/sat_proof_trim.cpp | 77 ++++++++++++++--------- src/sat/sat_proof_trim.h | 4 ++ 3 files changed, 65 insertions(+), 33 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 1e75b1590..6c4490d42 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -258,7 +258,7 @@ public: trim.assume(m_clauses.size()); clause1.push_back(hint); m_clauses.push_back(clause1); - m_is_infer.push_back(false); + m_is_infer.push_back(true); mk_clause(clause); trim.infer(m_clauses.size()); m_clauses.push_back(clause); @@ -278,7 +278,7 @@ public: m_clauses.push_back(clause); if (hint) m_clauses.back().push_back(hint); - m_is_infer.push_back(is_rup(hint)); + m_is_infer.push_back(true); if (clause.empty()) do_trim(std::cout); } @@ -295,16 +295,23 @@ public: bool is_infer = m_is_infer[id]; for (expr* e : clause) pp.collect(e); + pp.display_decls(out); - for (expr* e : clause) + for (expr* e : clause) { + m.is_not(e, e); pp.define_expr(out, e); + } if (!is_infer) out << "(assume"; else out << "(infer"; - for (expr* e : clause) - pp.display_expr_def(out << " ", e); + for (expr* e : clause) { + if (m.is_not(e, e)) + pp.display_expr_def(out << " (not ", e) << ")"; + else + pp.display_expr_def(out << " ", e); + } out << ")\n"; } } diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index 9e1ab7c06..8e3c14f94 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -171,34 +171,28 @@ namespace sat { void proof_trim::conflict_analysis_core(literal_vector const& cl, clause* cp) { IF_VERBOSE(3, verbose_stream() << "core " << cl << "\n"); - if (cl.empty()) { - add_core(~s.m_not_l, s.m_conflict); - add_core(s.m_not_l, s.get_justification(s.m_not_l)); - return; - } - SASSERT(!s.inconsistent()); - s.push(); - unsigned lvl = s.scope_lvl(); - for (auto lit : cl) - s.assign(~lit, justification(lvl)); unsigned trail_size0 = s.m_trail.size(); - s.propagate(false); - if (!s.inconsistent()) { - s.m_qhead = 0; + if (!cl.empty()) { + SASSERT(!s.inconsistent()); + s.push(); + unsigned lvl = s.scope_lvl(); + for (auto lit : cl) + s.assign(~lit, justification(lvl)); + trail_size0 = s.m_trail.size(); s.propagate(false); + if (!s.inconsistent()) { + s.m_qhead = 0; + s.propagate(false); + } + if (!s.inconsistent()) + IF_VERBOSE(0, s.display(verbose_stream())); + for (unsigned i = trail_size0; i < s.m_trail.size(); ++i) + m_propagated[s.m_trail[i].var()] = true; } - if (!s.inconsistent()) - IF_VERBOSE(0, s.display(verbose_stream())); - - SASSERT(s.inconsistent()); - for (unsigned i = trail_size0; i < s.m_trail.size(); ++i) - m_propagated[s.m_trail[i].var()] = true; - SASSERT(s.inconsistent()); IF_VERBOSE(3, verbose_stream() << s.m_not_l << " " << s.m_conflict << "\n"); if (s.m_not_l != null_literal) { - if (s.lvl(s.m_not_l) == 0) - add_core(~s.m_not_l, s.m_conflict); + add_core(~s.m_not_l, s.m_conflict); add_dependency(s.m_not_l); } add_dependency(s.m_conflict); @@ -208,22 +202,21 @@ namespace sat { m_propagated[v] = false; if (!s.is_marked(v)) continue; + add_core(v); s.reset_mark(v); add_dependency(s.get_justification(v)); } - s.pop(1); + if (!cl.empty()) + s.pop(1); } void proof_trim::add_dependency(literal lit) { bool_var v = lit.var(); if (m_propagated[v]) // literal was propagated after assuming ~C s.mark(v); - else if (s.lvl(v) == 0) { // literal depends on level 0, it is not assumed by ~C + else if (s.lvl(v) == 0) // literal depends on level 0, it is not assumed by ~C // inefficient for repeated insertions ? - auto j = s.get_justification(v); - literal lit = literal(v, s.value(v) == l_false); - add_core(lit, j); - } + add_core(v); } void proof_trim::add_dependency(justification j) { @@ -248,6 +241,12 @@ namespace sat { } } + void proof_trim::add_core(bool_var v) { + auto j = s.get_justification(v); + literal lit = literal(v, s.value(v) == l_false); + add_core(lit, j); + } + void proof_trim::add_core(literal l, justification j) { m_clause.reset(); @@ -275,6 +274,11 @@ namespace sat { std::sort(m_clause.begin(), m_clause.end()); IF_VERBOSE(3, verbose_stream() << "add core " << m_clause << "\n"); m_core_literals.insert(m_clause); + if (s.lvl(l) == 0) { + m_clause.reset(); + m_clause.push_back(l); + m_core_literals.insert(m_clause); + } } bool proof_trim::in_core(literal_vector const& cl, clause* cp) const { @@ -326,12 +330,29 @@ namespace sat { void proof_trim::assume(unsigned id, bool is_initial) { std::sort(m_clause.begin(), m_clause.end()); + if (unit_or_binary_occurs()) + return; IF_VERBOSE(3, verbose_stream() << (is_initial?"assume ":"rup ") << m_clause << "\n"); auto* cl = s.mk_clause(m_clause, status::redundant()); m_trail.push_back({ id, m_clause, cl, true, is_initial }); s.propagate(false); save(m_clause, cl); } + + /** + * Unit clauses (and binary clause) do not have multi-set semantics in the solver. + * So they should only be represented once. + */ + bool proof_trim::unit_or_binary_occurs() { + if (m_clause.size() == 1) { + literal lit = m_clause[0]; + if (m_units.contains(lit.index())) + return true; + m_units.insert(lit.index()); + } + // todo: binary? + return false; + } void proof_trim::del() { std::sort(m_clause.begin(), m_clause.end()); diff --git a/src/sat/sat_proof_trim.h b/src/sat/sat_proof_trim.h index bf0468bc9..6d996ad6e 100644 --- a/src/sat/sat_proof_trim.h +++ b/src/sat/sat_proof_trim.h @@ -58,14 +58,18 @@ namespace sat { void prune_trail(literal_vector const& cl, clause* cp); void conflict_analysis_core(literal_vector const& cl, clause* cp); + void add_dependency(literal lit); void add_dependency(justification j); + void add_core(bool_var v); void add_core(literal l, justification j); bool in_core(literal_vector const& cl, clause* cp) const; void revive(literal_vector const& cl, clause* cp); clause* del(literal_vector const& cl); void save(literal_vector const& lits, clause* cl); + uint_set m_units; + bool unit_or_binary_occurs(); public: From 661a1624b4e6670b29dc10d6364214b271c66a64 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 7 Oct 2022 14:03:13 +0100 Subject: [PATCH 113/477] avoid string copying in mpf_manager::set --- src/util/mpf.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 6841031c3..791390b11 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -200,30 +200,28 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode // We expect [i].[f]P[e], where P means that the exponent is interpreted as 2^e instead of 10^e. - std::string v(value); - - std::string f, e; + std::string_view v(value); bool sgn = false; - if (v.substr(0, 1) == "-") { + if (v[0] == '-') { sgn = true; v = v.substr(1); } - else if (v.substr(0, 1) == "+") + else if (v[0] == '+') v = v.substr(1); size_t e_pos = v.find('p'); - if (e_pos == std::string::npos) e_pos = v.find('P'); - f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v; - e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0"; + if (e_pos == std::string_view::npos) e_pos = v.find('P'); + const char *f = (e_pos != std::string_view::npos) ? v.substr(0, e_pos).data() : v.data(); + const char *e = (e_pos != std::string_view::npos) ? v.substr(e_pos+1).data() : "0"; TRACE("mpf_dbg", tout << "sgn = " << sgn << " f = " << f << " e = " << e << std::endl;); scoped_mpq q(m_mpq_manager); - m_mpq_manager.set(q, f.c_str()); + m_mpq_manager.set(q, f); scoped_mpz ex(m_mpq_manager); - m_mpz_manager.set(ex, e.c_str()); + m_mpz_manager.set(ex, e); set(o, ebits, sbits, rm, ex, q); o.sign = sgn; From 35639c5ac0bdde98385afca650a62da7ae15304b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Oct 2022 19:21:12 +0200 Subject: [PATCH 114/477] adding q proof hints Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 8 ++++ src/sat/sat_proof_trim.cpp | 6 +-- src/sat/smt/CMakeLists.txt | 1 + src/sat/smt/dt_solver.cpp | 10 +++-- src/sat/smt/euf_proof_checker.cpp | 16 +++++--- src/sat/smt/euf_proof_checker.h | 2 + src/sat/smt/sat_th.cpp | 48 +++++++++++------------ src/sat/smt/sat_th.h | 30 +++++++------- 8 files changed, 71 insertions(+), 50 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 6c4490d42..d792637ea 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -152,6 +152,14 @@ public: } } + // extract a simplified verification condition in case proof validation does not work. + // quantifier instantiation can be validated as follows: + // If quantifier instantiation claims that (forall x . phi(x)) => psi using instantiation x -> t + // then check the simplified VC: phi(t) => psi. + // in case psi is the literal instantiation, then the clause is a propositional tautology. + // The VC function is a no-op if the proof hint does not have an associated vc generator. + m_checker.vc(proof_hint, clause); + m_solver->push(); for (expr* lit : clause) m_solver->assert_expr(m.mk_not(lit)); diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index 8e3c14f94..0554eae1d 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -40,10 +40,10 @@ namespace sat { revive(cl, clp); continue; } - IF_VERBOSE(0, s.display(verbose_stream())); + IF_VERBOSE(10, s.display(verbose_stream())); prune_trail(cl, clp); - IF_VERBOSE(0, verbose_stream() << cl << " " << in_core(cl, clp) << ": "; for (auto const& c : m_core_literals) verbose_stream() << "{" << c << "} "); - IF_VERBOSE(0, s.display(verbose_stream() << "\n")); + IF_VERBOSE(10, verbose_stream() << cl << " " << in_core(cl, clp) << ": "; for (auto const& c : m_core_literals) verbose_stream() << "{" << c << "} "); + IF_VERBOSE(10, s.display(verbose_stream() << "\n")); del(cl, clp); if (!in_core(cl, clp)) continue; diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 51bd8bdd7..26bd835cc 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -36,6 +36,7 @@ z3_add_component(sat_smt q_mam.cpp q_mbi.cpp q_model_fixer.cpp + q_proof_checker.cpp q_queue.cpp q_solver.cpp recfun_solver.cpp diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index 751c43210..f2ce8803f 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -103,14 +103,18 @@ namespace dt { */ void solver::assert_eq_axiom(enode* n1, expr* e2, literal antecedent) { expr* e1 = n1->get_expr(); + euf::th_proof_hint* ph = nullptr; + if (ctx.use_drat()) { + // todo + } if (antecedent == sat::null_literal) - add_unit(eq_internalize(e1, e2)); + add_unit(eq_internalize(e1, e2), ph); else if (s().value(antecedent) == l_true) { euf::enode* n2 = e_internalize(e2); - ctx.propagate(n1, n2, euf::th_explain::propagate(*this, antecedent, n1, n2)); + ctx.propagate(n1, n2, euf::th_explain::propagate(*this, antecedent, n1, n2, ph)); } else - add_clause(~antecedent, eq_internalize(e1, e2)); + add_clause(~antecedent, eq_internalize(e1, e2), ph); } /** diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 158b850a5..fc9c80b75 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -21,6 +21,7 @@ Author: #include "ast/ast_ll_pp.h" #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_proof_checker.h" +#include "sat/smt/q_proof_checker.h" #include namespace euf { @@ -240,7 +241,7 @@ namespace euf { return false; return pc.check(proof1) && pc.check(proof2); } - + expr_ref_vector clause(app* jst) override { expr_ref_vector result(m); auto x = jst->args3(); @@ -272,6 +273,7 @@ namespace euf { add_plugin(alloc(arith::proof_checker, m)); add_plugin(alloc(eq_proof_checker, m)); add_plugin(alloc(res_proof_checker, m, *this)); + add_plugin(alloc(q::proof_checker, m)); } proof_checker::~proof_checker() { @@ -290,8 +292,7 @@ namespace euf { bool proof_checker::check(expr* e) { if (m_checked_clauses.contains(e)) - return true; - + return true; if (!e || !is_app(e)) return false; app* a = to_app(e); @@ -309,12 +310,17 @@ namespace euf { expr_ref_vector* rr; if (m_checked_clauses.find(e, rr)) return *rr; - SASSERT(is_app(e) && m_map.contains(to_app(e)->get_decl()->get_name())); - expr_ref_vector r = m_map[to_app(e)->get_decl()->get_name()]->clause(to_app(e)); + SASSERT(is_app(e) && m_map.contains(to_app(e)->get_name())); + expr_ref_vector r = m_map[to_app(e)->get_name()]->clause(to_app(e)); m_checked_clauses.insert(e, alloc(expr_ref_vector, r)); return r; } + void proof_checker::vc(expr* e, expr_ref_vector& clause) { + SASSERT(is_app(e) && m_map.contains(to_app(e)->get_name())); + m_map[to_app(e)->get_name()]->vc(to_app(e), clause); + } + bool proof_checker::check(expr_ref_vector const& clause1, expr* e, expr_ref_vector & units) { if (!check(e)) return false; diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 023bfae48..443d23186 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -30,6 +30,7 @@ namespace euf { virtual bool check(app* jst) = 0; virtual expr_ref_vector clause(app* jst) = 0; virtual void register_plugins(proof_checker& pc) = 0; + virtual void vc(app* jst, expr_ref_vector& clause) { } }; class proof_checker { @@ -44,6 +45,7 @@ namespace euf { void register_plugin(symbol const& rule, proof_checker_plugin*); bool check(expr* jst); expr_ref_vector clause(expr* jst); + void vc(expr* jst, expr_ref_vector& clause); bool check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units); }; diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 00a23d903..7fc54f7cd 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -129,9 +129,9 @@ namespace euf { return sat::status::th(m_is_redundant, get_id(), ps); } - bool th_euf_solver::add_unit(sat::literal lit) { + bool th_euf_solver::add_unit(sat::literal lit, th_proof_hint const* ps) { bool was_true = is_true(lit); - ctx.s().add_clause(1, &lit, mk_status()); + ctx.s().add_clause(1, &lit, mk_status(ps)); ctx.add_root(lit); return !was_true; } @@ -155,9 +155,9 @@ namespace euf { return add_clause(3, lits, ps); } - bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d) { + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d, th_proof_hint const* ps) { sat::literal lits[4] = { a, b, c, d }; - return add_clause(4, lits); + return add_clause(4, lits, ps); } bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps) { @@ -251,46 +251,46 @@ namespace euf { return new (sat::constraint_base::ptr2mem(mem)) th_explain(n_lits, lits, n_eqs, eqs, c, enode_pair(x, y), pma); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* pma) { - return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr, pma); + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* ph) { + return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr, ph); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma) { - return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, pma); + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* ph) { + return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, ph); } - th_explain* th_explain::propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma) { - return mk(th, 0, nullptr, eqs.size(), eqs.data(), sat::null_literal, x, y, pma); + th_explain* th_explain::propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* ph) { + return mk(th, 0, nullptr, eqs.size(), eqs.data(), sat::null_literal, x, y, ph); } - th_explain* th_explain::propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y) { - return mk(th, 1, &lit, 0, nullptr, sat::null_literal, x, y); + th_explain* th_explain::propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y, th_proof_hint const* ph) { + return mk(th, 1, &lit, 0, nullptr, sat::null_literal, x, y, ph); } - th_explain* th_explain::conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs) { - return conflict(th, lits.size(), lits.data(), eqs.size(), eqs.data()); + th_explain* th_explain::conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, th_proof_hint const* ph) { + return conflict(th, lits.size(), lits.data(), eqs.size(), eqs.data(), ph); } - th_explain* th_explain::conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs) { - return mk(th, n_lits, lits, n_eqs, eqs, sat::null_literal, nullptr, nullptr); + th_explain* th_explain::conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, th_proof_hint const* ph) { + return mk(th, n_lits, lits, n_eqs, eqs, sat::null_literal, nullptr, nullptr, ph); } - th_explain* th_explain::conflict(th_euf_solver& th, enode_pair_vector const& eqs) { - return conflict(th, 0, nullptr, eqs.size(), eqs.data()); + th_explain* th_explain::conflict(th_euf_solver& th, enode_pair_vector const& eqs, th_proof_hint const* ph) { + return conflict(th, 0, nullptr, eqs.size(), eqs.data(), ph); } - th_explain* th_explain::conflict(th_euf_solver& th, sat::literal lit) { - return conflict(th, 1, &lit, 0, nullptr); + th_explain* th_explain::conflict(th_euf_solver& th, sat::literal lit, th_proof_hint const* ph) { + return conflict(th, 1, &lit, 0, nullptr, ph); } - th_explain* th_explain::conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y) { + th_explain* th_explain::conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y, th_proof_hint const* ph) { enode_pair eq(x, y); - return conflict(th, 1, &lit, 1, &eq); + return conflict(th, 1, &lit, 1, &eq, ph); } - th_explain* th_explain::conflict(th_euf_solver& th, euf::enode* x, euf::enode* y) { + th_explain* th_explain::conflict(th_euf_solver& th, euf::enode* x, euf::enode* y, th_proof_hint const* ph) { enode_pair eq(x, y); - return conflict(th, 0, nullptr, 1, &eq); + return conflict(th, 0, nullptr, 1, &eq, ph); } std::ostream& th_explain::display(std::ostream& out) const { diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index a76b86cfd..cf645d21b 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -157,12 +157,12 @@ namespace euf { sat::status mk_status(th_proof_hint const* ps = nullptr); - bool add_unit(sat::literal lit); + bool add_unit(sat::literal lit, th_proof_hint const* ps = nullptr); bool add_units(sat::literal_vector const& lits); - bool add_clause(sat::literal lit) { return add_unit(lit); } + bool add_clause(sat::literal lit, th_proof_hint const* ps = nullptr) { return add_unit(lit, ps); } bool add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps = nullptr); bool add_clause(sat::literal a, sat::literal b, sat::literal c, th_proof_hint const* ps = nullptr); - bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d); + bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d, th_proof_hint const* ps = nullptr); bool add_clause(sat::literal_vector const& lits, th_proof_hint const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); } bool add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps = nullptr); void add_equiv(sat::literal a, sat::literal b); @@ -233,21 +233,21 @@ namespace euf { sat::literal* m_literals; enode_pair* m_eqs; static size_t get_obj_size(unsigned num_lits, unsigned num_eqs); - th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, th_proof_hint const* pma = nullptr); - static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, th_proof_hint const* pma = nullptr); + th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& eq, th_proof_hint const* ph = nullptr); + static th_explain* mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, th_proof_hint const* ph = nullptr); public: - static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs); + static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, th_proof_hint const* ph = nullptr); static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits) { return conflict(th, lits.size(), lits.data(), 0, nullptr); } - static th_explain* conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs); - static th_explain* conflict(th_euf_solver& th, enode_pair_vector const& eqs); - static th_explain* conflict(th_euf_solver& th, sat::literal lit); - static th_explain* conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y); - static th_explain* conflict(th_euf_solver& th, euf::enode* x, euf::enode* y); - static th_explain* propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y); - static th_explain* propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma = nullptr); - static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* pma = nullptr); - static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* pma = nullptr); + static th_explain* conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, th_proof_hint const* ph = nullptr); + static th_explain* conflict(th_euf_solver& th, enode_pair_vector const& eqs, th_proof_hint const* ph = nullptr); + static th_explain* conflict(th_euf_solver& th, sat::literal lit, th_proof_hint const* ph = nullptr); + static th_explain* conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y, th_proof_hint const* ph = nullptr); + static th_explain* conflict(th_euf_solver& th, euf::enode* x, euf::enode* y, th_proof_hint const* ph = nullptr); + static th_explain* propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y, th_proof_hint const* ph = nullptr); + static th_explain* propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* ph = nullptr); + static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* ph = nullptr); + static th_explain* propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* ph = nullptr); sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); From 6796ea7e49414d93dedc96f16379588b416bd51c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Oct 2022 19:22:36 +0200 Subject: [PATCH 115/477] add new files Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_proof_checker.cpp | 60 +++++++++++++++++++++++++++++++++ src/sat/smt/q_proof_checker.h | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 src/sat/smt/q_proof_checker.cpp create mode 100644 src/sat/smt/q_proof_checker.h diff --git a/src/sat/smt/q_proof_checker.cpp b/src/sat/smt/q_proof_checker.cpp new file mode 100644 index 000000000..eecf10fe6 --- /dev/null +++ b/src/sat/smt/q_proof_checker.cpp @@ -0,0 +1,60 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + q_proof_checker.cpp + +Abstract: + + Plugin for checking quantifier instantiations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-07 + +--*/ + +#include "ast/rewriter/var_subst.h" +#include "sat/smt/q_proof_checker.h" +#include "sat/smt/q_solver.h" + +namespace q { + + expr_ref_vector proof_checker::clause(app* jst) { + expr_ref_vector result(m); + for (expr* arg : *jst) + if (!is_bind(arg)) + result.push_back(arg); + return result; + } + + expr_ref_vector proof_checker::binding(app* jst) { + expr_ref_vector result(m); + for (expr* arg : *jst) + if (is_bind(arg)) + result.push_back(to_app(arg)->get_arg(0)); + return result; + } + + void proof_checker::vc(app* jst, expr_ref_vector& clause) { + expr* q = nullptr; + if (!is_inst(jst)) + return; + SASSERT(clause.size() >= 2); + VERIFY(m.is_not(clause.get(0), q) && is_forall(q)); + auto inst = binding(jst); + expr_ref qi = instantiate(m, to_quantifier(q), inst.begin()); + clause[0] = m.mk_not(qi); + } + + bool proof_checker::is_inst(expr* jst) { + return is_app(jst) && to_app(jst)->get_name() == m_inst && m.mk_proof_sort() == jst->get_sort(); + } + + bool proof_checker::is_bind(expr* e) { + return is_app(e) && to_app(e)->get_name() == m_bind && m.mk_proof_sort() == e->get_sort(); + } + + +} diff --git a/src/sat/smt/q_proof_checker.h b/src/sat/smt/q_proof_checker.h new file mode 100644 index 000000000..d60737585 --- /dev/null +++ b/src/sat/smt/q_proof_checker.h @@ -0,0 +1,60 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + q_proof_checker.h + +Abstract: + + Plugin for checking quantifier instantiations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-07 + + +--*/ +#pragma once + +#include "util/obj_pair_set.h" +#include "ast/ast_trail.h" +#include "ast/ast_util.h" +#include "sat/smt/euf_proof_checker.h" +#include + +namespace q { + + class proof_checker : public euf::proof_checker_plugin { + ast_manager& m; + symbol m_inst; + symbol m_bind; + + expr_ref_vector binding(app* jst); + + bool is_inst(expr* jst); + + bool is_bind(expr* e); + + public: + proof_checker(ast_manager& m): + m(m), + m_inst("inst"), + m_bind("bind") { + } + + ~proof_checker() override {} + + expr_ref_vector clause(app* jst) override; + + bool check(app* jst) override { return false; } + + void register_plugins(euf::proof_checker& pc) override { + pc.register_plugin(symbol("inst"), this); + } + + void vc(app* jst, expr_ref_vector& clause) override; + + }; + +} From 4623117af8c6d70f3d84274738013f45ff71a164 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 8 Oct 2022 20:12:57 +0200 Subject: [PATCH 116/477] wip - proof hints --- src/ast/ast_pp_util.cpp | 11 +++++ src/ast/ast_pp_util.h | 3 +- src/sat/smt/dt_solver.cpp | 33 +++++++++------ src/sat/smt/euf_proof.cpp | 70 ++++++++++++++++++++++++++++--- src/sat/smt/euf_proof_checker.cpp | 24 +++++++++-- src/sat/smt/euf_proof_checker.h | 17 ++++++++ src/sat/smt/euf_solver.cpp | 4 +- src/sat/smt/euf_solver.h | 37 +++++++++++++++- src/sat/smt/sat_th.h | 2 +- src/smt/smt_internalizer.cpp | 4 +- 10 files changed, 176 insertions(+), 29 deletions(-) diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index a74566199..c0608522f 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -64,6 +64,17 @@ void ast_pp_util::display_decls(std::ostream& out) { m_rec_decls = n; } +void ast_pp_util::reset() { + coll.reset(); + m_removed.reset(); + m_sorts.clear(0u); + m_decls.clear(0u); + m_rec_decls.clear(0u); + m_is_defined.reset(); + m_defined.reset(); + m_defined_lim.reset(); +} + void ast_pp_util::display_skolem_decls(std::ostream& out) { ast_smt_pp pp(m); unsigned n = coll.get_num_decls(); diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index 9cec62267..9dbfec6af 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -40,8 +40,7 @@ class ast_pp_util { ast_pp_util(ast_manager& m): m(m), m_env(m), m_rec_decls(0), m_decls(0), m_sorts(0), m_defined(m), coll(m) {} - void reset() { coll.reset(); m_removed.reset(); m_sorts.clear(0u); m_decls.clear(0u); m_rec_decls.clear(0u); - m_is_defined.reset(); m_defined.reset(); m_defined_lim.reset(); } + void reset(); void collect(expr* e); diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index f2ce8803f..a87f8770b 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -103,10 +103,7 @@ namespace dt { */ void solver::assert_eq_axiom(enode* n1, expr* e2, literal antecedent) { expr* e1 = n1->get_expr(); - euf::th_proof_hint* ph = nullptr; - if (ctx.use_drat()) { - // todo - } + euf::th_proof_hint* ph = ctx.mk_smt_prop_hint(name(), antecedent, e1, e2); if (antecedent == sat::null_literal) add_unit(eq_internalize(e1, e2), ph); else if (s().value(antecedent) == l_true) { @@ -166,7 +163,8 @@ namespace dt { literal l = ctx.enode2literal(r); SASSERT(s().value(l) == l_false); clear_mark(); - ctx.set_conflict(euf::th_explain::conflict(*this, ~l, c, r->get_arg(0))); + auto* ph = ctx.mk_smt_hint(name(), ~l, c, r->get_arg(0)); + ctx.set_conflict(euf::th_explain::conflict(*this, ~l, c, r->get_arg(0), ph)); } /** @@ -204,7 +202,9 @@ namespace dt { // update_field is identity if 'n' is not created by a matching constructor. assert_eq_axiom(n, arg1, ~is_con); app_ref n_is_con(m.mk_app(rec, own), m); - add_clause(~is_con, mk_literal(n_is_con)); + literal _n_is_con = mk_literal(n_is_con); + auto* ph = ctx.mk_smt_hint(name(), is_con, ~_n_is_con); + add_clause(~is_con, _n_is_con, ph); } euf::theory_var solver::mk_var(enode* n) { @@ -313,7 +313,8 @@ namespace dt { } } } - ctx.set_conflict(euf::th_explain::conflict(*this, m_lits)); + auto* ph = ctx.mk_smt_hint(name(), m_lits); + ctx.set_conflict(euf::th_explain::conflict(*this, m_lits, ph)); } /** @@ -449,8 +450,10 @@ namespace dt { ++idx; } TRACE("dt", tout << "propagate " << num_unassigned << " eqs: " << eqs.size() << "\n";); - if (num_unassigned == 0) - ctx.set_conflict(euf::th_explain::conflict(*this, m_lits, eqs)); + if (num_unassigned == 0) { + auto* ph = ctx.mk_smt_hint(name(), m_lits, eqs); + ctx.set_conflict(euf::th_explain::conflict(*this, m_lits, eqs, ph)); + } else if (num_unassigned == 1) { // propagate remaining recognizer SASSERT(!m_lits.empty()); @@ -464,7 +467,13 @@ namespace dt { app_ref rec_app(m.mk_app(rec, n->get_expr()), m); consequent = mk_literal(rec_app); } - ctx.propagate(consequent, euf::th_explain::propagate(*this, m_lits, eqs, consequent)); + euf::th_proof_hint* ph = nullptr; + if (ctx.use_drat()) { + m_lits.push_back(~consequent); + ph = ctx.mk_smt_hint(name(), m_lits, eqs); + m_lits.pop_back(); + } + ctx.propagate(consequent, euf::th_explain::propagate(*this, m_lits, eqs, consequent, ph)); } else if (get_config().m_dt_lazy_splits == 0 || (!srt->is_infinite() && get_config().m_dt_lazy_splits == 1)) // there are more than 2 unassigned recognizers... @@ -481,7 +490,7 @@ namespace dt { auto* con2 = d2->m_constructor; TRACE("dt", tout << "merging v" << v1 << " v" << v2 << "\n" << ctx.bpp(var2enode(v1)) << " == " << ctx.bpp(var2enode(v2)) << " " << ctx.bpp(con1) << " " << ctx.bpp(con2) << "\n";); if (con1 && con2 && con1->get_decl() != con2->get_decl()) - ctx.set_conflict(euf::th_explain::conflict(*this, con1, con2)); + ctx.set_conflict(euf::th_explain::conflict(*this, con1, con2, ctx.mk_smt_hint(name(), con1, con2))); else if (con2 && !con1) { ctx.push(set_ptr_trail(d1->m_constructor)); // check whether there is a recognizer in d1 that conflicts with con2; @@ -706,7 +715,7 @@ namespace dt { if (res) { clear_mark(); - ctx.set_conflict(euf::th_explain::conflict(*this, m_used_eqs)); + ctx.set_conflict(euf::th_explain::conflict(*this, m_used_eqs, ctx.mk_smt_hint(name(), m_used_eqs))); TRACE("dt", tout << "occurs check conflict: " << ctx.bpp(n) << "\n";); } return res; diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 99bc99d48..73037fc8b 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -79,13 +79,13 @@ namespace euf { return nullptr; push(value_trail(m_lit_tail)); push(value_trail(m_cc_tail)); - push(restore_size_trail(m_eq_proof_literals)); + push(restore_size_trail(m_proof_literals)); if (lit != sat::null_literal) - m_eq_proof_literals.push_back(~lit); - m_eq_proof_literals.append(r); + m_proof_literals.push_back(~lit); + m_proof_literals.append(r); m_lit_head = m_lit_tail; m_cc_head = m_cc_tail; - m_lit_tail = m_eq_proof_literals.size(); + m_lit_tail = m_proof_literals.size(); m_cc_tail = m_explain_cc.size(); return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); } @@ -114,7 +114,7 @@ namespace euf { return ta < tb; }; for (unsigned i = m_lit_head; i < m_lit_tail; ++i) - args.push_back(s.literal2expr(s.m_eq_proof_literals[i])); + args.push_back(s.literal2expr(s.m_proof_literals[i])); std::sort(s.m_explain_cc.data() + m_cc_head, s.m_explain_cc.data() + m_cc_tail, compare_ts); for (unsigned i = m_cc_head; i < m_cc_tail; ++i) { auto const& [a, b, ts, comm] = s.m_explain_cc[i]; @@ -126,6 +126,66 @@ namespace euf { func_decl* f = m.mk_func_decl(symbol("euf"), sorts.size(), sorts.data(), proof); return m.mk_app(f, args); } + + smt_proof_hint* solver::mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, expr_pair const* eqs, unsigned nd, expr_pair const* deqs) { + if (!use_drat()) + return nullptr; + push(value_trail(m_lit_tail)); + push(restore_size_trail(m_proof_literals)); + + for (unsigned i = 0; i < nl; ++i) + if (sat::null_literal != lits[i]) + m_proof_literals.push_back(lits[i]); + + push(value_trail(m_eq_tail)); + push(restore_size_trail(m_proof_eqs)); + m_proof_eqs.append(ne, eqs); + + push(value_trail(m_deq_tail)); + push(restore_size_trail(m_proof_deqs)); + m_proof_deqs.append(nd, deqs); + + m_lit_head = m_lit_tail; + m_eq_head = m_eq_tail; + m_deq_head = m_deq_tail; + m_lit_tail = m_proof_literals.size(); + m_eq_tail = m_proof_eqs.size(); + m_deq_tail = m_proof_deqs.size(); + + return new (get_region()) smt_proof_hint(n, m_lit_head, m_lit_tail, m_eq_head, m_eq_tail, m_deq_head, m_deq_tail); + } + + smt_proof_hint* solver::mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, enode_pair const* eqs) { + if (!use_drat()) + return nullptr; + m_expr_pairs.reset(); + for (unsigned i = 0; i < ne; ++i) + m_expr_pairs.push_back({ eqs[i].first->get_expr(), eqs[i].second->get_expr() }); + return mk_smt_hint(n, nl, lits, ne, m_expr_pairs.data()); + } + + + expr* smt_proof_hint::get_hint(euf::solver& s) const { + ast_manager& m = s.get_manager(); + sort* proof = m.mk_proof_sort(); + ptr_buffer sorts; + expr_ref_vector args(m); + + for (unsigned i = m_lit_head; i < m_lit_tail; ++i) + args.push_back(s.literal2expr(s.m_proof_literals[i])); + for (unsigned i = m_eq_head; i < m_eq_tail; ++i) { + auto const& [a, b] = s.m_proof_eqs[i]; + args.push_back(m.mk_eq(a, b)); + } + for (unsigned i = m_deq_head; i < m_deq_tail; ++i) { + auto const& [a, b] = s.m_proof_deqs[i]; + args.push_back(m.mk_not(m.mk_eq(a, b))); + } + for (auto * arg : args) + sorts.push_back(arg->get_sort()); + func_decl* f = m.mk_func_decl(m_name, sorts.size(), sorts.data(), proof); + return m.mk_app(f, args); + } void solver::set_tmp_bool_var(bool_var b, expr* e) { m_bool_var2expr.setx(b, e, nullptr); diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index fc9c80b75..befde07bf 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -145,8 +145,10 @@ namespace euf { else merge(x, y); } - else - IF_VERBOSE(0, verbose_stream() << "TODO " << mk_pp(arg, m) << " " << sign << "\n"); + else if (m.is_not(arg, arg)) + merge(arg, m.mk_false()); + else + merge(arg, m.mk_true()); } else if (m.is_proof(arg)) { if (!is_app(arg)) @@ -274,6 +276,7 @@ namespace euf { add_plugin(alloc(eq_proof_checker, m)); add_plugin(alloc(res_proof_checker, m, *this)); add_plugin(alloc(q::proof_checker, m)); + add_plugin(alloc(smt_proof_checker_plugin, m, symbol("datatype"))); // no-op datatype proof checker } proof_checker::~proof_checker() { @@ -317,8 +320,13 @@ namespace euf { } void proof_checker::vc(expr* e, expr_ref_vector& clause) { - SASSERT(is_app(e) && m_map.contains(to_app(e)->get_name())); - m_map[to_app(e)->get_name()]->vc(to_app(e), clause); + SASSERT(is_app(e)); + app* a = to_app(e); + proof_checker_plugin* p = nullptr; + if (m_map.find(a->get_name(), p)) + p->vc(a, clause); + else + IF_VERBOSE(0, verbose_stream() << "there is no proof plugin for " << mk_pp(e, m) << "\n"); } bool proof_checker::check(expr_ref_vector const& clause1, expr* e, expr_ref_vector & units) { @@ -347,5 +355,13 @@ namespace euf { return true; } + expr_ref_vector smt_proof_checker_plugin::clause(app* jst) { + expr_ref_vector result(m); + SASSERT(jst->get_name() == m_rule); + for (expr* arg : *jst) + result.push_back(mk_not(m, arg)); + return result; + } + } diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 443d23186..530644488 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -49,5 +49,22 @@ namespace euf { bool check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units); }; + /** + Base class for checking SMT proofs whose justifications are + provided as a set of literals and E-node equalities. + It provides shared implementations for clause and register_plugin. + It overrides check to always fail. + */ + class smt_proof_checker_plugin : public proof_checker_plugin { + ast_manager& m; + symbol m_rule; + public: + smt_proof_checker_plugin(ast_manager& m, symbol const& n): m(m), m_rule(n) {} + ~smt_proof_checker_plugin() override {} + bool check(app* jst) override { return false; } + expr_ref_vector clause(app* jst) override; + void register_plugins(proof_checker& pc) override { pc.register_plugin(m_rule, this); } + }; + } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 2e6b07e51..21290b70a 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -305,11 +305,9 @@ namespace euf { } void solver::asserted(literal l) { - m_relevancy.asserted(l); if (!m_relevancy.is_relevant(l)) return; - 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) @@ -334,7 +332,7 @@ namespace euf { 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); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index b5d65205c..1a8186eaa 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -68,10 +68,20 @@ namespace euf { expr* get_hint(euf::solver& s) const override; }; + class smt_proof_hint : public th_proof_hint { + symbol m_name; + unsigned m_lit_head, m_lit_tail, m_eq_head, m_eq_tail, m_deq_head, m_deq_tail; + public: + smt_proof_hint(symbol const& n, unsigned lh, unsigned lt, unsigned ch, unsigned ct, unsigned dh, unsigned dt): + m_name(n), m_lit_head(lh), m_lit_tail(lt), m_eq_head(ch), m_eq_tail(ct), m_deq_head(dh), m_deq_tail(dt) {} + expr* get_hint(euf::solver& s) const override; + }; + class solver : public sat::extension, public th_internalizer, public th_decompile, public sat::clause_eh { typedef top_sort deps_t; friend class ackerman; friend class eq_proof_hint; + friend class smt_proof_hint; class user_sort; struct stats { unsigned m_ackerman; @@ -130,6 +140,7 @@ namespace euf { constraint* m_eq = nullptr; constraint* m_lit = nullptr; + // internalization bool visit(expr* e) override; bool visited(expr* e) override; @@ -184,8 +195,12 @@ namespace euf { void log_antecedents(std::ostream& out, literal l, literal_vector const& r); void log_antecedents(literal l, literal_vector const& r, eq_proof_hint* hint); void log_justification(literal l, th_explain const& jst); - literal_vector m_eq_proof_literals; + + typedef std::pair expr_pair; + literal_vector m_proof_literals; + svector m_proof_eqs, m_proof_deqs, m_expr_pairs; unsigned m_lit_head = 0, m_lit_tail = 0, m_cc_head = 0, m_cc_tail = 0; + unsigned m_eq_head = 0, m_eq_tail = 0, m_deq_head = 0, m_deq_tail = 0; eq_proof_hint* mk_hint(literal lit, literal_vector const& r); bool m_proof_initialized = false; @@ -365,6 +380,26 @@ namespace euf { void visit_expr(std::ostream& out, expr* e); std::ostream& display_expr(std::ostream& out, expr* e); void on_instantiation(unsigned n, sat::literal const* lits, unsigned k, euf::enode* const* bindings); + smt_proof_hint* mk_smt_hint(symbol const& n, literal_vector const& lits, enode_pair_vector const& eqs) { + return mk_smt_hint(n, lits.size(), lits.data(), eqs.size(), eqs.data()); + } + smt_proof_hint* mk_smt_hint(symbol const& n, enode_pair_vector const& eqs) { + return mk_smt_hint(n, 0, nullptr, eqs.size(), eqs.data()); + } + smt_proof_hint* mk_smt_hint(symbol const& n, literal_vector const& lits) { + return mk_smt_hint(n, lits.size(), lits.data(), 0, (expr_pair const*) nullptr); + } + smt_proof_hint* mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, expr_pair const* eqs, unsigned nd = 0, expr_pair const* deqs = nullptr); + smt_proof_hint* mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, enode_pair const* eqs); + smt_proof_hint* mk_smt_hint(symbol const& n, literal lit, unsigned ne, expr_pair const* eqs) { return mk_smt_hint(n, 1, &lit, ne, eqs); } + smt_proof_hint* mk_smt_hint(symbol const& n, literal lit) { return mk_smt_hint(n, 1, &lit, 0, (expr_pair const*)nullptr); } + smt_proof_hint* mk_smt_hint(symbol const& n, literal l1, literal l2) { literal ls[2] = {l1,l2}; return mk_smt_hint(n, 2, ls, 0, (expr_pair const*)nullptr); } + smt_proof_hint* mk_smt_hint(symbol const& n, literal lit, expr* a, expr* b) { expr_pair e(a, b); return mk_smt_hint(n, 1, &lit, 1, &e); } + smt_proof_hint* mk_smt_hint(symbol const& n, literal lit, enode* a, enode* b) { expr_pair e(a->get_expr(), b->get_expr()); return mk_smt_hint(n, 1, &lit, 1, &e); } + smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, expr* a, expr* b) { expr_pair e(a, b); return mk_smt_hint(n, 1, &lit, 0, nullptr, 1, &e); } + smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, enode* a, enode* b) { return mk_smt_prop_hint(n, lit, a->get_expr(), b->get_expr()); } + smt_proof_hint* mk_smt_hint(symbol const& n, enode* a, enode* b) { expr_pair e(a->get_expr(), b->get_expr()); return mk_smt_hint(n, 0, nullptr, 1, &e); } + scoped_ptr m_proof_out; // decompile diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index cf645d21b..532d04a2e 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -238,7 +238,7 @@ namespace euf { public: static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, th_proof_hint const* ph = nullptr); - static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits) { return conflict(th, lits.size(), lits.data(), 0, nullptr); } + static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, th_proof_hint const* ph = nullptr) { return conflict(th, lits.size(), lits.data(), 0, nullptr, nullptr); } static th_explain* conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, th_proof_hint const* ph = nullptr); static th_explain* conflict(th_euf_solver& th, enode_pair_vector const& eqs, th_proof_hint const* ph = nullptr); static th_explain* conflict(th_euf_solver& th, sat::literal lit, th_proof_hint const* ph = nullptr); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index d87a4f971..ac433c602 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1383,6 +1383,8 @@ namespace smt { Z3_fallthrough; case CLS_AUX: { literal_buffer simp_lits; + if (m_searching) + dump_lemma(num_lits, lits); if (!simplify_aux_clause_literals(num_lits, lits, simp_lits)) { if (j && !j->in_region()) { j->del_eh(m); @@ -1394,6 +1396,7 @@ namespace smt { if (!simp_lits.empty()) { j = mk_justification(unit_resolution_justification(*this, j, simp_lits.size(), simp_lits.data())); } + break; } case CLS_TH_LEMMA: @@ -1525,7 +1528,6 @@ namespace smt { } void context::dump_lemma(unsigned n, literal const* lits) { - if (m_fparams.m_lemmas2console) { expr_ref fml(m); expr_ref_vector fmls(m); From de69874076673996685c6d1fbb49f821106d4668 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Oct 2022 09:46:22 +0200 Subject: [PATCH 117/477] wip - adding proof checkers, fixes to quantifier proof certificates --- src/cmd_context/extra_cmds/proof_cmds.cpp | 15 ++++- src/sat/smt/CMakeLists.txt | 1 + src/sat/smt/euf_internalize.cpp | 21 +++--- src/sat/smt/euf_proof.cpp | 9 +++ src/sat/smt/euf_proof_checker.cpp | 21 +++--- src/sat/smt/euf_proof_checker.h | 4 +- src/sat/smt/euf_solver.h | 4 +- src/sat/smt/q_ematch.cpp | 2 +- src/sat/smt/q_mbi.cpp | 9 +++ src/sat/smt/q_proof_checker.cpp | 22 ++++--- src/sat/smt/q_proof_checker.h | 2 +- src/sat/smt/q_solver.cpp | 2 + src/sat/smt/sat_th.cpp | 7 +- src/sat/smt/tseitin_proof_checker.cpp | 78 +++++++++++++++++++++++ src/sat/smt/tseitin_proof_checker.h | 50 +++++++++++++++ src/sat/tactic/goal2sat.cpp | 52 +++++++++------ 16 files changed, 241 insertions(+), 58 deletions(-) create mode 100644 src/sat/smt/tseitin_proof_checker.cpp create mode 100644 src/sat/smt/tseitin_proof_checker.h diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index d792637ea..6c5f90f0e 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -158,10 +158,15 @@ public: // then check the simplified VC: phi(t) => psi. // in case psi is the literal instantiation, then the clause is a propositional tautology. // The VC function is a no-op if the proof hint does not have an associated vc generator. - m_checker.vc(proof_hint, clause); + expr_ref_vector vc(clause); + if (m_checker.vc(proof_hint, clause, vc)) { + std::cout << "(verified-" << proof_hint->get_name() << ")\n"; + add_clause(clause); + return; + } m_solver->push(); - for (expr* lit : clause) + for (expr* lit : vc) m_solver->assert_expr(m.mk_not(lit)); lbool is_sat = m_solver->check_sat(); if (is_sat != l_false) { @@ -175,7 +180,11 @@ public: exit(0); } m_solver->pop(1); - std::cout << "(verified-smt)\n"; + std::cout << "(verified-smt"; + if (proof_hint) std::cout << " " << mk_pp(proof_hint, m); + for (expr* arg : clause) + std::cout << " " << mk_pp(arg, m); + std::cout << ")\n"; add_clause(clause); } diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 26bd835cc..6d75c0f1f 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -41,6 +41,7 @@ z3_add_component(sat_smt q_solver.cpp recfun_solver.cpp sat_th.cpp + tseitin_proof_checker.cpp user_solver.cpp COMPONENT_DEPENDENCIES sat diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index c8ae2a7c6..3c8956751 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -160,8 +160,13 @@ namespace euf { s().set_external(v); s().set_eliminated(v, false); sat::literal lit2 = literal(v, false); - s().mk_clause(~lit, lit2, sat::status::th(m_is_redundant, m.get_basic_family_id())); - s().mk_clause(lit, ~lit2, sat::status::th(m_is_redundant, m.get_basic_family_id())); + th_proof_hint* ph1 = nullptr, * ph2 = nullptr; + if (use_drat()) { + ph1 = mk_smt_hint(symbol("tseitin"), ~lit, lit2); + ph2 = mk_smt_hint(symbol("tseitin"), lit, ~lit2); + } + s().mk_clause(~lit, lit2, sat::status::th(m_is_redundant, m.get_basic_family_id(), ph1)); + s().mk_clause(lit, ~lit2, sat::status::th(m_is_redundant, m.get_basic_family_id(), ph2)); add_aux(~lit, lit2); add_aux(lit, ~lit2); lit = lit2; @@ -310,8 +315,8 @@ namespace euf { sat::literal lit_el = mk_literal(eq_el); add_root(~lit_c, lit_th); add_root(lit_c, lit_el); - s().add_clause(~lit_c, lit_th, st); - s().add_clause(lit_c, lit_el, st); + s().add_clause(~lit_c, lit_th, mk_tseitin_status(~lit_c, lit_th)); + s().add_clause(lit_c, lit_el, mk_tseitin_status(lit_c, lit_el)); } } else if (m.is_distinct(e)) { @@ -329,8 +334,8 @@ namespace euf { sat::literal some_eq = si.internalize(fml, m_is_redundant); add_root(~dist, ~some_eq); add_root(dist, some_eq); - s().add_clause(~dist, ~some_eq, st); - s().add_clause(dist, some_eq, st); + s().add_clause(~dist, ~some_eq, mk_tseitin_status(~dist, ~some_eq)); + s().add_clause(dist, some_eq, mk_tseitin_status(dist, some_eq)); } else if (m.is_eq(e, th, el) && !m.is_iff(e)) { sat::literal lit1 = expr2literal(e); @@ -341,8 +346,8 @@ namespace euf { sat::literal lit2 = expr2literal(e2); add_root(~lit1, lit2); add_root(lit1, ~lit2); - s().add_clause(~lit1, lit2, st); - s().add_clause(lit1, ~lit2, st); + s().add_clause(~lit1, lit2, mk_tseitin_status(~lit1, lit2)); + s().add_clause(lit1, ~lit2, mk_tseitin_status(lit1, ~lit2)); } } } diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 73037fc8b..cc675e589 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -164,7 +164,16 @@ namespace euf { return mk_smt_hint(n, nl, lits, ne, m_expr_pairs.data()); } + sat::status solver::mk_tseitin_status(sat::literal a, sat::literal b) { + sat::literal lits[2] = { a, b }; + return mk_tseitin_status(2, lits); + } + sat::status solver::mk_tseitin_status(unsigned n, sat::literal const* lits) { + th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("tseitin"), n, lits) : nullptr; + return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + } + expr* smt_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); sort* proof = m.mk_proof_sort(); diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index befde07bf..9b0f37c5e 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -22,6 +22,7 @@ Author: #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_proof_checker.h" #include "sat/smt/q_proof_checker.h" +#include "sat/smt/tseitin_proof_checker.h" #include namespace euf { @@ -145,10 +146,7 @@ namespace euf { else merge(x, y); } - else if (m.is_not(arg, arg)) - merge(arg, m.mk_false()); - else - merge(arg, m.mk_true()); + merge(arg, sign ? m.mk_false() : m.mk_true()); } else if (m.is_proof(arg)) { if (!is_app(arg)) @@ -277,6 +275,7 @@ namespace euf { add_plugin(alloc(res_proof_checker, m, *this)); add_plugin(alloc(q::proof_checker, m)); add_plugin(alloc(smt_proof_checker_plugin, m, symbol("datatype"))); // no-op datatype proof checker + add_plugin(alloc(tseitin::proof_checker, m)); } proof_checker::~proof_checker() { @@ -302,10 +301,8 @@ namespace euf { proof_checker_plugin* p = nullptr; if (!m_map.find(a->get_decl()->get_name(), p)) return false; - if (!p->check(a)) { - std::cout << "(missed-hint " << mk_pp(e, m) << ")\n"; - return false; - } + if (!p->check(a)) + return false; return true; } @@ -319,14 +316,14 @@ namespace euf { return r; } - void proof_checker::vc(expr* e, expr_ref_vector& clause) { + bool proof_checker::vc(expr* e, expr_ref_vector const& clause, expr_ref_vector& v) { SASSERT(is_app(e)); app* a = to_app(e); proof_checker_plugin* p = nullptr; if (m_map.find(a->get_name(), p)) - p->vc(a, clause); - else - IF_VERBOSE(0, verbose_stream() << "there is no proof plugin for " << mk_pp(e, m) << "\n"); + return p->vc(a, clause, v); + IF_VERBOSE(0, verbose_stream() << "there is no proof plugin for " << mk_pp(e, m) << "\n"); + return false; } bool proof_checker::check(expr_ref_vector const& clause1, expr* e, expr_ref_vector & units) { diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 530644488..0d3dbcb9e 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -30,7 +30,7 @@ namespace euf { virtual bool check(app* jst) = 0; virtual expr_ref_vector clause(app* jst) = 0; virtual void register_plugins(proof_checker& pc) = 0; - virtual void vc(app* jst, expr_ref_vector& clause) { } + virtual bool vc(app* jst, expr_ref_vector const& clause, expr_ref_vector& v) { return false; } }; class proof_checker { @@ -45,7 +45,7 @@ namespace euf { void register_plugin(symbol const& rule, proof_checker_plugin*); bool check(expr* jst); expr_ref_vector clause(expr* jst); - void vc(expr* jst, expr_ref_vector& clause); + bool vc(expr* jst, expr_ref_vector const& clause, expr_ref_vector& v); bool check(expr_ref_vector const& clause, expr* e, expr_ref_vector& units); }; diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 1a8186eaa..d6fac4aff 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -390,7 +390,7 @@ namespace euf { return mk_smt_hint(n, lits.size(), lits.data(), 0, (expr_pair const*) nullptr); } smt_proof_hint* mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, expr_pair const* eqs, unsigned nd = 0, expr_pair const* deqs = nullptr); - smt_proof_hint* mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, enode_pair const* eqs); + smt_proof_hint* mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne = 0, enode_pair const* eqs = nullptr); smt_proof_hint* mk_smt_hint(symbol const& n, literal lit, unsigned ne, expr_pair const* eqs) { return mk_smt_hint(n, 1, &lit, ne, eqs); } smt_proof_hint* mk_smt_hint(symbol const& n, literal lit) { return mk_smt_hint(n, 1, &lit, 0, (expr_pair const*)nullptr); } smt_proof_hint* mk_smt_hint(symbol const& n, literal l1, literal l2) { literal ls[2] = {l1,l2}; return mk_smt_hint(n, 2, ls, 0, (expr_pair const*)nullptr); } @@ -399,6 +399,8 @@ namespace euf { smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, expr* a, expr* b) { expr_pair e(a, b); return mk_smt_hint(n, 1, &lit, 0, nullptr, 1, &e); } smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, enode* a, enode* b) { return mk_smt_prop_hint(n, lit, a->get_expr(), b->get_expr()); } smt_proof_hint* mk_smt_hint(symbol const& n, enode* a, enode* b) { expr_pair e(a->get_expr(), b->get_expr()); return mk_smt_hint(n, 0, nullptr, 1, &e); } + sat::status mk_tseitin_status(sat::literal a, sat::literal b); + sat::status mk_tseitin_status(unsigned n, sat::literal const* lits); scoped_ptr m_proof_out; diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 4a834d355..2c5ab80ae 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -387,7 +387,7 @@ namespace q { m_qs.log_instantiation(lits, &j); euf::th_proof_hint* ph = nullptr; if (ctx.use_drat()) - ph = q_proof_hint::mk(ctx, lits, j.m_clause.size(), j.m_binding); + ph = q_proof_hint::mk(ctx, lits, j.m_clause.num_decls(), j.m_binding); m_qs.add_clause(lits, ph); } diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 0802f71c9..03f887ac1 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -232,6 +232,7 @@ namespace q { } expr_ref_vector mbqi::extract_binding(quantifier* q) { + SASSERT(!ctx.use_drat() || !m_defs.empty()); if (!m_defs.empty()) { expr_safe_replace sub(m); for (unsigned i = m_defs.size(); i-- > 0; ) { @@ -543,6 +544,14 @@ namespace q { body = subst(q_flat->get_expr(), binding); if (is_forall(q)) body = ::mk_not(m, body); + if (ctx.use_drat()) { + m_defs.reset(); + for (unsigned i = 0; i < binding.size(); ++i) { + expr_ref v(qb.vars.get(i), m); + expr_ref t(binding.get(i), m); + m_defs.push_back(mbp::def(v, t)); + } + } add_instantiation(q, body); ++num_bindings; } diff --git a/src/sat/smt/q_proof_checker.cpp b/src/sat/smt/q_proof_checker.cpp index eecf10fe6..8ddd3d75a 100644 --- a/src/sat/smt/q_proof_checker.cpp +++ b/src/sat/smt/q_proof_checker.cpp @@ -25,27 +25,33 @@ namespace q { expr_ref_vector result(m); for (expr* arg : *jst) if (!is_bind(arg)) - result.push_back(arg); + result.push_back(mk_not(m, arg)); return result; } expr_ref_vector proof_checker::binding(app* jst) { expr_ref_vector result(m); for (expr* arg : *jst) - if (is_bind(arg)) - result.push_back(to_app(arg)->get_arg(0)); + if (is_bind(arg)) { + result.append(to_app(arg)->get_num_args(), to_app(arg)->get_args()); + break; + } return result; } - void proof_checker::vc(app* jst, expr_ref_vector& clause) { + bool proof_checker::vc(app* jst, expr_ref_vector const& clause0, expr_ref_vector& v) { expr* q = nullptr; if (!is_inst(jst)) - return; - SASSERT(clause.size() >= 2); - VERIFY(m.is_not(clause.get(0), q) && is_forall(q)); + return false; + auto clause1 = clause(jst); + SASSERT(clause1.size() >= 2); + VERIFY(m.is_not(clause1.get(0), q) && is_forall(q)); auto inst = binding(jst); expr_ref qi = instantiate(m, to_quantifier(q), inst.begin()); - clause[0] = m.mk_not(qi); + clause1[0] = m.mk_not(qi); + v.reset(); + v.append(clause1); + return qi == clause1.get(1); } bool proof_checker::is_inst(expr* jst) { diff --git a/src/sat/smt/q_proof_checker.h b/src/sat/smt/q_proof_checker.h index d60737585..6b309d1c6 100644 --- a/src/sat/smt/q_proof_checker.h +++ b/src/sat/smt/q_proof_checker.h @@ -53,7 +53,7 @@ namespace q { pc.register_plugin(symbol("inst"), this); } - void vc(app* jst, expr_ref_vector& clause) override; + bool vc(app* jst, expr_ref_vector const& clause, expr_ref_vector& v) override; }; diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index c99311f4e..7fd7be97e 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -365,6 +365,7 @@ namespace q { } q_proof_hint* q_proof_hint::mk(euf::solver& s, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings) { + SASSERT(n > 0); auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, lits.size())); q_proof_hint* ph = new (mem) q_proof_hint(n, lits.size()); for (unsigned i = 0; i < n; ++i) @@ -375,6 +376,7 @@ namespace q { } q_proof_hint* q_proof_hint::mk(euf::solver& s, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings) { + SASSERT(n > 0); auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, 2)); q_proof_hint* ph = new (mem) q_proof_hint(n, 2); for (unsigned i = 0; i < n; ++i) diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 7fc54f7cd..bf2e04dc5 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -144,10 +144,9 @@ namespace euf { return is_new; } - bool th_euf_solver::add_clause(sat::literal a, sat::literal b, th_proof_hint const* ps) { - SASSERT(ps); + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, th_proof_hint const* ph) { sat::literal lits[2] = { a, b }; - return add_clause(2, lits, ps); + return add_clause(2, lits, ph); } bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, th_proof_hint const* ps) { @@ -161,7 +160,7 @@ namespace euf { } bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps) { - //SASSERT(!ctx.use_drat() || ps); - very far from true, and isn't a requirement + SASSERT(!ctx.use_drat() || ps); // - very far from true, and isn't a requirement bool was_true = false; for (unsigned i = 0; i < n; ++i) was_true |= is_true(lits[i]); diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp new file mode 100644 index 000000000..658a8d72c --- /dev/null +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -0,0 +1,78 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + tseitin_proof_checker.cpp + +Abstract: + + Plugin for checking quantifier instantiations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-07 + + +--*/ + +#include "sat/smt/tseitin_proof_checker.h" + +namespace tseitin { + + + expr_ref_vector proof_checker::clause(app* jst) { + expr_ref_vector result(m); + result.append(jst->get_num_args(), jst->get_args()); + return result; + } + + bool proof_checker::check(app* jst) { + expr* main_expr = nullptr; + unsigned max_depth = 0; + for (expr* arg : *jst) { + if (get_depth(arg) > max_depth) { + main_expr = arg; + max_depth = get_depth(arg); + } + } + if (!main_expr) + return false; + + expr* a; + if (m.is_not(main_expr, a)) { + for (expr* arg : *jst) + if (equiv(a, arg)) + return true; + + if (m.is_and(a)) + for (expr* arg1 : *to_app(a)) + for (expr* arg2 : *jst) + if (equiv(arg1, arg2)) + return true; + + if (m.is_or(a)) + return false; + if (m.is_implies(a)) + return false; + if (m.is_eq(a)) + return false; + if (m.is_ite(a)) + return false; + if (m.is_distinct(a)) + return false; + } + return false; + } + + bool proof_checker::equiv(expr* a, expr* b) { + if (a == b) + return true; + expr* x, *y, *z, *u; + if (m.is_eq(a, x, y) && m.is_eq(b, z, u)) + return x == u && y == z; + return false; + } + + +} diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_proof_checker.h new file mode 100644 index 000000000..8b975dbb6 --- /dev/null +++ b/src/sat/smt/tseitin_proof_checker.h @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + tseitin_proof_checker.h + +Abstract: + + Plugin for checking quantifier instantiations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-07 + + +--*/ +#pragma once + +#include "util/obj_pair_set.h" +#include "ast/ast_trail.h" +#include "ast/ast_util.h" +#include "sat/smt/euf_proof_checker.h" +#include + +namespace tseitin { + + class proof_checker : public euf::proof_checker_plugin { + ast_manager& m; + + bool equiv(expr* a, expr* b); + + public: + proof_checker(ast_manager& m): + m(m) { + } + + ~proof_checker() override {} + + expr_ref_vector clause(app* jst) override; + + bool check(app* jst) override; + + void register_plugins(euf::proof_checker& pc) override { + pc.register_plugin(symbol("tseitin"), this); + } + + }; + +} diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 2d390b4f2..ef156fbd5 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -68,15 +68,15 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::solver_core & m_solver; atom2bool_var & m_map; dep2asm_map & m_dep2asm; - obj_map* m_expr2var_replay { nullptr }; + obj_map* m_expr2var_replay = nullptr; bool m_ite_extra; unsigned long long m_max_memory; expr_ref_vector m_trail; func_decl_ref_vector m_unhandled_funs; bool m_default_external; - bool m_euf { false }; - bool m_is_redundant { false }; - bool m_top_level { false }; + bool m_euf = false; + bool m_is_redundant = false; + bool m_top_level = false; sat::literal_vector aig_lits; imp(ast_manager & _m, params_ref const & p, sat::solver_core & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): @@ -108,8 +108,24 @@ struct goal2sat::imp : public sat::sat_internalizer { throw tactic_exception(std::move(s0)); } - sat::status mk_status() const { - return sat::status::th(m_is_redundant, m.get_basic_family_id()); + symbol m_tseitin = symbol("tseitin"); + + euf::th_proof_hint* mk_tseitin(unsigned n, sat::literal const* lits) { + if (m_euf && ensure_euf()->use_drat()) + return ensure_euf()->mk_smt_hint(m_tseitin, n, lits); + return nullptr; + } + + euf::th_proof_hint* mk_tseitin(sat::literal a, sat::literal b) { + if (m_euf && ensure_euf()->use_drat()) { + sat::literal lits[2] = { a, b }; + return ensure_euf()->mk_smt_hint(m_tseitin, 2, lits); + } + return nullptr; + } + + sat::status mk_status(euf::th_proof_hint* ph = nullptr) const { + return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); } bool relevancy_enabled() { @@ -124,42 +140,42 @@ struct goal2sat::imp : public sat::sat_internalizer { mk_clause(1, &l); } - void mk_clause(sat::literal l1, sat::literal l2) { + void mk_clause(sat::literal l1, sat::literal l2, euf::th_proof_hint* ph = nullptr) { sat::literal lits[2] = { l1, l2 }; - mk_clause(2, lits); + mk_clause(2, lits, ph); } - void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3) { + void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3, euf::th_proof_hint* ph = nullptr) { sat::literal lits[3] = { l1, l2, l3 }; - mk_clause(3, lits); + mk_clause(3, lits, ph); } - void mk_clause(unsigned n, sat::literal * lits) { + void mk_clause(unsigned n, sat::literal * lits, euf::th_proof_hint* ph = nullptr) { TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < n; i++) tout << lits[i] << " "; tout << "\n";); if (relevancy_enabled()) ensure_euf()->add_aux(n, lits); - m_solver.add_clause(n, lits, mk_status()); + m_solver.add_clause(n, lits, mk_status(ph)); } void mk_root_clause(sat::literal l) { mk_root_clause(1, &l); } - void mk_root_clause(sat::literal l1, sat::literal l2) { + void mk_root_clause(sat::literal l1, sat::literal l2, euf::th_proof_hint* ph = nullptr) { sat::literal lits[2] = { l1, l2 }; - mk_root_clause(2, lits); + mk_root_clause(2, lits, ph); } - void mk_root_clause(sat::literal l1, sat::literal l2, sat::literal l3) { + void mk_root_clause(sat::literal l1, sat::literal l2, sat::literal l3, euf::th_proof_hint* ph = nullptr) { sat::literal lits[3] = { l1, l2, l3 }; - mk_root_clause(3, lits); + mk_root_clause(3, lits, ph); } - void mk_root_clause(unsigned n, sat::literal * lits) { + void mk_root_clause(unsigned n, sat::literal * lits, euf::th_proof_hint* ph = nullptr) { TRACE("goal2sat", tout << "mk_root_clause: "; for (unsigned i = 0; i < n; i++) tout << lits[i] << " "; tout << "\n";); if (relevancy_enabled()) ensure_euf()->add_root(n, lits); - m_solver.add_clause(n, lits, m_is_redundant ? mk_status() : sat::status::input()); + m_solver.add_clause(n, lits, m_is_redundant ? mk_status(ph) : sat::status::input()); } sat::bool_var add_var(bool is_ext, expr* n) { From fceedf60dc55af86e601b023642670657c481205 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Oct 2022 16:41:09 +0200 Subject: [PATCH 118/477] wip - proofs --- src/sat/sat_extension.h | 2 +- src/sat/smt/euf_proof.cpp | 14 ++++-- src/sat/smt/euf_proof_checker.cpp | 2 +- src/sat/smt/euf_solver.cpp | 1 + src/sat/smt/euf_solver.h | 4 +- src/sat/smt/q_mbi.cpp | 39 ++++++++-------- src/sat/smt/tseitin_proof_checker.cpp | 66 +++++++++++++++++++++++---- src/sat/smt/tseitin_proof_checker.h | 8 ++++ src/sat/tactic/goal2sat.cpp | 12 +++-- 9 files changed, 110 insertions(+), 38 deletions(-) diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 8730a2c2e..d6a956a32 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -72,7 +72,7 @@ namespace sat { extension(symbol const& name, int id): m_id(id), m_name(name) { } virtual ~extension() = default; int get_id() const { return m_id; } - void set_solver(solver* s) { m_solver = s; } + virtual void set_solver(solver* s) { m_solver = s; } solver& s() { return *m_solver; } solver const& s() const { return *m_solver; } symbol const& name() const { return m_name; } diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index cc675e589..b37cd1e99 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -28,7 +28,7 @@ namespace euf { } if (!m_proof_out && s().get_config().m_drat && (get_config().m_lemmas2console || s().get_config().m_smt_proof.is_non_empty_string())) { - TRACE("euf", tout << "init-proof\n"); + TRACE("euf", tout << "init-proof " << s().get_config().m_smt_proof << "\n"); m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); if (get_config().m_lemmas2console) get_drat().set_clause_eh(*this); @@ -284,10 +284,13 @@ namespace euf { } bool solver::visit_clause(std::ostream& out, unsigned n, literal const* lits) { + expr_ref k(m); for (unsigned i = 0; i < n; ++i) { expr* e = bool_var2expr(lits[i].var()); - if (!e) - return false; + if (!e) { + k = m.mk_const(symbol(lits[i].var()), m.mk_bool_sort()); + e = k; + } visit_expr(out, e); } return true; @@ -335,8 +338,13 @@ namespace euf { } std::ostream& solver::display_literals(std::ostream& out, unsigned n, literal const* lits) { + expr_ref k(m); for (unsigned i = 0; i < n; ++i) { expr* e = bool_var2expr(lits[i].var()); + if (!e) { + k = m.mk_const(symbol(lits[i].var()), m.mk_bool_sort()); + e = k; + } if (lits[i].sign()) display_expr(out << " (not ", e) << ")"; else diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 9b0f37c5e..ad929e71a 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -322,7 +322,7 @@ namespace euf { proof_checker_plugin* p = nullptr; if (m_map.find(a->get_name(), p)) return p->vc(a, clause, v); - IF_VERBOSE(0, verbose_stream() << "there is no proof plugin for " << mk_pp(e, m) << "\n"); + IF_VERBOSE(10, verbose_stream() << "there is no proof plugin for " << mk_pp(e, m) << "\n"); return false; } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 21290b70a..5994ee3be 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -72,6 +72,7 @@ namespace euf { void solver::updt_params(params_ref const& p) { m_config.updt_params(p); + use_drat(); } /** diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index d6fac4aff..c18124491 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -309,6 +309,7 @@ namespace euf { trail_stack& get_trail_stack() { return m_trail; } void updt_params(params_ref const& p); + void set_solver(sat::solver* s) override { m_solver = s; use_drat(); } void set_lookahead(sat::lookahead* s) override { m_lookahead = s; } void init_search() override; double get_reward(literal l, ext_constraint_idx idx, sat::literal_occs_fun& occs) const override; @@ -371,7 +372,7 @@ namespace euf { // proof - bool use_drat() { return s().get_config().m_drat && (init_proof(), true); } + bool use_drat() { return m_solver && s().get_config().m_drat && (init_proof(), true); } sat::drat& get_drat() { return s().get_drat(); } void set_tmp_bool_var(sat::bool_var b, expr* e); @@ -420,6 +421,7 @@ namespace euf { expr_ref mk_eq(euf::enode* n1, euf::enode* n2) { return mk_eq(n1->get_expr(), n2->get_expr()); } euf::enode* e_internalize(expr* e); euf::enode* mk_enode(expr* e, unsigned n, enode* const* args); + void set_bool_var2expr(sat::bool_var v, expr* e) { m_bool_var2expr.setx(v, e, nullptr); } expr* bool_var2expr(sat::bool_var v) const { return m_bool_var2expr.get(v, nullptr); } expr_ref literal2expr(sat::literal lit) const { expr* e = bool_var2expr(lit.var()); return (e && lit.sign()) ? expr_ref(m.mk_not(e), m) : expr_ref(e, m); } unsigned generation() const { return m_generation; } diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 03f887ac1..d81256393 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -113,6 +113,8 @@ namespace q { expr_ref mbqi::replace_model_value(expr* e) { auto const& v2r = ctx.values2root(); euf::enode* r = nullptr; + if (m.is_bool(e)) + return expr_ref(e, m); if (v2r.find(e, r)) return choose_term(r); if (is_app(e) && to_app(e)->get_num_args() > 0) { @@ -135,7 +137,7 @@ namespace q { r = n; } else if (n->generation() == gen) { - if ((m_qs.random() % ++count) == 0) + if ((m_qs.random() % ++count) == 0 && has_quantifiers(n->get_expr())) r = n; } if (count > m_max_choose_candidates) @@ -233,22 +235,21 @@ namespace q { expr_ref_vector mbqi::extract_binding(quantifier* q) { SASSERT(!ctx.use_drat() || !m_defs.empty()); - if (!m_defs.empty()) { - expr_safe_replace sub(m); - for (unsigned i = m_defs.size(); i-- > 0; ) { - sub(m_defs[i].term); - sub.insert(m_defs[i].var, m_defs[i].term); - } - q_body* qb = q2body(q); - expr_ref_vector inst(m); - for (expr* v : qb->vars) { - expr_ref t(m); - sub(v, t); - inst.push_back(t); - } - return inst; + if (m_defs.empty()) + return expr_ref_vector(m); + expr_safe_replace sub(m); + for (unsigned i = m_defs.size(); i-- > 0; ) { + sub(m_defs[i].term); + sub.insert(m_defs[i].var, m_defs[i].term); } - return expr_ref_vector(m); + q_body* qb = q2body(q); + expr_ref_vector inst(m); + for (expr* v : qb->vars) { + expr_ref t(m); + sub(v, t); + inst.push_back(t); + } + return inst; } @@ -344,8 +345,7 @@ namespace q { continue; if (ctx.use_drat()) { if (!p->project(*m_model, vars, fmls, m_defs)) - return expr_ref(m); - + return expr_ref(m); } else if (!(*p)(*m_model, vars, fmls)) { TRACE("q", tout << "theory projection failed\n"); @@ -363,7 +363,8 @@ namespace q { eqs.push_back(m.mk_eq(v, val)); } rep(fmls); - TRACE("q", tout << "generated formulas\n" << fmls << "\ngenerated eqs:\n" << eqs << "\n";); + TRACE("q", tout << "generated formulas\n" << fmls << "\ngenerated eqs:\n" << eqs << "\n"; + for (auto const& [v,t] : m_defs) tout << v << " := " << t << "\n"); return mk_and(fmls); } diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp index 658a8d72c..e54c2d3bc 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -31,28 +31,75 @@ namespace tseitin { expr* main_expr = nullptr; unsigned max_depth = 0; for (expr* arg : *jst) { - if (get_depth(arg) > max_depth) { + unsigned arg_depth = get_depth(arg); + if (arg_depth > max_depth) { main_expr = arg; - max_depth = get_depth(arg); + max_depth = arg_depth; } + if (arg_depth == max_depth && m.is_not(main_expr)) + main_expr = arg; } + if (!main_expr) return false; expr* a; + + // (or (and a b) (not a) (not b)) + if (m.is_and(main_expr)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + if (m.is_not(arg, arg)) + mark(arg); + for (expr* arg : *to_app(main_expr)) { + if (!is_marked(arg)) + return false; + } + return true; + } + + // (or (or a b) (not a)) + if (m.is_or(main_expr)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + if (m.is_not(arg, arg)) + mark(arg); + for (expr* arg : *to_app(main_expr)) { + if (is_marked(arg)) + return true; + } + return false; + } + if (m.is_not(main_expr, a)) { + + // (or (not a) a') for (expr* arg : *jst) if (equiv(a, arg)) return true; - if (m.is_and(a)) - for (expr* arg1 : *to_app(a)) - for (expr* arg2 : *jst) - if (equiv(arg1, arg2)) - return true; + // (or (not (and a b)) a) + if (m.is_and(a)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + mark(arg); + for (expr* arg : *to_app(a)) + if (is_marked(arg)) + return true; + } - if (m.is_or(a)) - return false; + // (or (not (or a b) a b)) + if (m.is_or(a)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + mark(arg); + for (expr* arg : *to_app(a)) + if (!is_marked(arg)) + return false; + return true; + } + +#if 0 if (m.is_implies(a)) return false; if (m.is_eq(a)) @@ -61,6 +108,7 @@ namespace tseitin { return false; if (m.is_distinct(a)) return false; +#endif } return false; } diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_proof_checker.h index 8b975dbb6..40d0f1d6b 100644 --- a/src/sat/smt/tseitin_proof_checker.h +++ b/src/sat/smt/tseitin_proof_checker.h @@ -28,8 +28,16 @@ namespace tseitin { class proof_checker : public euf::proof_checker_plugin { ast_manager& m; + expr_fast_mark1 m_mark; bool equiv(expr* a, expr* b); + void mark(expr* a) { m_mark.mark(a); } + bool is_marked(expr* a) { return m_mark.is_marked(a); } + struct scoped_mark { + proof_checker& pc; + scoped_mark(proof_checker& pc): pc(pc) {} + ~scoped_mark() { pc.m_mark.reset(); } + }; public: proof_checker(ast_manager& m): m(m) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index ef156fbd5..2f513170e 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -183,6 +183,8 @@ struct goal2sat::imp : public sat::sat_internalizer { if (m_expr2var_replay && m_expr2var_replay->find(n, v)) return v; v = m_solver.add_var(is_ext); + if (!is_ext && m_euf && ensure_euf()->use_drat()) + ensure_euf()->set_bool_var2expr(v, n); return v; } @@ -417,7 +419,7 @@ struct goal2sat::imp : public sat::sat_internalizer { cache(t, l); sat::literal * lits = m_result_stack.end() - num; for (unsigned i = 0; i < num; i++) - mk_clause(~lits[i], l); + mk_clause(~lits[i], l, mk_tseitin(~lits[i], l)); m_result_stack.push_back(~l); lits = m_result_stack.end() - num - 1; @@ -427,7 +429,7 @@ struct goal2sat::imp : public sat::sat_internalizer { } // remark: mk_clause may perform destructive updated to lits. // I have to execute it after the binary mk_clause above. - mk_clause(num+1, lits); + mk_clause(num+1, lits, mk_tseitin(num+1, lits)); if (aig()) aig()->add_or(l, num, aig_lits.data()); @@ -470,7 +472,7 @@ struct goal2sat::imp : public sat::sat_internalizer { // l => /\ lits for (unsigned i = 0; i < num; i++) { - mk_clause(~l, lits[i]); + mk_clause(~l, lits[i], mk_tseitin(~l, lits[i])); } // /\ lits => l for (unsigned i = 0; i < num; ++i) { @@ -482,7 +484,7 @@ struct goal2sat::imp : public sat::sat_internalizer { aig_lits.reset(); aig_lits.append(num, lits); } - mk_clause(num+1, lits); + mk_clause(num+1, lits, mk_tseitin(num+1, lits)); if (aig()) { aig()->add_and(l, num, aig_lits.data()); } @@ -934,6 +936,8 @@ struct goal2sat::imp : public sat::sat_internalizer { expr_ref f(m), d_new(m); ptr_vector deps; expr_ref_vector fmls(m); + if (m_euf) + ensure_euf(); for (unsigned idx = 0; idx < size; idx++) { f = g.form(idx); // Add assumptions. From cd8b8b603ad3c542d140caab7624109e56cf153c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Oct 2022 23:44:03 +0200 Subject: [PATCH 119/477] tseitin rule checking - wip Unit test ``` (set-option :sat.euf true) (set-option :sat.smt.proof tseitinproof.smt2) (declare-const a1 Bool) (declare-const a2 Bool) (declare-const a3 Bool) (declare-const a4 Bool) (declare-const a5 Bool) (declare-const a6 Bool) (declare-const a7 Bool) (declare-const a8 Bool) (declare-const a9 Bool) (declare-const a10 Bool) (declare-const a11 Bool) (declare-const a12 Bool) (declare-const a13 Bool) (declare-const a14 Bool) (declare-const a15 Bool) (declare-const a16 Bool) (declare-const a17 Bool) (declare-const a18 Bool) (declare-const a19 Bool) (declare-const x1 Bool) (declare-const x2 Bool) (declare-const x3 Bool) (declare-const x4 Bool) (declare-const x5 Bool) (declare-const x6 Bool) (declare-const x7 Bool) (declare-const x8 Bool) (declare-const x9 Bool) (assert (= x1 (and a1 a2))) (assert (= x2 (or a3 a4))) (assert (= x3 (=> a5 a6))) (assert (= x4 (= a7 a8))) (assert (= x5 (if a9 a10 a11))) (assert (= x6 (=> a12 a13))) (check-sat) ``` Output proof ``` (declare-fun a1 () Bool) (declare-fun a2 () Bool) (define-const $26 Bool (and a1 a2)) (declare-fun tseitin (Bool Bool) Proof) (define-const $60 Bool (not $26)) (define-const $61 Proof (tseitin $60 a1)) (infer a1 (not $26) $61) (define-const $62 Proof (tseitin $60 a2)) (infer a2 (not $26) $62) (declare-fun tseitin (Bool Bool Bool) Proof) (define-const $64 Bool (not a2)) (define-const $63 Bool (not a1)) (define-const $65 Proof (tseitin $63 $64 $26)) (infer (not a1) (not a2) $26 $65) (declare-fun x1 () Bool) (assume (not x1) $26) (assume x1 (not $26)) (declare-fun a3 () Bool) (declare-fun a4 () Bool) (define-const $31 Bool (or a3 a4)) (define-const $66 Bool (not a3)) (define-const $67 Proof (tseitin $66 $31)) (infer (not a3) $31 $67) (define-const $68 Bool (not a4)) (define-const $69 Proof (tseitin $68 $31)) (infer (not a4) $31 $69) (define-const $70 Bool (not $31)) (define-const $71 Proof (tseitin a3 a4 $70)) (infer a3 a4 (not $31) $71) (declare-fun x2 () Bool) (assume (not x2) $31) (assume x2 (not $31)) (declare-fun a6 () Bool) (declare-fun a5 () Bool) (define-const $38 Bool (not a5)) (define-const $39 Bool (or a6 $38)) (define-const $72 Bool (not a6)) (define-const $73 Proof (tseitin $72 $39)) (infer (not a6) $39 $73) (define-const $74 Proof (tseitin a5 $39)) (infer a5 $39 $74) (define-const $75 Bool (not $39)) (define-const $76 Proof (tseitin a6 $38 $75)) (infer a6 (not a5) (not $39) $76) (declare-fun x3 () Bool) (assume (not x3) $39) (assume x3 (not $39)) (declare-fun a7 () Bool) (declare-fun a8 () Bool) (define-const $44 Bool (= a7 a8)) (define-const $78 Bool (not a7)) (define-const $77 Bool (not $44)) (define-const $79 Proof (tseitin $77 a8 $78)) (infer (not a7) a8 (not $44) $79) (define-const $80 Bool (not a8)) (define-const $81 Proof (tseitin $77 $80 a7)) (infer a7 (not a8) (not $44) $81) (define-const $82 Proof (tseitin $44 a8 a7)) (infer a7 a8 $44 $82) (define-const $83 Proof (tseitin $44 $80 $78)) (infer (not a7) (not a8) $44 $83) (declare-fun x4 () Bool) (assume (not x4) $44) (assume x4 (not $44)) (declare-fun a9 () Bool) (declare-fun a10 () Bool) (declare-fun a11 () Bool) (define-const $50 Bool (ite a9 a10 a11)) (define-const $85 Bool (not a9)) (define-const $84 Bool (not $50)) (define-const $86 Proof (tseitin $84 $85 a10)) (infer (not a9) a10 (not $50) $86) (define-const $87 Proof (tseitin $84 a9 a11)) (infer a9 a11 (not $50) $87) (define-const $88 Bool (not a10)) (define-const $89 Proof (tseitin $50 $85 $88)) (infer (not a9) (not a10) $50 $89) (define-const $90 Bool (not a11)) (define-const $91 Proof (tseitin $50 a9 $90)) (infer a9 (not a11) $50 $91) (define-const $92 Proof (tseitin $88 $90 $50)) (infer (not a10) (not a11) $50 $92) (define-const $93 Proof (tseitin a10 a11 $84)) (infer a10 a11 (not $50) $93) (declare-fun x5 () Bool) (assume (not x5) $50) (assume x5 (not $50)) (declare-fun a13 () Bool) (declare-fun a12 () Bool) (define-const $57 Bool (not a12)) (define-const $58 Bool (or a13 $57)) (define-const $94 Bool (not a13)) (define-const $95 Proof (tseitin $94 $58)) (infer (not a13) $58 $95) (define-const $96 Proof (tseitin a12 $58)) (infer a12 $58 $96) (define-const $97 Bool (not $58)) (define-const $98 Proof (tseitin a13 $57 $97)) (infer a13 (not a12) (not $58) $98) (declare-fun x6 () Bool) (assume (not x6) $58) (assume x6 (not $58)) ``` --- src/sat/smt/tseitin_proof_checker.cpp | 100 ++++++++++++++++++++++---- src/sat/smt/tseitin_proof_checker.h | 21 +++++- src/sat/tactic/goal2sat.cpp | 38 ++++++---- 3 files changed, 131 insertions(+), 28 deletions(-) diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp index e54c2d3bc..cef7f4641 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -16,6 +16,7 @@ Author: --*/ +#include "ast/ast_pp.h" #include "sat/smt/tseitin_proof_checker.h" namespace tseitin { @@ -43,16 +44,17 @@ namespace tseitin { if (!main_expr) return false; - expr* a; + expr* a, * x, * y, *z; // (or (and a b) (not a) (not b)) + // (or (and (not a) b) a (not b)) if (m.is_and(main_expr)) { scoped_mark sm(*this); for (expr* arg : *jst) - if (m.is_not(arg, arg)) - mark(arg); + complement_mark(arg); + for (expr* arg : *to_app(main_expr)) { - if (!is_marked(arg)) + if (!is_complement(arg)) return false; } return true; @@ -62,15 +64,54 @@ namespace tseitin { if (m.is_or(main_expr)) { scoped_mark sm(*this); for (expr* arg : *jst) - if (m.is_not(arg, arg)) - mark(arg); - for (expr* arg : *to_app(main_expr)) { - if (is_marked(arg)) - return true; - } + complement_mark(arg); + for (expr* arg : *to_app(main_expr)) + if (is_complement(arg)) + return true; return false; } + // (or (= a b) a b) + // (or (= a b) (not a) (not b)) + // (or (= (not a) b) a (not b)) + if (m.is_eq(main_expr, x, y) && m.is_bool(x)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_marked(x) && is_marked(y)) + return true; + if (is_complement(x) && is_complement(y)) + return true; + } + + // (or (if a b c) (not b) (not c)) + // (or (if a b c) a (not c)) + // (or (if a b c) (not a) (not b)) + if (m.is_ite(main_expr, x, y, z) && m.is_bool(z)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_marked(x) && is_complement(z)) + return true; + if (is_complement(x) && is_complement(y)) + return true; + if (is_complement(y) && is_complement(z)) + return true; + IF_VERBOSE(0, verbose_stream() << mk_pp(main_expr, m) << "\n"); + } + + // (or (=> a b) a) + // (or (=> a b) (not b)) + if (m.is_implies(main_expr, x, y)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_marked(x)) + return true; + if (is_complement(y)) + return true; + } + if (m.is_not(main_expr, a)) { // (or (not a) a') @@ -99,11 +140,46 @@ namespace tseitin { return true; } + // (or (not (= a b) (not a) b) + if (m.is_eq(a, x, y) && m.is_bool(x)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_marked(x) && is_complement(y)) + return true; + if (is_marked(y) & is_complement(x)) + return true; + } + + // (or (not (if a b c)) (not a) b) + // (or (not (if a b c)) a c) + if (m.is_ite(a, x, y, z) && m.is_bool(z)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_complement(x) && is_marked(y)) + return true; + if (is_marked(x) && is_marked(z)) + return true; + if (is_marked(y) && is_marked(z)) + return true; + } + + // (or (not (=> a b)) b (not a)) + if (m.is_implies(a, x, y)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_complement(x) && is_marked(y)) + return true; + } + + IF_VERBOSE(0, verbose_stream() << "miss " << mk_pp(main_expr, m) << "\n"); + #if 0 if (m.is_implies(a)) return false; - if (m.is_eq(a)) - return false; + if (m.is_ite(a)) return false; if (m.is_distinct(a)) diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_proof_checker.h index 40d0f1d6b..de5978ac3 100644 --- a/src/sat/smt/tseitin_proof_checker.h +++ b/src/sat/smt/tseitin_proof_checker.h @@ -29,14 +29,33 @@ namespace tseitin { ast_manager& m; expr_fast_mark1 m_mark; + expr_fast_mark2 m_nmark; bool equiv(expr* a, expr* b); void mark(expr* a) { m_mark.mark(a); } bool is_marked(expr* a) { return m_mark.is_marked(a); } + + void nmark(expr* a) { m_nmark.mark(a); } + bool is_nmarked(expr* a) { return m_nmark.is_marked(a); } + + void complement_mark(expr* a) { + if (m.is_not(a, a)) + m_nmark.mark(a); + else + m_mark.mark(a); + } + + bool is_complement(expr* a) { + if (m.is_not(a, a)) + return is_marked(a); + else + return is_nmarked(a); + } + struct scoped_mark { proof_checker& pc; scoped_mark(proof_checker& pc): pc(pc) {} - ~scoped_mark() { pc.m_mark.reset(); } + ~scoped_mark() { pc.m_mark.reset(); pc.m_nmark.reset(); } }; public: proof_checker(ast_manager& m): diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 2f513170e..48ba17128 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -124,6 +124,14 @@ struct goal2sat::imp : public sat::sat_internalizer { return nullptr; } + euf::th_proof_hint* mk_tseitin(sat::literal a, sat::literal b, sat::literal c) { + if (m_euf && ensure_euf()->use_drat()) { + sat::literal lits[3] = { a, b, c }; + return ensure_euf()->mk_smt_hint(m_tseitin, 3, lits); + } + return nullptr; + } + sat::status mk_status(euf::th_proof_hint* ph = nullptr) const { return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); } @@ -522,13 +530,13 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::bool_var k = add_var(false, n); sat::literal l(k, false); cache(n, l); - mk_clause(~l, ~c, t); - mk_clause(~l, c, e); - mk_clause(l, ~c, ~t); - mk_clause(l, c, ~e); + mk_clause(~l, ~c, t, mk_tseitin(~l, ~c, t)); + mk_clause(~l, c, e, mk_tseitin(~l, c, e)); + mk_clause(l, ~c, ~t, mk_tseitin(l, ~c, ~t)); + mk_clause(l, c, ~e, mk_tseitin(l, c, ~e)); if (m_ite_extra) { - mk_clause(~t, ~e, l); - mk_clause(t, e, ~l); + mk_clause(~t, ~e, l, mk_tseitin(~t, ~e, l)); + mk_clause(t, e, ~l, mk_tseitin(t, e, ~l)); } if (aig()) aig()->add_ite(l, c, t, e); if (sign) @@ -555,8 +563,8 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::literal l(k, false); cache(t, l); // l <=> ~lit - mk_clause(lit, l); - mk_clause(~lit, ~l); + mk_clause(lit, l, mk_tseitin(lit, l)); + mk_clause(~lit, ~l, mk_tseitin(~lit, ~l)); if (sign) l.neg(); m_result_stack.push_back(l); @@ -587,9 +595,9 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::literal l(k, false); cache(t, l); // l <=> (l1 => l2) - mk_clause(~l, ~l1, l2); - mk_clause(l1, l); - mk_clause(~l2, l); + mk_clause(~l, ~l1, l2, mk_tseitin(~l, ~l1, l2)); + mk_clause(l1, l, mk_tseitin(l1, l)); + mk_clause(~l2, l, mk_tseitin(~l2, l)); if (sign) l.neg(); m_result_stack.push_back(l); @@ -625,10 +633,10 @@ struct goal2sat::imp : public sat::sat_internalizer { 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, mk_tseitin(~l, l1, ~l2)); + mk_clause(~l, ~l1, l2, mk_tseitin(~l, ~l1, l2)); + mk_clause(l, l1, l2, mk_tseitin(l, l1, l2)); + mk_clause(l, ~l1, ~l2, mk_tseitin(l, ~l1, ~l2)); if (aig()) aig()->add_iff(l, l1, l2); cache(t, l); From 62438da0f58cecd8937310f69f3fd47ce1a111b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Oct 2022 09:15:18 +0200 Subject: [PATCH 120/477] wip - add xor and non-bool ite tseitin rules --- src/sat/smt/tseitin_proof_checker.cpp | 64 ++++++++++++++++++++++----- src/sat/tactic/goal2sat.cpp | 12 ++--- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp index cef7f4641..ceecdb719 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -13,7 +13,17 @@ Author: Nikolaj Bjorner (nbjorner) 2022-10-07 +TODOs: +- handle distinct +- handle other internalization from euf_internalize +- equiv should be modulo commutativity (the E-graph indexes expressions modulo commutativity of top-level operator) + +- should we log rules for root clauses too? Root clauses should follow from input. + They may be simplified using Tseitin transformation. For example, (and a b) is clausified into + two clauses a, b. + +- Tesitin checking could also be performed by depth-bounded SAT (e.g., using BDDs) --*/ #include "ast/ast_pp.h" @@ -44,7 +54,7 @@ namespace tseitin { if (!main_expr) return false; - expr* a, * x, * y, *z; + expr* a, * x, * y, *z, *u, *v; // (or (and a b) (not a) (not b)) // (or (and (not a) b) a (not b)) @@ -53,10 +63,10 @@ namespace tseitin { for (expr* arg : *jst) complement_mark(arg); - for (expr* arg : *to_app(main_expr)) { + for (expr* arg : *to_app(main_expr)) if (!is_complement(arg)) return false; - } + return true; } @@ -83,6 +93,16 @@ namespace tseitin { return true; } + if (m.is_eq(main_expr, x, y) && m.is_ite(x, z, u, v)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + if (is_marked(z) && equiv(y, v)) + return true; + if (is_complement(z) && equiv(y, u)) + return true; + } + // (or (if a b c) (not b) (not c)) // (or (if a b c) a (not c)) // (or (if a b c) (not a) (not b)) @@ -112,6 +132,21 @@ namespace tseitin { return true; } + // (or (xor a b c d) a b (not c) (not d)) + if (m.is_xor(main_expr)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + int parity = 0; + for (expr* arg : *to_app(main_expr)) + if (is_marked(arg)) + parity++; + else if (is_complement(arg)) + parity--; + if ((parity % 2) == 0) + return true; + } + if (m.is_not(main_expr, a)) { // (or (not a) a') @@ -174,17 +209,24 @@ namespace tseitin { return true; } + // (or (not (xor a b c d)) a b c (not d)) + if (m.is_xor(a)) { + scoped_mark sm(*this); + for (expr* arg : *jst) + complement_mark(arg); + int parity = 1; + for (expr* arg : *to_app(main_expr)) + if (is_marked(arg)) + parity++; + else if (is_complement(arg)) + parity--; + if ((parity % 2) == 0) + return true; + } + IF_VERBOSE(0, verbose_stream() << "miss " << mk_pp(main_expr, m) << "\n"); -#if 0 - if (m.is_implies(a)) - return false; - if (m.is_ite(a)) - return false; - if (m.is_distinct(a)) - return false; -#endif } return false; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 48ba17128..ca2f8f8f6 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -142,23 +142,19 @@ struct goal2sat::imp : public sat::sat_internalizer { bool top_level_relevant() { return m_top_level && relevancy_enabled(); - } - - void mk_clause(sat::literal l) { - mk_clause(1, &l); - } + } - void mk_clause(sat::literal l1, sat::literal l2, euf::th_proof_hint* ph = nullptr) { + void mk_clause(sat::literal l1, sat::literal l2, euf::th_proof_hint* ph) { sat::literal lits[2] = { l1, l2 }; mk_clause(2, lits, ph); } - void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3, euf::th_proof_hint* ph = nullptr) { + void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3, euf::th_proof_hint* ph) { sat::literal lits[3] = { l1, l2, l3 }; mk_clause(3, lits, ph); } - void mk_clause(unsigned n, sat::literal * lits, euf::th_proof_hint* ph = nullptr) { + void mk_clause(unsigned n, sat::literal * lits, euf::th_proof_hint* ph) { TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < n; i++) tout << lits[i] << " "; tout << "\n";); if (relevancy_enabled()) ensure_euf()->add_aux(n, lits); From ffeb8f45726334bce148ad4869e46d471e3c87bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Oct 2022 09:21:36 +0200 Subject: [PATCH 121/477] wip - tseitin check ``` (set-option :sat.euf true) (set-option :sat.smt.proof tseitinproof.smt2) (set-option :tactic.default_tactic smt) (declare-const a1 Bool) (declare-const a2 Bool) (declare-const a3 Bool) (declare-const a4 Bool) (declare-const a5 Bool) (declare-const a6 Bool) (declare-const a7 Bool) (declare-const a8 Bool) (declare-const a9 Bool) (declare-const a10 Bool) (declare-const a11 Bool) (declare-const a12 Bool) (declare-const a13 Bool) (declare-const a14 Bool) (declare-const a15 Bool) (declare-const a16 Bool) (declare-const a17 Bool) (declare-const a18 Bool) (declare-const a19 Bool) (declare-const x1 Bool) (declare-const x2 Bool) (declare-const x3 Bool) (declare-const x4 Bool) (declare-const x5 Bool) (declare-const x6 Bool) (declare-const x7 Bool) (declare-const x8 Bool) (declare-const x9 Bool) (declare-const b1 Int) (declare-const b2 Int) (declare-const b3 Int) (declare-const b4 Int) (assert (= x1 (and a1 a2))) (assert (= x2 (or a3 a4))) (assert (= x3 (=> a5 a6))) (assert (= x4 (= a7 a8))) (assert (= x5 (if a9 a10 a11))) (assert (= x6 (=> a12 a13))) (assert (= x7 (xor a1 a2 a3))) (assert (= x7 (xor a1 a2 a3 a4 a5 (not a6)))) (assert (= x8 (= (ite a1 b1 b2) b3))) (check-sat) (exit) ``` --- src/sat/smt/tseitin_proof_checker.cpp | 2 -- src/sat/smt/tseitin_proof_checker.h | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp index ceecdb719..a257062c0 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -239,6 +239,4 @@ namespace tseitin { return x == u && y == z; return false; } - - } diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_proof_checker.h index de5978ac3..677eabfa4 100644 --- a/src/sat/smt/tseitin_proof_checker.h +++ b/src/sat/smt/tseitin_proof_checker.h @@ -39,10 +39,9 @@ namespace tseitin { bool is_nmarked(expr* a) { return m_nmark.is_marked(a); } void complement_mark(expr* a) { + m_mark.mark(a); if (m.is_not(a, a)) m_nmark.mark(a); - else - m_mark.mark(a); } bool is_complement(expr* a) { From 1b3684c9c1cedd777098c809c0c1ad7d8fc273a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Oct 2022 09:54:00 +0200 Subject: [PATCH 122/477] wip - fixes to implied-eq proof hints --- src/sat/smt/arith_diagnostics.cpp | 10 +++++----- src/sat/smt/arith_solver.cpp | 4 ++-- src/sat/smt/arith_solver.h | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index ec9b11e76..f74adf38b 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -82,9 +82,9 @@ namespace arith { if (m_nla) m_nla->collect_statistics(st); } - void solver::explain_assumptions() { + void solver::explain_assumptions(lp::explanation const& e) { unsigned i = 0; - for (auto const & ev : m_explanation) { + for (auto const & ev : e) { ++i; auto idx = ev.ci(); if (UINT_MAX == idx) @@ -118,17 +118,17 @@ namespace arith { if (!ctx.use_drat()) return nullptr; m_arith_hint.set_type(ctx, ty); - explain_assumptions(); + explain_assumptions(m_explanation); if (lit != sat::null_literal) m_arith_hint.add_lit(rational(1), ~lit); return m_arith_hint.mk(ctx); } - arith_proof_hint const* solver::explain_implied_eq(euf::enode* a, euf::enode* b) { + arith_proof_hint const* solver::explain_implied_eq(lp::explanation const& e, euf::enode* a, euf::enode* b) { if (!ctx.use_drat()) return nullptr; m_arith_hint.set_type(ctx, hint_type::implied_eq_h); - explain_assumptions(); + explain_assumptions(e); m_arith_hint.set_num_le(1); // TODO m_arith_hint.add_diseq(a, b); return m_arith_hint.mk(ctx); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 87e159b87..685d9249a 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -320,7 +320,7 @@ namespace arith { reset_evidence(); for (auto ev : e) set_evidence(ev.ci()); - auto* ex = explain_implied_eq(n1, n2); + auto* ex = explain_implied_eq(e, n1, n2); auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2, ex); ctx.propagate(n1, n2, jst->to_index()); return true; @@ -744,7 +744,7 @@ namespace arith { set_evidence(ci4); enode* x = var2enode(v1); enode* y = var2enode(v2); - auto* ex = explain_implied_eq(x, y); + auto* ex = explain_implied_eq(m_explanation, x, y); auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, x, y, ex); ctx.propagate(x, y, jst->to_index()); } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 4fdb57386..3d3f1ddd7 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -71,10 +71,10 @@ namespace arith { unsigned m_lit_head = 0, m_lit_tail = 0, m_eq_head = 0, m_eq_tail = 0; void reset() { m_lit_head = m_lit_tail; m_eq_head = m_eq_tail; } void add(euf::enode* a, euf::enode* b, bool is_eq) { - if (m_eq_tail < m_eqs.size()) - m_eqs[m_eq_tail] = std::tuple(a, b, is_eq); - else - m_eqs.push_back(std::tuple(a, b, is_eq)); + if (m_eq_tail < m_eqs.size()) + m_eqs[m_eq_tail] = { a, b, is_eq }; + else + m_eqs.push_back({a, b, is_eq }); m_eq_tail++; } public: @@ -476,9 +476,9 @@ namespace arith { arith_proof_hint_builder m_arith_hint; arith_proof_hint const* explain(hint_type ty, sat::literal lit = sat::null_literal); - arith_proof_hint const* explain_implied_eq(euf::enode* a, euf::enode* b); + arith_proof_hint const* explain_implied_eq(lp::explanation const& e, euf::enode* a, euf::enode* b); arith_proof_hint const* explain_trichotomy(sat::literal le, sat::literal ge, sat::literal eq); - void explain_assumptions(); + void explain_assumptions(lp::explanation const& e); public: From a41520acf18af8688e134dd5c4af481405327ea0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 11 Oct 2022 11:59:29 +0100 Subject: [PATCH 123/477] mpf: fix some string copies --- src/util/mpf.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 791390b11..ef0315bb6 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -212,16 +212,16 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode size_t e_pos = v.find('p'); if (e_pos == std::string_view::npos) e_pos = v.find('P'); - const char *f = (e_pos != std::string_view::npos) ? v.substr(0, e_pos).data() : v.data(); - const char *e = (e_pos != std::string_view::npos) ? v.substr(e_pos+1).data() : "0"; + auto f = (e_pos != std::string_view::npos) ? std::string(v.substr(0, e_pos)) : std::string(v); + auto e = (e_pos != std::string_view::npos) ? std::string(v.substr(e_pos+1)) : "0"; TRACE("mpf_dbg", tout << "sgn = " << sgn << " f = " << f << " e = " << e << std::endl;); scoped_mpq q(m_mpq_manager); - m_mpq_manager.set(q, f); + m_mpq_manager.set(q, f.c_str()); scoped_mpz ex(m_mpq_manager); - m_mpz_manager.set(ex, e); + m_mpz_manager.set(ex, e.c_str()); set(o, ebits, sbits, rm, ex, q); o.sign = sgn; @@ -1562,7 +1562,7 @@ std::string mpf_manager::to_string(mpf const & x) { if (m_mpq_manager.is_int(r)) ss << ".0"; ss << " " << exponent; - res += ss.str(); + res += std::move(ss).str(); } } @@ -1600,7 +1600,7 @@ std::string mpf_manager::to_string_raw(mpf const & x) { res += " "; std::stringstream ss(""); ss << exp(x); - res += ss.str(); + res += std::move(ss).str(); if (is_normal(x)) res += " N"; else @@ -1629,7 +1629,7 @@ std::string mpf_manager::to_string_hexfloat(mpf const & x) { ss.setf(ff); ss.precision(13); ss << std::hexfloat << to_double(x); - return ss.str(); + return std::move(ss).str(); } std::string mpf_manager::to_string_binary(mpf const & x, unsigned upper_extra, unsigned lower_extra) { From ace727ee0ffe28e4fa75ab411b4d9b1d7aaee60c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 12 Oct 2022 09:34:07 +0200 Subject: [PATCH 124/477] fix #6391 --- src/smt/theory_lra.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 642103f73..c46331d07 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1775,7 +1775,6 @@ public: hi = floor(hi/mul); lo = ceil(lo/mul); } - std::cout << mk_pp(p, m) << " " << mk_pp(n, m) << " " << hi << " " << lo << " " << div_r << "\n"; literal p_le_r1 = mk_literal(a.mk_le(p, a.mk_numeral(hi, true))); literal p_ge_r1 = mk_literal(a.mk_ge(p, a.mk_numeral(lo, true))); literal n_le_div = mk_literal(a.mk_le(n, a.mk_numeral(div_r, true))); From a2e0646eed72370abfb290cedfa519672ab9ef05 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 12 Oct 2022 09:34:45 +0200 Subject: [PATCH 125/477] wip - proof checker --- src/cmd_context/extra_cmds/proof_cmds.cpp | 5 +++-- src/sat/smt/euf_proof_checker.cpp | 10 +++------- src/sat/smt/tseitin_proof_checker.cpp | 14 ++++++++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 6c5f90f0e..50561ef60 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -42,6 +42,7 @@ Proof checker for clauses created during search. #include "util/small_object_allocator.h" #include "ast/ast_util.h" +#include "ast/ast_ll_pp.h" #include "smt/smt_solver.h" #include "sat/sat_solver.h" #include "sat/sat_drat.h" @@ -181,9 +182,9 @@ public: } m_solver->pop(1); std::cout << "(verified-smt"; - if (proof_hint) std::cout << " " << mk_pp(proof_hint, m); + if (proof_hint) std::cout << " " << mk_bounded_pp(proof_hint, m, 4); for (expr* arg : clause) - std::cout << " " << mk_pp(arg, m); + std::cout << " " << mk_bounded_pp(arg, m); std::cout << ")\n"; add_clause(clause); } diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index ad929e71a..5061ad88c 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -293,17 +293,13 @@ namespace euf { } bool proof_checker::check(expr* e) { - if (m_checked_clauses.contains(e)) - return true; if (!e || !is_app(e)) return false; + if (m_checked_clauses.contains(e)) + return true; app* a = to_app(e); proof_checker_plugin* p = nullptr; - if (!m_map.find(a->get_decl()->get_name(), p)) - return false; - if (!p->check(a)) - return false; - return true; + return m_map.find(a->get_decl()->get_name(), p) && p->check(a); } expr_ref_vector proof_checker::clause(expr* e) { diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp index a257062c0..df0d60435 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -234,9 +234,15 @@ namespace tseitin { bool proof_checker::equiv(expr* a, expr* b) { if (a == b) return true; - expr* x, *y, *z, *u; - if (m.is_eq(a, x, y) && m.is_eq(b, z, u)) - return x == u && y == z; - return false; + if (!is_app(a) || !is_app(b)) + return false; + if (to_app(a)->get_decl() != to_app(b)->get_decl()) + return false; + if (!to_app(a)->get_decl()->is_commutative()) + return false; + if (to_app(a)->get_num_args() != 2) + return false; + return to_app(a)->get_arg(0) == to_app(b)->get_arg(1) && + to_app(a)->get_arg(1) == to_app(b)->get_arg(0); } } From 8ad480ab5969ee8939455a71c2575f8ba82a23e4 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 12 Oct 2022 09:43:50 +0100 Subject: [PATCH 126/477] fix compiler warnings --- src/util/mpf.cpp | 6 --- src/util/mpf.h | 2 - src/util/mpff.cpp | 2 +- src/util/mpn.cpp | 116 ++++++++++++++++++++++------------------------ src/util/mpn.h | 47 +++++++++---------- src/util/mpz.cpp | 4 +- 6 files changed, 80 insertions(+), 97 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index ef0315bb6..d2f30e708 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -41,9 +41,6 @@ mpf::mpf(unsigned _ebits, unsigned _sbits): set(ebits, sbits); } -mpf::~mpf() { -} - void mpf::swap(mpf & other) { unsigned tmp = ebits; ebits = other.ebits; @@ -64,9 +61,6 @@ mpf_manager::mpf_manager() : m_powers2(m_mpz_manager) { } -mpf_manager::~mpf_manager() { -} - void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { static_assert(sizeof(int) == 4, "assume integers are 4 bytes"); diff --git a/src/util/mpf.h b/src/util/mpf.h index 466d23ea5..2c3e528d3 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -49,7 +49,6 @@ public: mpf(); mpf(unsigned ebits, unsigned sbits); mpf(mpf &&) = default; - ~mpf(); mpf & operator=(mpf const & other) = delete; unsigned get_ebits() const { return ebits; } unsigned get_sbits() const { return sbits; } @@ -64,7 +63,6 @@ public: typedef mpf numeral; mpf_manager(); - ~mpf_manager(); void reset(mpf & o, unsigned ebits, unsigned sbits) { set(o, ebits, sbits, 0); } void set(mpf & o, unsigned ebits, unsigned sbits, int value); diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index 547407ce0..41dee21ab 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -703,7 +703,7 @@ void mpff_manager::add_sub(bool is_sub, mpff const & a, mpff const & b, mpff & c if (sgn_a == sgn_b) { c.m_sign = sgn_a; unsigned * sig_r = m_buffers[1].data(); - size_t r_sz; + unsigned r_sz; m_mpn_manager.add(sig_a, m_precision, n_sig_b, m_precision, sig_r, m_precision + 1, &r_sz); SASSERT(r_sz <= m_precision + 1); unsigned num_leading_zeros = nlz(m_precision + 1, sig_r); diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index f36dd3d3d..0cbe9e9f8 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -28,20 +28,14 @@ static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment const mpn_digit mpn_manager::zero = 0; -mpn_manager::mpn_manager() { -} - -mpn_manager::~mpn_manager() { -} - -int mpn_manager::compare(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb) const { +int mpn_manager::compare(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb) const { int res = 0; trace(a, lnga); - size_t j = max(lnga, lngb) - 1; - for (; j != (size_t)-1 && res == 0; j--) { + unsigned j = max(lnga, lngb) - 1; + for (; j != -1u && res == 0; j--) { mpn_digit const & u_j = (j < lnga) ? a[j] : zero; mpn_digit const & v_j = (j < lngb) ? b[j] : zero; if (u_j > v_j) @@ -56,18 +50,18 @@ int mpn_manager::compare(mpn_digit const * a, size_t const lnga, return res; } -bool mpn_manager::add(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, - mpn_digit * c, size_t const lngc_alloc, - size_t * plngc) const { +bool mpn_manager::add(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, + mpn_digit * c, unsigned lngc_alloc, + unsigned * plngc) const { trace(a, lnga, b, lngb, "+"); // Essentially Knuth's Algorithm A - size_t len = max(lnga, lngb); + unsigned len = max(lnga, lngb); SASSERT(lngc_alloc == len+1 && len > 0); mpn_digit k = 0; mpn_digit r; bool c1, c2; - for (size_t j = 0; j < len; j++) { + for (unsigned j = 0; j < len; j++) { mpn_digit const & u_j = (j < lnga) ? a[j] : zero; mpn_digit const & v_j = (j < lngb) ? b[j] : zero; r = u_j + v_j; c1 = r < u_j; @@ -75,23 +69,23 @@ bool mpn_manager::add(mpn_digit const * a, size_t const lnga, k = c1 | c2; } c[len] = k; - size_t &os = *plngc; + unsigned &os = *plngc; for (os = len+1; os > 1 && c[os-1] == 0; ) os--; SASSERT(os > 0 && os <= len+1); trace_nl(c, os); return true; // return k != 0? } -bool mpn_manager::sub(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, +bool mpn_manager::sub(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, mpn_digit * c, mpn_digit * pborrow) const { trace(a, lnga, b, lngb, "-"); // Essentially Knuth's Algorithm S - size_t len = max(lnga, lngb); + unsigned len = max(lnga, lngb); mpn_digit & k = *pborrow; k = 0; mpn_digit r; bool c1, c2; - for (size_t j = 0; j < len; j++) { + for (unsigned j = 0; j < len; j++) { mpn_digit const & u_j = (j < lnga) ? a[j] : zero; mpn_digit const & v_j = (j < lngb) ? b[j] : zero; r = u_j - v_j; c1 = r > u_j; @@ -102,13 +96,13 @@ bool mpn_manager::sub(mpn_digit const * a, size_t const lnga, return true; // return k != 0? } -bool mpn_manager::mul(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, +bool mpn_manager::mul(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, mpn_digit * c) const { trace(a, lnga, b, lngb, "*"); // Essentially Knuth's Algorithm M. // Perhaps implement a more efficient version, see e.g., Knuth, Section 4.3.3. - size_t i; + unsigned i; mpn_digit k; #define DIGIT_BITS (sizeof(mpn_digit)*8) @@ -117,7 +111,7 @@ bool mpn_manager::mul(mpn_digit const * a, size_t const lnga, for (unsigned i = 0; i < lnga; i++) c[i] = 0; - for (size_t j = 0; j < lngb; j++) { + for (unsigned j = 0; j < lngb; j++) { mpn_digit const & v_j = b[j]; if (v_j == 0) { // This branch may be omitted according to Knuth. c[j+lnga] = 0; @@ -147,23 +141,23 @@ bool mpn_manager::mul(mpn_digit const * a, size_t const lnga, #define LAST_BITS(N, X) (((X) << (DIGIT_BITS-(N))) >> (DIGIT_BITS-(N))) #define BASE ((mpn_double_digit)0x01 << DIGIT_BITS) -bool mpn_manager::div(mpn_digit const * numer, size_t const lnum, - mpn_digit const * denom, size_t const lden, +bool mpn_manager::div(mpn_digit const * numer, unsigned lnum, + mpn_digit const * denom, unsigned lden, mpn_digit * quot, mpn_digit * rem) { trace(numer, lnum, denom, lden, "/"); bool res = false; if (lnum < lden) { - for (size_t i = 0; i < (lnum-lden+1); i++) + for (unsigned i = 0; i < (lnum-lden+1); i++) quot[i] = 0; - for (size_t i = 0; i < lden; i++) + for (unsigned i = 0; i < lden; i++) rem[i] = (i < lnum) ? numer[i] : 0; return false; } bool all_zero = true; - for (size_t i = 0; i < lden && all_zero; i++) + for (unsigned i = 0; i < lden && all_zero; i++) if (denom[i] != zero) all_zero = false; if (all_zero) { @@ -179,12 +173,12 @@ bool mpn_manager::div(mpn_digit const * numer, size_t const lnum, } else if (lnum < lden || (lnum == lden && numer[lnum-1] < denom[lden-1])) { *quot = 0; - for (size_t i = 0; i < lden; i++) + for (unsigned i = 0; i < lden; i++) rem[i] = (i < lnum) ? numer[i] : 0; } else { mpn_sbuffer u, v, t_ms, t_ab; - size_t d = div_normalize(numer, lnum, denom, lden, u, v); + unsigned d = div_normalize(numer, lnum, denom, lden, u, v); if (lden == 1) res = div_1(u, v[0], quot); else @@ -202,10 +196,10 @@ bool mpn_manager::div(mpn_digit const * numer, size_t const lnum, #ifdef Z3DEBUG mpn_sbuffer temp(lnum+1, 0); mul(quot, lnum-lden+1, denom, lden, temp.data()); - size_t real_size; + unsigned real_size; add(temp.data(), lnum, rem, lden, temp.data(), lnum+1, &real_size); bool ok = true; - for (size_t i = 0; i < lnum && ok; i++) + for (unsigned i = 0; i < lnum && ok; i++) if (temp[i] != numer[i]) ok = false; if (temp[lnum] != 0) ok = false; CTRACE("mpn_dbg", !ok, tout << "DIV BUG: quot * denom + rem = "; display_raw(tout, temp.data(), lnum+1); tout << std::endl; ); @@ -215,12 +209,12 @@ bool mpn_manager::div(mpn_digit const * numer, size_t const lnum, return res; } -size_t mpn_manager::div_normalize(mpn_digit const * numer, size_t const lnum, - mpn_digit const * denom, size_t const lden, +unsigned mpn_manager::div_normalize(mpn_digit const * numer, unsigned lnum, + mpn_digit const * denom, unsigned lden, mpn_sbuffer & n_numer, mpn_sbuffer & n_denom) const { - size_t d = 0; + unsigned d = 0; while (lden > 0 && ((denom[lden-1] << d) & MASK_FIRST) == 0) d++; SASSERT(d < DIGIT_BITS); @@ -229,19 +223,19 @@ size_t mpn_manager::div_normalize(mpn_digit const * numer, size_t const lnum, if (d == 0) { n_numer[lnum] = 0; - for (size_t i = 0; i < lnum; i++) + for (unsigned i = 0; i < lnum; i++) n_numer[i] = numer[i]; - for (size_t i = 0; i < lden; i++) + for (unsigned i = 0; i < lden; i++) n_denom[i] = denom[i]; } else if (lnum != 0) { SASSERT(lden > 0); mpn_digit q = FIRST_BITS(d, numer[lnum-1]); n_numer[lnum] = q; - for (size_t i = lnum-1; i > 0; i--) + for (unsigned i = lnum-1; i > 0; i--) n_numer[i] = (numer[i] << d) | FIRST_BITS(d, numer[i-1]); n_numer[0] = numer[0] << d; - for (size_t i = lden-1; i > 0; i--) + for (unsigned i = lden-1; i > 0; i--) n_denom[i] = denom[i] << d | FIRST_BITS(d, denom[i-1]); n_denom[0] = denom[0] << d; } @@ -255,13 +249,13 @@ size_t mpn_manager::div_normalize(mpn_digit const * numer, size_t const lnum, } void mpn_manager::div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom, - size_t const d, mpn_digit * rem) const { + unsigned d, mpn_digit * rem) const { if (d == 0) { - for (size_t i = 0; i < denom.size(); i++) + for (unsigned i = 0; i < denom.size(); i++) rem[i] = numer[i]; } else { - for (size_t i = 0; i < denom.size()-1; i++) + for (unsigned i = 0; i < denom.size()-1; i++) rem[i] = numer[i] >> d | (LAST_BITS(d, numer[i+1]) << (DIGIT_BITS-d)); rem[denom.size()-1] = numer[denom.size()-1] >> d; } @@ -272,7 +266,7 @@ bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, mpn_double_digit q_hat, temp, ms; mpn_digit borrow; - for (size_t j = numer.size()-1; j > 0; j--) { + for (unsigned j = numer.size()-1; j > 0; j--) { temp = (((mpn_double_digit)numer[j]) << DIGIT_BITS) | ((mpn_double_digit)numer[j-1]); q_hat = temp / (mpn_double_digit) denom; if (q_hat >= BASE) { @@ -306,8 +300,8 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom, SASSERT(denom.size() > 1); // This is essentially Knuth's Algorithm D. - size_t m = numer.size() - denom.size(); - size_t n = denom.size(); + unsigned m = numer.size() - denom.size(); + unsigned n = denom.size(); SASSERT(numer.size() == m+n); @@ -316,7 +310,7 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom, mpn_double_digit q_hat, temp, r_hat; mpn_digit borrow; - for (size_t j = m-1; j != (size_t)-1; j--) { + for (unsigned j = m-1; j != -1u; j--) { temp = (((mpn_double_digit)numer[j+n]) << DIGIT_BITS) | ((mpn_double_digit)numer[j+n-1]); q_hat = temp / (mpn_double_digit) denom[n-1]; r_hat = temp % (mpn_double_digit) denom[n-1]; @@ -337,9 +331,9 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom, if (borrow) { quot[j]--; ab.resize(n+2); - size_t real_size; + unsigned real_size; add(denom.data(), n, &numer[j], n+1, ab.data(), n+2, &real_size); - for (size_t i = 0; i < n+1; i++) + for (unsigned i = 0; i < n+1; i++) numer[j+i] = ab[i]; } TRACE("mpn_div", tout << "q_hat=" << q_hat << " r_hat=" << r_hat; @@ -352,7 +346,7 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom, return true; // return rem != 0? } -char * mpn_manager::to_string(mpn_digit const * a, size_t const lng, char * buf, size_t const lbuf) const { +char * mpn_manager::to_string(mpn_digit const * a, unsigned lng, char * buf, unsigned lbuf) const { SASSERT(buf && lbuf > 0); TRACE("mpn_to_string", tout << "[mpn] to_string "; display_raw(tout, a, lng); tout << " == "; ); @@ -368,11 +362,11 @@ char * mpn_manager::to_string(mpn_digit const * a, size_t const lng, char * buf, for (unsigned i = 0; i < lng; i++) temp[i] = a[i]; - size_t j = 0; + unsigned j = 0; mpn_digit rem; mpn_digit ten = 10; while (!temp.empty() && (temp.size() > 1 || temp[0] != 0)) { - size_t d = div_normalize(&temp[0], temp.size(), &ten, 1, t_numer, t_denom); + unsigned d = div_normalize(&temp[0], temp.size(), &ten, 1, t_numer, t_denom); div_1(t_numer, t_denom[0], &temp[0]); div_unnormalize(t_numer, t_denom, d, &rem); buf[j++] = '0' + rem; @@ -382,8 +376,8 @@ char * mpn_manager::to_string(mpn_digit const * a, size_t const lng, char * buf, buf[j] = 0; j--; - size_t mid = (j/2) + ((j % 2) ? 1 : 0); - for (size_t i = 0; i < mid; i++) + unsigned mid = (j/2) + ((j % 2) ? 1 : 0); + for (unsigned i = 0; i < mid; i++) std::swap(buf[i], buf[j-i]); } @@ -392,14 +386,14 @@ char * mpn_manager::to_string(mpn_digit const * a, size_t const lng, char * buf, return buf; } -void mpn_manager::display_raw(std::ostream & out, mpn_digit const * a, size_t const lng) const { +void mpn_manager::display_raw(std::ostream & out, mpn_digit const * a, unsigned lng) const { out << "["; - for (size_t i = lng-1; i != (size_t)-1; i-- ) { out << a[i]; if (i != 0) out << "|"; } + for (unsigned i = lng-1; i != -1u; i-- ) { out << a[i]; if (i != 0) out << "|"; } out << "]"; } -void mpn_manager::trace(mpn_digit const * a, size_t const lnga, - mpn_digit const * b, size_t const lngb, +void mpn_manager::trace(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, const char * op) const { #ifdef Z3DEBUG char char_buf[4096]; @@ -409,14 +403,14 @@ void mpn_manager::trace(mpn_digit const * a, size_t const lnga, #endif } -void mpn_manager::trace(mpn_digit const * a, size_t const lnga) const { +void mpn_manager::trace(mpn_digit const * a, unsigned lnga) const { #ifdef Z3DEBUG char char_buf[4096]; TRACE("mpn", tout << to_string(a, lnga, char_buf, sizeof(char_buf)); ); #endif } -void mpn_manager::trace_nl(mpn_digit const * a, size_t const lnga) const { +void mpn_manager::trace_nl(mpn_digit const * a, unsigned lnga) const { #ifdef Z3DEBUG char char_buf[4096]; TRACE("mpn", tout << to_string(a, lnga, char_buf, sizeof(char_buf)) << std::endl; ); diff --git a/src/util/mpn.h b/src/util/mpn.h index 45209c269..7cf3eafb6 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -27,45 +27,42 @@ typedef unsigned int mpn_digit; class mpn_manager { public: - mpn_manager(); - ~mpn_manager(); + int compare(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb) const; - int compare(mpn_digit const * a, size_t lnga, - mpn_digit const * b, size_t lngb) const; + bool add(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, + mpn_digit *c, unsigned lngc_alloc, + unsigned * plngc) const; - bool add(mpn_digit const * a, size_t lnga, - mpn_digit const * b, size_t lngb, - mpn_digit *c, size_t lngc_alloc, - size_t * plngc) const; - - bool sub(mpn_digit const * a, size_t lnga, - mpn_digit const * b, size_t lngb, + bool sub(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, mpn_digit * c, mpn_digit * pborrow) const; - bool mul(mpn_digit const * a, size_t lnga, - mpn_digit const * b, size_t lngb, + bool mul(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, mpn_digit * c) const; - bool div(mpn_digit const * numer, size_t lnum, - mpn_digit const * denom, size_t lden, + bool div(mpn_digit const * numer, unsigned lnum, + mpn_digit const * denom, unsigned lden, mpn_digit * quot, mpn_digit * rem); - char * to_string(mpn_digit const * a, size_t lng, - char * buf, size_t lbuf) const; + char * to_string(mpn_digit const * a, unsigned lng, + char * buf, unsigned lbuf) const; private: using mpn_sbuffer = sbuffer; static const mpn_digit zero; - void display_raw(std::ostream & out, mpn_digit const * a, size_t lng) const; + void display_raw(std::ostream & out, mpn_digit const * a, unsigned lng) const; - size_t div_normalize(mpn_digit const * numer, size_t lnum, - mpn_digit const * denom, size_t lden, + unsigned div_normalize(mpn_digit const * numer, unsigned lnum, + mpn_digit const * denom, unsigned lden, mpn_sbuffer & n_numer, mpn_sbuffer & n_denom) const; void div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom, - size_t d, mpn_digit * rem) const; + unsigned d, mpn_digit * rem) const; bool div_1(mpn_sbuffer & numer, mpn_digit denom, mpn_digit * quot) const; @@ -74,10 +71,10 @@ private: mpn_digit * quot, mpn_digit * rem, mpn_sbuffer & ms, mpn_sbuffer & ab) const; - void trace(mpn_digit const * a, size_t lnga, - mpn_digit const * b, size_t lngb, + void trace(mpn_digit const * a, unsigned lnga, + mpn_digit const * b, unsigned lngb, const char * op) const; - void trace(mpn_digit const * a, size_t lnga) const; - void trace_nl(mpn_digit const * a, size_t lnga) const; + void trace(mpn_digit const * a, unsigned lnga) const; + void trace_nl(mpn_digit const * a, unsigned lnga) const; }; diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 316a1bba1..9b0da70fc 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -695,7 +695,7 @@ void mpz_manager::big_add_sub(mpz const & a, mpz const & b, mpz & c) { mpz_stack tmp; if (SUB) sign_b = -sign_b; - size_t real_sz; + unsigned real_sz; if (ca.sign() == sign_b) { unsigned sz = std::max(ca.cell()->m_size, cb.cell()->m_size)+1; allocate_if_needed(tmp, sz); @@ -703,7 +703,7 @@ void mpz_manager::big_add_sub(mpz const & a, mpz const & b, mpz & c) { cb.cell()->m_digits, cb.cell()->m_size, tmp.m_ptr->m_digits, sz, &real_sz); SASSERT(real_sz <= sz); - set(*tmp.m_ptr, c, ca.sign(), static_cast(real_sz)); + set(*tmp.m_ptr, c, ca.sign(), real_sz); } else { digit_t borrow; From a7f018aa039953df7152bac469033eb1ff568378 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 12 Oct 2022 10:02:21 +0100 Subject: [PATCH 127/477] fix compiler warnings --- src/sat/smt/arith_proof_checker.h | 2 -- src/sat/smt/euf_ackerman.h | 8 ++++---- src/sat/smt/euf_proof_checker.cpp | 5 ----- src/sat/smt/euf_proof_checker.h | 1 - src/sat/smt/q_proof_checker.h | 2 -- src/sat/smt/tseitin_proof_checker.h | 2 -- 6 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index df1dc00f1..6f471f58e 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -303,8 +303,6 @@ namespace arith { m_implied_eq("implied-eq"), m_bound("bound") {} - ~proof_checker() override {} - void reset() { m_ineq.reset(); m_conseq.reset(); diff --git a/src/sat/smt/euf_ackerman.h b/src/sat/smt/euf_ackerman.h index 479ad2933..17c7404f2 100644 --- a/src/sat/smt/euf_ackerman.h +++ b/src/sat/smt/euf_ackerman.h @@ -29,12 +29,12 @@ namespace euf { class ackerman { struct inference : dll_base{ - bool is_cc; expr* a, *b, *c; unsigned m_count{ 0 }; - inference():is_cc(false), a(nullptr), b(nullptr), c(nullptr) {} - inference(app* a, app* b):is_cc(true), a(a), b(b), c(nullptr) {} - inference(expr* a, expr* b, expr* c):is_cc(false), a(a), b(b), c(c) {} + bool is_cc; + inference(): a(nullptr), b(nullptr), c(nullptr), is_cc(false) {} + inference(app* a, app* b): a(a), b(b), c(nullptr), is_cc(true) {} + inference(expr* a, expr* b, expr* c): a(a), b(b), c(c), is_cc(false) {} }; struct inference_eq { diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 5061ad88c..f432443e9 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -23,7 +23,6 @@ Author: #include "sat/smt/arith_proof_checker.h" #include "sat/smt/q_proof_checker.h" #include "sat/smt/tseitin_proof_checker.h" -#include namespace euf { @@ -121,8 +120,6 @@ namespace euf { public: eq_proof_checker(ast_manager& m): m(m) {} - ~eq_proof_checker() override {} - expr_ref_vector clause(app* jst) override { expr_ref_vector result(m); for (expr* arg : *jst) @@ -213,8 +210,6 @@ namespace euf { public: res_proof_checker(ast_manager& m, proof_checker& pc): m(m), pc(pc) {} - - ~res_proof_checker() override {} bool check(app* jst) override { if (jst->get_num_args() != 3) diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 0d3dbcb9e..8b1b5d671 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -60,7 +60,6 @@ namespace euf { symbol m_rule; public: smt_proof_checker_plugin(ast_manager& m, symbol const& n): m(m), m_rule(n) {} - ~smt_proof_checker_plugin() override {} bool check(app* jst) override { return false; } expr_ref_vector clause(app* jst) override; void register_plugins(proof_checker& pc) override { pc.register_plugin(m_rule, this); } diff --git a/src/sat/smt/q_proof_checker.h b/src/sat/smt/q_proof_checker.h index 6b309d1c6..4072739c7 100644 --- a/src/sat/smt/q_proof_checker.h +++ b/src/sat/smt/q_proof_checker.h @@ -42,8 +42,6 @@ namespace q { m_inst("inst"), m_bind("bind") { } - - ~proof_checker() override {} expr_ref_vector clause(app* jst) override; diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_proof_checker.h index 677eabfa4..86a109ed8 100644 --- a/src/sat/smt/tseitin_proof_checker.h +++ b/src/sat/smt/tseitin_proof_checker.h @@ -61,8 +61,6 @@ namespace tseitin { m(m) { } - ~proof_checker() override {} - expr_ref_vector clause(app* jst) override; bool check(app* jst) override; From ddf4895c2f4cab93216233fb10f600158b41f6bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 12 Oct 2022 12:09:43 +0200 Subject: [PATCH 128/477] admit timeouts and other resource limits for get-core #6310 --- src/api/api_solver.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 5048f39fe..963a57666 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -692,7 +692,29 @@ extern "C" { RESET_ERROR_CODE(); init_solver(c, s); expr_ref_vector core(mk_c(c)->m()); - to_solver_ref(s)->get_unsat_core(core); + solver_params sp(to_solver(s)->m_params); + unsigned timeout = mk_c(c)->get_timeout(); + timeout = to_solver(s)->m_params.get_uint("timeout", timeout); + timeout = sp.timeout() != UINT_MAX ? sp.timeout() : timeout; + unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true); + cancel_eh eh(mk_c(c)->m().limit()); + to_solver(s)->set_eh(&eh); + { + scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + try { + to_solver_ref(s)->get_unsat_core(core); + } + catch (...) { + to_solver_ref(s)->set_reason_unknown(eh); + to_solver(s)->set_eh(nullptr); + if (core.empty()) + throw; + } + } + to_solver(s)->set_eh(nullptr); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); for (expr* e : core) { From 93e1db0b0ba7aa9846d0e65c801abea4ecff6127 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 13 Oct 2022 11:16:14 +0200 Subject: [PATCH 129/477] fix #6398 --- src/smt/mam.cpp | 22 +++++++++++++--------- src/smt/smt_context.cpp | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index ea335b1dc..44a435041 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -2006,33 +2006,36 @@ namespace { m_backtrack_stack.resize(t->get_num_choices()); } - void execute(code_tree * t) { + bool execute(code_tree * t) { TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout);); init(t); +#define CLEANUP for (enode* app : t->get_candidates()) if (app->is_marked()) app->unset_mark(); if (t->filter_candidates()) { for (enode* app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_expr(), m) << "\n";); if (!app->is_marked() && app->is_cgr()) { - if (m_context.resource_limits_exceeded() || !execute_core(t, app)) - return; + if (m_context.resource_limits_exceeded() || !execute_core(t, app)) { + CLEANUP; + return false; + } app->set_mark(); } } - for (enode* app : t->get_candidates()) { - if (app->is_marked()) - app->unset_mark(); - } + CLEANUP; + } else { for (enode* app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_expr(), m) << "\n";); if (app->is_cgr()) { TRACE("trigger_bug", tout << "is_cgr\n";); + // scoped_suspend_rlimit susp(m.limit(), false); if (m_context.resource_limits_exceeded() || !execute_core(t, app)) - return; + return false; } } } + return true; } // init(t) must be invoked before execute_core @@ -3886,7 +3889,8 @@ namespace { TRACE("trigger_bug", tout << "match\n"; display(tout);); for (code_tree* t : m_to_match) { SASSERT(t->has_candidates()); - m_interpreter.execute(t); + if (!m_interpreter.execute(t)) + return; t->reset_candidates(); } m_to_match.reset(); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 1bae0ef86..84b4906ca 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1723,7 +1723,7 @@ namespace smt { return false; } if (!get_cancel_flag()) { - scoped_suspend_rlimit _suspend_cancel(m.limit(), at_base_level()); +// scoped_suspend_rlimit _suspend_cancel(m.limit(), at_base_level()); m_qmanager->propagate(); } if (inconsistent()) From 8a30128933a1cdc638fbadd0c89361a580fae45b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 13 Oct 2022 15:20:24 +0200 Subject: [PATCH 130/477] formatting updates --- src/ast/macros/quasi_macros.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 2920c9667..dff36278d 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -114,10 +114,9 @@ bool quasi_macros::fully_depends_on(app * a, quantifier * q) const { if (is_var(arg)) bitset.set(to_var(arg)->get_idx(), true); - for (unsigned i = 0; i < bitset.size() ; i++) { + for (unsigned i = 0; i < bitset.size() ; i++) if (!bitset.get(i)) - return false; - } + return false; return true; } @@ -167,18 +166,18 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const { quantifier * q = to_quantifier(e); expr * qe = q->get_expr(), *lhs = nullptr, *rhs = nullptr; if (m.is_eq(qe, lhs, rhs)) { - if (is_quasi_def(q, lhs, rhs)) { + if (is_quasi_def(q, lhs, rhs)) { a = to_app(lhs); t = rhs; return true; - } else if (is_quasi_def(q, rhs, lhs)) { + } else if (is_quasi_def(q, rhs, lhs)) { a = to_app(rhs); t = lhs; return true; } } else if (m.is_not(qe, lhs) && is_non_ground_uninterp(lhs) && - is_unique(to_app(lhs)->get_decl())) { // this is like f(...) = false + is_unique(to_app(lhs)->get_decl())) { // this is like f(...) = false a = to_app(lhs); t = m.mk_false(); return true; @@ -189,8 +188,8 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const { return true; } else if (m.is_not(qe, lhs) && m.is_eq(lhs, lhs, rhs) && m.is_bool(lhs)) { - if (is_quasi_def(q, lhs, rhs)) { - a = to_app(lhs); + if (is_quasi_def(q, lhs, rhs)) { + a = to_app(lhs); t = m.mk_not(rhs); return true; } else if (is_quasi_def(q, rhs, lhs)) { From 2449ba93c5311477b3621e4bb722b43432643bb5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 13 Oct 2022 15:20:43 +0200 Subject: [PATCH 131/477] add (disabled) experiment to use quot-rem instead of division circuit --- src/smt/theory_bv.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++ src/smt/theory_bv.h | 3 +++ 2 files changed, 50 insertions(+) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index a01fdd483..f195e0c9d 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -885,6 +885,7 @@ namespace smt { find_wpos(v); } + bool theory_bv::internalize_term_core(app * term) { SASSERT(term->get_family_id() == get_family_id()); TRACE("bv", tout << "internalizing term: " << mk_bounded_pp(term, m) << "\n";); @@ -898,6 +899,7 @@ namespace smt { case OP_BMUL: internalize_mul(term); return true; case OP_BSDIV_I: internalize_sdiv(term); return true; case OP_BUDIV_I: internalize_udiv(term); return true; + // case OP_BUDIV_I: internalize_udiv_quot_rem(term); return true; case OP_BSREM_I: internalize_srem(term); return true; case OP_BUREM_I: internalize_urem(term); return true; case OP_BSMOD_I: internalize_smod(term); return true; @@ -1392,6 +1394,13 @@ namespace smt { ctx.mark_as_relevant(n->get_arg(0)); assert_int2bv_axiom(n); } +#if 0 + else if (m_util.is_bv_udivi(n)) { + ctx.mark_as_relevant(n->get_arg(0)); + ctx.mark_as_relevant(n->get_arg(1)); + assert_udiv_quot_rem_axiom(n); + } +#endif else if (ctx.e_internalized(n)) { enode * e = ctx.get_enode(n); theory_var v = e->get_th_var(get_id()); @@ -1985,5 +1994,43 @@ namespace smt { return true; } +#if 0 + void theory_bv::internalize_udiv_quot_rem(app* n) { + process_args(n); + mk_enode(n); + theory_var v = ctx.get_enode(n)->get_th_var(get_id()); + mk_bits(v); + if (!ctx.relevancy()) + assert_udiv_quot_rem_axiom(n); + } + + + void theory_bv::assert_udiv_quot_rem_axiom(app * q) { + // Axioms for quotient/remainder: + // a = b*q + r + // no-mul-overflow(b,q) + // no-add-overflow(bq, r) + // b != 0 => r < b + // b = 0 => q = -1 + expr* a, *b; + VERIFY(m_util.is_bv_udivi(q, a, b)); + sort* srt = q->get_sort(); + func_decl_ref rf(m.mk_func_decl(symbol("rem"), srt, srt, srt), m); + expr_ref r(m.mk_app(rf, a, b), m); + expr_ref bq(m_util.mk_bv_mul(b, q), m); + expr_ref bqr(m_util.mk_bv_add(bq, r), m); + literal eq = mk_literal(m.mk_eq(a, bqr)); + literal obq = mk_literal(m_util.mk_bvumul_no_ovfl(b, q)); + literal obqr = mk_literal(m_util.mk_ule(r, bqr)); + literal b0 = mk_literal(m.mk_eq(b, m_util.mk_numeral(rational::zero(), srt))); + + ctx.mk_th_axiom(get_id(), 1, &eq); + ctx.mk_th_axiom(get_id(), 1, &obq); + ctx.mk_th_axiom(get_id(), 1, &obqr); + ctx.mk_th_axiom(get_id(), b0, ~mk_literal(m_util.mk_ule(b, r))); + ctx.mk_th_axiom(get_id(), ~b0, mk_literal(m.mk_eq(q, m_util.mk_numeral(rational(-1), srt)))); + } +#endif + }; diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index a66aaab8a..588f19d89 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -188,6 +188,7 @@ namespace smt { void internalize_urem(app * n); void internalize_srem(app * n); void internalize_smod(app * n); + void internalize_udiv_quot_rem(app* n); void internalize_shl(app * n); void internalize_lshr(app * n); void internalize_ashr(app * n); @@ -227,6 +228,8 @@ namespace smt { void assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc); void assert_int2bv_axiom(app* n); void assert_bv2int_axiom(app* n); + void assert_udiv_quot_rem_axiom(app * n); + protected: theory_var mk_var(enode * n) override; From 9bf5e3f5fccb7767d80f2a2fa0c95b8491b6e241 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 13 Oct 2022 15:22:19 +0200 Subject: [PATCH 132/477] fixes for #6388 --- src/qe/mbp/mbp_term_graph.cpp | 26 +++++++++++++++------ src/tactic/core/propagate_values_tactic.cpp | 9 ++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/qe/mbp/mbp_term_graph.cpp b/src/qe/mbp/mbp_term_graph.cpp index 76b6a2b31..47cece75a 100644 --- a/src/qe/mbp/mbp_term_graph.cpp +++ b/src/qe/mbp/mbp_term_graph.cpp @@ -1020,12 +1020,7 @@ namespace mbp { vector result; expr_ref_vector pinned(m); obj_map pid; - model::scoped_model_completion _smc(mdl, true); - for (term *t : m_tg.m_terms) { - expr* a = t->get_expr(); - if (!is_app(a)) continue; - if (m.is_bool(a) && !include_bool) continue; - expr_ref val = mdl(a); + auto insert_val = [&](expr* a, expr* val) { unsigned p = 0; // NB. works for simple domains Integers, Rationals, // but not for algebraic numerals. @@ -1036,7 +1031,18 @@ namespace mbp { result.push_back(expr_ref_vector(m)); } result[p].push_back(a); + }; + model::scoped_model_completion _smc(mdl, true); + for (term *t : m_tg.m_terms) { + expr* a = t->get_expr(); + if (!is_app(a)) + continue; + if (m.is_bool(a) && !include_bool) + continue; + expr_ref val = mdl(a); + insert_val(a, val); } + return result; } @@ -1238,7 +1244,13 @@ namespace mbp { for (expr* e : vec) term2pid.insert(e, id); ++id; } - auto partition_of = [&](expr* e) { return partitions[term2pid[e]]; }; + expr_ref_vector empty(m); + auto partition_of = [&](expr* e) { + unsigned pid; + if (!term2pid.find(e, pid)) + return empty; + return partitions[pid]; + }; auto in_table = [&](expr* a, expr* b) { return diseqs.contains(pair_t(a, b)); }; diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index b2ed7cab9..5b7fcbf10 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -74,10 +74,13 @@ class propagate_values_tactic : public tactic { void push_result(expr * new_curr, proof * new_pr) { if (m_goal->proofs_enabled()) { - proof * pr = m_goal->pr(m_idx); - new_pr = m.mk_modus_ponens(pr, new_pr); + proof* pr = m_goal->pr(m_idx); + new_pr = m.mk_modus_ponens(pr, new_pr); } - + else + new_pr = nullptr; + + expr_dependency_ref new_d(m); if (m_goal->unsat_core_enabled()) { new_d = m_goal->dep(m_idx); From e2cfc53c9fe44690bf4310ad0ce8d0b6deea91f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 13 Oct 2022 15:31:58 +0200 Subject: [PATCH 133/477] #6364 skip proof hint unless proofs are on --- 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 d81256393..4530e9f93 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -71,7 +71,7 @@ namespace q { for (auto const& [qlit, fml, inst, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ~ctx.mk_literal(fml); - auto* ph = q_proof_hint::mk(ctx, ~qlit, lit, inst.size(), inst.data()); + auto* ph = ctx.use_drat()? q_proof_hint::mk(ctx, ~qlit, lit, inst.size(), inst.data()) : nullptr; m_qs.add_clause(~qlit, lit, ph); m_qs.log_instantiation(~qlit, lit); } From 87e45221fd71e88ca56ea8e06e34d22b4c7f8f5a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 14 Oct 2022 09:43:18 +0100 Subject: [PATCH 134/477] add missing break stmt to example Reported by Henrique Preto --- examples/c/test_capi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 6e6bf84fe..98842bb9c 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -561,6 +561,7 @@ void display_ast(Z3_context c, FILE * out, Z3_ast v) } case Z3_QUANTIFIER_AST: { fprintf(out, "quantifier"); + break; } default: fprintf(out, "#unknown"); From 4388719848f94cd6bf7025ac308d83c22b658169 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 14 Oct 2022 18:56:18 +0200 Subject: [PATCH 135/477] adjust logging --- src/sat/sat_drat.cpp | 1 - src/sat/smt/arith_diagnostics.cpp | 2 +- src/sat/smt/arith_solver.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 17de0fe3b..647f8681c 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -656,7 +656,6 @@ namespace sat { if (m_out) dump(1, &l, st); if (m_bout) bdump(1, &l, st); if (m_check) append(l, st); - TRACE("sat", tout << "add " << m_clause_eh << "\n"); if (m_clause_eh) m_clause_eh->on_clause(1, &l, st); } void drat::add(literal l1, literal l2, status st) { diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index f74adf38b..2be19182a 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -69,7 +69,7 @@ namespace arith { } std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const { - return euf::th_explain::from_index(idx).display(out); + return euf::th_explain::from_index(idx).display(out << "arith "); } std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 685d9249a..f7e3f6293 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -76,7 +76,6 @@ namespace arith { } bool solver::unit_propagate() { - TRACE("arith", tout << "unit propagate\n";); m_model_is_initialized = false; if (!m_solver->has_changed_columns() && !m_new_eq && m_new_bounds.empty() && m_asserted_qhead == m_asserted.size()) return false; From 993ff408263c4a9431e7bcbb4e81fe4b53eef4ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 15 Oct 2022 12:42:50 +0200 Subject: [PATCH 136/477] fixes to proof logging and checking --- src/cmd_context/extra_cmds/proof_cmds.cpp | 4 +- src/sat/smt/arith_proof_checker.h | 62 ++++++++++++++++------- src/sat/smt/euf_proof.cpp | 2 +- src/sat/smt/euf_proof_checker.cpp | 19 ++++++- src/sat/smt/euf_solver.cpp | 34 ++++++++++++- src/sat/smt/euf_solver.h | 2 +- src/sat/tactic/goal2sat.cpp | 4 ++ 7 files changed, 100 insertions(+), 27 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index 50561ef60..b90daf29a 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -182,9 +182,9 @@ public: } m_solver->pop(1); std::cout << "(verified-smt"; - if (proof_hint) std::cout << " " << mk_bounded_pp(proof_hint, m, 4); + if (proof_hint) std::cout << "\n" << mk_bounded_pp(proof_hint, m, 4); for (expr* arg : clause) - std::cout << " " << mk_bounded_pp(arg, m); + std::cout << "\n " << mk_bounded_pp(arg, m); std::cout << ")\n"; add_clause(clause); } diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_proof_checker.h index 6f471f58e..0e5c891d5 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_proof_checker.h @@ -143,17 +143,13 @@ namespace arith { SASSERT(m_todo.empty()); m_todo.push_back({ mul, e }); rational coeff1; - expr* e1, *e2, *e3; + expr* e1, *e2; for (unsigned i = 0; i < m_todo.size(); ++i) { auto [coeff, e] = m_todo[i]; - if (a.is_mul(e, e1, e2) && a.is_numeral(e1, coeff1)) + if (a.is_mul(e, e1, e2) && is_numeral(e1, coeff1)) m_todo.push_back({coeff*coeff1, e2}); - else if (a.is_mul(e, e1, e2) && a.is_uminus(e1, e3) && a.is_numeral(e3, coeff1)) - m_todo.push_back({-coeff*coeff1, e2}); - else if (a.is_mul(e, e1, e2) && a.is_uminus(e2, e3) && a.is_numeral(e3, coeff1)) - m_todo.push_back({ -coeff * coeff1, e1 }); - else if (a.is_mul(e, e1, e2) && a.is_numeral(e2, coeff1)) - m_todo.push_back({coeff*coeff1, e1}); + else if (a.is_mul(e, e1, e2) && is_numeral(e2, coeff1)) + m_todo.push_back({ coeff * coeff1, e1 }); else if (a.is_add(e)) for (expr* arg : *to_app(e)) m_todo.push_back({coeff, arg}); @@ -163,15 +159,21 @@ namespace arith { m_todo.push_back({coeff, e1}); m_todo.push_back({-coeff, e2}); } - else if (a.is_numeral(e, coeff1)) + else if (is_numeral(e, coeff1)) r.m_coeff += coeff*coeff1; - else if (a.is_uminus(e, e1) && a.is_numeral(e1, coeff1)) - r.m_coeff -= coeff*coeff1; else add(r, e, coeff); } m_todo.reset(); } + + bool is_numeral(expr* e, rational& n) { + if (a.is_numeral(e, n)) + return true; + if (a.is_uminus(e, e) && a.is_numeral(e, n)) + return n.neg(), true; + return false; + } bool check_ineq(row& r) { if (r.m_coeffs.empty() && r.m_coeff > 0) @@ -182,9 +184,12 @@ namespace arith { } // triangulate equalities, substitute results into m_ineq, m_conseq. - void reduce_eq() { + // check consistency of equalities (they may be inconsisent) + bool reduce_eq() { for (unsigned i = 0; i < m_eqs.size(); ++i) { auto& r = m_eqs[i]; + if (r.m_coeffs.empty() && r.m_coeff != 0) + return false; if (r.m_coeffs.empty()) continue; auto [v, coeff] = *r.m_coeffs.begin(); @@ -193,6 +198,7 @@ namespace arith { resolve(v, m_ineq, coeff, r); resolve(v, m_conseq, coeff, r); } + return true; } @@ -231,7 +237,8 @@ namespace arith { bool check_farkas() { if (check_ineq(m_ineq)) return true; - reduce_eq(); + if (!reduce_eq()) + return true; if (check_ineq(m_ineq)) return true; @@ -244,7 +251,8 @@ namespace arith { // after all inequalities in ineq have been added up // bool check_bound() { - reduce_eq(); + if (!reduce_eq()) + return true; if (check_ineq(m_conseq)) return true; if (m_ineq.m_coeffs.empty() || @@ -401,8 +409,10 @@ namespace arith { return false; } num_le = coeff.get_unsigned(); - if (!add_implied_ineq(false, jst)) + if (!add_implied_ineq(false, jst)) { + IF_VERBOSE(0, display(verbose_stream() << "did not add implied eq")); return false; + } ++j; continue; } @@ -418,10 +428,24 @@ namespace arith { if (num_le == 0) { // we processed all the first inequalities, // check that they imply one half of the implied equality. - if (!check()) - return false; - reset(); - VERIFY(add_implied_ineq(true, jst)); + if (!check()) { + // we might have added the wrong direction of the implied equality. + // so try the opposite inequality. + add_implied_ineq(true, jst); + add_implied_ineq(true, jst); + if (check()) { + reset(); + add_implied_ineq(false, jst); + } + else { + IF_VERBOSE(0, display(verbose_stream() << "failed to check implied eq ")); + return false; + } + } + else { + reset(); + VERIFY(add_implied_ineq(true, jst)); + } } } else diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index b37cd1e99..8ee1a1d28 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -46,7 +46,7 @@ namespace euf { * so it isn't necessarily an axiom over EUF, * We will here leave it to the EUF checker to perform resolution steps. */ - void solver::log_antecedents(literal l, literal_vector const& r, eq_proof_hint* hint) { + void solver::log_antecedents(literal l, literal_vector const& r, th_proof_hint* hint) { TRACE("euf", log_antecedents(tout, l, r);); if (!use_drat()) return; diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index f432443e9..e7a77df5c 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -19,6 +19,7 @@ Author: #include "ast/ast_pp.h" #include "ast/ast_util.h" #include "ast/ast_ll_pp.h" +#include "ast/arith_decl_plugin.h" #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_proof_checker.h" #include "sat/smt/q_proof_checker.h" @@ -58,15 +59,29 @@ namespace euf { class eq_proof_checker : public proof_checker_plugin { ast_manager& m; + arith_util m_arith; + expr_ref_vector m_trail; basic_union_find m_uf; svector> m_expr2id; ptr_vector m_id2expr; - svector> m_diseqs; + svector> m_diseqs; unsigned m_ts = 0; void merge(expr* x, expr* y) { m_uf.merge(expr2id(x), expr2id(y)); IF_VERBOSE(10, verbose_stream() << "merge " << mk_bounded_pp(x, m) << " == " << mk_bounded_pp(y, m) << "\n"); + merge_numeral(x); + merge_numeral(y); + } + + void merge_numeral(expr* x) { + rational n; + expr* y; + if (m_arith.is_uminus(x, y) && m_arith.is_numeral(y, n)) { + y = m_arith.mk_numeral(-n, x->get_sort()); + m_trail.push_back(y); + m_uf.merge(expr2id(x), expr2id(y)); + } } bool are_equal(expr* x, expr* y) { @@ -118,7 +133,7 @@ namespace euf { } public: - eq_proof_checker(ast_manager& m): m(m) {} + eq_proof_checker(ast_manager& m): m(m), m_arith(m), m_trail(m) {} expr_ref_vector clause(app* jst) override { expr_ref_vector result(m); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 5994ee3be..c29652803 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -200,16 +200,36 @@ namespace euf { s().assign(lit, sat::justification::mk_ext_justification(s().scope_lvl(), idx)); } + /** + Retrieve set of literals r that imply r. + Since the set of literals are retrieved modulo multiple theories in a single implication + we lose theory specific justifications. For proof logging we use a catch all rule "smt" + for the case where an equality is derived using more than congruence closure. + To create fully decomposed justifications it will be necessary to augment the justification + data-structure with information about the equality that is implied by the theory. + Then each justification will imply an equality s = t assuming literals 'r'. + The theory lemma is then r -> s = t, where s = t is an equality that is available for the EUF hint. + The EUF hint is resolved against r -> s = t to eliminate s = t and to create the resulting explanation. + + Example: + x - 3 = 0 => x = 3 by arithmetic + x = 3 => f(x) = f(3) by EUF + resolve to produce clause x - 3 = 0 => f(x) = f(3) + */ + void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) { m_egraph.begin_explain(); m_explain.reset(); if (use_drat() && !probing) push(restore_size_trail(m_explain_cc, m_explain_cc.size())); auto* ext = sat::constraint_base::to_extension(idx); + bool has_theory = false; if (ext == this) get_antecedents(l, constraint::from_idx(idx), r, probing); - else + else { ext->get_antecedents(l, idx, r, probing); + has_theory = true; + } for (unsigned qhead = 0; qhead < m_explain.size(); ++qhead) { size_t* e = m_explain[qhead]; if (is_literal(e)) @@ -220,10 +240,20 @@ namespace euf { SASSERT(ext != this); sat::literal lit = sat::null_literal; ext->get_antecedents(lit, idx, r, probing); + has_theory = true; } } m_egraph.end_explain(); - eq_proof_hint* hint = (use_drat() && !probing) ? mk_hint(l, r) : nullptr; + th_proof_hint* hint = nullptr; + if (use_drat() && !probing) { + if (has_theory) { + r.push_back(~l); + hint = mk_smt_hint(symbol("smt"), r); + r.pop_back(); + } + else + hint = mk_hint(l, r); + } unsigned j = 0; for (sat::literal lit : r) if (s().lvl(lit) > 0) r[j++] = lit; diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index c18124491..bf18ca4bc 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -193,7 +193,7 @@ namespace euf { // proofs void log_antecedents(std::ostream& out, literal l, literal_vector const& r); - void log_antecedents(literal l, literal_vector const& r, eq_proof_hint* hint); + void log_antecedents(literal l, literal_vector const& r, th_proof_hint* hint); void log_justification(literal l, th_explain const& jst); typedef std::pair expr_pair; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index ca2f8f8f6..038cd337b 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -284,11 +284,15 @@ struct goal2sat::imp : public sat::sat_internalizer { if (v == sat::null_bool_var) { if (m.is_true(t)) { sat::literal tt = sat::literal(mk_bool_var(t), false); + if (m_euf && ensure_euf()->use_drat()) + ensure_euf()->set_bool_var2expr(tt.var(), t); mk_root_clause(tt); l = sign ? ~tt : tt; } else if (m.is_false(t)) { sat::literal ff = sat::literal(mk_bool_var(t), false); + if (m_euf && ensure_euf()->use_drat()) + ensure_euf()->set_bool_var2expr(ff.var(), t); mk_root_clause(~ff); l = sign ? ~ff : ff; } From ac1552d19417700e5da3b5486a0c6963ac417871 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2022 23:33:30 +0200 Subject: [PATCH 137/477] wip - updates to proof logging and self-checking move self-checking functionality to inside sat/smt so it can be used on-line and not just off-line. when self-validation fails, use vs, not clause, to check. It allows self-validation without checking and maintaining RUP validation. new options sat.smt.proof.check_rup, sat.smt.proof.check for online validation. z3 sat.smt.proof.check=true sat.euf=true /v:1 sat.smt.proof.check_rup=true /st file.smt2 sat.smt.proof=p.smt2 --- src/ast/euf/euf_egraph.cpp | 3 +- src/ast/euf/euf_egraph.h | 2 +- src/cmd_context/extra_cmds/proof_cmds.cpp | 155 +------------ src/model/model.cpp | 14 ++ src/model/model.h | 2 + src/sat/sat_config.cpp | 11 +- src/sat/sat_config.h | 2 + src/sat/sat_extension.h | 2 +- src/sat/sat_params.pyg | 2 + src/sat/sat_solver.cpp | 7 +- src/sat/smt/CMakeLists.txt | 2 +- src/sat/smt/arith_solver.cpp | 2 +- src/sat/smt/arith_solver.h | 2 +- ...proof_checker.h => arith_theory_checker.h} | 6 +- src/sat/smt/array_solver.h | 2 +- src/sat/smt/bv_solver.cpp | 13 +- src/sat/smt/bv_solver.h | 2 +- src/sat/smt/dt_solver.cpp | 2 +- src/sat/smt/dt_solver.h | 2 +- src/sat/smt/euf_ackerman.cpp | 71 +++--- src/sat/smt/euf_ackerman.h | 14 +- src/sat/smt/euf_proof.cpp | 90 ++++++-- src/sat/smt/euf_proof_checker.cpp | 208 +++++++++++++++--- src/sat/smt/euf_proof_checker.h | 127 +++++++++-- src/sat/smt/euf_solver.cpp | 33 +-- src/sat/smt/euf_solver.h | 10 +- src/sat/smt/fpa_solver.h | 2 +- src/sat/smt/pb_solver.cpp | 8 +- src/sat/smt/pb_solver.h | 2 +- src/sat/smt/q_solver.cpp | 2 +- src/sat/smt/q_solver.h | 2 +- ...proof_checker.cpp => q_theory_checker.cpp} | 14 +- .../{q_proof_checker.h => q_theory_checker.h} | 8 +- src/sat/smt/recfun_solver.cpp | 2 +- src/sat/smt/recfun_solver.h | 2 +- src/sat/smt/tseitin_proof_checker.cpp | 6 +- src/sat/smt/tseitin_proof_checker.h | 10 +- src/sat/smt/user_solver.cpp | 2 +- src/sat/smt/user_solver.h | 2 +- src/shell/drat_frontend.cpp | 110 +-------- 40 files changed, 539 insertions(+), 419 deletions(-) rename src/sat/smt/{arith_proof_checker.h => arith_theory_checker.h} (98%) rename src/sat/smt/{q_proof_checker.cpp => q_theory_checker.cpp} (79%) rename src/sat/smt/{q_proof_checker.h => q_theory_checker.h} (83%) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 30dd1d720..8f04b1b00 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -571,6 +571,7 @@ namespace euf { m_updates.push_back(update_record(false, update_record::inconsistent())); m_n1 = n1; m_n2 = n2; + TRACE("euf", tout << "conflict " << bpp(n1) << " " << bpp(n2) << " " << j << "\n"); m_justification = j; } @@ -723,7 +724,7 @@ namespace euf { else if (j.is_congruence()) push_congruence(a, b, j.is_commutative()); if (cc && j.is_congruence()) - cc->push_back(std::tuple(a, b, j.timestamp(), j.is_commutative())); + cc->push_back(std::tuple(a->get_app(), b->get_app(), j.timestamp(), j.is_commutative())); } diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index c0d7f03d8..53aaf481a 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -77,7 +77,7 @@ namespace euf { // It is the only information collected from justifications in order to // reconstruct EUF proofs. Transitivity, Symmetry of equality are not // tracked. - typedef std::tuple cc_justification_record; + typedef std::tuple cc_justification_record; typedef svector cc_justification; class egraph { diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index b90daf29a..c3269253f 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -52,153 +52,6 @@ Proof checker for clauses created during search. #include "params/solver_params.hpp" #include -class smt_checker { - ast_manager& m; - params_ref m_params; - - // for checking proof rules (hints) - euf::proof_checker m_checker; - - // for fallback SMT checker - scoped_ptr m_solver; - - // for RUP - symbol m_rup; - sat::solver m_sat_solver; - sat::drat m_drat; - sat::literal_vector m_units; - sat::literal_vector m_clause; - - void add_units() { - auto const& units = m_drat.units(); - for (unsigned i = m_units.size(); i < units.size(); ++i) - m_units.push_back(units[i].first); - } - -public: - smt_checker(ast_manager& m): - m(m), - m_checker(m), - m_sat_solver(m_params, m.limit()), - m_drat(m_sat_solver) - { - m_params.set_bool("drat.check_unsat", true); - m_sat_solver.updt_params(m_params); - m_drat.updt_config(); - m_solver = mk_smt_solver(m, m_params, symbol()); - m_rup = symbol("rup"); - } - - bool is_rup(app* proof_hint) { - return - proof_hint && - proof_hint->get_name() == m_rup; - } - - void mk_clause(expr_ref_vector const& clause) { - m_clause.reset(); - for (expr* e : clause) { - bool sign = false; - while (m.is_not(e, e)) - sign = !sign; - m_clause.push_back(sat::literal(e->get_id(), sign)); - } - } - - void mk_clause(expr* e) { - m_clause.reset(); - bool sign = false; - while (m.is_not(e, e)) - sign = !sign; - m_clause.push_back(sat::literal(e->get_id(), sign)); - } - - bool check_rup(expr_ref_vector const& clause) { - add_units(); - mk_clause(clause); - return m_drat.is_drup(m_clause.size(), m_clause.data(), m_units); - } - - bool check_rup(expr* u) { - add_units(); - mk_clause(u); - return m_drat.is_drup(m_clause.size(), m_clause.data(), m_units); - } - - void add_clause(expr_ref_vector const& clause) { - mk_clause(clause); - m_drat.add(m_clause, sat::status::input()); - } - - void check(expr_ref_vector& clause, app* proof_hint) { - - if (is_rup(proof_hint) && check_rup(clause)) { - std::cout << "(verified-rup)\n"; - return; - } - - expr_ref_vector units(m); - if (m_checker.check(clause, proof_hint, units)) { - bool units_are_rup = true; - for (expr* u : units) { - if (!check_rup(u)) { - std::cout << "unit " << mk_pp(u, m) << " is not rup\n"; - units_are_rup = false; - } - } - if (units_are_rup) { - std::cout << "(verified-" << proof_hint->get_name() << ")\n"; - add_clause(clause); - return; - } - } - - // extract a simplified verification condition in case proof validation does not work. - // quantifier instantiation can be validated as follows: - // If quantifier instantiation claims that (forall x . phi(x)) => psi using instantiation x -> t - // then check the simplified VC: phi(t) => psi. - // in case psi is the literal instantiation, then the clause is a propositional tautology. - // The VC function is a no-op if the proof hint does not have an associated vc generator. - expr_ref_vector vc(clause); - if (m_checker.vc(proof_hint, clause, vc)) { - std::cout << "(verified-" << proof_hint->get_name() << ")\n"; - add_clause(clause); - return; - } - - m_solver->push(); - for (expr* lit : vc) - m_solver->assert_expr(m.mk_not(lit)); - lbool is_sat = m_solver->check_sat(); - if (is_sat != l_false) { - std::cout << "did not verify: " << is_sat << " " << clause << "\n\n"; - m_solver->display(std::cout); - if (is_sat == l_true) { - model_ref mdl; - m_solver->get_model(mdl); - std::cout << *mdl << "\n"; - } - exit(0); - } - m_solver->pop(1); - std::cout << "(verified-smt"; - if (proof_hint) std::cout << "\n" << mk_bounded_pp(proof_hint, m, 4); - for (expr* arg : clause) - std::cout << "\n " << mk_bounded_pp(arg, m); - std::cout << ")\n"; - add_clause(clause); - } - - void assume(expr_ref_vector const& clause) { - add_clause(clause); - m_solver->assert_expr(mk_or(clause)); - } - - void del(expr_ref_vector const& clause) { - - } - -}; /** * Replay proof entierly, then walk backwards extracting reduced proof. @@ -207,7 +60,7 @@ class proof_trim { cmd_context& ctx; ast_manager& m; sat::proof_trim trim; - euf::proof_checker m_checker; + euf::theory_checker m_checker; vector m_clauses; bool_vector m_is_infer; symbol m_rup; @@ -371,11 +224,11 @@ class proof_cmds_imp : public proof_cmds { bool m_check = true; bool m_save = false; bool m_trim = false; - scoped_ptr m_checker; + scoped_ptr m_checker; scoped_ptr m_saver; scoped_ptr m_trimmer; - smt_checker& checker() { if (!m_checker) m_checker = alloc(smt_checker, m); return *m_checker; } + euf::smt_proof_checker& checker() { params_ref p; if (!m_checker) m_checker = alloc(euf::smt_proof_checker, m, p); return *m_checker; } proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; } proof_trim& trim() { if (!m_trimmer) m_trimmer = alloc(proof_trim, ctx); return *m_trimmer; } @@ -404,7 +257,7 @@ public: void end_infer() override { if (m_check) - checker().check(m_lits, m_proof_hint); + checker().infer(m_lits, m_proof_hint); if (m_save) saver().infer(m_lits, m_proof_hint); if (m_trim) diff --git a/src/model/model.cpp b/src/model/model.cpp index dfa76db68..c89ff59a2 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -225,6 +225,20 @@ struct model::top_sort : public ::top_sort { } }; +void model::evaluate_constants() { + for (auto& [k, p] : m_interp) { + auto & [i, e] = p; + if (m.is_value(e)) + continue; + expr_ref val(m); + val = (*this)(e); + m.dec_ref(e); + m.inc_ref(val); + p.second = val; + } +} + + void model::compress(bool force_inline) { if (m_cleaned) return; diff --git a/src/model/model.h b/src/model/model.h index 07049a522..a93fc1b4f 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -94,6 +94,8 @@ public: void compress(bool force_inline = false); + void evaluate_constants(); + void set_model_completion(bool f) { m_mev.set_model_completion(f); } void updt_params(params_ref const & p); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index d21ec5b93..2330fe401 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -198,7 +198,16 @@ namespace sat { m_drat_check_sat = p.drat_check_sat(); m_drat_file = p.drat_file(); m_smt_proof = p.smt_proof(); - m_drat = !p.drat_disable() && (sp.lemmas2console() || m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_smt_proof.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1; + m_smt_proof_check = p.smt_proof_check(); + m_smt_proof_check_rup = p.smt_proof_check_rup(); + m_drat = + !p.drat_disable() && p.threads() == 1 && + (sp.lemmas2console() || + m_drat_check_unsat || + m_drat_file.is_non_empty_string() || + m_smt_proof.is_non_empty_string() || + m_smt_proof_check || + m_drat_check_sat); m_drat_binary = p.drat_binary(); m_drat_activity = p.drat_activity(); m_dyn_sub_res = p.dyn_sub_res(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 7d98b092c..2d609b1bc 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -178,6 +178,8 @@ namespace sat { bool m_drat_binary; symbol m_drat_file; symbol m_smt_proof; + bool m_smt_proof_check; + bool m_smt_proof_check_rup; bool m_drat_check_unsat; bool m_drat_check_sat; bool m_drat_activity; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index d6a956a32..8f15f5f68 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -89,7 +89,7 @@ namespace sat { virtual bool unit_propagate() = 0; virtual bool is_external(bool_var v) { return false; } virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const { return 0; } - virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r, bool probing) = 0; + virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r, bool probing, proof_hint*& ph) = 0; virtual bool is_extended_binary(ext_justification_idx idx, literal_vector & r) { return false; } virtual bool decide(bool_var& var, lbool& phase) { return false; } virtual bool get_case_split(bool_var& var, lbool& phase) { return false; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 41bfa7afa..c35e97b92 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -48,6 +48,8 @@ def_module_params('sat', ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.disable', BOOL, False, 'override anything that enables DRAT'), ('smt.proof', SYMBOL, '', 'add SMT proof to file'), + ('smt.proof.check', BOOL, False, 'check SMT proof while it is created'), + ('smt.proof.check_rup', BOOL, True, 'apply forward RUP proof checking'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.binary', BOOL, False, 'use Binary DRAT output format'), ('drat.check_unsat', BOOL, False, 'build up internal proof and check'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d10e1124d..7f7b34ea8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -402,8 +402,8 @@ namespace sat { extension::scoped_drating _sd(*m_ext.get()); if (j.get_kind() == justification::EXT_JUSTIFICATION) fill_ext_antecedents(lit, j, false); - TRACE("sat", tout << "drat-unit\n"); - m_drat.add(lit, m_searching); + else + m_drat.add(lit, m_searching); } void solver::drat_log_clause(unsigned num_lits, literal const* lits, sat::status st) { @@ -2890,7 +2890,8 @@ namespace sat { SASSERT(m_ext); auto idx = js.get_ext_justification_idx(); m_ext_antecedents.reset(); - m_ext->get_antecedents(consequent, idx, m_ext_antecedents, probing); + proof_hint* ph = nullptr; + m_ext->get_antecedents(consequent, idx, m_ext_antecedents, probing, ph); } bool solver::is_two_phase() const { diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 6d75c0f1f..0b1e68e96 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -36,7 +36,7 @@ z3_add_component(sat_smt q_mam.cpp q_mbi.cpp q_model_fixer.cpp - q_proof_checker.cpp + q_theory_checker.cpp q_queue.cpp q_solver.cpp recfun_solver.cpp diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index f7e3f6293..5db5688b3 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1476,7 +1476,7 @@ namespace arith { return r; } - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { auto& jst = euf::th_explain::from_index(idx); ctx.get_antecedents(l, jst, r, probing); } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 3d3f1ddd7..672477df2 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -485,7 +485,7 @@ namespace arith { solver(euf::solver& ctx, theory_id id); ~solver() override; bool is_external(bool_var v) override { return false; } - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override; void asserted(literal l) override; sat::check_result check() override; void simplify() override {} diff --git a/src/sat/smt/arith_proof_checker.h b/src/sat/smt/arith_theory_checker.h similarity index 98% rename from src/sat/smt/arith_proof_checker.h rename to src/sat/smt/arith_theory_checker.h index 0e5c891d5..f11e7ae29 100644 --- a/src/sat/smt/arith_proof_checker.h +++ b/src/sat/smt/arith_theory_checker.h @@ -34,7 +34,7 @@ The module assumes a limited repertoire of arithmetic proof rules. namespace arith { - class proof_checker : public euf::proof_checker_plugin { + class theory_checker : public euf::theory_checker_plugin { struct row { obj_map m_coeffs; rational m_coeff; @@ -304,7 +304,7 @@ namespace arith { } public: - proof_checker(ast_manager& m): + theory_checker(ast_manager& m): m(m), a(m), m_farkas("farkas"), @@ -468,7 +468,7 @@ namespace arith { return check(); } - void register_plugins(euf::proof_checker& pc) override { + void register_plugins(euf::theory_checker& pc) override { pc.register_plugin(m_farkas, this); pc.register_plugin(m_bound, this); pc.register_plugin(m_implied_eq, this); diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 5c2708842..f161af01a 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -278,7 +278,7 @@ namespace array { solver(euf::solver& ctx, theory_id id); ~solver() override; bool is_external(bool_var v) override { return false; } - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override {} + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override {} void asserted(literal l) override {} sat::check_result check() override; diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 8ef2c5cd5..631f954b1 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -306,7 +306,7 @@ namespace bv { bool solver::is_extended_binary(sat::ext_justification_idx idx, literal_vector& r) { return false; } bool solver::is_external(bool_var v) { return true; } - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { auto& c = bv_justification::from_index(idx); TRACE("bv", display_constraint(tout, idx) << "\n";); switch (c.m_kind) { @@ -395,6 +395,7 @@ namespace bv { sat::literal leq1(s().num_vars() + 1, false); sat::literal leq2(s().num_vars() + 2, false); expr_ref eq1(m), eq2(m); + sat::proof_hint* ph = nullptr; if (c.m_kind == bv_justification::kind_t::bv2int) { eq1 = m.mk_eq(c.a->get_expr(), c.b->get_expr()); eq2 = m.mk_eq(c.a->get_expr(), c.c->get_expr()); @@ -416,24 +417,24 @@ namespace bv { lits.push_back(c.m_consequent); break; case bv_justification::kind_t::ne2bit: - get_antecedents(c.m_consequent, c.to_index(), lits, true); + get_antecedents(c.m_consequent, c.to_index(), lits, true, ph); lits.push_back(c.m_consequent); break; case bv_justification::kind_t::bit2eq: - get_antecedents(leq1, c.to_index(), lits, true); + get_antecedents(leq1, c.to_index(), lits, true, ph); for (auto& lit : lits) lit.neg(); lits.push_back(leq1); break; case bv_justification::kind_t::bit2ne: - get_antecedents(c.m_consequent, c.to_index(), lits, true); + get_antecedents(c.m_consequent, c.to_index(), lits, true, ph); for (auto& lit : lits) lit.neg(); lits.push_back(c.m_consequent); break; case bv_justification::kind_t::bv2int: - get_antecedents(leq1, c.to_index(), lits, true); - get_antecedents(leq2, c.to_index(), lits, true); + get_antecedents(leq1, c.to_index(), lits, true, ph); + get_antecedents(leq2, c.to_index(), lits, true, ph); for (auto& lit : lits) lit.neg(); lits.push_back(leq1); diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index 2c8fb4ae9..313679443 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -335,7 +335,7 @@ namespace bv { double get_reward(literal l, sat::ext_constraint_idx idx, sat::literal_occs_fun& occs) const override; bool is_extended_binary(sat::ext_justification_idx idx, literal_vector& r) override; bool is_external(bool_var v) override; - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing, sat::proof_hint*& ph) override; void asserted(literal l) override; sat::check_result check() override; void push_core() override; diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index a87f8770b..80846ec58 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -755,7 +755,7 @@ namespace dt { SASSERT(m_find.get_num_vars() == get_num_vars()); } - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { auto& jst = euf::th_explain::from_index(idx); ctx.get_antecedents(l, jst, r, probing); } diff --git a/src/sat/smt/dt_solver.h b/src/sat/smt/dt_solver.h index 4e2524f6b..136e40eac 100644 --- a/src/sat/smt/dt_solver.h +++ b/src/sat/smt/dt_solver.h @@ -140,7 +140,7 @@ namespace dt { ~solver() override; bool is_external(bool_var v) override { return false; } - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override; void asserted(literal l) override; sat::check_result check() override; diff --git a/src/sat/smt/euf_ackerman.cpp b/src/sat/smt/euf_ackerman.cpp index c8639e302..2026120e4 100644 --- a/src/sat/smt/euf_ackerman.cpp +++ b/src/sat/smt/euf_ackerman.cpp @@ -20,7 +20,7 @@ Author: namespace euf { - ackerman::ackerman(solver& s, ast_manager& m): s(s), m(m) { + ackerman::ackerman(solver& ctx, ast_manager& m): ctx(ctx), m(m) { new_tmp(); } @@ -100,31 +100,31 @@ namespace euf { } bool ackerman::enable_cc(app* a, app* b) { - if (!s.enable_ackerman_axioms(a)) + if (!ctx.enable_ackerman_axioms(a)) return false; - if (!s.enable_ackerman_axioms(b)) + if (!ctx.enable_ackerman_axioms(b)) return false; for (expr* arg : *a) - if (!s.enable_ackerman_axioms(arg)) + if (!ctx.enable_ackerman_axioms(arg)) return false; for (expr* arg : *b) - if (!s.enable_ackerman_axioms(arg)) + if (!ctx.enable_ackerman_axioms(arg)) return false; return true; } bool ackerman::enable_eq(expr* a, expr* b, expr* c) { - return s.enable_ackerman_axioms(a) && - s.enable_ackerman_axioms(b) && - s.enable_ackerman_axioms(c); + return ctx.enable_ackerman_axioms(a) && + ctx.enable_ackerman_axioms(b) && + ctx.enable_ackerman_axioms(c); } void ackerman::cg_conflict_eh(expr * n1, expr * n2) { if (!is_app(n1) || !is_app(n2)) return; - if (!s.enable_ackerman_axioms(n1)) + if (!ctx.enable_ackerman_axioms(n1)) return; - SASSERT(!s.m_drating); + SASSERT(!ctx.m_drating); app* a = to_app(n1); app* b = to_app(n2); if (a->get_decl() != b->get_decl() || a->get_num_args() != b->get_num_args()) @@ -139,7 +139,7 @@ namespace euf { void ackerman::used_eq_eh(expr* a, expr* b, expr* c) { if (a == b || a == c || b == c) return; - if (s.m_drating) + if (ctx.m_drating) return; if (!enable_eq(a, b, c)) return; @@ -149,7 +149,7 @@ namespace euf { } void ackerman::used_cc_eh(app* a, app* b) { - if (s.m_drating) + if (ctx.m_drating) return; TRACE("ack", tout << "used cc: " << mk_pp(a, m) << " == " << mk_pp(b, m) << "\n";); SASSERT(a->get_decl() == b->get_decl()); @@ -162,7 +162,7 @@ namespace euf { void ackerman::gc() { m_num_propagations_since_last_gc++; - if (m_num_propagations_since_last_gc <= s.m_config.m_dack_gc) + if (m_num_propagations_since_last_gc <= ctx.m_config.m_dack_gc) return; m_num_propagations_since_last_gc = 0; @@ -175,14 +175,14 @@ namespace euf { } void ackerman::propagate() { - SASSERT(s.s().at_base_lvl()); + SASSERT(ctx.s().at_base_lvl()); auto* n = m_queue; inference* k = nullptr; - unsigned num_prop = static_cast(s.s().get_stats().m_conflict * s.m_config.m_dack_factor); + unsigned num_prop = static_cast(ctx.s().get_stats().m_conflict * ctx.m_config.m_dack_factor); num_prop = std::min(num_prop, m_table.size()); for (unsigned i = 0; i < num_prop; ++i, n = k) { k = n->next(); - if (n->m_count < s.m_config.m_dack_threshold) + if (n->m_count < ctx.m_config.m_dack_threshold) continue; if (n->m_count >= m_high_watermark && num_prop < m_table.size()) ++num_prop; @@ -190,13 +190,13 @@ namespace euf { add_cc(n->a, n->b); else add_eq(n->a, n->b, n->c); - ++s.m_stats.m_ackerman; + ++ctx.m_stats.m_ackerman; remove(n); } } void ackerman::add_cc(expr* _a, expr* _b) { - flet _is_redundant(s.m_is_redundant, true); + flet _is_redundant(ctx.m_is_redundant, true); app* a = to_app(_a); app* b = to_app(_b); TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << "\n";); @@ -204,24 +204,33 @@ namespace euf { unsigned sz = a->get_num_args(); for (unsigned i = 0; i < sz; ++i) { - expr_ref eq = s.mk_eq(a->get_arg(i), b->get_arg(i)); - lits.push_back(~s.mk_literal(eq)); + expr* ai = a->get_arg(i); + expr* bi = b->get_arg(i); + if (ai != bi) { + expr_ref eq = ctx.mk_eq(ai, bi); + lits.push_back(~ctx.mk_literal(eq)); + } } - expr_ref eq = s.mk_eq(a, b); - lits.push_back(s.mk_literal(eq)); - s.s().mk_clause(lits, sat::status::th(true, m.get_basic_family_id())); + expr_ref eq = ctx.mk_eq(a, b); + lits.push_back(ctx.mk_literal(eq)); + th_proof_hint* ph = ctx.mk_cc_proof_hint(lits, a, b); + ctx.s().mk_clause(lits, sat::status::th(true, m.get_basic_family_id(), ph)); } void ackerman::add_eq(expr* a, expr* b, expr* c) { - flet _is_redundant(s.m_is_redundant, true); + if (a == c || b == c) + return; + flet _is_redundant(ctx.m_is_redundant, true); sat::literal lits[3]; - expr_ref eq1(s.mk_eq(a, c), m); - expr_ref eq2(s.mk_eq(b, c), m); - expr_ref eq3(s.mk_eq(a, b), m); + expr_ref eq1(ctx.mk_eq(a, c), m); + expr_ref eq2(ctx.mk_eq(b, c), m); + expr_ref eq3(ctx.mk_eq(a, b), m); TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << " " << mk_pp(c, m) << "\n";); - lits[0] = ~s.mk_literal(eq1); - lits[1] = ~s.mk_literal(eq2); - lits[2] = s.mk_literal(eq3); - s.s().mk_clause(3, lits, sat::status::th(true, m.get_basic_family_id())); + lits[0] = ~ctx.mk_literal(eq1); + lits[1] = ~ctx.mk_literal(eq2); + lits[2] = ctx.mk_literal(eq3); + th_proof_hint* ph = ctx.mk_tc_proof_hint(lits); + ctx.s().mk_clause(3, lits, sat::status::th(true, m.get_basic_family_id(), ph)); } + } diff --git a/src/sat/smt/euf_ackerman.h b/src/sat/smt/euf_ackerman.h index 17c7404f2..b5af2f689 100644 --- a/src/sat/smt/euf_ackerman.h +++ b/src/sat/smt/euf_ackerman.h @@ -52,14 +52,14 @@ namespace euf { typedef hashtable table_t; - solver& s; + solver& ctx; ast_manager& m; table_t m_table; - inference* m_queue { nullptr }; - inference* m_tmp_inference { nullptr }; - unsigned m_gc_threshold { 100 }; - unsigned m_high_watermark { 1000 }; - unsigned m_num_propagations_since_last_gc { 0 }; + inference* m_queue = nullptr; + inference* m_tmp_inference = nullptr; + unsigned m_gc_threshold = 100; + unsigned m_high_watermark = 1000 ; + unsigned m_num_propagations_since_last_gc = 0; void reset(); void new_tmp(); @@ -75,7 +75,7 @@ namespace euf { public: - ackerman(solver& s, ast_manager& m); + ackerman(solver& ctx, ast_manager& m); ~ackerman(); void cg_conflict_eh(expr * n1, expr * n2); diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 8ee1a1d28..dbabb1a7b 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -27,13 +27,12 @@ namespace euf { get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); } if (!m_proof_out && s().get_config().m_drat && - (get_config().m_lemmas2console || s().get_config().m_smt_proof.is_non_empty_string())) { + (get_config().m_lemmas2console || + s().get_config().m_smt_proof_check || + s().get_config().m_smt_proof.is_non_empty_string())) { TRACE("euf", tout << "init-proof " << s().get_config().m_smt_proof << "\n"); m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); - if (get_config().m_lemmas2console) - get_drat().set_clause_eh(*this); - if (s().get_config().m_smt_proof.is_non_empty_string()) - get_drat().set_clause_eh(*this); + get_drat().set_clause_eh(*this); } m_proof_initialized = true; } @@ -90,6 +89,46 @@ namespace euf { return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); } + th_proof_hint* solver::mk_cc_proof_hint(sat::literal_vector const& ante, app* a, app* b) { + if (!use_drat()) + return nullptr; + SASSERT(a->get_decl() == b->get_decl()); + push(value_trail(m_lit_tail)); + push(value_trail(m_cc_tail)); + push(restore_size_trail(m_proof_literals)); + push(restore_size_trail(m_explain_cc, m_explain_cc.size())); + + for (auto lit : ante) + m_proof_literals.push_back(~lit); + + m_explain_cc.push_back({a, b, 0, false}); + + m_lit_head = m_lit_tail; + m_cc_head = m_cc_tail; + m_lit_tail = m_proof_literals.size(); + m_cc_tail = m_explain_cc.size(); + return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); + } + + th_proof_hint* solver::mk_tc_proof_hint(sat::literal const* clause) { + if (!use_drat()) + return nullptr; + push(value_trail(m_lit_tail)); + push(value_trail(m_cc_tail)); + push(restore_size_trail(m_proof_literals)); + + for (unsigned i = 0; i < 3; ++i) + m_proof_literals.push_back(~clause[i]); + + + m_lit_head = m_lit_tail; + m_cc_head = m_cc_tail; + m_lit_tail = m_proof_literals.size(); + m_cc_tail = m_explain_cc.size(); + return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); + } + + expr* eq_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); func_decl_ref cc(m), cc_comm(m); @@ -118,7 +157,7 @@ namespace euf { std::sort(s.m_explain_cc.data() + m_cc_head, s.m_explain_cc.data() + m_cc_tail, compare_ts); for (unsigned i = m_cc_head; i < m_cc_tail; ++i) { auto const& [a, b, ts, comm] = s.m_explain_cc[i]; - args.push_back(cc_proof(comm, m.mk_eq(a->get_expr(), b->get_expr()))); + args.push_back(cc_proof(comm, m.mk_eq(a, b))); } for (auto * arg : args) sorts.push_back(arg->get_sort()); @@ -126,6 +165,8 @@ namespace euf { func_decl* f = m.mk_func_decl(symbol("euf"), sorts.size(), sorts.data(), proof); return m.mk_app(f, args); } + + smt_proof_hint* solver::mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, expr_pair const* eqs, unsigned nd, expr_pair const* deqs) { if (!use_drat()) @@ -134,8 +175,14 @@ namespace euf { push(restore_size_trail(m_proof_literals)); for (unsigned i = 0; i < nl; ++i) - if (sat::null_literal != lits[i]) + if (sat::null_literal != lits[i]) { + if (!literal2expr(lits[i])) + IF_VERBOSE(0, verbose_stream() << lits[i] << "\n"; display(verbose_stream())); + + + SASSERT(literal2expr(lits[i])); m_proof_literals.push_back(lits[i]); + } push(value_trail(m_eq_tail)); push(restore_size_trail(m_proof_eqs)); @@ -231,6 +278,7 @@ namespace euf { TRACE("euf", tout << "on-clause " << n << "\n"); on_lemma(n, lits, st); on_proof(n, lits, st); + on_check(n, lits, st); } void solver::on_proof(unsigned n, literal const* lits, sat::status st) { @@ -252,6 +300,21 @@ namespace euf { UNREACHABLE(); out.flush(); } + + void solver::on_check(unsigned n, literal const* lits, sat::status st) { + if (!s().get_config().m_smt_proof_check) + return; + expr_ref_vector clause(m); + for (unsigned i = 0; i < n; ++i) + clause.push_back(literal2expr(lits[i])); + auto hint = status2proof_hint(st); + if (st.is_asserted() || st.is_redundant()) + m_smt_proof_checker.infer(clause, hint); + else if (st.is_deleted()) + m_smt_proof_checker.del(clause); + else if (st.is_input()) + m_smt_proof_checker.assume(clause); + } void solver::on_lemma(unsigned n, literal const* lits, sat::status st) { if (!get_config().m_lemmas2console) @@ -320,21 +383,21 @@ namespace euf { if (proof_hint) return display_expr(out << " ", proof_hint); else - return out; + return out; } - expr_ref solver::status2proof_hint(sat::status st) { + app_ref solver::status2proof_hint(sat::status st) { if (st.is_sat()) - return expr_ref(m.mk_const("rup", m.mk_proof_sort()), m); // provable by reverse unit propagation + return app_ref(m.mk_const("rup", m.mk_proof_sort()), m); // provable by reverse unit propagation auto* h = reinterpret_cast(st.get_hint()); if (!h) - return expr_ref(m); + return app_ref(m); expr* e = h->get_hint(*this); if (e) - return expr_ref(e, m); + return app_ref(to_app(e), m); - return expr_ref(m); + return app_ref(m); } std::ostream& solver::display_literals(std::ostream& out, unsigned n, literal const* lits) { @@ -345,6 +408,7 @@ namespace euf { k = m.mk_const(symbol(lits[i].var()), m.mk_bool_sort()); e = k; } + SASSERT(e); if (lits[i].sign()) display_expr(out << " (not ", e) << ")"; else diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index e7a77df5c..98032a86b 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -20,11 +20,14 @@ Author: #include "ast/ast_util.h" #include "ast/ast_ll_pp.h" #include "ast/arith_decl_plugin.h" +#include "smt/smt_solver.h" +#include "sat/sat_params.hpp" #include "sat/smt/euf_proof_checker.h" -#include "sat/smt/arith_proof_checker.h" -#include "sat/smt/q_proof_checker.h" +#include "sat/smt/arith_theory_checker.h" +#include "sat/smt/q_theory_checker.h" #include "sat/smt/tseitin_proof_checker.h" + namespace euf { /** @@ -57,7 +60,7 @@ namespace euf { * union-find checker. */ - class eq_proof_checker : public proof_checker_plugin { + class eq_theory_checker : public theory_checker_plugin { ast_manager& m; arith_util m_arith; expr_ref_vector m_trail; @@ -133,7 +136,7 @@ namespace euf { } public: - eq_proof_checker(ast_manager& m): m(m), m_arith(m), m_trail(m) {} + eq_theory_checker(ast_manager& m): m(m), m_arith(m), m_trail(m) {} expr_ref_vector clause(app* jst) override { expr_ref_vector result(m); @@ -208,7 +211,7 @@ namespace euf { return false; } - void register_plugins(proof_checker& pc) override { + void register_plugins(theory_checker& pc) override { pc.register_plugin(symbol("euf"), this); } }; @@ -219,12 +222,12 @@ namespace euf { The pivot occurs with opposite signs in proof1 and proof2 */ - class res_proof_checker : public proof_checker_plugin { + class res_checker : public theory_checker_plugin { ast_manager& m; - proof_checker& pc; + theory_checker& pc; public: - res_proof_checker(ast_manager& m, proof_checker& pc): m(m), pc(pc) {} + res_checker(ast_manager& m, theory_checker& pc): m(m), pc(pc) {} bool check(app* jst) override { if (jst->get_num_args() != 3) @@ -273,46 +276,46 @@ namespace euf { return result; } - void register_plugins(proof_checker& pc) override { + void register_plugins(theory_checker& pc) override { pc.register_plugin(symbol("res"), this); } }; - proof_checker::proof_checker(ast_manager& m): + theory_checker::theory_checker(ast_manager& m): m(m) { - add_plugin(alloc(arith::proof_checker, m)); - add_plugin(alloc(eq_proof_checker, m)); - add_plugin(alloc(res_proof_checker, m, *this)); - add_plugin(alloc(q::proof_checker, m)); - add_plugin(alloc(smt_proof_checker_plugin, m, symbol("datatype"))); // no-op datatype proof checker - add_plugin(alloc(tseitin::proof_checker, m)); + add_plugin(alloc(arith::theory_checker, m)); + add_plugin(alloc(eq_theory_checker, m)); + add_plugin(alloc(res_checker, m, *this)); + add_plugin(alloc(q::theory_checker, m)); + add_plugin(alloc(smt_theory_checker_plugin, m, symbol("datatype"))); // no-op datatype proof checker + add_plugin(alloc(tseitin::theory_checker, m)); } - proof_checker::~proof_checker() { + theory_checker::~theory_checker() { for (auto& [k, v] : m_checked_clauses) dealloc(v); } - void proof_checker::add_plugin(proof_checker_plugin* p) { + void theory_checker::add_plugin(theory_checker_plugin* p) { m_plugins.push_back(p); p->register_plugins(*this); } - void proof_checker::register_plugin(symbol const& rule, proof_checker_plugin* p) { + void theory_checker::register_plugin(symbol const& rule, theory_checker_plugin* p) { m_map.insert(rule, p); } - bool proof_checker::check(expr* e) { + bool theory_checker::check(expr* e) { if (!e || !is_app(e)) return false; if (m_checked_clauses.contains(e)) return true; app* a = to_app(e); - proof_checker_plugin* p = nullptr; + theory_checker_plugin* p = nullptr; return m_map.find(a->get_decl()->get_name(), p) && p->check(a); } - expr_ref_vector proof_checker::clause(expr* e) { + expr_ref_vector theory_checker::clause(expr* e) { expr_ref_vector* rr; if (m_checked_clauses.find(e, rr)) return *rr; @@ -322,17 +325,17 @@ namespace euf { return r; } - bool proof_checker::vc(expr* e, expr_ref_vector const& clause, expr_ref_vector& v) { + bool theory_checker::vc(expr* e, expr_ref_vector const& clause, expr_ref_vector& v) { SASSERT(is_app(e)); app* a = to_app(e); - proof_checker_plugin* p = nullptr; + theory_checker_plugin* p = nullptr; if (m_map.find(a->get_name(), p)) return p->vc(a, clause, v); IF_VERBOSE(10, verbose_stream() << "there is no proof plugin for " << mk_pp(e, m) << "\n"); return false; } - bool proof_checker::check(expr_ref_vector const& clause1, expr* e, expr_ref_vector & units) { + bool theory_checker::check(expr_ref_vector const& clause1, expr* e, expr_ref_vector & units) { if (!check(e)) return false; units.reset(); @@ -358,13 +361,166 @@ namespace euf { return true; } - expr_ref_vector smt_proof_checker_plugin::clause(app* jst) { + expr_ref_vector smt_theory_checker_plugin::clause(app* jst) { expr_ref_vector result(m); SASSERT(jst->get_name() == m_rule); for (expr* arg : *jst) result.push_back(mk_not(m, arg)); return result; } + + + smt_proof_checker::smt_proof_checker(ast_manager& m, params_ref const& p): + m(m), + m_params(p), + m_checker(m), + m_sat_solver(m_params, m.limit()), + m_drat(m_sat_solver) + { + m_params.set_bool("drat.check_unsat", true); + m_params.set_bool("euf", false); + m_sat_solver.updt_params(m_params); + m_drat.updt_config(); + m_rup = symbol("rup"); + sat_params sp(m_params); + m_check_rup = sp.smt_proof_check_rup(); + } + + void smt_proof_checker::ensure_solver() { + if (!m_solver) + m_solver = mk_smt_solver(m, m_params, symbol()); + } + + + void smt_proof_checker::log_verified(app* proof_hint) { + symbol n = proof_hint->get_name(); + if (n == m_last_rule) { + ++m_num_last_rules; + return; + } + if (m_num_last_rules > 0) + std::cout << "(verified-" << m_last_rule << "+" << m_num_last_rules << ")\n"; + + std::cout << "(verified-" << n << ")\n"; + m_last_rule = n; + m_num_last_rules = 0; + + } + + bool smt_proof_checker::check_rup(expr_ref_vector const& clause) { + if (!m_check_rup) + return true; + add_units(); + mk_clause(clause); + return m_drat.is_drup(m_clause.size(), m_clause.data(), m_units); + } + + bool smt_proof_checker::check_rup(expr* u) { + if (!m_check_rup) + return true; + add_units(); + mk_clause(u); + return m_drat.is_drup(m_clause.size(), m_clause.data(), m_units); + } + + void smt_proof_checker::infer(expr_ref_vector& clause, app* proof_hint) { + + if (is_rup(proof_hint) && check_rup(clause)) { + if (m_check_rup) { + log_verified(proof_hint); + add_clause(clause); + } + return; + } + + expr_ref_vector units(m); + if (m_checker.check(clause, proof_hint, units)) { + bool units_are_rup = true; + for (expr* u : units) { + if (!check_rup(u)) { + std::cout << "unit " << mk_bounded_pp(u, m) << " is not rup\n"; + units_are_rup = false; + } + } + if (units_are_rup) { + log_verified(proof_hint); + add_clause(clause); + return; + } + } + + // extract a simplified verification condition in case proof validation does not work. + // quantifier instantiation can be validated as follows: + // If quantifier instantiation claims that (forall x . phi(x)) => psi using instantiation x -> t + // then check the simplified VC: phi(t) => psi. + // in case psi is the literal instantiation, then the clause is a propositional tautology. + // The VC function is a no-op if the proof hint does not have an associated vc generator. + expr_ref_vector vc(clause); + if (m_checker.vc(proof_hint, clause, vc)) { + log_verified(proof_hint); + add_clause(clause); + return; + } + + ensure_solver(); + m_solver->push(); + for (expr* lit : vc) + m_solver->assert_expr(m.mk_not(lit)); + lbool is_sat = m_solver->check_sat(); + if (is_sat != l_false) { + std::cout << "did not verify: " << is_sat << " " << clause << "\n"; + if (proof_hint) + std::cout << "hint: " << mk_bounded_pp(proof_hint, m, 4) << "\n"; + m_solver->display(std::cout); + if (is_sat == l_true) { + model_ref mdl; + m_solver->get_model(mdl); + mdl->evaluate_constants(); + std::cout << *mdl << "\n"; + } + exit(0); + } + m_solver->pop(1); + std::cout << "(verified-smt"; + if (proof_hint) std::cout << "\n" << mk_bounded_pp(proof_hint, m, 4); + for (expr* arg : clause) + std::cout << "\n " << mk_bounded_pp(arg, m); + std::cout << ")\n"; + if (is_rup(proof_hint)) + diagnose_rup_failure(clause); + + add_clause(clause); + } + + void smt_proof_checker::diagnose_rup_failure(expr_ref_vector const& clause) { + expr_ref_vector fmls(m), assumptions(m), core(m); + m_solver->get_assertions(fmls); + for (unsigned i = 0; i < fmls.size(); ++i) { + assumptions.push_back(m.mk_fresh_const("a", m.mk_bool_sort())); + fmls[i] = m.mk_implies(assumptions.back(), fmls.get(i)); + } + + ref<::solver> core_solver = mk_smt_solver(m, m_params, symbol()); + // core_solver->assert_expr(fmls); + core_solver->assert_expr(m.mk_not(mk_or(clause))); + lbool ch = core_solver->check_sat(assumptions); + std::cout << "failed to verify\n" << clause << "\n"; + if (ch == l_false) { + core_solver->get_unsat_core(core); + std::cout << "core\n"; + for (expr* f : core) + std::cout << mk_pp(f, m) << "\n"; + } + SASSERT(false); + + exit(0); + } + + void smt_proof_checker::collect_statistics(statistics& st) const { + if (m_solver) + m_solver->collect_statistics(st); + + } } diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 8b1b5d671..6d5cb3290 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -19,30 +19,35 @@ Author: #include "util/map.h" #include "util/scoped_ptr_vector.h" #include "ast/ast.h" +#include "ast/ast_util.h" +#include "solver/solver.h" +#include "sat/sat_solver.h" +#include "sat/sat_drat.h" + namespace euf { - class proof_checker; + class theory_checker; - class proof_checker_plugin { + class theory_checker_plugin { public: - virtual ~proof_checker_plugin() {} + virtual ~theory_checker_plugin() {} virtual bool check(app* jst) = 0; virtual expr_ref_vector clause(app* jst) = 0; - virtual void register_plugins(proof_checker& pc) = 0; - virtual bool vc(app* jst, expr_ref_vector const& clause, expr_ref_vector& v) { return false; } + virtual void register_plugins(theory_checker& pc) = 0; + virtual bool vc(app* jst, expr_ref_vector const& clause, expr_ref_vector& v) { v.reset(); v.append(this->clause(jst)); return false; } }; - class proof_checker { + class theory_checker { ast_manager& m; - scoped_ptr_vector m_plugins; // plugins of proof checkers - map m_map; // symbol table of proof checkers + scoped_ptr_vector m_plugins; // plugins of proof checkers + map m_map; // symbol table of proof checkers obj_map m_checked_clauses; // cache of previously checked proofs and their clauses. - void add_plugin(proof_checker_plugin* p); + void add_plugin(theory_checker_plugin* p); public: - proof_checker(ast_manager& m); - ~proof_checker(); - void register_plugin(symbol const& rule, proof_checker_plugin*); + theory_checker(ast_manager& m); + ~theory_checker(); + void register_plugin(symbol const& rule, theory_checker_plugin*); bool check(expr* jst); expr_ref_vector clause(expr* jst); bool vc(expr* jst, expr_ref_vector const& clause, expr_ref_vector& v); @@ -55,15 +60,107 @@ namespace euf { It provides shared implementations for clause and register_plugin. It overrides check to always fail. */ - class smt_proof_checker_plugin : public proof_checker_plugin { + class smt_theory_checker_plugin : public theory_checker_plugin { ast_manager& m; symbol m_rule; public: - smt_proof_checker_plugin(ast_manager& m, symbol const& n): m(m), m_rule(n) {} + smt_theory_checker_plugin(ast_manager& m, symbol const& n): m(m), m_rule(n) {} bool check(app* jst) override { return false; } expr_ref_vector clause(app* jst) override; - void register_plugins(proof_checker& pc) override { pc.register_plugin(m_rule, this); } + void register_plugins(theory_checker& pc) override { pc.register_plugin(m_rule, this); } }; + + class smt_proof_checker { + ast_manager& m; + params_ref m_params; + + // for checking proof rules (hints) + euf::theory_checker m_checker; + + // for fallback SMT checker + scoped_ptr<::solver> m_solver; + + // for RUP + symbol m_rup; + sat::solver m_sat_solver; + sat::drat m_drat; + sat::literal_vector m_units; + sat::literal_vector m_clause; + bool m_check_rup = false; + + // for logging + symbol m_last_rule; + unsigned m_num_last_rules = 0; + + void add_units() { + auto const& units = m_drat.units(); + for (unsigned i = m_units.size(); i < units.size(); ++i) + m_units.push_back(units[i].first); + } + + void log_verified(app* proof_hint); + + void diagnose_rup_failure(expr_ref_vector const& clause); + + void ensure_solver(); + + public: + smt_proof_checker(ast_manager& m, params_ref const& p); + + bool is_rup(app* proof_hint) { + return + proof_hint && + proof_hint->get_name() == m_rup; + } + + void mk_clause(expr_ref_vector const& clause) { + m_clause.reset(); + for (expr* e : clause) { + bool sign = false; + while (m.is_not(e, e)) + sign = !sign; + m_clause.push_back(sat::literal(e->get_id(), sign)); + } + } + + void mk_clause(expr* e) { + m_clause.reset(); + bool sign = false; + while (m.is_not(e, e)) + sign = !sign; + m_clause.push_back(sat::literal(e->get_id(), sign)); + } + + bool check_rup(expr_ref_vector const& clause); + + bool check_rup(expr* u); + + void add_clause(expr_ref_vector const& clause) { + if (!m_check_rup) + return; + mk_clause(clause); + m_drat.add(m_clause, sat::status::input()); + } + + void assume(expr_ref_vector const& clause) { + add_clause(clause); + if (!m_check_rup) + return; + ensure_solver(); + m_solver->assert_expr(mk_or(clause)); + } + + void del(expr_ref_vector const& clause) { + } + + + void infer(expr_ref_vector& clause, app* proof_hint); + + void collect_statistics(statistics& st) const; + + }; + + } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index c29652803..cde3ef2e0 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -50,7 +50,8 @@ namespace euf { m_to_m(&m), m_to_si(&si), m_values(m), - m_clause_visitor(m) + m_clause_visitor(m), + m_smt_proof_checker(m, p) { updt_params(p); m_relevancy.set_enabled(get_config().m_relevancy_lvl > 2); @@ -72,7 +73,7 @@ namespace euf { void solver::updt_params(params_ref const& p) { m_config.updt_params(p); - use_drat(); + use_drat(); } /** @@ -215,19 +216,25 @@ namespace euf { x - 3 = 0 => x = 3 by arithmetic x = 3 => f(x) = f(3) by EUF resolve to produce clause x - 3 = 0 => f(x) = f(3) + + The last argument to get_assumptions is a place-holder to retrieve a justification of a propagation. + Theory solver would have to populate this hint and the combined hint would have to be composed from the + sub-hints. */ - void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) { + void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { m_egraph.begin_explain(); m_explain.reset(); if (use_drat() && !probing) push(restore_size_trail(m_explain_cc, m_explain_cc.size())); auto* ext = sat::constraint_base::to_extension(idx); + th_proof_hint* hint = nullptr; + sat::proof_hint* shint = nullptr; bool has_theory = false; if (ext == this) get_antecedents(l, constraint::from_idx(idx), r, probing); else { - ext->get_antecedents(l, idx, r, probing); + ext->get_antecedents(l, idx, r, probing, shint); has_theory = true; } for (unsigned qhead = 0; qhead < m_explain.size(); ++qhead) { @@ -239,20 +246,19 @@ namespace euf { auto* ext = sat::constraint_base::to_extension(idx); SASSERT(ext != this); sat::literal lit = sat::null_literal; - ext->get_antecedents(lit, idx, r, probing); + ext->get_antecedents(lit, idx, r, probing, shint); has_theory = true; } } m_egraph.end_explain(); - th_proof_hint* hint = nullptr; - if (use_drat() && !probing) { - if (has_theory) { - r.push_back(~l); - hint = mk_smt_hint(symbol("smt"), r); - r.pop_back(); - } - else + if (use_drat() && !probing) { + if (!has_theory) hint = mk_hint(l, r); + else { + if (l != sat::null_literal) r.push_back(~l); + hint = mk_smt_hint(symbol("smt"), r); + if (l != sat::null_literal) r.pop_back(); + } } unsigned j = 0; for (sat::literal lit : r) @@ -957,6 +963,7 @@ namespace euf { m_egraph.collect_statistics(st); for (auto* e : m_solvers) e->collect_statistics(st); + m_smt_proof_checker.collect_statistics(st); st.update("euf ackerman", m_stats.m_ackerman); st.update("euf final check", m_stats.m_final_checks); } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index bf18ca4bc..cedfcf2da 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -28,6 +28,7 @@ Author: #include "sat/smt/euf_ackerman.h" #include "sat/smt/user_solver.h" #include "sat/smt/euf_relevancy.h" +#include "sat/smt/euf_proof_checker.h" #include "smt/params/smt_params.h" @@ -203,19 +204,22 @@ namespace euf { unsigned m_eq_head = 0, m_eq_tail = 0, m_deq_head = 0, m_deq_tail = 0; eq_proof_hint* mk_hint(literal lit, literal_vector const& r); + bool m_proof_initialized = false; void init_proof(); ast_pp_util m_clause_visitor; bool m_display_all_decls = false; + smt_proof_checker m_smt_proof_checker; void on_clause(unsigned n, literal const* lits, sat::status st) override; void on_lemma(unsigned n, literal const* lits, sat::status st); void on_proof(unsigned n, literal const* lits, sat::status st); + void on_check(unsigned n, literal const* lits, sat::status st); std::ostream& display_literals(std::ostream& out, unsigned n, sat::literal const* lits); void display_assume(std::ostream& out, unsigned n, literal const* lits); void display_inferred(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint); void display_deleted(std::ostream& out, unsigned n, literal const* lits); std::ostream& display_hint(std::ostream& out, expr* proof_hint); - expr_ref status2proof_hint(sat::status st); + app_ref status2proof_hint(sat::status st); // relevancy bool is_propagated(sat::literal lit); @@ -334,7 +338,7 @@ namespace euf { bool set_root(literal l, literal r) override; void flush_roots() override; - void get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) override; + void get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override; void get_antecedents(literal l, th_explain& jst, literal_vector& r, bool probing); void add_antecedent(bool probing, enode* a, enode* b); void add_diseq_antecedent(ptr_vector& ex, cc_justification* cc, enode* a, enode* b); @@ -400,6 +404,8 @@ namespace euf { smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, expr* a, expr* b) { expr_pair e(a, b); return mk_smt_hint(n, 1, &lit, 0, nullptr, 1, &e); } smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, enode* a, enode* b) { return mk_smt_prop_hint(n, lit, a->get_expr(), b->get_expr()); } smt_proof_hint* mk_smt_hint(symbol const& n, enode* a, enode* b) { expr_pair e(a->get_expr(), b->get_expr()); return mk_smt_hint(n, 0, nullptr, 1, &e); } + th_proof_hint* mk_cc_proof_hint(sat::literal_vector const& ante, app* a, app* b); + th_proof_hint* mk_tc_proof_hint(sat::literal const* ternary_clause); sat::status mk_tseitin_status(sat::literal a, sat::literal b); sat::status mk_tseitin_status(unsigned n, sat::literal const* lits); diff --git a/src/sat/smt/fpa_solver.h b/src/sat/smt/fpa_solver.h index 38abb399d..537ae0895 100644 --- a/src/sat/smt/fpa_solver.h +++ b/src/sat/smt/fpa_solver.h @@ -71,7 +71,7 @@ namespace fpa { void finalize_model(model& mdl) override; bool unit_propagate() override; - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override { UNREACHABLE(); } + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) override { UNREACHABLE(); } sat::check_result check() override; euf::th_solver* clone(euf::solver& ctx) override { return alloc(solver, ctx); } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 1c762cb3f..2a29f07d5 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -722,7 +722,8 @@ namespace pb { auto* ext = sat::constraint_base::to_extension(cindex); if (ext != this) { m_lemma.reset(); - ext->get_antecedents(consequent, idx, m_lemma, false); + sat::proof_hint* ph = nullptr; + ext->get_antecedents(consequent, idx, m_lemma, false, ph); for (literal l : m_lemma) process_antecedent(~l, offset); break; } @@ -1052,7 +1053,8 @@ namespace pb { auto* ext = sat::constraint_base::to_extension(index); if (ext != this) { m_lemma.reset(); - ext->get_antecedents(consequent, index, m_lemma, false); + sat::proof_hint* ph = nullptr; + ext->get_antecedents(consequent, index, m_lemma, false, ph); for (literal l : m_lemma) process_antecedent(~l, 1); break; @@ -1688,7 +1690,7 @@ namespace pb { // ---------------------------- // constraint generic methods - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing, sat::proof_hint*& ph) { get_antecedents(l, index2constraint(idx), r, probing); } diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h index 09c0e47e0..9f9e6835c 100644 --- a/src/sat/smt/pb_solver.h +++ b/src/sat/smt/pb_solver.h @@ -377,7 +377,7 @@ namespace pb { bool propagated(literal l, sat::ext_constraint_idx idx) override; bool unit_propagate() override { return false; } lbool resolve_conflict() override; - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing, sat::proof_hint*& ph) override; void asserted(literal l) override; sat::check_result check() override; void push() override; diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 7fd7be97e..7bddcbd9f 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -353,7 +353,7 @@ namespace q { return !m.is_and(arg) && !m.is_or(arg) && !m.is_iff(arg) && !m.is_implies(arg); } - void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) { + void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) { m_ematch.get_antecedents(l, idx, r, probing); } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 3a95a00be..f199db610 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -83,7 +83,7 @@ namespace q { solver(euf::solver& ctx, family_id fid); bool is_external(sat::bool_var v) override { return false; } - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) override; void asserted(sat::literal l) override; sat::check_result check() override; diff --git a/src/sat/smt/q_proof_checker.cpp b/src/sat/smt/q_theory_checker.cpp similarity index 79% rename from src/sat/smt/q_proof_checker.cpp rename to src/sat/smt/q_theory_checker.cpp index 8ddd3d75a..be246dd3c 100644 --- a/src/sat/smt/q_proof_checker.cpp +++ b/src/sat/smt/q_theory_checker.cpp @@ -3,7 +3,7 @@ Copyright (c) 2022 Microsoft Corporation Module Name: - q_proof_checker.cpp + q_theory_checker.cpp Abstract: @@ -16,12 +16,12 @@ Author: --*/ #include "ast/rewriter/var_subst.h" -#include "sat/smt/q_proof_checker.h" +#include "sat/smt/q_theory_checker.h" #include "sat/smt/q_solver.h" namespace q { - expr_ref_vector proof_checker::clause(app* jst) { + expr_ref_vector theory_checker::clause(app* jst) { expr_ref_vector result(m); for (expr* arg : *jst) if (!is_bind(arg)) @@ -29,7 +29,7 @@ namespace q { return result; } - expr_ref_vector proof_checker::binding(app* jst) { + expr_ref_vector theory_checker::binding(app* jst) { expr_ref_vector result(m); for (expr* arg : *jst) if (is_bind(arg)) { @@ -39,7 +39,7 @@ namespace q { return result; } - bool proof_checker::vc(app* jst, expr_ref_vector const& clause0, expr_ref_vector& v) { + bool theory_checker::vc(app* jst, expr_ref_vector const& clause0, expr_ref_vector& v) { expr* q = nullptr; if (!is_inst(jst)) return false; @@ -54,11 +54,11 @@ namespace q { return qi == clause1.get(1); } - bool proof_checker::is_inst(expr* jst) { + bool theory_checker::is_inst(expr* jst) { return is_app(jst) && to_app(jst)->get_name() == m_inst && m.mk_proof_sort() == jst->get_sort(); } - bool proof_checker::is_bind(expr* e) { + bool theory_checker::is_bind(expr* e) { return is_app(e) && to_app(e)->get_name() == m_bind && m.mk_proof_sort() == e->get_sort(); } diff --git a/src/sat/smt/q_proof_checker.h b/src/sat/smt/q_theory_checker.h similarity index 83% rename from src/sat/smt/q_proof_checker.h rename to src/sat/smt/q_theory_checker.h index 4072739c7..70c9938fe 100644 --- a/src/sat/smt/q_proof_checker.h +++ b/src/sat/smt/q_theory_checker.h @@ -3,7 +3,7 @@ Copyright (c) 2022 Microsoft Corporation Module Name: - q_proof_checker.h + q_theory_checker.h Abstract: @@ -25,7 +25,7 @@ Author: namespace q { - class proof_checker : public euf::proof_checker_plugin { + class theory_checker : public euf::theory_checker_plugin { ast_manager& m; symbol m_inst; symbol m_bind; @@ -37,7 +37,7 @@ namespace q { bool is_bind(expr* e); public: - proof_checker(ast_manager& m): + theory_checker(ast_manager& m): m(m), m_inst("inst"), m_bind("bind") { @@ -47,7 +47,7 @@ namespace q { bool check(app* jst) override { return false; } - void register_plugins(euf::proof_checker& pc) override { + void register_plugins(euf::theory_checker& pc) override { pc.register_plugin(symbol("inst"), this); } diff --git a/src/sat/smt/recfun_solver.cpp b/src/sat/smt/recfun_solver.cpp index c88138d3f..ebb1ec7c1 100644 --- a/src/sat/smt/recfun_solver.cpp +++ b/src/sat/smt/recfun_solver.cpp @@ -180,7 +180,7 @@ namespace recfun { add_clause(clause); } - void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) { + void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) { UNREACHABLE(); } diff --git a/src/sat/smt/recfun_solver.h b/src/sat/smt/recfun_solver.h index 4e41a35a9..463aee6d6 100644 --- a/src/sat/smt/recfun_solver.h +++ b/src/sat/smt/recfun_solver.h @@ -92,7 +92,7 @@ namespace recfun { solver(euf::solver& ctx); ~solver() override; bool is_external(sat::bool_var v) override { return false; } - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) override; void asserted(sat::literal l) override; sat::check_result check() override; std::ostream& display(std::ostream& out) const override; diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_proof_checker.cpp index df0d60435..19f6e8660 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_proof_checker.cpp @@ -32,13 +32,13 @@ TODOs: namespace tseitin { - expr_ref_vector proof_checker::clause(app* jst) { + expr_ref_vector theory_checker::clause(app* jst) { expr_ref_vector result(m); result.append(jst->get_num_args(), jst->get_args()); return result; } - bool proof_checker::check(app* jst) { + bool theory_checker::check(app* jst) { expr* main_expr = nullptr; unsigned max_depth = 0; for (expr* arg : *jst) { @@ -231,7 +231,7 @@ namespace tseitin { return false; } - bool proof_checker::equiv(expr* a, expr* b) { + bool theory_checker::equiv(expr* a, expr* b) { if (a == b) return true; if (!is_app(a) || !is_app(b)) diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_proof_checker.h index 86a109ed8..8bbacd53b 100644 --- a/src/sat/smt/tseitin_proof_checker.h +++ b/src/sat/smt/tseitin_proof_checker.h @@ -25,7 +25,7 @@ Author: namespace tseitin { - class proof_checker : public euf::proof_checker_plugin { + class theory_checker : public euf::theory_checker_plugin { ast_manager& m; expr_fast_mark1 m_mark; @@ -52,12 +52,12 @@ namespace tseitin { } struct scoped_mark { - proof_checker& pc; - scoped_mark(proof_checker& pc): pc(pc) {} + theory_checker& pc; + scoped_mark(theory_checker& pc): pc(pc) {} ~scoped_mark() { pc.m_mark.reset(); pc.m_nmark.reset(); } }; public: - proof_checker(ast_manager& m): + theory_checker(ast_manager& m): m(m) { } @@ -65,7 +65,7 @@ namespace tseitin { bool check(app* jst) override; - void register_plugins(euf::proof_checker& pc) override { + void register_plugins(euf::theory_checker& pc) override { pc.register_plugin(symbol("tseitin"), this); } diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 5c98a6fac..34fd26c77 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -201,7 +201,7 @@ namespace user_solver { return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); } - void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) { + void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing, sat::proof_hint*& ph) { auto& j = justification::from_index(idx); auto const& prop = m_prop[j.m_propagation_index]; for (unsigned id : prop.m_ids) diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index 28528b9a1..c996d1878 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -152,7 +152,7 @@ namespace user_solver { void push_core() override; void pop_core(unsigned n) override; bool unit_propagate() override; - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing, sat::proof_hint*& ph) override; void collect_statistics(statistics& st) const override; sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; void internalize(expr* e, bool redundant) override; diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 091d8cd4d..b0b711ef0 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -5,20 +5,14 @@ Copyright (c) 2020 Microsoft Corporation #include #include -#include "ast/bv_decl_plugin.h" #include "util/memory_manager.h" #include "util/statistics.h" +#include "ast/proofs/proof_checker.h" +#include "ast/reg_decl_plugins.h" #include "sat/dimacs.h" #include "sat/sat_solver.h" #include "sat/sat_drat.h" -#include "smt/smt_solver.h" #include "shell/drat_frontend.h" -#include "parsers/smt2/smt2parser.h" -#include "cmd_context/cmd_context.h" -#include "ast/proofs/proof_checker.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/reg_decl_plugins.h" -#include "sat/smt/arith_proof_checker.h" class drup_checker { @@ -104,103 +98,3 @@ unsigned read_drat(char const* drat_file) { } return 0; } - - -#if 0 - - bool validate_hint(expr_ref_vector const& exprs, sat::literal_vector const& lits, sat::proof_hint const& hint) { - arith_util autil(m); - arith::proof_checker achecker(m); - proof_checker pc(m); - switch (hint.m_ty) { - case sat::hint_type::null_h: - break; - case sat::hint_type::bound_h: - case sat::hint_type::farkas_h: - case sat::hint_type::implied_eq_h: { - achecker.reset(); - for (auto const& [a, b]: hint.m_eqs) { - expr* x = exprs[a]; - expr* y = exprs[b]; - achecker.add_eq(x, y); - } - for (auto const& [a, b]: hint.m_diseqs) { - expr* x = exprs[a]; - expr* y = exprs[b]; - achecker.add_diseq(x, y); - } - - unsigned sz = hint.m_literals.size(); - for (unsigned i = 0; i < sz; ++i) { - auto const& [coeff, lit] = hint.m_literals[i]; - app_ref e(to_app(m_b2e[lit.var()]), m); - if (i + 1 == sz && sat::hint_type::bound_h == hint.m_ty) { - if (!achecker.add_conseq(coeff, e, lit.sign())) { - std::cout << "p failed checking hint " << e << "\n"; - return false; - } - - } - else if (!achecker.add_ineq(coeff, e, lit.sign())) { - std::cout << "p failed checking hint " << e << "\n"; - return false; - } - } - - // achecker.display(std::cout << "checking\n"); - bool ok = achecker.check(); - - if (!ok) { - rational lc(1); - for (auto const& [coeff, lit] : hint.m_literals) - lc = lcm(lc, denominator(coeff)); - bool is_strict = false; - expr_ref sum(m); - for (auto const& [coeff, lit] : hint.m_literals) { - app_ref e(to_app(m_b2e[lit.var()]), m); - VERIFY(pc.check_arith_literal(!lit.sign(), e, coeff*lc, sum, is_strict)); - std::cout << "sum: " << sum << "\n"; - } - sort* s = sum->get_sort(); - if (is_strict) - sum = autil.mk_lt(sum, autil.mk_numeral(rational(0), s)); - else - sum = autil.mk_le(sum, autil.mk_numeral(rational(0), s)); - th_rewriter rw(m); - rw(sum); - std::cout << "sum: " << sum << "\n"; - - for (auto const& [a, b]: hint.m_eqs) { - expr* x = exprs[a]; - expr* y = exprs[b]; - app_ref e(m.mk_eq(x, y), m); - std::cout << e << "\n"; - } - for (auto const& [a, b]: hint.m_diseqs) { - expr* x = exprs[a]; - expr* y = exprs[b]; - app_ref e(m.mk_not(m.mk_eq(x, y)), m); - std::cout << e << "\n"; - } - for (auto const& [coeff, lit] : hint.m_literals) { - app_ref e(to_app(m_b2e[lit.var()]), m); - if (lit.sign()) e = m.mk_not(e); - std::cout << e << "\n"; - } - achecker.display(std::cout); - std::cout << "p hint not verified\n"; - return false; - } - - std::cout << "p hint verified\n"; - return true; - break; - } - default: - UNREACHABLE(); - break; - } - return false; - } - -#endif From ea55f69a9294c7c8b803c96de4d84fd69c92aa57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2022 23:42:11 +0200 Subject: [PATCH 138/477] fix python build --- scripts/mk_project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index fa67f9340..2704a8735 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -51,14 +51,14 @@ def init_project_def(): add_lib('mbp', ['model', 'simplex'], 'qe/mbp') add_lib('qe_lite', ['tactic', 'mbp'], 'qe/lite') add_lib('solver_assertions', ['pattern','smt_params','cmd_context','qe_lite'], 'solver/assertions') - add_lib('sat_smt', ['sat', 'euf', 'tactic', 'solver', 'smt_params', 'bit_blaster', 'fpa', 'mbp', 'normal_forms', 'lp', 'pattern', 'qe_lite'], 'sat/smt') - add_lib('sat_tactic', ['tactic', 'sat', 'solver', 'sat_smt'], 'sat/tactic') - add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model') add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', 'solver_assertions', 'substitution', 'grobner', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp']) + add_lib('sat_smt', ['sat', 'euf', 'smt', 'tactic', 'solver', 'smt_params', 'bit_blaster', 'fpa', 'mbp', 'normal_forms', 'lp', 'pattern', 'qe_lite'], 'sat/smt') + add_lib('sat_tactic', ['tactic', 'sat', 'solver', 'sat_smt'], 'sat/tactic') + add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv') add_lib('fuzzing', ['ast'], 'test/fuzzing') add_lib('smt_tactic', ['smt'], 'smt/tactic') From 3ed791b16a629ad84558e570e387aa1139d30f5c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2022 15:01:42 -0700 Subject: [PATCH 139/477] fix build Signed-off-by: Nikolaj Bjorner --- src/sat/smt/xor_solver.cpp | 2 +- src/sat/smt/xor_solver.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/xor_solver.cpp b/src/sat/smt/xor_solver.cpp index 27354eac2..941cd21d4 100644 --- a/src/sat/smt/xor_solver.cpp +++ b/src/sat/smt/xor_solver.cpp @@ -37,7 +37,7 @@ namespace xr { } void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, - sat::literal_vector & r, bool probing) { + sat::literal_vector & r, bool probing, sat::proof_hint*& ph) { } diff --git a/src/sat/smt/xor_solver.h b/src/sat/smt/xor_solver.h index 3da30c580..0748e1e9b 100644 --- a/src/sat/smt/xor_solver.h +++ b/src/sat/smt/xor_solver.h @@ -30,7 +30,7 @@ namespace xr { void asserted(sat::literal l) override; bool unit_propagate() override; - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing, sat::proof_hint*& ph) override; void pre_simplify() override; void simplify() override; From d88384fd5137a702a12605ecddfc65c2c8cd37fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2022 15:03:46 -0700 Subject: [PATCH 140/477] fix compiler warning Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index c3269253f..e544d353b 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -277,7 +277,7 @@ public: m_proof_hint.reset(); } - void updt_params(params_ref const& p) { + void updt_params(params_ref const& p) override { solver_params sp(p); m_check = sp.proof_check(); m_save = sp.proof_save(); From a25247aa7bef669a55b0dbdfbd8fe39aeea108cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2022 17:18:08 -0700 Subject: [PATCH 141/477] wip - remove stale skaffolding for retrieving sub-hints. --- src/sat/sat_extension.h | 2 +- src/sat/sat_solver.cpp | 3 +-- src/sat/smt/arith_solver.cpp | 2 +- src/sat/smt/arith_solver.h | 2 +- src/sat/smt/array_solver.h | 2 +- src/sat/smt/bv_solver.cpp | 13 ++++++------- src/sat/smt/bv_solver.h | 2 +- src/sat/smt/dt_solver.cpp | 2 +- src/sat/smt/dt_solver.h | 2 +- src/sat/smt/euf_solver.cpp | 11 ++++++----- src/sat/smt/euf_solver.h | 2 +- src/sat/smt/fpa_solver.h | 2 +- src/sat/smt/pb_solver.cpp | 8 +++----- src/sat/smt/pb_solver.h | 2 +- src/sat/smt/q_solver.cpp | 2 +- src/sat/smt/q_solver.h | 2 +- src/sat/smt/recfun_solver.cpp | 2 +- src/sat/smt/recfun_solver.h | 2 +- src/sat/smt/user_solver.cpp | 2 +- src/sat/smt/user_solver.h | 2 +- src/sat/smt/xor_solver.cpp | 2 +- src/sat/smt/xor_solver.h | 2 +- 22 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 8f15f5f68..d6a956a32 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -89,7 +89,7 @@ namespace sat { virtual bool unit_propagate() = 0; virtual bool is_external(bool_var v) { return false; } virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const { return 0; } - virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r, bool probing, proof_hint*& ph) = 0; + virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r, bool probing) = 0; virtual bool is_extended_binary(ext_justification_idx idx, literal_vector & r) { return false; } virtual bool decide(bool_var& var, lbool& phase) { return false; } virtual bool get_case_split(bool_var& var, lbool& phase) { return false; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7f7b34ea8..8f9938dbb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2890,8 +2890,7 @@ namespace sat { SASSERT(m_ext); auto idx = js.get_ext_justification_idx(); m_ext_antecedents.reset(); - proof_hint* ph = nullptr; - m_ext->get_antecedents(consequent, idx, m_ext_antecedents, probing, ph); + m_ext->get_antecedents(consequent, idx, m_ext_antecedents, probing); } bool solver::is_two_phase() const { diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 5db5688b3..f7e3f6293 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1476,7 +1476,7 @@ namespace arith { return r; } - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) { auto& jst = euf::th_explain::from_index(idx); ctx.get_antecedents(l, jst, r, probing); } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 672477df2..3d3f1ddd7 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -485,7 +485,7 @@ namespace arith { solver(euf::solver& ctx, theory_id id); ~solver() override; bool is_external(bool_var v) override { return false; } - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override; void asserted(literal l) override; sat::check_result check() override; void simplify() override {} diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index f161af01a..5c2708842 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -278,7 +278,7 @@ namespace array { solver(euf::solver& ctx, theory_id id); ~solver() override; bool is_external(bool_var v) override { return false; } - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override {} + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override {} void asserted(literal l) override {} sat::check_result check() override; diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 631f954b1..8ef2c5cd5 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -306,7 +306,7 @@ namespace bv { bool solver::is_extended_binary(sat::ext_justification_idx idx, literal_vector& r) { return false; } bool solver::is_external(bool_var v) { return true; } - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) { auto& c = bv_justification::from_index(idx); TRACE("bv", display_constraint(tout, idx) << "\n";); switch (c.m_kind) { @@ -395,7 +395,6 @@ namespace bv { sat::literal leq1(s().num_vars() + 1, false); sat::literal leq2(s().num_vars() + 2, false); expr_ref eq1(m), eq2(m); - sat::proof_hint* ph = nullptr; if (c.m_kind == bv_justification::kind_t::bv2int) { eq1 = m.mk_eq(c.a->get_expr(), c.b->get_expr()); eq2 = m.mk_eq(c.a->get_expr(), c.c->get_expr()); @@ -417,24 +416,24 @@ namespace bv { lits.push_back(c.m_consequent); break; case bv_justification::kind_t::ne2bit: - get_antecedents(c.m_consequent, c.to_index(), lits, true, ph); + get_antecedents(c.m_consequent, c.to_index(), lits, true); lits.push_back(c.m_consequent); break; case bv_justification::kind_t::bit2eq: - get_antecedents(leq1, c.to_index(), lits, true, ph); + get_antecedents(leq1, c.to_index(), lits, true); for (auto& lit : lits) lit.neg(); lits.push_back(leq1); break; case bv_justification::kind_t::bit2ne: - get_antecedents(c.m_consequent, c.to_index(), lits, true, ph); + get_antecedents(c.m_consequent, c.to_index(), lits, true); for (auto& lit : lits) lit.neg(); lits.push_back(c.m_consequent); break; case bv_justification::kind_t::bv2int: - get_antecedents(leq1, c.to_index(), lits, true, ph); - get_antecedents(leq2, c.to_index(), lits, true, ph); + get_antecedents(leq1, c.to_index(), lits, true); + get_antecedents(leq2, c.to_index(), lits, true); for (auto& lit : lits) lit.neg(); lits.push_back(leq1); diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index 313679443..2c8fb4ae9 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -335,7 +335,7 @@ namespace bv { double get_reward(literal l, sat::ext_constraint_idx idx, sat::literal_occs_fun& occs) const override; bool is_extended_binary(sat::ext_justification_idx idx, literal_vector& r) override; bool is_external(bool_var v) override; - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) override; void asserted(literal l) override; sat::check_result check() override; void push_core() override; diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index 80846ec58..a87f8770b 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -755,7 +755,7 @@ namespace dt { SASSERT(m_find.get_num_vars() == get_num_vars()); } - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) { auto& jst = euf::th_explain::from_index(idx); ctx.get_antecedents(l, jst, r, probing); } diff --git a/src/sat/smt/dt_solver.h b/src/sat/smt/dt_solver.h index 136e40eac..4e2524f6b 100644 --- a/src/sat/smt/dt_solver.h +++ b/src/sat/smt/dt_solver.h @@ -140,7 +140,7 @@ namespace dt { ~solver() override; bool is_external(bool_var v) override { return false; } - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override; void asserted(literal l) override; sat::check_result check() override; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index cde3ef2e0..f0d40a13f 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -222,19 +222,19 @@ namespace euf { sub-hints. */ - void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) { m_egraph.begin_explain(); m_explain.reset(); if (use_drat() && !probing) push(restore_size_trail(m_explain_cc, m_explain_cc.size())); auto* ext = sat::constraint_base::to_extension(idx); th_proof_hint* hint = nullptr; - sat::proof_hint* shint = nullptr; bool has_theory = false; + bool has_nested_theory = false; if (ext == this) get_antecedents(l, constraint::from_idx(idx), r, probing); else { - ext->get_antecedents(l, idx, r, probing, shint); + ext->get_antecedents(l, idx, r, probing); has_theory = true; } for (unsigned qhead = 0; qhead < m_explain.size(); ++qhead) { @@ -246,12 +246,13 @@ namespace euf { auto* ext = sat::constraint_base::to_extension(idx); SASSERT(ext != this); sat::literal lit = sat::null_literal; - ext->get_antecedents(lit, idx, r, probing, shint); + ext->get_antecedents(lit, idx, r, probing); has_theory = true; + has_nested_theory = true; } } m_egraph.end_explain(); - if (use_drat() && !probing) { + if (use_drat() && !probing) { if (!has_theory) hint = mk_hint(l, r); else { diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index cedfcf2da..5e38768ee 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -338,7 +338,7 @@ namespace euf { bool set_root(literal l, literal r) override; void flush_roots() override; - void get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) override; void get_antecedents(literal l, th_explain& jst, literal_vector& r, bool probing); void add_antecedent(bool probing, enode* a, enode* b); void add_diseq_antecedent(ptr_vector& ex, cc_justification* cc, enode* a, enode* b); diff --git a/src/sat/smt/fpa_solver.h b/src/sat/smt/fpa_solver.h index 537ae0895..38abb399d 100644 --- a/src/sat/smt/fpa_solver.h +++ b/src/sat/smt/fpa_solver.h @@ -71,7 +71,7 @@ namespace fpa { void finalize_model(model& mdl) override; bool unit_propagate() override; - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) override { UNREACHABLE(); } + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override { UNREACHABLE(); } sat::check_result check() override; euf::th_solver* clone(euf::solver& ctx) override { return alloc(solver, ctx); } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 2a29f07d5..1c762cb3f 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -722,8 +722,7 @@ namespace pb { auto* ext = sat::constraint_base::to_extension(cindex); if (ext != this) { m_lemma.reset(); - sat::proof_hint* ph = nullptr; - ext->get_antecedents(consequent, idx, m_lemma, false, ph); + ext->get_antecedents(consequent, idx, m_lemma, false); for (literal l : m_lemma) process_antecedent(~l, offset); break; } @@ -1053,8 +1052,7 @@ namespace pb { auto* ext = sat::constraint_base::to_extension(index); if (ext != this) { m_lemma.reset(); - sat::proof_hint* ph = nullptr; - ext->get_antecedents(consequent, index, m_lemma, false, ph); + ext->get_antecedents(consequent, index, m_lemma, false); for (literal l : m_lemma) process_antecedent(~l, 1); break; @@ -1690,7 +1688,7 @@ namespace pb { // ---------------------------- // constraint generic methods - void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) { get_antecedents(l, index2constraint(idx), r, probing); } diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h index 9f9e6835c..09c0e47e0 100644 --- a/src/sat/smt/pb_solver.h +++ b/src/sat/smt/pb_solver.h @@ -377,7 +377,7 @@ namespace pb { bool propagated(literal l, sat::ext_constraint_idx idx) override; bool unit_propagate() override { return false; } lbool resolve_conflict() override; - void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) override; void asserted(literal l) override; sat::check_result check() override; void push() override; diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 7bddcbd9f..7fd7be97e 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -353,7 +353,7 @@ namespace q { return !m.is_and(arg) && !m.is_or(arg) && !m.is_iff(arg) && !m.is_implies(arg); } - void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) { m_ematch.get_antecedents(l, idx, r, probing); } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index f199db610..3a95a00be 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -83,7 +83,7 @@ namespace q { solver(euf::solver& ctx, family_id fid); bool is_external(sat::bool_var v) override { return false; } - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override; void asserted(sat::literal l) override; sat::check_result check() override; diff --git a/src/sat/smt/recfun_solver.cpp b/src/sat/smt/recfun_solver.cpp index ebb1ec7c1..c88138d3f 100644 --- a/src/sat/smt/recfun_solver.cpp +++ b/src/sat/smt/recfun_solver.cpp @@ -180,7 +180,7 @@ namespace recfun { add_clause(clause); } - void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) { UNREACHABLE(); } diff --git a/src/sat/smt/recfun_solver.h b/src/sat/smt/recfun_solver.h index 463aee6d6..4e41a35a9 100644 --- a/src/sat/smt/recfun_solver.h +++ b/src/sat/smt/recfun_solver.h @@ -92,7 +92,7 @@ namespace recfun { solver(euf::solver& ctx); ~solver() override; bool is_external(sat::bool_var v) override { return false; } - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) override; void asserted(sat::literal l) override; sat::check_result check() override; std::ostream& display(std::ostream& out) const override; diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 34fd26c77..5c98a6fac 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -201,7 +201,7 @@ namespace user_solver { return sat::justification::mk_ext_justification(s().scope_lvl(), constraint->to_index()); } - void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing, sat::proof_hint*& ph) { + void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) { auto& j = justification::from_index(idx); auto const& prop = m_prop[j.m_propagation_index]; for (unsigned id : prop.m_ids) diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index c996d1878..28528b9a1 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -152,7 +152,7 @@ namespace user_solver { void push_core() override; void pop_core(unsigned n) override; bool unit_propagate() override; - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override; void collect_statistics(statistics& st) const override; sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; void internalize(expr* e, bool redundant) override; diff --git a/src/sat/smt/xor_solver.cpp b/src/sat/smt/xor_solver.cpp index 941cd21d4..27354eac2 100644 --- a/src/sat/smt/xor_solver.cpp +++ b/src/sat/smt/xor_solver.cpp @@ -37,7 +37,7 @@ namespace xr { } void solver::get_antecedents(sat::literal l, sat::ext_justification_idx idx, - sat::literal_vector & r, bool probing, sat::proof_hint*& ph) { + sat::literal_vector & r, bool probing) { } diff --git a/src/sat/smt/xor_solver.h b/src/sat/smt/xor_solver.h index 0748e1e9b..3da30c580 100644 --- a/src/sat/smt/xor_solver.h +++ b/src/sat/smt/xor_solver.h @@ -30,7 +30,7 @@ namespace xr { void asserted(sat::literal l) override; bool unit_propagate() override; - void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing, sat::proof_hint*& ph) override; + void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override; void pre_simplify() override; void simplify() override; From 5b76a7c2f2710c5c33a80ddb843f078db66f230f Mon Sep 17 00:00:00 2001 From: Gleb Popov <6yearold@gmail.com> Date: Mon, 17 Oct 2022 20:14:04 +0300 Subject: [PATCH 142/477] Enable HAS_MALLOC_USABLE_SIZE on FreeBSD (#6402) --- src/util/memory_manager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 85d673f7c..a2c8e31a4 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -17,6 +17,10 @@ Copyright (c) 2015 Microsoft Corporation # include # define HAS_MALLOC_USABLE_SIZE #endif +#ifdef __FreeBSD__ +# include +# define HAS_MALLOC_USABLE_SIZE +#endif // The following two function are automatically generated by the mk_make.py script. // The script collects ADD_INITIALIZER and ADD_FINALIZER commands in the .h files. From 98fe2e637a23ceef08aaea3eae5bf7da212276b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2022 10:17:08 -0700 Subject: [PATCH 143/477] add generic theory lemma in default case. Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_proof.cpp | 17 +++++++++++++++++ src/sat/smt/euf_solver.h | 1 + src/sat/smt/sat_th.cpp | 4 +++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index dbabb1a7b..78b207f94 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -166,7 +166,24 @@ namespace euf { return m.mk_app(f, args); } + smt_proof_hint* solver::mk_smt_clause(symbol const& n, unsigned nl, literal const* lits) { + if (!use_drat()) + return nullptr; + push(value_trail(m_lit_tail)); + push(restore_size_trail(m_proof_literals)); + for (unsigned i = 0; i < nl; ++i) + m_proof_literals.push_back(~lits[i]); + + m_lit_head = m_lit_tail; + m_eq_head = m_eq_tail; + m_deq_head = m_deq_tail; + m_lit_tail = m_proof_literals.size(); + m_eq_tail = m_proof_eqs.size(); + m_deq_tail = m_proof_deqs.size(); + + return new (get_region()) smt_proof_hint(n, m_lit_head, m_lit_tail, m_eq_head, m_eq_tail, m_deq_head, m_deq_tail); + } smt_proof_hint* solver::mk_smt_hint(symbol const& n, unsigned nl, literal const* lits, unsigned ne, expr_pair const* eqs, unsigned nd, expr_pair const* deqs) { if (!use_drat()) diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 5e38768ee..62e7abcae 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -404,6 +404,7 @@ namespace euf { smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, expr* a, expr* b) { expr_pair e(a, b); return mk_smt_hint(n, 1, &lit, 0, nullptr, 1, &e); } smt_proof_hint* mk_smt_prop_hint(symbol const& n, literal lit, enode* a, enode* b) { return mk_smt_prop_hint(n, lit, a->get_expr(), b->get_expr()); } smt_proof_hint* mk_smt_hint(symbol const& n, enode* a, enode* b) { expr_pair e(a->get_expr(), b->get_expr()); return mk_smt_hint(n, 0, nullptr, 1, &e); } + smt_proof_hint* mk_smt_clause(symbol const& n, unsigned nl, literal const* lits); th_proof_hint* mk_cc_proof_hint(sat::literal_vector const& ante, app* a, app* b); th_proof_hint* mk_tc_proof_hint(sat::literal const* ternary_clause); sat::status mk_tseitin_status(sat::literal a, sat::literal b); diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index bf2e04dc5..ad280eff8 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -160,7 +160,9 @@ namespace euf { } bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps) { - SASSERT(!ctx.use_drat() || ps); // - very far from true, and isn't a requirement + if (ctx.use_drat() && !ps) + ps = ctx.mk_smt_clause(name(), n, lits); + bool was_true = false; for (unsigned i = 0; i < n; ++i) was_true |= is_true(lits[i]); From 541aba308cdd01070515e11c9d5e3fbab98d27a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2022 10:27:15 -0700 Subject: [PATCH 144/477] fix #6401 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 8f227649c..ca3bc6f53 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6653,7 +6653,7 @@ class ModelRef(Z3PPObject): n = Z3_func_entry_get_num_args(x.ctx_ref(), e.entry) v = AstVector() for j in range(n): - v.push(entry.arg_value(j)) + v.push(e.arg_value(j)) val = Z3_func_entry_get_value(x.ctx_ref(), e.entry) Z3_func_interp_add_entry(x.ctx_ref(), fi2.f, v.vector, val) return From d4885abdc0579ed40bd23848d5e3ee07d1c3bfa7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2022 11:00:21 -0700 Subject: [PATCH 145/477] fix #6400 bi-implication was treated as an atomic formula leading to incorrect projection. --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 14 ++++++++++++-- src/qe/mbp/mbp_term_graph.cpp | 24 ++++++++---------------- src/qe/qe_mbi.cpp | 9 ++++----- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index c6f0b479a..278c0a205 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -405,8 +405,18 @@ public: if (!m.is_bool(*m_a) || !m.is_bool(*m_b)) throw default_exception("interpolation requires two Boolean arguments"); expr_ref itp(m); - mbi.pogo(ctx.get_solver_factory(), *m_a, *m_b, itp); - ctx.regular_stream() << itp << "\n"; + lbool r = mbi.pogo(ctx.get_solver_factory(), *m_a, *m_b, itp); + switch (r) { + case l_true: + ctx.regular_stream() << "sat\n"; + break; + case l_undef: + ctx.regular_stream() << "unknown\n"; + break; + case l_false: + ctx.regular_stream() << itp << "\n"; + break; + } } }; diff --git a/src/qe/mbp/mbp_term_graph.cpp b/src/qe/mbp/mbp_term_graph.cpp index 47cece75a..4709c8c72 100644 --- a/src/qe/mbp/mbp_term_graph.cpp +++ b/src/qe/mbp/mbp_term_graph.cpp @@ -307,9 +307,8 @@ namespace mbp { term *term_graph::mk_term(expr *a) { expr_ref e(a, m); term * t = alloc(term, e, m_app2term); - if (t->get_num_args() == 0 && m.is_unique_value(a)){ + if (t->get_num_args() == 0 && m.is_unique_value(a)) t->mark_as_interpreted(); - } m_terms.push_back(t); m_app2term.insert(a->get_id(), t); @@ -700,30 +699,23 @@ namespace mbp { if (p1 != p2) res.push_back(m.mk_eq(p1, p2)); } - else { + else TRACE("qe", tout << "skipping " << mk_pp(lit, m) << "\n";); - } } else if (m.is_distinct(lit)) { ptr_buffer diff; - for (expr* arg : *to_app(lit)) { - if (find_app(arg, p1)) { + for (expr* arg : *to_app(lit)) + if (find_app(arg, p1)) diff.push_back(p1); - } - } - if (diff.size() > 1) { + if (diff.size() > 1) res.push_back(m.mk_distinct(diff.size(), diff.data())); - } - else { + else TRACE("qe", tout << "skipping " << mk_pp(lit, m) << "\n";); - } } - else if (find_app(lit, p1)) { + else if (find_app(lit, p1)) res.push_back(p1); - } - else { + else TRACE("qe", tout << "skipping " << mk_pp(lit, m) << "\n";); - } } remove_duplicates(res); TRACE("qe", tout << "literals: " << res << "\n";); diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index b261e44be..dea1b11c0 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -127,6 +127,7 @@ namespace qe { mbi_result prop_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { lbool r = m_solver->check_sat(lits); + TRACE("qe", tout << r << " " << lits << "\n"); switch (r) { case l_false: lits.reset(); @@ -138,12 +139,10 @@ namespace qe { for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { func_decl* c = mdl->get_constant(i); if (is_shared(c)) { - if (m.is_true(mdl->get_const_interp(c))) { + if (m.is_true(mdl->get_const_interp(c))) lits.push_back(m.mk_const(c)); - } - else if (m.is_false(mdl->get_const_interp(c))) { + else if (m.is_false(mdl->get_const_interp(c))) lits.push_back(m.mk_not(m.mk_const(c))); - } } } return mbi_sat; @@ -172,7 +171,7 @@ namespace qe { if (m_atom_set.contains(a)) { // continue } - else if (m.is_eq(a)) { + else if (m.is_eq(a) && !m.is_iff(a)) { m_atoms.push_back(a); m_atom_set.insert(a); } From f175fcbb54c3bd18de96cc9b889e110cf4234809 Mon Sep 17 00:00:00 2001 From: Walden Yan Date: Mon, 17 Oct 2022 14:10:36 -0400 Subject: [PATCH 146/477] JS/TS API Array support (#6393) * feat: basic array support Still need deeper type support for Arrays * fixed broken format rules * spaces inside curly * feat: range sort type inference * feat: better type inference in model eval * doc: fixed some incorrect documentation * feat: domain type inference * feat: addressed suggestions * feat: addressed suggestions * chore: moved ts-expect from deps to dev-deps * test: added z3guide examples * fix: removed ts-expect from dependencies again * docs: fixed some documentation --- src/api/js/package-lock.json | 8312 +++--------------- src/api/js/package.json | 4 +- src/api/js/src/high-level/high-level.test.ts | 104 +- src/api/js/src/high-level/high-level.ts | 244 +- src/api/js/src/high-level/types.ts | 438 +- 5 files changed, 1767 insertions(+), 7335 deletions(-) diff --git a/src/api/js/package-lock.json b/src/api/js/package-lock.json index d736468a9..c0ece3ae4 100644 --- a/src/api/js/package-lock.json +++ b/src/api/js/package-lock.json @@ -1,6579 +1,7 @@ { "name": "z3-solver", - "lockfileVersion": 2, "requires": true, - "packages": { - "": { - "name": "z3-solver", - "license": "MIT", - "dependencies": { - "async-mutex": "^0.3.2" - }, - "devDependencies": { - "@types/jest": "^27.5.1", - "@types/node": "^17.0.8", - "@types/prettier": "^2.6.1", - "@types/sprintf-js": "^1.1.2", - "check-engine": "^1.10.1", - "iter-tools": "^7.3.1", - "jest": "^28.1.0", - "npm-run-all": "^4.1.5", - "prettier": "^2.5.1", - "rimraf": "^3.0.2", - "sprintf-js": "^1.1.2", - "ts-jest": "^28.0.3", - "ts-node": "^10.8.0", - "typedoc": "^0.22.17", - "typescript": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", - "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", - "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", - "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", - "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", - "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", - "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", - "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", - "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz", - "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", - "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", - "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", - "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-environment-visitor": "^7.18.2", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.18.0", - "@babel/types": "^7.18.2", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz", - "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.0.tgz", - "integrity": "sha512-tscn3dlJFGay47kb4qVruQg/XWlmvU0xp3EJOjzzY+sBaI+YgwKcvAmTcyYU7xEiLLIY5HCdWRooAL8dqkFlDA==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^28.1.0", - "jest-util": "^28.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.0.tgz", - "integrity": "sha512-/2PTt0ywhjZ4NwNO4bUqD9IVJfmFVhVKGlhvSpmEfUCuxYf/3NHcKmRFI+I71lYzbTT3wMuYpETDCTHo81gC/g==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.0", - "@jest/reporters": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.0.2", - "jest-config": "^28.1.0", - "jest-haste-map": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.0", - "jest-resolve-dependencies": "^28.1.0", - "jest-runner": "^28.1.0", - "jest-runtime": "^28.1.0", - "jest-snapshot": "^28.1.0", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", - "jest-watcher": "^28.1.0", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", - "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/node": "*", - "jest-mock": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.0.tgz", - "integrity": "sha512-be9ETznPLaHOmeJqzYNIXv1ADEzENuQonIoobzThOYPuK/6GhrWNIJDVTgBLCrz3Am73PyEU2urQClZp0hLTtA==", - "dev": true, - "dependencies": { - "expect": "^28.1.0", - "jest-snapshot": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.0.tgz", - "integrity": "sha512-5BrG48dpC0sB80wpeIX5FU6kolDJI4K0n5BM9a5V38MGx0pyRvUBSS0u2aNTdDzmOrCjhOg8pGs6a20ivYkdmw==", - "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", - "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "@sinonjs/fake-timers": "^9.1.1", - "@types/node": "*", - "jest-message-util": "^28.1.0", - "jest-mock": "^28.1.0", - "jest-util": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.0.tgz", - "integrity": "sha512-3m7sTg52OTQR6dPhsEQSxAvU+LOBbMivZBwOvKEZ+Rb+GyxVnXi9HKgOTYkx/S99T8yvh17U4tNNJPIEQmtwYw==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.0", - "@jest/expect": "^28.1.0", - "@jest/types": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.0.tgz", - "integrity": "sha512-qxbFfqap/5QlSpIizH9c/bFCDKsQlM4uAKSOvZrP+nIdrjqre3FmKzpTtYyhsaVcOSNK7TTt2kjm+4BJIjysFA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", - "@jridgewell/trace-mapping": "^0.3.7", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-util": "^28.1.0", - "jest-worker": "^28.1.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", - "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.23.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", - "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.7", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.0.tgz", - "integrity": "sha512-sBBFIyoPzrZho3N+80P35A5oAkSKlGfsEFfXFWuPGBsW40UAjCkGakZhn4UQK4iQlW2vgCDMRDOob9FGKV8YoQ==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.0.tgz", - "integrity": "sha512-tZCEiVWlWNTs/2iK9yi6o3AlMfbbYgV4uuZInSVdzZ7ftpHZhCMuhvk2HLYhCZzLgPFQ9MnM1YaxMnh3TILFiQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^28.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.0.tgz", - "integrity": "sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^28.1.0", - "@jridgewell/trace-mapping": "^0.3.7", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", - "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", - "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", - "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==", - "dev": true, - "dependencies": { - "jest-matcher-utils": "^27.0.0", - "pretty-format": "^27.0.0" - } - }, - "node_modules/@types/node": { - "version": "17.0.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prettier": { - "version": "2.6.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/sprintf-js": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.7.1", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/argparse/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async-mutex": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.3.2.tgz", - "integrity": "sha512-HuTK7E7MT7jZEh1P9GtRW9+aTWiDWWi9InbZ5hjxrnRa39KS4BW04+xLBhYNS2aXhHUIKZSw3gj4Pn1pj+qGAA==", - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/babel-jest": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", - "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", - "dev": true, - "dependencies": { - "@jest/transform": "^28.1.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.0.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", - "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", - "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^28.0.2", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001344", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", - "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/check-engine": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/check-engine/-/check-engine-1.10.1.tgz", - "integrity": "sha512-KqZ6sV7onqcc81qoK+NsCNjNfik1rRHzmxYJ+tDdCc+6nbpaj0X8SKSzb8lYIcQ+ire5ypMr4YP832/7RH843Q==", - "dev": true, - "dependencies": { - "bluebird": "3.7.2", - "colors": "1.4.0", - "command-line-usage": "6.1.0", - "jsonfile": "6.0.1", - "semver": "7.3.2", - "yargs": "16.1.0" - }, - "bin": { - "check-engine": "bin/check-engine.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/check-engine/node_modules/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/check-engine/node_modules/yargs": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.1.0.tgz", - "integrity": "sha512-upWFJOmDdHN0syLuESuvXDmrRcWd1QafJolHskzaw79uZa7/x53gxQKiR07W59GWY1tFhhU/Th9DrtSfpS782g==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.2", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", - "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", - "dev": true - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/command-line-usage": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.0.tgz", - "integrity": "sha512-Ew1clU4pkUeo6AFVDFxCbnN7GIZfXl48HIOQeFQnkO3oOqvpI7wdqtLRwv9iOCZ/7A+z4csVZeiDdEcj8g6Wiw==", - "dev": true, - "dependencies": { - "array-back": "^4.0.0", - "chalk": "^2.4.2", - "table-layout": "^1.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.140", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.140.tgz", - "integrity": "sha512-NLz5va823QfJBYOO/hLV4AfU4Crmkl/6Hl2pH3qdJcmi0ySZ3YTWHxOlDm3uJOFBEPy3pIhu8gKQo6prQTWKKA==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", - "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.20.1", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/execa/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.0.tgz", - "integrity": "sha512-qFXKl8Pmxk8TBGfaFKRtcQjfXEnKAs+dmlxdwvukJZorwrAabT7M3h8oLOG01I2utEhkmUTi17CHaPBovZsKdw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^28.1.0", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-util": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/expect/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/expect/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/expect/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/expect/node_modules/diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/expect/node_modules/jest-diff": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", - "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/jest-matcher-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", - "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.0", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/expect/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/expect/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/expect/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "dev": true, - "license": "ISC" - }, - "node_modules/has": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "dev": true, - "license": "ISC" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "license": "ISC" - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.9.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/iter-tools": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/iter-tools/-/iter-tools-7.3.1.tgz", - "integrity": "sha512-XYS0CjthZqQ7MomjB4Ww9NqrVKRlP2qoa1oWFcIQrkMykhkgFTpSNG+sRcqzHBp6fSxk8oDIjudFTgQ6nnA4mA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.1" - } - }, - "node_modules/jest": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", - "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", - "dev": true, - "dependencies": { - "@jest/core": "^28.1.0", - "import-local": "^3.0.2", - "jest-cli": "^28.1.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", - "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.0.tgz", - "integrity": "sha512-rNYfqfLC0L0zQKRKsg4n4J+W1A2fbyGH7Ss/kDIocp9KXD9iaL111glsLu7+Z7FHuZxwzInMDXq+N1ZIBkI/TQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.0", - "@jest/expect": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.0", - "jest-matcher-utils": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-runtime": "^28.1.0", - "jest-snapshot": "^28.1.0", - "jest-util": "^28.1.0", - "pretty-format": "^28.1.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/jest-diff": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", - "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/jest-matcher-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", - "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.0", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.0.tgz", - "integrity": "sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==", - "dev": true, - "dependencies": { - "@jest/core": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/types": "^28.1.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^28.1.0", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.0.tgz", - "integrity": "sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.0", - "@jest/types": "^28.1.0", - "babel-jest": "^28.1.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.0", - "jest-environment-node": "^28.1.0", - "jest-get-type": "^28.0.2", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.0", - "jest-runner": "^28.1.0", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^28.1.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-docblock": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", - "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-each": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.0.tgz", - "integrity": "sha512-a/XX02xF5NTspceMpHujmOexvJ4GftpYXqr6HhhmKmExtMXsyIN/fvanQlt/BcgFoRKN4OCXxLQKth9/n6OPFg==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "jest-util": "^28.1.0", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-node": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.0.tgz", - "integrity": "sha512-gBLZNiyrPw9CSMlTXF1yJhaBgWDPVvH0Pq6bOEwGMXaYNzhzhw2kA/OijNF8egbCgDS0/veRv97249x2CX+udQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.0", - "@jest/fake-timers": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/node": "*", - "jest-mock": "^28.1.0", - "jest-util": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.0.tgz", - "integrity": "sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.0", - "jest-worker": "^28.1.0", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.0.tgz", - "integrity": "sha512-uIJDQbxwEL2AMMs2xjhZl2hw8s77c3wrPaQ9v6tXJLGaaQ+4QrNJH5vuw7hA7w/uGT/iJ42a83opAqxGHeyRIA==", - "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", - "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", - "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "@types/node": "*" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", - "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.0.tgz", - "integrity": "sha512-vvfN7+tPNnnhDvISuzD1P+CRVP8cK0FHXRwPAcdDaQv4zgvwvag2n55/h5VjYcM5UJG7L4TwE5tZlzcI0X2Lhw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.0.tgz", - "integrity": "sha512-Ue1VYoSZquPwEvng7Uefw8RmZR+me/1kr30H2jMINjGeHgeO/JgrR6wxj2ofkJ7KSAA11W3cOrhNCbj5Dqqd9g==", - "dev": true, - "dependencies": { - "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.0.tgz", - "integrity": "sha512-FBpmuh1HB2dsLklAlRdOxNTTHKFR6G1Qmd80pVDvwbZXTriqjWqjei5DKFC1UlM732KjYcE6yuCdiF0WUCOS2w==", - "dev": true, - "dependencies": { - "@jest/console": "^28.1.0", - "@jest/environment": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "graceful-fs": "^4.2.9", - "jest-docblock": "^28.0.2", - "jest-environment-node": "^28.1.0", - "jest-haste-map": "^28.1.0", - "jest-leak-detector": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-resolve": "^28.1.0", - "jest-runtime": "^28.1.0", - "jest-util": "^28.1.0", - "jest-watcher": "^28.1.0", - "jest-worker": "^28.1.0", - "source-map-support": "0.5.13", - "throat": "^6.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.0.tgz", - "integrity": "sha512-wNYDiwhdH/TV3agaIyVF0lsJ33MhyujOe+lNTUiolqKt8pchy1Hq4+tDMGbtD5P/oNLA3zYrpx73T9dMTOCAcg==", - "dev": true, - "dependencies": { - "@jest/environment": "^28.1.0", - "@jest/fake-timers": "^28.1.0", - "@jest/globals": "^28.1.0", - "@jest/source-map": "^28.0.2", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-mock": "^28.1.0", - "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.0", - "jest-snapshot": "^28.1.0", - "jest-util": "^28.1.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.0.tgz", - "integrity": "sha512-ex49M2ZrZsUyQLpLGxQtDbahvgBjlLPgklkqGM0hq/F7W/f8DyqZxVHjdy19QKBm4O93eDp+H5S23EiTbbUmHw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^28.1.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.0", - "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.0", - "jest-matcher-utils": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-util": "^28.1.0", - "natural-compare": "^1.4.0", - "pretty-format": "^28.1.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", - "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", - "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.0", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", - "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.0.tgz", - "integrity": "sha512-Lly7CJYih3vQBfjLeANGgBSBJ7pEa18cxpQfQEq2go2xyEzehnHfQTjoUia8xUv4x4J80XKFIDwJJThXtRFQXQ==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^28.0.2", - "leven": "^3.1.0", - "pretty-format": "^28.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.0.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.0.tgz", - "integrity": "sha512-tNHMtfLE8Njcr2IRS+5rXYA4BhU90gAOwI9frTGOqd+jX0P/Au/JfRSNqsf5nUTcWdbVYuLxS1KjnzILSoR5hA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^28.1.0", - "@jest/types": "^28.1.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.10.2", - "jest-util": "^28.1.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.0.tgz", - "integrity": "sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", - "dev": true, - "dependencies": { - "universalify": "^1.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/marked": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", - "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-inspect": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.3.1", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "dev": true, - "license": "MIT" - }, - "node_modules/shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", - "dev": true, - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.11", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/sprintf-js": { - "version": "1.1.2", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.padend": { - "version": "3.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/table-layout": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", - "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", - "dev": true, - "dependencies": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-jest": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.3.tgz", - "integrity": "sha512-HzgbEDQ2KgVtDmpXToqAcKTyGHdHsG23i/iUjfxji92G5eT09S1m9UHZd7csF0Bfgh9txM4JzwHnv7r1waFPlw==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^28.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^20.x" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@types/jest": "^27.0.0", - "babel-jest": "^28.0.0", - "jest": "^28.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "10.8.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedoc": { - "version": "0.22.17", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", - "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", - "dev": true, - "dependencies": { - "glob": "^8.0.3", - "lunr": "^2.3.9", - "marked": "^4.0.16", - "minimatch": "^5.1.0", - "shiki": "^0.10.1" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 12.10.0" - }, - "peerDependencies": { - "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x || 4.7.x" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typescript": { - "version": "4.7.2", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", - "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.7", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", - "dev": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "1.3.1", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wordwrapjs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", - "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", - "dev": true, - "dependencies": { - "reduce-flatten": "^2.0.0", - "typical": "^5.2.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - } - }, + "lockfileVersion": 1, "dependencies": { "@ampproject/remapping": { "version": "2.2.0", @@ -6586,36 +14,36 @@ } }, "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.18.6" } }, "@babel/compat-data": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", - "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", "dev": true }, "@babel/core": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", - "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", + "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-compilation-targets": "^7.18.2", - "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.2", - "@babel/parser": "^7.18.0", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.3", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.3", + "@babel/types": "^7.19.3", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -6632,23 +60,23 @@ } }, "@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.5.tgz", + "integrity": "sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==", "dev": true, "requires": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, "dependencies": { "@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.0.0", + "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.9" } @@ -6656,14 +84,14 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", - "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", "dev": true, "requires": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.20.2", + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", "semver": "^6.3.0" }, "dependencies": { @@ -6676,117 +104,123 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", - "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true }, "@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", "dev": true, "requires": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" } }, "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, "@babel/helper-module-transforms": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", - "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" } }, "@babel/helper-plugin-utils": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", - "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", "dev": true }, "@babel/helper-simple-access": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", - "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", "dev": true, "requires": { - "@babel/types": "^7.18.2" + "@babel/types": "^7.19.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.18.6" } }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", "dev": true }, "@babel/helpers": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", - "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", "dev": true, "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.2", - "@babel/types": "^7.18.2" + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" } }, "@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz", - "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.4.tgz", + "integrity": "sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -6898,59 +332,60 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", - "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", + "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.17.12" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/runtime": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz", - "integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", - "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz", + "integrity": "sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-environment-visitor": "^7.18.2", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.18.0", - "@babel/types": "^7.18.2", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.4", + "@babel/types": "^7.19.4", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz", - "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" } }, @@ -6962,9 +397,23 @@ }, "@cspotcode/source-map-support": { "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "requires": { "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } } }, "@istanbuljs/load-nyc-config": { @@ -6987,16 +436,16 @@ "dev": true }, "@jest/console": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.0.tgz", - "integrity": "sha512-tscn3dlJFGay47kb4qVruQg/XWlmvU0xp3EJOjzzY+sBaI+YgwKcvAmTcyYU7xEiLLIY5HCdWRooAL8dqkFlDA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", "dev": true, "requires": { - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^28.1.0", - "jest-util": "^28.1.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0" }, "dependencies": { @@ -7052,37 +501,37 @@ } }, "@jest/core": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.0.tgz", - "integrity": "sha512-/2PTt0ywhjZ4NwNO4bUqD9IVJfmFVhVKGlhvSpmEfUCuxYf/3NHcKmRFI+I71lYzbTT3wMuYpETDCTHo81gC/g==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", "dev": true, "requires": { - "@jest/console": "^28.1.0", - "@jest/reporters": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^28.0.2", - "jest-config": "^28.1.0", - "jest-haste-map": "^28.1.0", - "jest-message-util": "^28.1.0", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.0", - "jest-resolve-dependencies": "^28.1.0", - "jest-runner": "^28.1.0", - "jest-runtime": "^28.1.0", - "jest-snapshot": "^28.1.0", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", - "jest-watcher": "^28.1.0", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", "micromatch": "^4.0.4", - "pretty-format": "^28.1.0", + "pretty-format": "^28.1.3", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" @@ -7129,12 +578,12 @@ "dev": true }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -7149,9 +598,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -7166,73 +615,81 @@ } }, "@jest/environment": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", - "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", "dev": true, "requires": { - "@jest/fake-timers": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^28.1.0" + "jest-mock": "^28.1.3" } }, "@jest/expect": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.0.tgz", - "integrity": "sha512-be9ETznPLaHOmeJqzYNIXv1ADEzENuQonIoobzThOYPuK/6GhrWNIJDVTgBLCrz3Am73PyEU2urQClZp0hLTtA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", "dev": true, "requires": { - "expect": "^28.1.0", - "jest-snapshot": "^28.1.0" + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" } }, "@jest/expect-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.0.tgz", - "integrity": "sha512-5BrG48dpC0sB80wpeIX5FU6kolDJI4K0n5BM9a5V38MGx0pyRvUBSS0u2aNTdDzmOrCjhOg8pGs6a20ivYkdmw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", "dev": true, "requires": { "jest-get-type": "^28.0.2" + }, + "dependencies": { + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + } } }, "@jest/fake-timers": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", - "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", "dev": true, "requires": { - "@jest/types": "^28.1.0", - "@sinonjs/fake-timers": "^9.1.1", + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", "@types/node": "*", - "jest-message-util": "^28.1.0", - "jest-mock": "^28.1.0", - "jest-util": "^28.1.0" + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" } }, "@jest/globals": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.0.tgz", - "integrity": "sha512-3m7sTg52OTQR6dPhsEQSxAvU+LOBbMivZBwOvKEZ+Rb+GyxVnXi9HKgOTYkx/S99T8yvh17U4tNNJPIEQmtwYw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", "dev": true, "requires": { - "@jest/environment": "^28.1.0", - "@jest/expect": "^28.1.0", - "@jest/types": "^28.1.0" + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" } }, "@jest/reporters": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.0.tgz", - "integrity": "sha512-qxbFfqap/5QlSpIizH9c/bFCDKsQlM4uAKSOvZrP+nIdrjqre3FmKzpTtYyhsaVcOSNK7TTt2kjm+4BJIjysFA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", - "@jridgewell/trace-mapping": "^0.3.7", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -7244,13 +701,14 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-util": "^28.1.0", - "jest-worker": "^28.1.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^9.0.0" + "v8-to-istanbul": "^9.0.1" }, "dependencies": { "ansi-styles": { @@ -7305,66 +763,66 @@ } }, "@jest/schemas": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", - "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", "dev": true, "requires": { - "@sinclair/typebox": "^0.23.3" + "@sinclair/typebox": "^0.24.1" } }, "@jest/source-map": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", - "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.7", + "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", "graceful-fs": "^4.2.9" } }, "@jest/test-result": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.0.tgz", - "integrity": "sha512-sBBFIyoPzrZho3N+80P35A5oAkSKlGfsEFfXFWuPGBsW40UAjCkGakZhn4UQK4iQlW2vgCDMRDOob9FGKV8YoQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", "dev": true, "requires": { - "@jest/console": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.0.tgz", - "integrity": "sha512-tZCEiVWlWNTs/2iK9yi6o3AlMfbbYgV4uuZInSVdzZ7ftpHZhCMuhvk2HLYhCZzLgPFQ9MnM1YaxMnh3TILFiQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", "dev": true, "requires": { - "@jest/test-result": "^28.1.0", + "@jest/test-result": "^28.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", + "jest-haste-map": "^28.1.3", "slash": "^3.0.0" } }, "@jest/transform": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.0.tgz", - "integrity": "sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/types": "^28.1.0", - "@jridgewell/trace-mapping": "^0.3.7", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", + "jest-haste-map": "^28.1.3", "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.0", + "jest-util": "^28.1.3", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -7423,12 +881,12 @@ } }, "@jest/types": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", - "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", @@ -7498,31 +956,37 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.7", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true }, "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.13", + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.9", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@sinclair/typebox": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", - "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "version": "0.24.46", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.46.tgz", + "integrity": "sha512-ng4ut1z2MCBhK/NwDVwIQp3pAUOCs/KNaW3cBxdFB2xTDrOuo1xuNmpr/9HHFhxqIvHrs1NTH3KJg6q+JSy1Kw==", "dev": true }, "@sinonjs/commons": { @@ -7544,19 +1008,27 @@ } }, "@tsconfig/node10": { - "version": "1.0.8", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", "dev": true }, "@tsconfig/node12": { - "version": "1.0.9", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true }, "@tsconfig/node14": { - "version": "1.0.1", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, "@tsconfig/node16": { - "version": "1.0.2", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, "@types/babel__core": { @@ -7592,9 +1064,9 @@ } }, "@types/babel__traverse": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", - "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -7634,9 +1106,9 @@ } }, "@types/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ==", + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", "dev": true, "requires": { "jest-matcher-utils": "^27.0.0", @@ -7644,15 +1116,21 @@ } }, "@types/node": { - "version": "17.0.8", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "@types/prettier": { - "version": "2.6.1", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", "dev": true }, "@types/sprintf-js": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-hkgzYF+qnIl8uTO8rmUSVSfQ8BIfMXC4yJAF4n8BE758YsKBZvFC4NumnAegj7KmylP0liEZNpb9RRGFMbFejA==", "dev": true }, "@types/stack-utils": { @@ -7662,9 +1140,9 @@ "dev": true }, "@types/yargs": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", - "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -7677,11 +1155,15 @@ "dev": true }, "acorn": { - "version": "8.7.1", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true }, "acorn-walk": { "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, "ansi-escapes": { @@ -7701,6 +1183,8 @@ }, "ansi-styles": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -7718,6 +1202,8 @@ }, "arg": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "argparse": { @@ -7732,7 +1218,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true } } @@ -7752,15 +1238,15 @@ } }, "babel-jest": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", - "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", "dev": true, "requires": { - "@jest/transform": "^28.1.0", + "@jest/transform": "^28.1.3", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^28.0.2", + "babel-preset-jest": "^28.1.3", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -7831,9 +1317,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", - "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -7863,17 +1349,19 @@ } }, "babel-preset-jest": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", - "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^28.0.2", + "babel-plugin-jest-hoist": "^28.1.3", "babel-preset-current-node-syntax": "^1.0.0" } }, "balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "bluebird": { @@ -7884,6 +1372,8 @@ }, "brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -7900,16 +1390,15 @@ } }, "browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" } }, "bs-logger": { @@ -7938,6 +1427,8 @@ }, "call-bind": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -7957,13 +1448,15 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001344", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", - "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "version": "1.0.30001419", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001419.tgz", + "integrity": "sha512-aFO1r+g6R7TW+PNQxKzjITwLOyDhVRLjW0LcwS/HCZGUUKTGNp9+IwLC4xyDSZBygVL/mxaFR3HIV6wEKQuSzw==", "dev": true }, "chalk": { "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -8015,9 +1508,9 @@ } }, "ci-info": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", - "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, "cjs-module-lexer": { @@ -8051,6 +1544,8 @@ }, "color-convert": { "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { "color-name": "1.1.3" @@ -8058,6 +1553,8 @@ }, "color-name": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "colors": { @@ -8080,23 +1577,26 @@ }, "concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "create-require": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, "cross-spawn": { "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -8118,7 +1618,7 @@ "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, "deep-extend": { @@ -8135,6 +1635,8 @@ }, "define-properties": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "requires": { "has-property-descriptors": "^1.0.0", @@ -8149,6 +1651,8 @@ }, "diff": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "diff-sequences": { @@ -8158,9 +1662,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.140", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.140.tgz", - "integrity": "sha512-NLz5va823QfJBYOO/hLV4AfU4Crmkl/6Hl2pH3qdJcmi0ySZ3YTWHxOlDm3uJOFBEPy3pIhu8gKQo6prQTWKKA==", + "version": "1.4.282", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.282.tgz", + "integrity": "sha512-Dki0WhHNh/br/Xi1vAkueU5mtIc9XLHcMKB6tNfQKk+kPG0TEUjRh5QEMAUbRp30/rYNMFD1zKKvbVzwq/4wmg==", "dev": true }, "emittery": { @@ -8177,6 +1681,8 @@ }, "error-ex": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" @@ -8184,6 +1690,8 @@ }, "es-abstract": { "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -8213,6 +1721,8 @@ }, "es-to-primitive": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -8228,6 +1738,8 @@ }, "escape-string-regexp": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "esprima": { @@ -8299,20 +1811,20 @@ "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, "expect": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.0.tgz", - "integrity": "sha512-qFXKl8Pmxk8TBGfaFKRtcQjfXEnKAs+dmlxdwvukJZorwrAabT7M3h8oLOG01I2utEhkmUTi17CHaPBovZsKdw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", "dev": true, "requires": { - "@jest/expect-utils": "^28.1.0", + "@jest/expect-utils": "^28.1.3", "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-util": "^28.1.0" + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" }, "dependencies": { "ansi-styles": { @@ -8350,9 +1862,9 @@ "dev": true }, "diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", "dev": true }, "has-flag": { @@ -8362,36 +1874,42 @@ "dev": true }, "jest-diff": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", - "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", + "diff-sequences": "^28.1.1", "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" } }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "jest-matcher-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", - "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^28.1.0", + "jest-diff": "^28.1.3", "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" } }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -8406,9 +1924,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -8429,9 +1947,9 @@ "dev": true }, "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "requires": { "bser": "2.1.1" @@ -8458,6 +1976,8 @@ }, "fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "fsevents": { @@ -8469,10 +1989,14 @@ }, "function-bind": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "function.prototype.name": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -8483,6 +2007,8 @@ }, "functions-have-names": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, "gensync": { @@ -8499,6 +2025,8 @@ }, "get-intrinsic": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -8520,6 +2048,8 @@ }, "get-symbol-description": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -8528,6 +2058,8 @@ }, "glob": { "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -8546,10 +2078,14 @@ }, "graceful-fs": { "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "has": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" @@ -8557,14 +2093,20 @@ }, "has-bigints": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true }, "has-flag": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "has-property-descriptors": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, "requires": { "get-intrinsic": "^1.1.1" @@ -8572,10 +2114,14 @@ }, "has-symbols": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, "has-tostringtag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "requires": { "has-symbols": "^1.0.2" @@ -8583,6 +2129,8 @@ }, "hosted-git-info": { "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "html-escaper": { @@ -8610,11 +2158,13 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -8623,10 +2173,14 @@ }, "inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "internal-slot": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "requires": { "get-intrinsic": "^1.1.0", @@ -8636,10 +2190,14 @@ }, "is-arrayish": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-bigint": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, "requires": { "has-bigints": "^1.0.1" @@ -8647,6 +2205,8 @@ }, "is-boolean-object": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -8655,10 +2215,14 @@ }, "is-callable": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, "is-core-module": { "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "requires": { "has": "^1.0.3" @@ -8666,6 +2230,8 @@ }, "is-date-object": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -8685,6 +2251,8 @@ }, "is-negative-zero": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true }, "is-number": { @@ -8695,6 +2263,8 @@ }, "is-number-object": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -8702,6 +2272,8 @@ }, "is-regex": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -8710,6 +2282,8 @@ }, "is-shared-array-buffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, "requires": { "call-bind": "^1.0.2" @@ -8723,6 +2297,8 @@ }, "is-string": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -8730,6 +2306,8 @@ }, "is-symbol": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "requires": { "has-symbols": "^1.0.2" @@ -8737,6 +2315,8 @@ }, "is-weakref": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, "requires": { "call-bind": "^1.0.2" @@ -8744,6 +2324,8 @@ }, "isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "istanbul-lib-coverage": { @@ -8753,9 +2335,9 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -8813,9 +2395,9 @@ } }, "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -8823,60 +2405,143 @@ } }, "iter-tools": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/iter-tools/-/iter-tools-7.3.1.tgz", - "integrity": "sha512-XYS0CjthZqQ7MomjB4Ww9NqrVKRlP2qoa1oWFcIQrkMykhkgFTpSNG+sRcqzHBp6fSxk8oDIjudFTgQ6nnA4mA==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/iter-tools/-/iter-tools-7.5.0.tgz", + "integrity": "sha512-L0p/RG3Hwk1urilryDKqU8pQ1t5AaaMc7CHmiwJD/uh63Lv7VyjNng/esstf+Tct1587IpetpcDFdufz8sG+sQ==", "dev": true, "requires": { "@babel/runtime": "^7.12.1" } }, "jest": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", - "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "requires": { - "@jest/core": "^28.1.0", + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", "import-local": "^3.0.2", - "jest-cli": "^28.1.0" + "jest-cli": "^28.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-cli": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "dev": true, + "requires": { + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, "jest-changed-files": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", - "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", "dev": true, "requires": { "execa": "^5.0.0", - "throat": "^6.0.1" + "p-limit": "^3.1.0" + }, + "dependencies": { + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + } } }, "jest-circus": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.0.tgz", - "integrity": "sha512-rNYfqfLC0L0zQKRKsg4n4J+W1A2fbyGH7Ss/kDIocp9KXD9iaL111glsLu7+Z7FHuZxwzInMDXq+N1ZIBkI/TQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", "dev": true, "requires": { - "@jest/environment": "^28.1.0", - "@jest/expect": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", "is-generator-fn": "^2.0.0", - "jest-each": "^28.1.0", - "jest-matcher-utils": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-runtime": "^28.1.0", - "jest-snapshot": "^28.1.0", - "jest-util": "^28.1.0", - "pretty-format": "^28.1.0", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "stack-utils": "^2.0.3" }, "dependencies": { "ansi-styles": { @@ -8914,9 +2579,9 @@ "dev": true }, "diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", "dev": true }, "has-flag": { @@ -8926,36 +2591,51 @@ "dev": true }, "jest-diff": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", - "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", + "diff-sequences": "^28.1.1", "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" } }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "jest-matcher-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", - "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^28.1.0", + "jest-diff": "^28.1.3", "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" } }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -8970,80 +2650,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-cli": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.0.tgz", - "integrity": "sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==", - "dev": true, - "requires": { - "@jest/core": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/types": "^28.1.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^28.1.0", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -9058,31 +2667,31 @@ } }, "jest-config": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.0.tgz", - "integrity": "sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^28.1.0", - "@jest/types": "^28.1.0", - "babel-jest": "^28.1.0", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^28.1.0", - "jest-environment-node": "^28.1.0", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", "jest-get-type": "^28.0.2", "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.0", - "jest-runner": "^28.1.0", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^28.1.0", + "pretty-format": "^28.1.3", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -9127,6 +2736,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -9140,12 +2755,12 @@ } }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -9160,9 +2775,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -9228,12 +2843,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9246,25 +2855,25 @@ } }, "jest-docblock": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", - "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.0.tgz", - "integrity": "sha512-a/XX02xF5NTspceMpHujmOexvJ4GftpYXqr6HhhmKmExtMXsyIN/fvanQlt/BcgFoRKN4OCXxLQKth9/n6OPFg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", "dev": true, "requires": { - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "jest-get-type": "^28.0.2", - "jest-util": "^28.1.0", - "pretty-format": "^28.1.0" + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" }, "dependencies": { "ansi-styles": { @@ -9307,13 +2916,19 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -9328,9 +2943,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -9345,32 +2960,32 @@ } }, "jest-environment-node": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.0.tgz", - "integrity": "sha512-gBLZNiyrPw9CSMlTXF1yJhaBgWDPVvH0Pq6bOEwGMXaYNzhzhw2kA/OijNF8egbCgDS0/veRv97249x2CX+udQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", "dev": true, "requires": { - "@jest/environment": "^28.1.0", - "@jest/fake-timers": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^28.1.0", - "jest-util": "^28.1.0" + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" } }, "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", "dev": true }, "jest-haste-map": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.0.tgz", - "integrity": "sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", "dev": true, "requires": { - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", @@ -9378,20 +2993,20 @@ "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", "jest-regex-util": "^28.0.2", - "jest-util": "^28.1.0", - "jest-worker": "^28.1.0", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "micromatch": "^4.0.4", - "walker": "^1.0.7" + "walker": "^1.0.8" } }, "jest-leak-detector": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.0.tgz", - "integrity": "sha512-uIJDQbxwEL2AMMs2xjhZl2hw8s77c3wrPaQ9v6tXJLGaaQ+4QrNJH5vuw7hA7w/uGT/iJ42a83opAqxGHeyRIA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", "dev": true, "requires": { "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" }, "dependencies": { "ansi-styles": { @@ -9400,22 +3015,28 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true } } @@ -9472,12 +3093,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9490,18 +3105,18 @@ } }, "jest-message-util": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", - "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.1.0", + "pretty-format": "^28.1.3", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -9547,12 +3162,12 @@ "dev": true }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -9567,9 +3182,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -9584,12 +3199,12 @@ } }, "jest-mock": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", - "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "dev": true, "requires": { - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "@types/node": "*" } }, @@ -9597,8 +3212,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "28.0.2", @@ -9607,17 +3221,17 @@ "dev": true }, "jest-resolve": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.0.tgz", - "integrity": "sha512-vvfN7+tPNnnhDvISuzD1P+CRVP8cK0FHXRwPAcdDaQv4zgvwvag2n55/h5VjYcM5UJG7L4TwE5tZlzcI0X2Lhw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", + "jest-haste-map": "^28.1.3", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^28.1.0", - "jest-validate": "^28.1.0", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" @@ -9675,42 +3289,42 @@ } }, "jest-resolve-dependencies": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.0.tgz", - "integrity": "sha512-Ue1VYoSZquPwEvng7Uefw8RmZR+me/1kr30H2jMINjGeHgeO/JgrR6wxj2ofkJ7KSAA11W3cOrhNCbj5Dqqd9g==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", "dev": true, "requires": { "jest-regex-util": "^28.0.2", - "jest-snapshot": "^28.1.0" + "jest-snapshot": "^28.1.3" } }, "jest-runner": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.0.tgz", - "integrity": "sha512-FBpmuh1HB2dsLklAlRdOxNTTHKFR6G1Qmd80pVDvwbZXTriqjWqjei5DKFC1UlM732KjYcE6yuCdiF0WUCOS2w==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", "dev": true, "requires": { - "@jest/console": "^28.1.0", - "@jest/environment": "^28.1.0", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.10.2", "graceful-fs": "^4.2.9", - "jest-docblock": "^28.0.2", - "jest-environment-node": "^28.1.0", - "jest-haste-map": "^28.1.0", - "jest-leak-detector": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-resolve": "^28.1.0", - "jest-runtime": "^28.1.0", - "jest-util": "^28.1.0", - "jest-watcher": "^28.1.0", - "jest-worker": "^28.1.0", - "source-map-support": "0.5.13", - "throat": "^6.0.1" + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" }, "dependencies": { "ansi-styles": { @@ -9753,6 +3367,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9765,31 +3388,31 @@ } }, "jest-runtime": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.0.tgz", - "integrity": "sha512-wNYDiwhdH/TV3agaIyVF0lsJ33MhyujOe+lNTUiolqKt8pchy1Hq4+tDMGbtD5P/oNLA3zYrpx73T9dMTOCAcg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", "dev": true, "requires": { - "@jest/environment": "^28.1.0", - "@jest/fake-timers": "^28.1.0", - "@jest/globals": "^28.1.0", - "@jest/source-map": "^28.0.2", - "@jest/test-result": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-mock": "^28.1.0", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", "jest-regex-util": "^28.0.2", - "jest-resolve": "^28.1.0", - "jest-snapshot": "^28.1.0", - "jest-util": "^28.1.0", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -9852,9 +3475,9 @@ } }, "jest-snapshot": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.0.tgz", - "integrity": "sha512-ex49M2ZrZsUyQLpLGxQtDbahvgBjlLPgklkqGM0hq/F7W/f8DyqZxVHjdy19QKBm4O93eDp+H5S23EiTbbUmHw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -9862,23 +3485,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^28.1.0", - "@jest/transform": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^28.1.0", + "expect": "^28.1.3", "graceful-fs": "^4.2.9", - "jest-diff": "^28.1.0", + "jest-diff": "^28.1.3", "jest-get-type": "^28.0.2", - "jest-haste-map": "^28.1.0", - "jest-matcher-utils": "^28.1.0", - "jest-message-util": "^28.1.0", - "jest-util": "^28.1.0", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "natural-compare": "^1.4.0", - "pretty-format": "^28.1.0", + "pretty-format": "^28.1.3", "semver": "^7.3.5" }, "dependencies": { @@ -9917,9 +3540,9 @@ "dev": true }, "diff-sequences": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", - "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", "dev": true }, "has-flag": { @@ -9929,36 +3552,42 @@ "dev": true }, "jest-diff": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", - "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^28.0.2", + "diff-sequences": "^28.1.1", "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" } }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "jest-matcher-utils": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", - "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^28.1.0", + "jest-diff": "^28.1.3", "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" } }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -9973,15 +3602,15 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -9999,12 +3628,12 @@ } }, "jest-util": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", - "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", "dev": true, "requires": { - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -10064,17 +3693,17 @@ } }, "jest-validate": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.0.tgz", - "integrity": "sha512-Lly7CJYih3vQBfjLeANGgBSBJ7pEa18cxpQfQEq2go2xyEzehnHfQTjoUia8xUv4x4J80XKFIDwJJThXtRFQXQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", "dev": true, "requires": { - "@jest/types": "^28.1.0", + "@jest/types": "^28.1.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^28.0.2", "leven": "^3.1.0", - "pretty-format": "^28.1.0" + "pretty-format": "^28.1.3" }, "dependencies": { "ansi-styles": { @@ -10123,13 +3752,19 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, "pretty-format": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", - "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "requires": { - "@jest/schemas": "^28.0.2", + "@jest/schemas": "^28.1.3", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" @@ -10144,9 +3779,9 @@ } }, "react-is": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", - "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, "supports-color": { @@ -10161,18 +3796,18 @@ } }, "jest-watcher": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.0.tgz", - "integrity": "sha512-tNHMtfLE8Njcr2IRS+5rXYA4BhU90gAOwI9frTGOqd+jX0P/Au/JfRSNqsf5nUTcWdbVYuLxS1KjnzILSoR5hA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", "dev": true, "requires": { - "@jest/test-result": "^28.1.0", - "@jest/types": "^28.1.0", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.10.2", - "jest-util": "^28.1.0", + "jest-util": "^28.1.3", "string-length": "^4.0.1" }, "dependencies": { @@ -10228,9 +3863,9 @@ } }, "jest-worker": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.0.tgz", - "integrity": "sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", "dev": true, "requires": { "@types/node": "*", @@ -10279,6 +3914,8 @@ }, "json-parse-better-errors": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "json-parse-even-better-errors": { @@ -10294,9 +3931,9 @@ "dev": true }, "jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "jsonfile": { @@ -10329,6 +3966,8 @@ }, "load-json-file": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -10349,7 +3988,7 @@ "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, "lru-cache": { @@ -10386,6 +4025,8 @@ }, "make-error": { "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "makeerror": { @@ -10398,13 +4039,15 @@ } }, "marked": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", - "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", + "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", "dev": true }, "memorystream": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true }, "merge-stream": { @@ -10431,6 +4074,8 @@ }, "minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -10445,27 +4090,31 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "nice-try": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", "dev": true }, "normalize-package-data": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -10482,6 +4131,8 @@ }, "npm-run-all": { "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -10514,14 +4165,20 @@ }, "object-inspect": { "version": "1.12.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", + "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==", "dev": true }, "object-keys": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object.assign": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { "call-bind": "^1.0.0", @@ -10532,6 +4189,8 @@ }, "once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -10572,6 +4231,8 @@ }, "parse-json": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, "requires": { "error-ex": "^1.3.1", @@ -10586,18 +4247,26 @@ }, "path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true }, "path-parse": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { "pify": "^3.0.0" @@ -10617,10 +4286,14 @@ }, "pidtree": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true }, "pify": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true }, "pirates": { @@ -10639,7 +4312,9 @@ } }, "prettier": { - "version": "2.5.1", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, "pretty-format": { @@ -10679,6 +4354,8 @@ }, "read-pkg": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "requires": { "load-json-file": "^4.0.0", @@ -10693,13 +4370,15 @@ "dev": true }, "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "version": "0.13.10", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", + "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==", "dev": true }, "regexp.prototype.flags": { "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10715,6 +4394,8 @@ }, "resolve": { "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { "is-core-module": "^2.8.1", @@ -10745,23 +4426,23 @@ }, "rimraf": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "semver": { "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "shebang-command": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "requires": { "shebang-regex": "^1.0.0" @@ -10769,10 +4450,14 @@ }, "shebang-regex": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true }, "shell-quote": { "version": "1.7.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", + "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", "dev": true }, "shiki": { @@ -10788,6 +4473,8 @@ }, "side-channel": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "requires": { "call-bind": "^1.0.0", @@ -10831,6 +4518,8 @@ }, "spdx-correct": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -10839,10 +4528,14 @@ }, "spdx-exceptions": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "spdx-expression-parse": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -10851,10 +4544,14 @@ }, "spdx-license-ids": { "version": "3.0.11", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", + "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", "dev": true }, "sprintf-js": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", "dev": true }, "stack-utils": { @@ -10897,6 +4594,8 @@ }, "string.prototype.padend": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz", + "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10906,6 +4605,8 @@ }, "string.prototype.trimend": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10915,6 +4616,8 @@ }, "string.prototype.trimstart": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -10933,6 +4636,8 @@ }, "strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true }, "strip-final-newline": { @@ -10949,15 +4654,17 @@ }, "supports-color": { "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" } }, "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -10983,6 +4690,8 @@ }, "supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, "table-layout": { @@ -11018,12 +4727,6 @@ "minimatch": "^3.0.4" } }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -11033,7 +4736,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true }, "to-regex-range": { @@ -11045,10 +4748,16 @@ "is-number": "^7.0.0" } }, + "ts-expect": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-expect/-/ts-expect-1.3.0.tgz", + "integrity": "sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==", + "dev": true + }, "ts-jest": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.3.tgz", - "integrity": "sha512-HzgbEDQ2KgVtDmpXToqAcKTyGHdHsG23i/iUjfxji92G5eT09S1m9UHZd7csF0Bfgh9txM4JzwHnv7r1waFPlw==", + "version": "28.0.8", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", + "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", "dev": true, "requires": { "bs-logger": "0.x", @@ -11058,22 +4767,30 @@ "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "^20.x" + "yargs-parser": "^21.0.1" }, "dependencies": { "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true } } }, "ts-node": { - "version": "10.8.0", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", @@ -11109,9 +4826,9 @@ "dev": true }, "typedoc": { - "version": "0.22.17", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.17.tgz", - "integrity": "sha512-h6+uXHVVCPDaANzjwzdsj9aePBjZiBTpiMpBBeyh1zcN2odVsDCNajz8zyKnixF93HJeGpl34j/70yoEE5BfNg==", + "version": "0.22.18", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.18.tgz", + "integrity": "sha512-NK9RlLhRUGMvc6Rw5USEYgT4DVAUFk7IF7Q6MYfpJ88KnTZP7EneEa4RcP+tX1auAcz7QT1Iy0bUSZBYYHdoyA==", "dev": true, "requires": { "glob": "^8.0.3", @@ -11155,7 +4872,9 @@ } }, "typescript": { - "version": "4.7.2", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", "dev": true }, "typical": { @@ -11166,6 +4885,8 @@ }, "unbox-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -11180,23 +4901,37 @@ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", "dev": true }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "v8-compile-cache-lib": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, "v8-to-istanbul": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", - "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.7", + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0" } }, "validate-npm-package-license": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -11226,6 +4961,8 @@ }, "which": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -11233,6 +4970,8 @@ }, "which-boxed-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "requires": { "is-bigint": "^1.0.1", @@ -11291,12 +5030,14 @@ }, "wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "requires": { "imurmurhash": "^0.1.4", @@ -11316,12 +5057,12 @@ "dev": true }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -11330,10 +5071,21 @@ "yargs-parser": "^21.0.0" }, "dependencies": { + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true } } @@ -11346,6 +5098,14 @@ }, "yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true } } diff --git a/src/api/js/package.json b/src/api/js/package.json index 7249b85a2..90a7bfa3d 100644 --- a/src/api/js/package.json +++ b/src/api/js/package.json @@ -35,7 +35,8 @@ "contributors": [ "Kevin Gibbons ", "Nikolaj Bjorner", - "Olaf Tomalka " + "Olaf Tomalka ", + "Walden Yan " ], "devDependencies": { "@types/jest": "^27.5.1", @@ -49,6 +50,7 @@ "prettier": "^2.5.1", "rimraf": "^3.0.2", "sprintf-js": "^1.1.2", + "ts-expect": "^1.3.0", "ts-jest": "^28.0.3", "ts-node": "^10.8.0", "typedoc": "^0.22.17", diff --git a/src/api/js/src/high-level/high-level.test.ts b/src/api/js/src/high-level/high-level.test.ts index 7fb20e627..70c11b875 100644 --- a/src/api/js/src/high-level/high-level.test.ts +++ b/src/api/js/src/high-level/high-level.test.ts @@ -2,6 +2,7 @@ import assert from 'assert'; import asyncToArray from 'iter-tools/methods/async-to-array'; import { init, killThreads } from '../jest'; import { Arith, Bool, Model, Z3AssertionError, Z3HighLevel } from './types'; +import { expectType } from "ts-expect"; /** * Generate all possible solutions from given assumptions. @@ -113,7 +114,7 @@ describe('high-level', () => { const { Solver, Not, Int } = api.Context('main'); const solver = new Solver(); solver.fromString("(declare-const x Int) (assert (and (< x 2) (> x 0)))") - expect(await solver.check()).toStrictEqual('sat') + expect(await solver.check()).toStrictEqual('sat') const x = Int.const('x') solver.add(Not(x.eq(1))) expect(await solver.check()).toStrictEqual('unsat') @@ -211,6 +212,7 @@ describe('high-level', () => { } return cells; } + const INSTANCE = toSudoku(` ....94.3. ...51...7 @@ -390,6 +392,106 @@ describe('high-level', () => { }); }); + describe('arrays', () => { + + it('Example 1', async () => { + const Z3 = api.Context('main'); + + const arr = Z3.Array.const('arr', Z3.Int.sort(), Z3.Int.sort()); + const [idx, val] = Z3.Int.consts('idx val'); + + const conjecture = (arr.store(idx, val).select(idx).eq(val)); + await prove(conjecture); + }); + + it('domain and range type inference', async () => { + const { BitVec, Array, isArray, isArraySort } = api.Context('main'); + + const arr = Array.const('arr', BitVec.sort(160), BitVec.sort(256)); + + const domain = arr.domain(); + expect(domain.size()).toStrictEqual(160); + expect(arr.domain_n(0).size()).toStrictEqual(160); + const range = arr.range(); + expect(range.size()).toStrictEqual(256); + + assert(isArray(arr) && isArraySort(arr.sort)); + + const arr2 = Array.const('arr2', BitVec.sort(1), BitVec.sort(2), BitVec.sort(3)); + const dom2 = arr2.domain_n(1); + + // We can call size() on dom2 and see that it is two bits + // purely from type inference + expectType<2>(dom2.size()); + + // Won't let us create an array constant with only one of domain/range + // and is detected at compile time + // @ts-expect-error + const arr3 = Array.const('arr3', BitVec.sort(1)); + }) + + it('can do simple proofs', async () => { + const { BitVec, Array, isArray, isArraySort, isConstArray, Eq, Not } = api.Context('main'); + + const idx = BitVec.const('idx', 160); + const val = BitVec.const('val', 256); + + const FIVE_VAL = BitVec.val(5, 256); + + const arr = Array.const('arr', BitVec.sort(160), BitVec.sort(256)); + + const constArr = Array.K(BitVec.sort(160), FIVE_VAL); + assert(isArray(arr) && isArraySort(arr.sort) && isConstArray(constArr)); + + const arr2 = arr.store(0, 5); + await prove(Eq(arr2.select(0), FIVE_VAL)); + await prove(Not(Eq(arr2.select(0), BitVec.val(6, 256)))); + await prove(Eq(arr2.store(idx, val).select(idx), constArr.store(idx, val).select(idx))); + + // TODO: add in Quantifiers and better typing of arrays + // await prove( + // ForAll([idx], idx.add(1).ugt(idx).and(arr.select(idx.add(1)).ugt(arr.select(idx)))).implies( + // arr.select(0).ult(arr.select(1000)) + // ) + // ); + }); + + it('Finds arrays that differ but that sum to the same', async () => { + const Z3 = api.Context('main'); + const { Array, BitVec } = Z3; + + const mod = 1n << 32n; + + const arr1 = Array.const('arr', BitVec.sort(2), BitVec.sort(32)); + const arr2 = Array.const('arr2', BitVec.sort(2), BitVec.sort(32)); + + const same_sum = arr1.select(0) + .add(arr1.select(1)) + .add(arr1.select(2)) + .add(arr1.select(3)) + .eq( + arr2.select(0) + .add(arr2.select(1)) + .add(arr2.select(2)) + .add(arr2.select(3)) + ); + + const different = arr1.select(0).neq(arr2.select(0)) + .or(arr1.select(1).neq(arr2.select(1))) + .or(arr1.select(2).neq(arr2.select(2))) + .or(arr1.select(3).neq(arr2.select(3))); + + const model = await solve(same_sum.and(different)); + + const arr1Vals = [0, 1, 2, 3].map(i => model.eval(arr1.select(i)).value()); + const arr2Vals = [0, 1, 2, 3].map(i => model.eval(arr2.select(i)).value()); + expect((arr1Vals.reduce((a, b) => a + b, 0n) % mod) === arr2Vals.reduce((a, b) => a + b, 0n) % mod); + for (let i = 0; i < 4; i++) { + expect(arr1Vals[i] !== arr2Vals[i]); + } + }); + }); + describe('Solver', () => { it('can use push and pop', async () => { const { Solver, Int } = api.Context('main'); diff --git a/src/api/js/src/high-level/high-level.ts b/src/api/js/src/high-level/high-level.ts index e1a2b35ab..59a0b1e36 100644 --- a/src/api/js/src/high-level/high-level.ts +++ b/src/api/js/src/high-level/high-level.ts @@ -37,7 +37,7 @@ import { AnyExpr, AnySort, Arith, - ArithSort, + ArithSort, ArrayIndexType, Ast, AstMap, AstMapCtor, @@ -48,7 +48,7 @@ import { BitVecSort, Bool, BoolSort, - CheckSatResult, + CheckSatResult, CoercibleFromMap, CoercibleRational, CoercibleToBitVec, CoercibleToExpr, @@ -63,6 +63,8 @@ import { Model, Probe, RatNum, + SMTArray, + SMTArraySort, Solver, Sort, SortToExprMap, @@ -86,12 +88,11 @@ function isCoercibleRational(obj: any): obj is CoercibleRational { (obj.denominator !== null && (typeof obj.denominator === 'number' || typeof obj.denominator === 'bigint')) ); - r && - assert( - (typeof obj.numerator !== 'number' || Number.isSafeInteger(obj.numerator)) && - (typeof obj.denominator !== 'number' || Number.isSafeInteger(obj.denominator)), - 'Fraction numerator and denominator must be integers', - ); + r && assert( + (typeof obj!.numerator !== 'number' || Number.isSafeInteger(obj!.numerator)) && + (typeof obj!.denominator !== 'number' || Number.isSafeInteger(obj!.denominator)), + 'Fraction numerator and denominator must be integers', + ); return r; } @@ -151,7 +152,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel { function createContext(name: Name, options?: Record): Context { const cfg = Z3.mk_config(); if (options != null) { - Object.entries(options).forEach(([key, value]) => check(Z3.set_param_value(cfg, key, value.toString()))); + Object.entries(options).forEach( + ([key, value]) => check(Z3.set_param_value(cfg, key, value.toString())) + ); } const contextPtr = Z3.mk_context_rc(cfg); Z3.set_ast_print_mode(contextPtr, Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT); @@ -216,20 +219,22 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return new ArithSortImpl(ast); case Z3_sort_kind.Z3_BV_SORT: return new BitVecSortImpl(ast); + case Z3_sort_kind.Z3_ARRAY_SORT: + return new ArraySortImpl(ast); default: return new SortImpl(ast); } } - function _toExpr(ast: Z3_ast): Bool | IntNum | RatNum | Arith | Expr { + function _toExpr(ast: Z3_ast): AnyExpr { const kind = check(Z3.get_ast_kind(contextPtr, ast)); if (kind === Z3_ast_kind.Z3_QUANTIFIER_AST) { if (Z3.is_quantifier_forall(contextPtr, ast)) - return new BoolImpl(ast); + return new BoolImpl(ast); if (Z3.is_quantifier_exists(contextPtr, ast)) - return new BoolImpl(ast); + return new BoolImpl(ast); if (Z3.is_lambda(contextPtr, ast)) - return new ExprImpl(ast); + return new ExprImpl(ast); assert(false); } const sortKind = check(Z3.get_sort_kind(contextPtr, Z3.get_sort(contextPtr, ast))); @@ -251,6 +256,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return new BitVecNumImpl(ast); } return new BitVecImpl(ast); + case Z3_sort_kind.Z3_ARRAY_SORT: + return new ArrayImpl(ast); default: return new ExprImpl(ast); } @@ -440,6 +447,22 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return r; } + function isArraySort(obj: unknown): obj is SMTArraySort { + const r = obj instanceof ArraySortImpl; + r && _assertContext(obj); + return r; + } + + function isArray(obj: unknown): obj is SMTArray { + const r = obj instanceof ArrayImpl; + r && _assertContext(obj); + return r; + } + + function isConstArray(obj: unknown): boolean { + return isAppOf(obj, Z3_decl_kind.Z3_OP_CONST_ARRAY); + } + function isProbe(obj: unknown): obj is Probe { const r = obj instanceof ProbeImpl; r && _assertContext(obj); @@ -508,9 +531,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel { // expression simplification // /////////////////////////////// - async function simplify(e : Expr) { - const result = await Z3.simplify(contextPtr, e.ast) - return _toExpr(check(result)); + async function simplify(e: Expr) { + const result = await Z3.simplify(contextPtr, e.ast) + return _toExpr(check(result)); } ///////////// @@ -677,6 +700,44 @@ export function createApi(Z3: Z3Core): Z3HighLevel { ); }, }; + const Array = { + sort, ...AnySort[]], RangeSort extends AnySort>( + ...sig: [...DomainSort, RangeSort] + ): SMTArraySort { + const arity = sig.length - 1; + const r = sig[arity]; + const d = sig[0]; + if (arity === 1) { + return new ArraySortImpl(Z3.mk_array_sort(contextPtr, d.ptr, r.ptr)); + } + const dom = sig.slice(0, arity); + return new ArraySortImpl(Z3.mk_array_sort_n(contextPtr, dom.map(s => s.ptr), r.ptr)); + }, + const, ...AnySort[]], RangeSort extends AnySort>( + name: string, ...sig: [...DomainSort, RangeSort] + ): SMTArray { + return new ArrayImpl( + check(Z3.mk_const(contextPtr, _toSymbol(name), Array.sort(...sig).ptr)) + ); + }, + consts, ...AnySort[]], RangeSort extends AnySort>( + names: string | string[], + ...sig: [...DomainSort, RangeSort] + ): SMTArray[] { + if (typeof names === 'string') { + names = names.split(' '); + } + return names.map(name => Array.const(name, ...sig)); + }, + K, RangeSort extends AnySort>( + domain: DomainSort, + value: SortToExprMap + ): SMTArray { + return new ArrayImpl<[DomainSort], RangeSort>( + check(Z3.mk_const_array(contextPtr, domain.ptr, value.ptr)) + ); + } + } //////////////// // Operations // @@ -948,6 +1009,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { readonly ptr: Z3_solver; readonly ctx: Context; + constructor(ptr: Z3_solver | string = Z3.mk_solver(contextPtr)) { this.ctx = ctx; let myPtr: Z3_solver; @@ -964,21 +1026,26 @@ export function createApi(Z3: Z3Core): Z3HighLevel { push() { Z3.solver_push(contextPtr, this.ptr); } + pop(num: number = 1) { Z3.solver_pop(contextPtr, this.ptr, num); } + numScopes() { return Z3.solver_get_num_scopes(contextPtr, this.ptr); } + reset() { Z3.solver_reset(contextPtr, this.ptr); } + add(...exprs: (Bool | AstVector>)[]) { _flattenArgs(exprs).forEach(expr => { _assertContext(expr); check(Z3.solver_assert(contextPtr, this.ptr, expr.ast)); }); } + addAndTrack(expr: Bool, constant: Bool | string) { if (typeof constant === 'string') { constant = Bool.const(constant); @@ -1019,7 +1086,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return check(Z3.solver_to_string(contextPtr, this.ptr)); } - fromString(s : string) { + fromString(s: string) { Z3.solver_from_string(contextPtr, this.ptr, s); throwIfError(); } @@ -1043,20 +1110,20 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return this.values(); } - *entries(): IterableIterator<[number, FuncDecl]> { + * entries(): IterableIterator<[number, FuncDecl]> { const length = this.length(); for (let i = 0; i < length; i++) { yield [i, this.get(i)]; } } - *keys(): IterableIterator { + * keys(): IterableIterator { for (const [key] of this.entries()) { yield key; } } - *values(): IterableIterator> { + * values(): IterableIterator> { for (const [, value] of this.entries()) { yield value; } @@ -1076,11 +1143,12 @@ export function createApi(Z3: Z3Core): Z3HighLevel { eval(expr: Bool, modelCompletion?: boolean): Bool; eval(expr: Arith, modelCompletion?: boolean): Arith; + eval(expr: BitVec, modelCompletion?: boolean): BitVecNum; eval(expr: Expr, modelCompletion: boolean = false) { _assertContext(expr); const r = check(Z3.model_eval(contextPtr, this.ptr, expr.ast, modelCompletion)); if (r === null) { - throw new Z3Error('Failed to evaluatio expression in the model'); + throw new Z3Error('Failed to evaluate expression in the model'); } return _toExpr(r); } @@ -1092,7 +1160,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { get(sort: Sort): AstVector>; get( i: number | FuncDecl | Expr | Sort, - to?: number, + to?: number ): FuncDecl | FuncInterp | Expr | AstVector> | FuncDecl[] { assert(to === undefined || typeof i === 'number'); if (typeof i === 'number') { @@ -1362,15 +1430,22 @@ export function createApi(Z3: Z3Core): Z3HighLevel { not(): Bool { return Not(this); } + and(other: Bool | boolean): Bool { return And(this, other); } + or(other: Bool | boolean): Bool { return Or(this, other); } + xor(other: Bool | boolean): Bool { return Xor(this, other); } + + implies(other: Bool | boolean): Bool { + return Implies(this, other); + } } class ProbeImpl implements Probe { @@ -1571,27 +1646,35 @@ export function createApi(Z3: Z3Core): Z3HighLevel { add(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvadd(contextPtr, this.ast, this.sort.cast(other).ast))); } + mul(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvmul(contextPtr, this.ast, this.sort.cast(other).ast))); } + sub(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvsub(contextPtr, this.ast, this.sort.cast(other).ast))); } + sdiv(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvsdiv(contextPtr, this.ast, this.sort.cast(other).ast))); } + udiv(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvudiv(contextPtr, this.ast, this.sort.cast(other).ast))); } + smod(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvsmod(contextPtr, this.ast, this.sort.cast(other).ast))); } + urem(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvurem(contextPtr, this.ast, this.sort.cast(other).ast))); } + srem(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvsrem(contextPtr, this.ast, this.sort.cast(other).ast))); } + neg(): BitVec { return new BitVecImpl(check(Z3.mk_bvneg(contextPtr, this.ast))); } @@ -1599,33 +1682,43 @@ export function createApi(Z3: Z3Core): Z3HighLevel { or(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvor(contextPtr, this.ast, this.sort.cast(other).ast))); } + and(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvand(contextPtr, this.ast, this.sort.cast(other).ast))); } + nand(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvnand(contextPtr, this.ast, this.sort.cast(other).ast))); } + xor(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvxor(contextPtr, this.ast, this.sort.cast(other).ast))); } + xnor(other: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvxnor(contextPtr, this.ast, this.sort.cast(other).ast))); } + shr(count: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvashr(contextPtr, this.ast, this.sort.cast(count).ast))); } + lshr(count: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvlshr(contextPtr, this.ast, this.sort.cast(count).ast))); } + shl(count: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_bvshl(contextPtr, this.ast, this.sort.cast(count).ast))); } + rotateRight(count: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_ext_rotate_right(contextPtr, this.ast, this.sort.cast(count).ast))); } + rotateLeft(count: CoercibleToBitVec): BitVec { return new BitVecImpl(check(Z3.mk_ext_rotate_left(contextPtr, this.ast, this.sort.cast(count).ast))); } + not(): BitVec { return new BitVecImpl(check(Z3.mk_bvnot(contextPtr, this.ast))); } @@ -1633,12 +1726,15 @@ export function createApi(Z3: Z3Core): Z3HighLevel { extract(high: number, low: number): BitVec { return new BitVecImpl(check(Z3.mk_extract(contextPtr, high, low, this.ast))); } + signExt(count: number): BitVec { return new BitVecImpl(check(Z3.mk_sign_ext(contextPtr, count, this.ast))); } + zeroExt(count: number): BitVec { return new BitVecImpl(check(Z3.mk_zero_ext(contextPtr, count, this.ast))); } + repeat(count: number): BitVec { return new BitVecImpl(check(Z3.mk_repeat(contextPtr, count, this.ast))); } @@ -1646,24 +1742,31 @@ export function createApi(Z3: Z3Core): Z3HighLevel { sle(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvsle(contextPtr, this.ast, this.sort.cast(other).ast))); } + ule(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvule(contextPtr, this.ast, this.sort.cast(other).ast))); } + slt(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvslt(contextPtr, this.ast, this.sort.cast(other).ast))); } + ult(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvult(contextPtr, this.ast, this.sort.cast(other).ast))); } + sge(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvsge(contextPtr, this.ast, this.sort.cast(other).ast))); } + uge(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvuge(contextPtr, this.ast, this.sort.cast(other).ast))); } + sgt(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvsgt(contextPtr, this.ast, this.sort.cast(other).ast))); } + ugt(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvugt(contextPtr, this.ast, this.sort.cast(other).ast))); } @@ -1671,6 +1774,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { redAnd(): BitVec { return new BitVecImpl(check(Z3.mk_bvredand(contextPtr, this.ast))); } + redOr(): BitVec { return new BitVecImpl(check(Z3.mk_bvredor(contextPtr, this.ast))); } @@ -1678,24 +1782,31 @@ export function createApi(Z3: Z3Core): Z3HighLevel { addNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool { return new BoolImpl(check(Z3.mk_bvadd_no_overflow(contextPtr, this.ast, this.sort.cast(other).ast, isSigned))); } + addNoUnderflow(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvadd_no_underflow(contextPtr, this.ast, this.sort.cast(other).ast))); } + subNoOverflow(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvsub_no_overflow(contextPtr, this.ast, this.sort.cast(other).ast))); } + subNoUndeflow(other: CoercibleToBitVec, isSigned: boolean): Bool { return new BoolImpl(check(Z3.mk_bvsub_no_underflow(contextPtr, this.ast, this.sort.cast(other).ast, isSigned))); } + sdivNoOverflow(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvsdiv_no_overflow(contextPtr, this.ast, this.sort.cast(other).ast))); } + mulNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool { return new BoolImpl(check(Z3.mk_bvmul_no_overflow(contextPtr, this.ast, this.sort.cast(other).ast, isSigned))); } + mulNoUndeflow(other: CoercibleToBitVec): Bool { return new BoolImpl(check(Z3.mk_bvmul_no_underflow(contextPtr, this.ast, this.sort.cast(other).ast))); } + negNoOverflow(): Bool { return new BoolImpl(check(Z3.mk_bvneg_no_overflow(contextPtr, this.ast))); } @@ -1703,6 +1814,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { class BitVecNumImpl extends BitVecImpl implements BitVecNum { declare readonly __typename: BitVecNum['__typename']; + value() { return BigInt(this.asString()); } @@ -1718,14 +1830,87 @@ export function createApi(Z3: Z3Core): Z3HighLevel { } return val; } + asString() { return Z3.get_numeral_string(contextPtr, this.ast); } + asBinaryString() { return Z3.get_numeral_binary_string(contextPtr, this.ast); } } + class ArraySortImpl, ...AnySort[]] = [Sort, ...Sort[]], + RangeSort extends AnySort = Sort> + extends SortImpl + implements SMTArraySort { + declare readonly __typename: SMTArraySort['__typename']; + + domain(): DomainSort[0] { + return _toSort(check(Z3.get_array_sort_domain(contextPtr, this.ptr))); + } + + domain_n(i: T): DomainSort[T] { + return _toSort(check(Z3.get_array_sort_domain_n(contextPtr, this.ptr, i))); + } + + range(): RangeSort { + return _toSort(check(Z3.get_array_sort_range(contextPtr, this.ptr))) as RangeSort; + } + + } + + class ArrayImpl< + DomainSort extends [AnySort, ...AnySort[]] = [Sort, ...Sort[]], + RangeSort extends AnySort = Sort + > extends ExprImpl> + implements SMTArray { + declare readonly __typename: SMTArray['__typename']; + + domain(): DomainSort[0] { + return this.sort.domain(); + } + + domain_n(i: T): DomainSort[T] { + return this.sort.domain_n(i); + } + + range(): RangeSort { + return this.sort.range(); + } + + select(...indices: ArrayIndexType): SortToExprMap { + const args = indices.map((arg, i) => this.domain_n(i).cast(arg as any)); + if (args.length === 1) { + return _toExpr(check(Z3.mk_select(contextPtr, this.ast, args[0].ast))) as SortToExprMap; + } + const _args = args.map(arg => arg.ast); + return _toExpr(check(Z3.mk_select_n(contextPtr, this.ast, _args))) as SortToExprMap; + } + + store( + ...indicesAndValue: [ + ...ArrayIndexType, + CoercibleFromMap, Name> + ] + ): SMTArray { + const args = indicesAndValue.map((arg, i) => { + if (i === indicesAndValue.length - 1) { + return this.range().cast(arg as CoercibleFromMap, Name>); + } + return this.domain_n(i).cast(arg as any); + }); + if (args.length <= 1) { + throw new Z3Error("Array store requires both index and value arguments"); + } + if (args.length === 2) { + return _toExpr(check(Z3.mk_store(contextPtr, this.ast, args[0].ast, args[1].ast))) as SMTArray; + } + const _idxs = args.slice(0, args.length - 1).map(arg => arg.ast); + return _toExpr(check(Z3.mk_store_n(contextPtr, this.ast, _idxs, args[args.length - 1].ast))) as SMTArray; + } + } + class AstVectorImpl> { declare readonly __typename: AstVector['__typename']; readonly ctx: Context; @@ -1744,20 +1929,20 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return this.values(); } - *entries(): IterableIterator<[number, Item]> { + * entries(): IterableIterator<[number, Item]> { const length = this.length(); for (let i = 0; i < length; i++) { yield [i, this.get(i)]; } } - *keys(): IterableIterator { + * keys(): IterableIterator { for (let [key] of this.entries()) { yield key; } } - *values(): IterableIterator { + * values(): IterableIterator { for (let [, value] of this.entries()) { yield value; } @@ -1842,7 +2027,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return Z3.ast_map_size(contextPtr, this.ptr); } - *entries(): IterableIterator<[Key, Value]> { + * entries(): IterableIterator<[Key, Value]> { for (const key of this.keys()) { yield [key, this.get(key)]; } @@ -1852,11 +2037,12 @@ export function createApi(Z3: Z3Core): Z3HighLevel { return new AstVectorImpl(Z3.ast_map_keys(contextPtr, this.ptr)); } - *values(): IterableIterator { + * values(): IterableIterator { for (const [_, value] of this.entries()) { yield value; } } + get(key: Key): Value { return _toAst(check(Z3.ast_map_find(contextPtr, this.ptr, key.ast))) as Value; } @@ -1928,6 +2114,9 @@ export function createApi(Z3: Z3Core): Z3HighLevel { isBitVecSort, isBitVec, isBitVecVal, // TODO fix ordering + isArraySort, + isArray, + isConstArray, isProbe, isTactic, isAstVector, @@ -1946,6 +2135,7 @@ export function createApi(Z3: Z3Core): Z3HighLevel { Int, Real, BitVec, + Array, //////////////// // Operations // diff --git a/src/api/js/src/high-level/types.ts b/src/api/js/src/high-level/types.ts index 57e5c37f8..a6cb01e79 100644 --- a/src/api/js/src/high-level/types.ts +++ b/src/api/js/src/high-level/types.ts @@ -20,7 +20,8 @@ export type AnySort = | Sort | BoolSort | ArithSort - | BitVecSort; + | BitVecSort + | SMTArraySort, ...AnySort[]], AnySort>; /** @hidden */ export type AnyExpr = | Expr @@ -29,31 +30,54 @@ export type AnyExpr = | IntNum | RatNum | BitVec - | BitVecNum; + | BitVecNum + | SMTArray, ...AnySort[]], AnySort>; /** @hidden */ export type AnyAst = AnyExpr | AnySort | FuncDecl; /** @hidden */ -export type SortToExprMap, Name extends string = 'main'> = S extends BoolSort - ? Bool - : S extends ArithSort - ? Arith - : S extends BitVecSort - ? BitVec - : S extends Sort - ? Expr - : never; +export type SortToExprMap, Name extends string = 'main'> = + S extends BoolSort + ? Bool + : S extends ArithSort + ? Arith + : S extends BitVecSort + ? BitVec + : S extends SMTArraySort + ? SMTArray + : S extends Sort + ? Expr + : never; /** @hidden */ -export type CoercibleToExprMap, Name extends string = 'main'> = S extends bigint - ? IntNum - : S extends number | CoercibleRational - ? RatNum - : S extends boolean - ? Bool - : S extends Expr - ? S - : never; +export type CoercibleToExprMap, Name extends string = 'main'> = + S extends bigint + ? ArithSort + : S extends number | CoercibleRational + ? RatNum + : S extends boolean + ? Bool + : S extends Expr + ? S + : never; + +/** @hidden */ +export type CoercibleFromMap, Name extends string = 'main'> = + S extends Bool + ? (boolean | Bool) + : S extends IntNum + ? (bigint | number | IntNum) + : S extends RatNum + ? (bigint | number | CoercibleRational | RatNum) + : S extends Arith + ? (bigint | number | CoercibleRational | Arith) + : S extends BitVec + ? (number | BitVec) + : S extends SMTArray + ? SMTArray + : S extends Expr + ? Expr + : never; /** * Used to create a Real constant @@ -78,8 +102,11 @@ export type CoercibleRational = { numerator: bigint | number; denominator: bigin /** @hidden */ export type CoercibleToExpr = number | bigint | boolean | CoercibleRational | Expr; -export class Z3Error extends Error {} -export class Z3AssertionError extends Z3Error {} +export class Z3Error extends Error { +} + +export class Z3AssertionError extends Z3Error { +} /** @category Global */ export type CheckSatResult = 'sat' | 'unsat' | 'unknown'; @@ -109,98 +136,148 @@ export interface Context { /////////////// /** @category Functions */ interrupt(): void; + /** @category Functions */ isModel(obj: unknown): obj is Model; + /** @category Functions */ isAst(obj: unknown): obj is Ast; + /** @category Functions */ isSort(obj: unknown): obj is Sort; + /** @category Functions */ isFuncDecl(obj: unknown): obj is FuncDecl; + /** @category Functions */ isApp(obj: unknown): boolean; + /** @category Functions */ isConst(obj: unknown): boolean; + /** @category Functions */ isExpr(obj: unknown): obj is Expr; + /** @category Functions */ isVar(obj: unknown): boolean; + /** @category Functions */ isAppOf(obj: unknown, kind: Z3_decl_kind): boolean; + /** @category Functions */ isBool(obj: unknown): obj is Bool; + /** @category Functions */ isTrue(obj: unknown): boolean; + /** @category Functions */ isFalse(obj: unknown): boolean; + /** @category Functions */ isAnd(obj: unknown): boolean; + /** @category Functions */ isOr(obj: unknown): boolean; + /** @category Functions */ isImplies(obj: unknown): boolean; + /** @category Functions */ isNot(obj: unknown): boolean; + /** @category Functions */ isEq(obj: unknown): boolean; + /** @category Functions */ isDistinct(obj: unknown): boolean; + /** @category Functions */ isArith(obj: unknown): obj is Arith; + /** @category Functions */ isArithSort(obj: unknown): obj is ArithSort; + /** @category Functions */ isInt(obj: unknown): boolean; + /** @category Functions */ isIntVal(obj: unknown): obj is IntNum; + /** @category Functions */ isIntSort(obj: unknown): boolean; + /** @category Functions */ isReal(obj: unknown): boolean; + /** @category Functions */ isRealVal(obj: unknown): obj is RatNum; + /** @category Functions */ isRealSort(obj: unknown): boolean; + /** @category Functions */ isBitVecSort(obj: unknown): obj is BitVecSort; + /** @category Functions */ isBitVec(obj: unknown): obj is BitVec; + /** @category Functions */ isBitVecVal(obj: unknown): obj is BitVecNum; + + /** @category Functions */ + isArraySort(obj: unknown): obj is SMTArraySort, ...AnySort[]], AnySort>; + + /** @category Functions */ + isArray(obj: unknown): obj is SMTArray, ...AnySort[]], AnySort>; + + /** @category Functions */ + isConstArray(obj: unknown): boolean; + /** @category Functions */ isProbe(obj: unknown): obj is Probe; + /** @category Functions */ isTactic(obj: unknown): obj is Tactic; + /** @category Functions */ isAstVector(obj: unknown): obj is AstVector>; + /** * Returns whether two Asts are the same thing * @category Functions */ eqIdentity(a: Ast, b: Ast): boolean; + /** @category Functions */ getVarIndex(obj: Expr): number; + /** * Coerce a boolean into a Bool expression * @category Functions */ from(primitive: boolean): Bool; + /** * Coerce a number to an Int or Real expression (integral numbers become Ints) * @category Functions */ from(primitive: number): IntNum | RatNum; + /** * Coerce a rational into a Real expression * @category Functions */ from(primitive: CoercibleRational): RatNum; + /** * Coerce a big number into a Integer expression * @category Functions */ from(primitive: bigint): IntNum; + /** * Returns whatever expression was given * @category Functions */ from>(expr: E): E; + /** @hidden */ from(value: CoercibleToExpr): AnyExpr; + /** * Sugar function for getting a model for given assertions * @@ -259,60 +336,84 @@ export interface Context { readonly Real: RealCreation; /** @category Expressions */ readonly BitVec: BitVecCreation; + /** @category Expressions */ + readonly Array: SMTArrayCreation; //////////////// // Operations // //////////////// /** @category Operations */ Const>(name: string, sort: S): SortToExprMap; + /** @category Operations */ Consts>(name: string | string[], sort: S): SortToExprMap[]; + /** @category Operations */ FreshConst>(sort: S, prefix?: string): SortToExprMap; + /** @category Operations */ Var>(idx: number, sort: S): SortToExprMap; + // Booleans /** @category Operations */ If(condition: Probe, onTrue: Tactic, onFalse: Tactic): Tactic; + /** @category Operations */ If, OnFalseRef extends CoercibleToExpr>( condition: Bool | boolean, onTrue: OnTrueRef, onFalse: OnFalseRef, ): CoercibleToExprMap; + /** @category Operations */ Distinct(...args: CoercibleToExpr[]): Bool; + /** @category Operations */ Implies(a: Bool | boolean, b: Bool | boolean): Bool; + /** @category Operations */ Eq(a: CoercibleToExpr, b: CoercibleToExpr): Bool; + /** @category Operations */ Xor(a: Bool | boolean, b: Bool | boolean): Bool; + /** @category Operations */ Not(a: Probe): Probe; + /** @category Operations */ Not(a: Bool | boolean): Bool; + /** @category Operations */ And(): Bool; + /** @category Operations */ And(vector: AstVector>): Bool; + /** @category Operations */ And(...args: (Bool | boolean)[]): Bool; + /** @category Operations */ And(...args: Probe[]): Probe; + /** @category Operations */ Or(): Bool; + /** @category Operations */ Or(vector: AstVector>): Bool; + /** @category Operations */ Or(...args: (Bool | boolean)[]): Bool; + /** @category Operations */ Or(...args: Probe[]): Probe; + // Arithmetic /** @category Operations */ ToReal(expr: Arith | bigint): Arith; + /** @category Operations */ ToInt(expr: Arith | number | CoercibleRational | string): Arith; + /** * Create an IsInt Z3 predicate * @@ -325,6 +426,7 @@ export interface Context { * ``` * @category Operations */ IsInt(expr: Arith | number | CoercibleRational | string): Bool; + /** * Returns a Z3 expression representing square root of a * @@ -336,6 +438,7 @@ export interface Context { * ``` * @category Operations */ Sqrt(a: Arith | number | bigint | string | CoercibleRational): Arith; + /** * Returns a Z3 expression representing cubic root of a * @@ -347,13 +450,17 @@ export interface Context { * ``` * @category Operations */ Cbrt(a: Arith | number | bigint | string | CoercibleRational): Arith; + // Bit Vectors /** @category Operations */ BV2Int(a: BitVec, isSigned: boolean): Arith; + /** @category Operations */ Int2BV(a: Arith | bigint | number, bits: Bits): BitVec; + /** @category Operations */ Concat(...bitvecs: BitVec[]): BitVec; + /** @category Operations */ Cond(probe: Probe, onTrue: Tactic, onFalse: Tactic): Tactic } @@ -365,21 +472,27 @@ export interface Ast { readonly ctx: Context; /** @hidden */ readonly ptr: Ptr; + /** @virtual */ get ast(): Z3_ast; + /** @virtual */ id(): number; eqIdentity(other: Ast): boolean; + neqIdentity(other: Ast): boolean; + sexpr(): string; + hash(): number; } /** @hidden */ export interface SolverCtor { - new (): Solver; + new(): Solver; } + export interface Solver { /** @hidden */ readonly __typename: 'Solver'; @@ -392,21 +505,31 @@ export interface Solver { set(params: Record): void; */ push(): void; + pop(num?: number): void; + numScopes(): number; + reset(): void; + add(...exprs: (Bool | AstVector>)[]): void; + addAndTrack(expr: Bool, constant: Bool | string): void; + assertions(): AstVector>; - fromString(s : string): void; + + fromString(s: string): void; + check(...exprs: (Bool | AstVector>)[]): Promise; + model(): Model; } /** @hidden */ export interface ModelCtor { - new (): Model; + new(): Model; } + export interface Model extends Iterable> { /** @hidden */ readonly __typename: 'Model'; @@ -417,17 +540,31 @@ export interface Model extends Iterable]>; + keys(): IterableIterator; + values(): IterableIterator>; + decls(): FuncDecl[]; + sexpr(): string; + eval(expr: Bool, modelCompletion?: boolean): Bool; + eval(expr: Arith, modelCompletion?: boolean): Arith; + + eval(expr: BitVec, modelCompletion?: boolean): BitVecNum; + eval(expr: Expr, modelCompletion?: boolean): Expr; + get(i: number): FuncDecl; + get(from: number, to: number): FuncDecl[]; + get(declaration: FuncDecl): FuncInterp | Expr; + get(constant: Expr): Expr; + get(sort: Sort): AstVector>; } @@ -450,15 +587,24 @@ export interface Model extends Iterable { declare(name: string): Sort; } + export interface Sort extends Ast { /** @hidden */ - readonly __typename: 'Sort' | BoolSort['__typename'] | ArithSort['__typename'] | BitVecSort['__typename']; + readonly __typename: + | 'Sort' + | BoolSort['__typename'] + | ArithSort['__typename'] + | BitVecSort['__typename'] + | SMTArraySort['__typename']; kind(): Z3_sort_kind; + /** @virtual */ subsort(other: Sort): boolean; + /** @virtual */ cast(expr: CoercibleToExpr): Expr; + name(): string | number; } @@ -475,6 +621,7 @@ export interface FuncInterp { /** @hidden */ export type FuncDeclSignature = [Sort, Sort, ...Sort[]]; + /** * Part of {@link Context}. Used to declare functions * @category Functions @@ -493,15 +640,19 @@ export interface FuncDeclCreation { * @param signature The domains, and last parameter - the range of the function */ declare(name: string, ...signature: FuncDeclSignature): FuncDecl; + fresh(...signature: FuncDeclSignature): FuncDecl; } + /** * @category Functions */ export interface RecFuncCreation { declare(name: string, ...signature: FuncDeclSignature): FuncDecl; + addDefinition(f: FuncDecl, args: Expr[], body: Expr): void; } + /** * @category Functions */ @@ -510,27 +661,39 @@ export interface FuncDecl extends Ast; + range(): Sort; + kind(): Z3_decl_kind; + params(): (number | string | Z3_symbol | Sort | Expr | FuncDecl)[]; + call(...args: CoercibleToExpr[]): AnyExpr; } export interface Expr = AnySort, Ptr = unknown> extends Ast { /** @hidden */ - readonly __typename: 'Expr' | Bool['__typename'] | Arith['__typename'] | BitVec['__typename']; + readonly __typename: 'Expr' | Bool['__typename'] | Arith['__typename'] | BitVec['__typename'] | SMTArray['__typename']; get sort(): S; eq(other: CoercibleToExpr): Bool; + neq(other: CoercibleToExpr): Bool; + params(): ReturnType['params']>; + decl(): FuncDecl; + numArgs(): number; + arg(i: number): AnyExpr; + children(): AnyExpr[]; } @@ -540,28 +703,39 @@ export interface BoolSort extends Sort { readonly __typename: 'BoolSort'; cast(expr: Bool | boolean): Bool; + cast(expr: CoercibleToExpr): never; } + /** @category Booleans */ export interface BoolCreation { sort(): BoolSort; const(name: string): Bool; + consts(names: string | string[]): Bool[]; + vector(prefix: string, count: number): Bool[]; + fresh(prefix?: string): Bool; val(value: boolean): Bool; } + /** @category Booleans */ export interface Bool extends Expr, Z3_ast> { /** @hidden */ readonly __typename: 'Bool'; not(): Bool; + and(other: Bool | boolean): Bool; + or(other: Bool | boolean): Bool; + xor(other: Bool | boolean): Bool; + + implies(other: Bool | boolean): Bool; } /** @@ -573,33 +747,46 @@ export interface ArithSort extends Sort { readonly __typename: 'ArithSort'; cast(other: bigint | number | string): IntNum | RatNum; + cast(other: CoercibleRational | RatNum): RatNum; + cast(other: IntNum): IntNum; + cast(other: bigint | number | string | Bool | Arith | CoercibleRational): Arith; + cast(other: CoercibleToExpr | string): never; } + /** @category Arithmetic */ export interface IntCreation { sort(): ArithSort; const(name: string): Arith; + consts(names: string | string[]): Arith[]; + vector(prefix: string, count: number): Arith[]; + fresh(prefix?: string): Arith; val(value: bigint | number | string): IntNum; } + /** @category Arithmetic */ export interface RealCreation { sort(): ArithSort; const(name: string): Arith; + consts(names: string | string[]): Arith[]; + vector(prefix: string, count: number): Arith[]; + fresh(prefix?: string): Arith; val(value: number | string | bigint | CoercibleRational): RatNum; } + /** * Represents Integer or Real number expression * @category Arithmetic @@ -612,14 +799,17 @@ export interface Arith extends Expr | number | bigint | string): Arith; + /** * Multiplies two numbers together */ mul(other: Arith | number | bigint | string): Arith; + /** * Subtract second number from the first one */ sub(other: Arith | number | bigint | string): Arith; + /** * Applies power to the number * @@ -631,10 +821,12 @@ export interface Arith extends Expr | number | bigint | string): Arith; + /** * Divides the number by the second one */ div(other: Arith | number | bigint | string): Arith; + /** * Returns a number modulo second one * @@ -646,22 +838,27 @@ export interface Arith extends Expr | number | bigint | string): Arith; + /** * Returns a negation of the number */ neg(): Arith; + /** * Return whether the number is less or equal than the second one (`<=`) */ le(other: Arith | number | bigint | string): Bool; + /** * Returns whether the number is less than the second one (`<`) */ lt(other: Arith | number | bigint | string): Bool; + /** * Returns whether the number is greater than the second one (`>`) */ gt(other: Arith | number | bigint | string): Bool; + /** * Returns whether the number is greater or equal than the second one (`>=`) */ @@ -677,7 +874,9 @@ export interface IntNum extends Arith { readonly __typename: 'IntNum'; value(): bigint; + asString(): string; + asBinary(): string; } @@ -701,10 +900,15 @@ export interface RatNum extends Arith { readonly __typename: 'RatNum'; value(): { numerator: bigint; denominator: bigint }; + numerator(): IntNum; + denominator(): IntNum; + asNumber(): number; + asDecimal(prec?: number): string; + asString(): string; } @@ -731,6 +935,7 @@ export interface BitVecSort): BitVec; + cast(other: CoercibleToExpr): Expr; } @@ -739,11 +944,13 @@ export type CoercibleToBitVec; + /** @category Bit Vectors */ export interface BitVecCreation { sort(bits: Bits): BitVecSort; const(name: string, bits: Bits | BitVecSort): BitVec; + consts( names: string | string[], bits: Bits | BitVecSort, @@ -754,6 +961,7 @@ export interface BitVecCreation { bits: Bits | BitVecSort, ): BitVecNum; } + /** * Represents Bit Vector expression * @category Bit Vectors @@ -783,20 +991,28 @@ export interface BitVec): BitVec; + /** * Creates a bitwise-and between two bitvectors * @category Bitwise */ and(other: CoercibleToBitVec): BitVec; + /** * Creates a bitwise-not-and between two bitvectors * @category Bitwise */ nand(other: CoercibleToBitVec): BitVec; + /** * Creates a bitwise-exclusive-or between two bitvectors * @category Bitwise */ xor(other: CoercibleToBitVec): BitVec; + /** * Creates a bitwise-exclusive-not-or between two bitvectors * @category Bitwise */ xnor(other: CoercibleToBitVec): BitVec; + /** * Creates an arithmetic shift right operation * @category Bitwise */ shr(count: CoercibleToBitVec): BitVec; + /** * Creates a logical shift right operation * @category Bitwise */ lshr(count: CoercibleToBitVec): BitVec; + /** * Creates a shift left operation * @category Bitwise */ shl(count: CoercibleToBitVec): BitVec; + /** * Creates a rotate right operation * @category Bitwise */ rotateRight(count: CoercibleToBitVec): BitVec; + /** * Creates a rotate left operation * @category Bitwise */ rotateLeft(count: CoercibleToBitVec): BitVec; + /** * Creates a bitwise not operation * @category Bitwise @@ -872,8 +1098,11 @@ export interface BitVec): Bool; + /** * Creates an unsigned less-or-equal operation (`<=`) * @category Comparison */ ule(other: CoercibleToBitVec): Bool; + /** * Creates a signed less-than operation (`<`) * @category Comparison */ slt(other: CoercibleToBitVec): Bool; + /** * Creates an unsigned less-than operation (`<`) * @category Comparison */ ult(other: CoercibleToBitVec): Bool; + /** * Creates a signed greater-or-equal operation (`>=`) * @category Comparison */ sge(other: CoercibleToBitVec): Bool; + /** * Creates an unsigned greater-or-equal operation (`>=`) * @category Comparison */ uge(other: CoercibleToBitVec): Bool; + /** * Creates a signed greater-than operation (`>`) * @category Comparison */ sgt(other: CoercibleToBitVec): Bool; + /** * Creates an unsigned greater-than operation (`>`) * @category Comparison @@ -921,6 +1157,7 @@ export interface BitVec, isSigned: boolean): Bool; + /** @category Boolean */ addNoUnderflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ subNoOverflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ subNoUndeflow(other: CoercibleToBitVec, isSigned: boolean): Bool; + /** @category Boolean */ sdivNoOverflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ mulNoOverflow(other: CoercibleToBitVec, isSigned: boolean): Bool; + /** @category Boolean */ mulNoUndeflow(other: CoercibleToBitVec): Bool; + /** @category Boolean */ negNoOverflow(): Bool; } @@ -953,11 +1197,113 @@ export interface BitVecNum, ...AnySort[]] = [Sort, ...Sort[]], + RangeSort extends AnySort = AnySort, + > extends Sort { + /** @hidden */ + readonly __typename: 'ArraySort'; + + /** + * The sort of the first dimension of the domain + */ + domain(): DomainSort[0]; + + /** + * The sort of the i-th (0-indexed) dimension of the domain + * + * @param i index of the dimension of the domain being requested + */ + domain_n(i: T): DomainSort[T]; + + /** + * The sort of the range + */ + range(): RangeSort; + +} + +/** @category Arrays */ +export interface SMTArrayCreation { + sort, ...AnySort[]], RangeSort extends AnySort>( + ...sig: [...DomainSort, RangeSort] + ): SMTArraySort; + + const, ...AnySort[]], RangeSort extends AnySort>( + name: string, ...sig: [...DomainSort, RangeSort] + ): SMTArray; + + consts, ...AnySort[]], RangeSort extends AnySort>( + names: string | string[], + ...sig: [...DomainSort, RangeSort] + ): SMTArray[]; + + K, RangeSort extends AnySort>( + domain: DomainSort, + value: SortToExprMap + ): SMTArray; +} + +export type ArrayIndexType, ...AnySort[]] = [Sort, ...Sort[]]> = [...{ + [Index in keyof DomainSort]: DomainSort[Index] extends AnySort ? + CoercibleFromMap, Name> : + DomainSort[Index]; +}] + +/** + * Represents Array expression + * + * @typeParam DomainSort The sort of the domain of the array (provided as an array of sorts) + * @typeParam RangeSort The sort of the array range + * @category Arrays + */ +export interface SMTArray, ...AnySort[]] = [Sort, ...Sort[]], + RangeSort extends AnySort = AnySort> + extends Expr, Z3_ast> { + + /** @hidden */ + readonly __typename: 'Array'; + + domain(): DomainSort[0]; + + domain_n(i: T): DomainSort[T]; + + range(): RangeSort; + + select(...indices: ArrayIndexType): SortToExprMap; + + /** + * value should be coercible to RangeSort + * + * @param indicesAndValue (idx0, idx1, ..., idxN, value) + */ + store( + ...indicesAndValue: [ + ...ArrayIndexType, + CoercibleFromMap, Name> + ] + ): SMTArray; + +} + export interface Probe { /** @hidden */ readonly __typename: 'Probe'; @@ -968,8 +1314,9 @@ export interface Probe { /** @hidden */ export interface TacticCtor { - new (name: string): Tactic; + new(name: string): Tactic; } + export interface Tactic { /** @hidden */ readonly __typename: 'Tactic'; @@ -980,8 +1327,9 @@ export interface Tactic { /** @hidden */ export interface AstVectorCtor { - new = AnyAst>(): AstVector; + new = AnyAst>(): AstVector; } + /** * Stores multiple {@link Ast} objects * @@ -1004,24 +1352,35 @@ export interface AstVector readonly ctx: Context; readonly ptr: Z3_ast_vector; + length(): number; entries(): IterableIterator<[number, Item]>; + keys(): IterableIterator; + values(): IterableIterator; + get(i: number): Item; + get(from: number, to: number): Item[]; + set(i: number, v: Item): void; + push(v: Item): void; + resize(size: number): void; + has(v: Item): boolean; + sexpr(): string; } /** @hidden */ export interface AstMapCtor { - new = AnyAst, Value extends Ast = AnyAst>(): AstMap; + new = AnyAst, Value extends Ast = AnyAst>(): AstMap; } + /** * Stores a mapping between different {@link Ast} objects * @@ -1050,16 +1409,25 @@ export interface AstMap = An readonly ctx: Context; readonly ptr: Z3_ast_map; + get size(): number; entries(): IterableIterator<[Key, Value]>; + keys(): AstVector; + values(): IterableIterator; + get(key: Key): Value | undefined; + set(key: Key, value: Value): void; + delete(key: Key): void; + clear(): void; + has(key: Key): boolean; + sexpr(): string; } @@ -1069,17 +1437,24 @@ export interface AstMap = An export interface Z3HighLevel { // Global functions enableTrace(tag: string): void; + disableTrace(tag: string): void; + getVersion(): { major: number; minor: number; build_number: number; revision_number: number; }; + getVersionString(): string; + getFullVersion(): string; + openLog(filename: string): boolean; + appendLog(s: string): void; + /** * Set a Z3 parameter * @@ -1088,6 +1463,7 @@ export interface Z3HighLevel { * ``` */ setParam(key: string, value: any): void; + /** * Set multiple Z3 parameters at once * @@ -1099,10 +1475,12 @@ export interface Z3HighLevel { * ``` */ setParam(key: Record): void; + /** * Resets all Z3 parameters */ resetParams(): void; + /** * Returns a global Z3 parameter */ From b758d5b2b1fbf5efc2b606dc199cb00e01791b76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2022 17:51:01 -0700 Subject: [PATCH 147/477] wip - proof checking, add support for distinct, other fixes --- src/math/lp/lar_solver.h | 44 ++++++++++------ src/sat/smt/CMakeLists.txt | 2 +- src/sat/smt/arith_theory_checker.h | 6 ++- src/sat/smt/distinct_theory_checker.h | 50 +++++++++++++++++++ src/sat/smt/euf_internalize.cpp | 22 ++++---- src/sat/smt/euf_proof.cpp | 5 ++ src/sat/smt/euf_proof_checker.cpp | 6 ++- src/sat/smt/euf_solver.h | 5 ++ ...checker.cpp => tseitin_theory_checker.cpp} | 18 +++++-- ...oof_checker.h => tseitin_theory_checker.h} | 4 +- 10 files changed, 124 insertions(+), 38 deletions(-) create mode 100644 src/sat/smt/distinct_theory_checker.h rename src/sat/smt/{tseitin_proof_checker.cpp => tseitin_theory_checker.cpp} (94%) rename src/sat/smt/{tseitin_proof_checker.h => tseitin_theory_checker.h} (95%) diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index e7f8d0ea4..f13231610 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -295,70 +295,86 @@ class lar_solver : public column_namer { public: // this function just looks at the status bool is_feasible() const; + const map, default_eq>& fixed_var_table_int() const { return m_fixed_var_table_int; } + map, default_eq>& fixed_var_table_int() { return m_fixed_var_table_int; } + const map, default_eq>& fixed_var_table_real() const { return m_fixed_var_table_real; } + map, default_eq>& fixed_var_table_real() { return m_fixed_var_table_real; } bool find_in_fixed_tables(const rational& mpq, bool is_int, unsigned & j) const { - return is_int? fixed_var_table_int().find(mpq, j) : - fixed_var_table_real().find(mpq, j); + return is_int? fixed_var_table_int().find(mpq, j) : fixed_var_table_real().find(mpq, j); } template void remove_non_fixed_from_table(T&); + unsigned external_to_column_index(unsigned) const; + bool inside_bounds(lpvar, const impq&) const; + inline void set_column_value(unsigned j, const impq& v) { m_mpq_lar_core_solver.m_r_solver.update_x(j, v); } + inline void set_column_value_test(unsigned j, const impq& v) { set_column_value(j, v); } + unsigned get_total_iterations() const; + var_index add_named_var(unsigned ext_j, bool is_integer, const std::string&); + lp_status maximize_term(unsigned j_or_term, impq &term_max); - inline - core_solver_pretty_printer pp(std::ostream& out) const { return - core_solver_pretty_printer(m_mpq_lar_core_solver.m_r_solver, out); } + + inline core_solver_pretty_printer pp(std::ostream& out) const { + return core_solver_pretty_printer(m_mpq_lar_core_solver.m_r_solver, out); + } + void get_infeasibility_explanation(explanation &) const; + inline void backup_x() { m_backup_x = m_mpq_lar_core_solver.m_r_x; } + inline void restore_x() { m_mpq_lar_core_solver.m_r_x = m_backup_x; } + template void explain_implied_bound(const implied_bound & ib, lp_bound_propagator & bp) { unsigned i = ib.m_row_or_term_index; - int bound_sign = ib.m_is_lower_bound? 1: -1; - int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; + int bound_sign = (ib.m_is_lower_bound ? 1 : -1); + int j_sign = (ib.m_coeff_before_j_is_pos ? 1 : -1) * bound_sign; unsigned bound_j = ib.m_j; - if (tv::is_term(bound_j)) { + if (tv::is_term(bound_j)) bound_j = m_var_register.external_to_local(bound_j); - } - for (auto const& r : A_r().m_rows[i]) { + + for (auto const& r : get_row(i)) { unsigned j = r.var(); - if (j == bound_j) continue; + if (j == bound_j) + continue; mpq const& a = r.coeff(); - int a_sign = is_pos(a)? 1: -1; + int a_sign = is_pos(a) ? 1 : -1; int sign = j_sign * a_sign; const ul_pair & ul = m_columns_to_ul_pairs[j]; - auto witness = sign > 0? ul.upper_bound_witness(): ul.lower_bound_witness(); + auto witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness(); lp_assert(is_valid(witness)); bp.consume(a, witness); } } void set_value_for_nbasic_column(unsigned j, const impq& new_val); + inline unsigned get_base_column_in_row(unsigned row_index) const { return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index); } - // lp_assert(implied_bound_is_correctly_explained(ib, explanation)); } constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side); void activate_check_on_equal(constraint_index, var_index&); diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 0b1e68e96..cef7f96c4 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -41,7 +41,7 @@ z3_add_component(sat_smt q_solver.cpp recfun_solver.cpp sat_th.cpp - tseitin_proof_checker.cpp + tseitin_theory_checker.cpp user_solver.cpp COMPONENT_DEPENDENCIES sat diff --git a/src/sat/smt/arith_theory_checker.h b/src/sat/smt/arith_theory_checker.h index f11e7ae29..65c647658 100644 --- a/src/sat/smt/arith_theory_checker.h +++ b/src/sat/smt/arith_theory_checker.h @@ -241,7 +241,7 @@ namespace arith { return true; if (check_ineq(m_ineq)) return true; - + IF_VERBOSE(3, display_row(verbose_stream() << "Failed to verify Farkas with reduced row ", m_ineq) << "\n"); // convert to expression, maybe follows from a cut. return false; } @@ -452,7 +452,9 @@ namespace arith { add_ineq(coeff, arg, sign); } else if (m.is_eq(arg, x, y)) { - if (sign) + if (is_bound && j + 1 == jst->get_num_args()) + add_conseq(coeff, arg, sign); + else if (sign) return check(); // it should be an implied equality else add_eq(x, y); diff --git a/src/sat/smt/distinct_theory_checker.h b/src/sat/smt/distinct_theory_checker.h new file mode 100644 index 000000000..a2fb366f7 --- /dev/null +++ b/src/sat/smt/distinct_theory_checker.h @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + distinct_proof_checker.h + +Abstract: + + Plugin for checking distinct internalization + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-07 + +Note: + + First version just trusts that distinct is internalized correctly. + + +--*/ +#pragma once + +#include "sat/smt/euf_proof_checker.h" +#include + +namespace distinct { + + class theory_checker : public euf::theory_checker_plugin { + ast_manager& m; + public: + theory_checker(ast_manager& m): + m(m) { + } + + expr_ref_vector clause(app* jst) override { + expr_ref_vector result(m); + result.append(jst->get_num_args(), jst->get_args()); + return result; + } + + bool check(app* jst) override { return true; } + + void register_plugins(euf::theory_checker& pc) override { + pc.register_plugin(symbol("distinct"), this); + } + + }; + +} diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 3c8956751..1bad6fc6b 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -216,10 +216,9 @@ namespace euf { void solver::add_not_distinct_axiom(app* e, enode* const* args) { SASSERT(m.is_distinct(e)); unsigned sz = e->get_num_args(); - sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id()); if (sz <= 1) { - s().mk_clause(0, nullptr, st); + s().mk_clause(0, nullptr, mk_distinct_status(0, nullptr)); return; } @@ -234,7 +233,7 @@ namespace euf { } } add_root(lits); - s().mk_clause(lits, st); + s().mk_clause(lits, mk_distinct_status(lits)); } else { // g(f(x_i)) = x_i @@ -252,13 +251,13 @@ namespace euf { expr_ref gapp(m.mk_app(g, fapp.get()), m); expr_ref eq = mk_eq(gapp, arg); sat::literal lit = mk_literal(eq); - s().add_clause(lit, st); + s().add_clause(lit, mk_distinct_status(lit)); eqs.push_back(mk_eq(fapp, a)); } pb_util pb(m); expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.data(), 2), m); sat::literal lit = si.internalize(at_least2, m_is_redundant); - s().add_clause(lit, st); + s().add_clause(lit, mk_distinct_status(lit)); } } @@ -266,19 +265,19 @@ namespace euf { SASSERT(m.is_distinct(e)); static const unsigned distinct_max_args = 32; unsigned sz = e->get_num_args(); - sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id()); + if (sz <= 1) - return; + return; sort* srt = e->get_arg(0)->get_sort(); auto sort_sz = srt->get_num_elements(); if (sort_sz.is_finite() && sort_sz.size() < sz) - s().add_clause(0, nullptr, st); + s().add_clause(0, nullptr, mk_tseitin_status(0, nullptr)); else if (sz <= distinct_max_args) { for (unsigned i = 0; i < sz; ++i) { for (unsigned j = i + 1; j < sz; ++j) { expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr()); sat::literal lit = ~mk_literal(eq); - s().add_clause(lit, st); + s().add_clause(lit, mk_distinct_status(lit)); } } } @@ -294,20 +293,19 @@ namespace euf { n->mark_interpreted(); expr_ref eq = mk_eq(fapp, fresh); sat::literal lit = mk_literal(eq); - s().add_clause(lit, st); + s().add_clause(lit, mk_distinct_status(lit)); } } } void solver::axiomatize_basic(enode* n) { expr* e = n->get_expr(); - sat::status st = sat::status::th(m_is_redundant, m.get_basic_family_id()); expr* c = nullptr, * th = nullptr, * el = nullptr; if (!m.is_bool(e) && m.is_ite(e, c, th, el)) { expr_ref eq_th = mk_eq(e, th); sat::literal lit_th = mk_literal(eq_th); if (th == el) { - s().add_clause(lit_th, st); + s().add_clause(lit_th, mk_tseitin_status(lit_th)); } else { sat::literal lit_c = mk_literal(c); diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 78b207f94..4f2677208 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -237,6 +237,11 @@ namespace euf { th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("tseitin"), n, lits) : nullptr; return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); } + + sat::status solver::mk_distinct_status(unsigned n, sat::literal const* lits) { + th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("distinct"), n, lits) : nullptr; + return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + } expr* smt_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 98032a86b..c6218f2fe 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -25,7 +25,8 @@ Author: #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_theory_checker.h" #include "sat/smt/q_theory_checker.h" -#include "sat/smt/tseitin_proof_checker.h" +#include "sat/smt/distinct_theory_checker.h" +#include "sat/smt/tseitin_theory_checker.h" namespace euf { @@ -287,6 +288,7 @@ namespace euf { add_plugin(alloc(eq_theory_checker, m)); add_plugin(alloc(res_checker, m, *this)); add_plugin(alloc(q::theory_checker, m)); + add_plugin(alloc(distinct::theory_checker, m)); add_plugin(alloc(smt_theory_checker_plugin, m, symbol("datatype"))); // no-op datatype proof checker add_plugin(alloc(tseitin::theory_checker, m)); } @@ -437,7 +439,7 @@ namespace euf { if (m_checker.check(clause, proof_hint, units)) { bool units_are_rup = true; for (expr* u : units) { - if (!check_rup(u)) { + if (!m.is_true(u) && !check_rup(u)) { std::cout << "unit " << mk_bounded_pp(u, m) << " is not rup\n"; units_are_rup = false; } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 62e7abcae..f4109bed1 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -407,8 +407,13 @@ namespace euf { smt_proof_hint* mk_smt_clause(symbol const& n, unsigned nl, literal const* lits); th_proof_hint* mk_cc_proof_hint(sat::literal_vector const& ante, app* a, app* b); th_proof_hint* mk_tc_proof_hint(sat::literal const* ternary_clause); + sat::status mk_tseitin_status(sat::literal a) { return mk_tseitin_status(1, &a); } sat::status mk_tseitin_status(sat::literal a, sat::literal b); sat::status mk_tseitin_status(unsigned n, sat::literal const* lits); + sat::status mk_distinct_status(sat::literal a) { return mk_distinct_status(1, &a); } + sat::status mk_distinct_status(sat::literal a, sat::literal b) { sat::literal lits[2] = { a, b }; return mk_distinct_status(2, lits); } + sat::status mk_distinct_status(sat::literal_vector const& lits) { return mk_distinct_status(lits.size(), lits.data()); } + sat::status mk_distinct_status(unsigned n, sat::literal const* lits); scoped_ptr m_proof_out; diff --git a/src/sat/smt/tseitin_proof_checker.cpp b/src/sat/smt/tseitin_theory_checker.cpp similarity index 94% rename from src/sat/smt/tseitin_proof_checker.cpp rename to src/sat/smt/tseitin_theory_checker.cpp index 19f6e8660..a15d0277b 100644 --- a/src/sat/smt/tseitin_proof_checker.cpp +++ b/src/sat/smt/tseitin_theory_checker.cpp @@ -3,7 +3,7 @@ Copyright (c) 2022 Microsoft Corporation Module Name: - tseitin_proof_checker.cpp + tseitin_theory_checker.cpp Abstract: @@ -27,7 +27,7 @@ TODOs: --*/ #include "ast/ast_pp.h" -#include "sat/smt/tseitin_proof_checker.h" +#include "sat/smt/tseitin_theory_checker.h" namespace tseitin { @@ -41,20 +41,28 @@ namespace tseitin { bool theory_checker::check(app* jst) { expr* main_expr = nullptr; unsigned max_depth = 0; + expr* a, * x, * y, * z, * u, * v; + for (expr* arg : *jst) { unsigned arg_depth = get_depth(arg); if (arg_depth > max_depth) { main_expr = arg; max_depth = arg_depth; } - if (arg_depth == max_depth && m.is_not(main_expr)) - main_expr = arg; + if (arg_depth == max_depth && m.is_not(main_expr)) { + if (m.is_not(arg, x) && m.is_not(main_expr, y) && + is_app(x) && is_app(y) && + to_app(x)->get_num_args() < to_app(y)->get_num_args()) + continue; + + main_expr = arg; + } } if (!main_expr) return false; - expr* a, * x, * y, *z, *u, *v; + // (or (and a b) (not a) (not b)) // (or (and (not a) b) a (not b)) diff --git a/src/sat/smt/tseitin_proof_checker.h b/src/sat/smt/tseitin_theory_checker.h similarity index 95% rename from src/sat/smt/tseitin_proof_checker.h rename to src/sat/smt/tseitin_theory_checker.h index 8bbacd53b..f9ed071bc 100644 --- a/src/sat/smt/tseitin_proof_checker.h +++ b/src/sat/smt/tseitin_theory_checker.h @@ -3,11 +3,11 @@ Copyright (c) 2022 Microsoft Corporation Module Name: - tseitin_proof_checker.h + tseitin_theory_checker.h Abstract: - Plugin for checking quantifier instantiations + Plugin for checking tseitin internalization Author: From 3bf1b606df9a090e49929df6ee859c9e123384b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 07:53:42 -0700 Subject: [PATCH 148/477] remove on-the fly ackerman reduction because it interferes with conflict resolution --- src/sat/smt/euf_ackerman.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/sat/smt/euf_ackerman.cpp b/src/sat/smt/euf_ackerman.cpp index 2026120e4..19b1a28de 100644 --- a/src/sat/smt/euf_ackerman.cpp +++ b/src/sat/smt/euf_ackerman.cpp @@ -74,14 +74,7 @@ namespace euf { m.inc_ref(inf->c); new_tmp(); } - other->m_count++; - if (other->m_count > m_high_watermark) { - if (other->is_cc) - add_cc(other->a, other->b); - else - add_eq(other->a, other->b, other->c); - other->m_count = 0; - } + other->m_count++; inference::push_to_front(m_queue, other); } From 7b3a634b8de2c3134c11df26baebb6e0b17a7477 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 07:54:49 -0700 Subject: [PATCH 149/477] wip - features and bug-fixes to proof logging --- src/ast/euf/euf_egraph.cpp | 2 +- src/sat/sat_solver.cpp | 14 +++++++++----- src/sat/smt/distinct_theory_checker.h | 2 +- src/sat/smt/euf_internalize.cpp | 2 +- src/sat/smt/euf_proof.cpp | 17 ++++++++--------- src/sat/smt/euf_proof_checker.cpp | 18 ++++++++---------- src/sat/smt/euf_proof_checker.h | 5 +++-- src/sat/smt/euf_solver.cpp | 15 +++++---------- src/sat/smt/euf_solver.h | 9 ++++++--- src/sat/smt/sat_th.cpp | 2 ++ src/sat/smt/sat_th.h | 2 +- 11 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 8f04b1b00..6034d8428 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -650,7 +650,7 @@ namespace euf { SASSERT(n1->get_decl() == n2->get_decl()); m_uses_congruence = true; if (m_used_cc && !comm) { - m_used_cc(to_app(n1->get_expr()), to_app(n2->get_expr())); + m_used_cc(n1->get_app(), n2->get_app()); } if (comm && n1->get_arg(0)->get_root() == n2->get_arg(1)->get_root() && diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8f9938dbb..15bc20a58 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -432,15 +432,17 @@ namespace sat { m_mc.add_clause(num_lits, lits); } - switch (num_lits) { case 0: set_conflict(); return nullptr; case 1: - if (!logged && m_config.m_drat && (!st.is_sat() || st.is_input())) + if (!logged && m_config.m_drat) drat_log_clause(num_lits, lits, st); - assign_unit(lits[0]); + { + flet _disable_drat(m_config.m_drat, false); + assign(lits[0], justification(0)); + } return nullptr; case 2: mk_bin_clause(lits[0], lits[1], st); @@ -460,6 +462,9 @@ namespace sat { bool redundant = st.is_redundant(); m_touched[l1.var()] = m_touch_index; m_touched[l2.var()] = m_touch_index; + + if (m_config.m_drat) + m_drat.add(l1, l2, st); if (redundant && !m_trim && find_binary_watch(get_wlist(~l1), ~l2) && value(l1) == l_undef) { assign_unit(l1); @@ -484,8 +489,7 @@ namespace sat { push_reinit_stack(l1, l2); return; } - if (m_config.m_drat) - m_drat.add(l1, l2, st); + if (propagate_bin_clause(l1, l2)) { if (!at_base_lvl()) push_reinit_stack(l1, l2); diff --git a/src/sat/smt/distinct_theory_checker.h b/src/sat/smt/distinct_theory_checker.h index a2fb366f7..81092b445 100644 --- a/src/sat/smt/distinct_theory_checker.h +++ b/src/sat/smt/distinct_theory_checker.h @@ -42,7 +42,7 @@ namespace distinct { bool check(app* jst) override { return true; } void register_plugins(euf::theory_checker& pc) override { - pc.register_plugin(symbol("distinct"), this); + pc.register_plugin(symbol("alldiff"), this); } }; diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 1bad6fc6b..a03af92c7 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -288,7 +288,7 @@ namespace euf { func_decl_ref f(m.mk_fresh_func_decl("dist-f", "", 1, &srt, u), m); for (unsigned i = 0; i < sz; ++i) { expr_ref fapp(m.mk_app(f, e->get_arg(i)), m); - expr_ref fresh(m.mk_fresh_const("dist-value", u), m); + expr_ref fresh(m.mk_model_value(i, u), m); enode* n = mk_enode(fresh, 0, nullptr); n->mark_interpreted(); expr_ref eq = mk_eq(fapp, fresh); diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 4f2677208..3e42d130e 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -73,20 +73,20 @@ namespace euf { } } - eq_proof_hint* solver::mk_hint(literal lit, literal_vector const& r) { + eq_proof_hint* solver::mk_hint(symbol const& th, literal conseq, literal_vector const& r) { if (!use_drat()) return nullptr; push(value_trail(m_lit_tail)); push(value_trail(m_cc_tail)); push(restore_size_trail(m_proof_literals)); - if (lit != sat::null_literal) - m_proof_literals.push_back(~lit); + if (conseq != sat::null_literal) + m_proof_literals.push_back(~conseq); m_proof_literals.append(r); m_lit_head = m_lit_tail; m_cc_head = m_cc_tail; m_lit_tail = m_proof_literals.size(); m_cc_tail = m_explain_cc.size(); - return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); + return new (get_region()) eq_proof_hint(th, m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); } th_proof_hint* solver::mk_cc_proof_hint(sat::literal_vector const& ante, app* a, app* b) { @@ -107,7 +107,7 @@ namespace euf { m_cc_head = m_cc_tail; m_lit_tail = m_proof_literals.size(); m_cc_tail = m_explain_cc.size(); - return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); + return new (get_region()) eq_proof_hint(m_euf, m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); } th_proof_hint* solver::mk_tc_proof_hint(sat::literal const* clause) { @@ -119,13 +119,12 @@ namespace euf { for (unsigned i = 0; i < 3; ++i) m_proof_literals.push_back(~clause[i]); - m_lit_head = m_lit_tail; m_cc_head = m_cc_tail; m_lit_tail = m_proof_literals.size(); m_cc_tail = m_explain_cc.size(); - return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); + return new (get_region()) eq_proof_hint(m_euf, m_lit_head, m_lit_tail, m_cc_head, m_cc_tail); } @@ -162,7 +161,7 @@ namespace euf { for (auto * arg : args) sorts.push_back(arg->get_sort()); - func_decl* f = m.mk_func_decl(symbol("euf"), sorts.size(), sorts.data(), proof); + func_decl* f = m.mk_func_decl(th, sorts.size(), sorts.data(), proof); return m.mk_app(f, args); } @@ -239,7 +238,7 @@ namespace euf { } sat::status solver::mk_distinct_status(unsigned n, sat::literal const* lits) { - th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("distinct"), n, lits) : nullptr; + th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("alldiff"), n, lits) : nullptr; return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); } diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index c6218f2fe..ff2803cb8 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -396,17 +396,15 @@ namespace euf { void smt_proof_checker::log_verified(app* proof_hint) { symbol n = proof_hint->get_name(); - if (n == m_last_rule) { - ++m_num_last_rules; - return; - } - if (m_num_last_rules > 0) - std::cout << "(verified-" << m_last_rule << "+" << m_num_last_rules << ")\n"; - - std::cout << "(verified-" << n << ")\n"; - m_last_rule = n; - m_num_last_rules = 0; + m_hint2hit.insert_if_not_there(n, 0)++; + ++m_num_logs; + if (m_num_logs < 100 || (m_num_logs % 1000) == 0) { + std::cout << "(verified"; + for (auto const& [k, v] : m_hint2hit) + std::cout << " :" << k << " " << v; + std::cout << ")\n"; + } } bool smt_proof_checker::check_rup(expr_ref_vector const& clause) { diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 6d5cb3290..ae8b9a407 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -90,8 +90,9 @@ namespace euf { bool m_check_rup = false; // for logging - symbol m_last_rule; - unsigned m_num_last_rules = 0; + + map m_hint2hit; + unsigned m_num_logs = 0; void add_units() { auto const& units = m_drat.units(); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index f0d40a13f..b462998a2 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -225,8 +225,9 @@ namespace euf { void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) { m_egraph.begin_explain(); m_explain.reset(); - if (use_drat() && !probing) + if (use_drat() && !probing) { push(restore_size_trail(m_explain_cc, m_explain_cc.size())); + } auto* ext = sat::constraint_base::to_extension(idx); th_proof_hint* hint = nullptr; bool has_theory = false; @@ -252,15 +253,9 @@ namespace euf { } } m_egraph.end_explain(); - if (use_drat() && !probing) { - if (!has_theory) - hint = mk_hint(l, r); - else { - if (l != sat::null_literal) r.push_back(~l); - hint = mk_smt_hint(symbol("smt"), r); - if (l != sat::null_literal) r.pop_back(); - } - } + if (use_drat() && !probing) + hint = mk_hint(has_theory ? m_smt : m_euf, l, r); + unsigned j = 0; for (sat::literal lit : r) if (s().lvl(lit) > 0) r[j++] = lit; diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index f4109bed1..b423b1768 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -62,10 +62,11 @@ namespace euf { }; class eq_proof_hint : public th_proof_hint { + symbol th; unsigned m_lit_head, m_lit_tail, m_cc_head, m_cc_tail; public: - eq_proof_hint(unsigned lh, unsigned lt, unsigned ch, unsigned ct): - m_lit_head(lh), m_lit_tail(lt), m_cc_head(ch), m_cc_tail(ct) {} + eq_proof_hint(symbol const& th, unsigned lh, unsigned lt, unsigned ch, unsigned ct): + th(th), m_lit_head(lh), m_lit_tail(lt), m_cc_head(ch), m_cc_tail(ct) {} expr* get_hint(euf::solver& s) const override; }; @@ -202,7 +203,9 @@ namespace euf { svector m_proof_eqs, m_proof_deqs, m_expr_pairs; unsigned m_lit_head = 0, m_lit_tail = 0, m_cc_head = 0, m_cc_tail = 0; unsigned m_eq_head = 0, m_eq_tail = 0, m_deq_head = 0, m_deq_tail = 0; - eq_proof_hint* mk_hint(literal lit, literal_vector const& r); + symbol m_euf = symbol("euf"); + symbol m_smt = symbol("smt"); + eq_proof_hint* mk_hint(symbol const& th, literal lit, literal_vector const& r); bool m_proof_initialized = false; diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index ad280eff8..81fd7e384 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -130,6 +130,8 @@ namespace euf { } bool th_euf_solver::add_unit(sat::literal lit, th_proof_hint const* ps) { + if (ctx.use_drat() && !ps) + ps = ctx.mk_smt_clause(name(), 1, &lit); bool was_true = is_true(lit); ctx.s().add_clause(1, &lit, mk_status(ps)); ctx.add_root(lit); diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 532d04a2e..d64b65635 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -238,7 +238,7 @@ namespace euf { public: static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, th_proof_hint const* ph = nullptr); - static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, th_proof_hint const* ph = nullptr) { return conflict(th, lits.size(), lits.data(), 0, nullptr, nullptr); } + static th_explain* conflict(th_euf_solver& th, sat::literal_vector const& lits, th_proof_hint const* ph = nullptr) { return conflict(th, lits.size(), lits.data(), 0, nullptr, ph); } static th_explain* conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, th_proof_hint const* ph = nullptr); static th_explain* conflict(th_euf_solver& th, enode_pair_vector const& eqs, th_proof_hint const* ph = nullptr); static th_explain* conflict(th_euf_solver& th, sat::literal lit, th_proof_hint const* ph = nullptr); From 1fc77c8c004521867f1a78368f3c956c3ecfdbb8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 09:02:50 -0700 Subject: [PATCH 150/477] wip - proof checking fixes to smt_theory_checker. Generalize it to apply to arrays and fpa. Missing: bv --- src/sat/smt/euf_proof.cpp | 32 +++++++++++++++++-------------- src/sat/smt/euf_proof_checker.cpp | 19 +++++++++--------- src/sat/smt/euf_proof_checker.h | 6 ++---- src/sat/smt/euf_solver.cpp | 2 ++ src/sat/smt/euf_solver.h | 5 ++++- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 3e42d130e..bfda8aad6 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -22,19 +22,22 @@ Author: namespace euf { void solver::init_proof() { - if (!m_proof_initialized) { - get_drat().add_theory(get_id(), symbol("euf")); - get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); - } - if (!m_proof_out && s().get_config().m_drat && + if (m_proof_initialized) + return; + + if (s().get_config().m_drat && (get_config().m_lemmas2console || s().get_config().m_smt_proof_check || s().get_config().m_smt_proof.is_non_empty_string())) { + + get_drat().add_theory(get_id(), symbol("euf")); + get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); TRACE("euf", tout << "init-proof " << s().get_config().m_smt_proof << "\n"); - m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); + if (s().get_config().m_smt_proof.is_non_empty_string()) + m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); get_drat().set_clause_eh(*this); + m_proof_initialized = true; } - m_proof_initialized = true; } /** @@ -133,7 +136,8 @@ namespace euf { func_decl_ref cc(m), cc_comm(m); sort* proof = m.mk_proof_sort(); ptr_buffer sorts; - expr_ref_vector args(m); + expr_ref_vector& args = s.m_expr_args; + args.reset(); if (m_cc_head < m_cc_tail) { sort* sorts[1] = { m.mk_bool_sort() }; cc_comm = m.mk_func_decl(symbol("comm"), 1, sorts, proof); @@ -325,16 +329,16 @@ namespace euf { void solver::on_check(unsigned n, literal const* lits, sat::status st) { if (!s().get_config().m_smt_proof_check) return; - expr_ref_vector clause(m); + m_clause.reset(); for (unsigned i = 0; i < n; ++i) - clause.push_back(literal2expr(lits[i])); + m_clause.push_back(literal2expr(lits[i])); auto hint = status2proof_hint(st); if (st.is_asserted() || st.is_redundant()) - m_smt_proof_checker.infer(clause, hint); + m_smt_proof_checker.infer(m_clause, hint); else if (st.is_deleted()) - m_smt_proof_checker.del(clause); + m_smt_proof_checker.del(m_clause); else if (st.is_input()) - m_smt_proof_checker.assume(clause); + m_smt_proof_checker.assume(m_clause); } void solver::on_lemma(unsigned n, literal const* lits, sat::status st) { @@ -391,7 +395,7 @@ namespace euf { void solver::display_inferred(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint) { expr_ref hint(proof_hint, m); if (!hint) - hint = m.mk_const(symbol("smt"), m.mk_proof_sort()); + hint = m.mk_const(m_smt, m.mk_proof_sort()); visit_expr(out, hint); display_hint(display_literals(out << "(infer", n, lits), hint) << ")\n"; } diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index ff2803cb8..097bc7b61 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -214,6 +214,7 @@ namespace euf { void register_plugins(theory_checker& pc) override { pc.register_plugin(symbol("euf"), this); + pc.register_plugin(symbol("smt"), this); } }; @@ -289,13 +290,11 @@ namespace euf { add_plugin(alloc(res_checker, m, *this)); add_plugin(alloc(q::theory_checker, m)); add_plugin(alloc(distinct::theory_checker, m)); - add_plugin(alloc(smt_theory_checker_plugin, m, symbol("datatype"))); // no-op datatype proof checker + add_plugin(alloc(smt_theory_checker_plugin, m)); add_plugin(alloc(tseitin::theory_checker, m)); } theory_checker::~theory_checker() { - for (auto& [k, v] : m_checked_clauses) - dealloc(v); } void theory_checker::add_plugin(theory_checker_plugin* p) { @@ -310,20 +309,14 @@ namespace euf { bool theory_checker::check(expr* e) { if (!e || !is_app(e)) return false; - if (m_checked_clauses.contains(e)) - return true; app* a = to_app(e); theory_checker_plugin* p = nullptr; return m_map.find(a->get_decl()->get_name(), p) && p->check(a); } expr_ref_vector theory_checker::clause(expr* e) { - expr_ref_vector* rr; - if (m_checked_clauses.find(e, rr)) - return *rr; SASSERT(is_app(e) && m_map.contains(to_app(e)->get_name())); expr_ref_vector r = m_map[to_app(e)->get_name()]->clause(to_app(e)); - m_checked_clauses.insert(e, alloc(expr_ref_vector, r)); return r; } @@ -365,12 +358,16 @@ namespace euf { expr_ref_vector smt_theory_checker_plugin::clause(app* jst) { expr_ref_vector result(m); - SASSERT(jst->get_name() == m_rule); for (expr* arg : *jst) result.push_back(mk_not(m, arg)); return result; } + void smt_theory_checker_plugin::register_plugins(theory_checker& pc) { + pc.register_plugin(symbol("datatype"), this); + pc.register_plugin(symbol("array"), this); + pc.register_plugin(symbol("fpa"), this); + } smt_proof_checker::smt_proof_checker(ast_manager& m, params_ref const& p): m(m), @@ -469,6 +466,7 @@ namespace euf { lbool is_sat = m_solver->check_sat(); if (is_sat != l_false) { std::cout << "did not verify: " << is_sat << " " << clause << "\n"; + std::cout << "vc:\n" << vc << "\n"; if (proof_hint) std::cout << "hint: " << mk_bounded_pp(proof_hint, m, 4) << "\n"; m_solver->display(std::cout); @@ -486,6 +484,7 @@ namespace euf { for (expr* arg : clause) std::cout << "\n " << mk_bounded_pp(arg, m); std::cout << ")\n"; + if (is_rup(proof_hint)) diagnose_rup_failure(clause); diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index ae8b9a407..17a867104 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -42,7 +42,6 @@ namespace euf { ast_manager& m; scoped_ptr_vector m_plugins; // plugins of proof checkers map m_map; // symbol table of proof checkers - obj_map m_checked_clauses; // cache of previously checked proofs and their clauses. void add_plugin(theory_checker_plugin* p); public: theory_checker(ast_manager& m); @@ -62,12 +61,11 @@ namespace euf { */ class smt_theory_checker_plugin : public theory_checker_plugin { ast_manager& m; - symbol m_rule; public: - smt_theory_checker_plugin(ast_manager& m, symbol const& n): m(m), m_rule(n) {} + smt_theory_checker_plugin(ast_manager& m): m(m) {} bool check(app* jst) override { return false; } expr_ref_vector clause(app* jst) override; - void register_plugins(theory_checker& pc) override { pc.register_plugin(m_rule, this); } + void register_plugins(theory_checker& pc) override; }; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index b462998a2..128f6ecc9 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -50,6 +50,8 @@ namespace euf { m_to_m(&m), m_to_si(&si), m_values(m), + m_clause(m), + m_expr_args(m), m_clause_visitor(m), m_smt_proof_checker(m, p) { diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index b423b1768..720053d7d 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -200,11 +200,14 @@ namespace euf { typedef std::pair expr_pair; literal_vector m_proof_literals; - svector m_proof_eqs, m_proof_deqs, m_expr_pairs; + svector m_proof_eqs, m_proof_deqs, m_expr_pairs; unsigned m_lit_head = 0, m_lit_tail = 0, m_cc_head = 0, m_cc_tail = 0; unsigned m_eq_head = 0, m_eq_tail = 0, m_deq_head = 0, m_deq_tail = 0; symbol m_euf = symbol("euf"); symbol m_smt = symbol("smt"); + expr_ref_vector m_clause; + expr_ref_vector m_expr_args; + eq_proof_hint* mk_hint(symbol const& th, literal lit, literal_vector const& r); From f0b85716a950aa52d4bd8411e9cbb309188d648a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 11:20:56 -0700 Subject: [PATCH 151/477] wip - proof logging fixes --- src/sat/smt/euf_internalize.cpp | 3 +++ src/sat/smt/euf_proof_checker.cpp | 24 +++++++++++++++++------- src/sat/smt/euf_proof_checker.h | 4 ++-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index a03af92c7..865f58fde 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -159,6 +159,9 @@ namespace euf { v = si.add_bool_var(e); s().set_external(v); s().set_eliminated(v, false); + m_bool_var2expr.reserve(v + 1, nullptr); + m_bool_var2expr[v] = e; + m_var_trail.push_back(v); sat::literal lit2 = literal(v, false); th_proof_hint* ph1 = nullptr, * ph2 = nullptr; if (use_drat()) { diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 097bc7b61..9bb2cfbaa 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -391,15 +391,23 @@ namespace euf { } - void smt_proof_checker::log_verified(app* proof_hint) { + void smt_proof_checker::log_verified(app* proof_hint, bool success) { + if (!proof_hint) + return; + symbol n = proof_hint->get_name(); - m_hint2hit.insert_if_not_there(n, 0)++; + if (success) + m_hint2hit.insert_if_not_there(n, 0)++; + else + m_hint2miss.insert_if_not_there(n, 0)++; ++m_num_logs; if (m_num_logs < 100 || (m_num_logs % 1000) == 0) { - std::cout << "(verified"; + std::cout << "(proofs"; for (auto const& [k, v] : m_hint2hit) - std::cout << " :" << k << " " << v; + std::cout << " +" << k << " " << v; + for (auto const& [k, v] : m_hint2miss) + std::cout << " -" << k << " " << v; std::cout << ")\n"; } } @@ -424,7 +432,7 @@ namespace euf { if (is_rup(proof_hint) && check_rup(clause)) { if (m_check_rup) { - log_verified(proof_hint); + log_verified(proof_hint, true); add_clause(clause); } return; @@ -440,7 +448,7 @@ namespace euf { } } if (units_are_rup) { - log_verified(proof_hint); + log_verified(proof_hint, true); add_clause(clause); return; } @@ -454,11 +462,13 @@ namespace euf { // The VC function is a no-op if the proof hint does not have an associated vc generator. expr_ref_vector vc(clause); if (m_checker.vc(proof_hint, clause, vc)) { - log_verified(proof_hint); + log_verified(proof_hint, true); add_clause(clause); return; } + log_verified(proof_hint, false); + ensure_solver(); m_solver->push(); for (expr* lit : vc) diff --git a/src/sat/smt/euf_proof_checker.h b/src/sat/smt/euf_proof_checker.h index 17a867104..9a84015e4 100644 --- a/src/sat/smt/euf_proof_checker.h +++ b/src/sat/smt/euf_proof_checker.h @@ -89,7 +89,7 @@ namespace euf { // for logging - map m_hint2hit; + map m_hint2hit, m_hint2miss; unsigned m_num_logs = 0; void add_units() { @@ -98,7 +98,7 @@ namespace euf { m_units.push_back(units[i].first); } - void log_verified(app* proof_hint); + void log_verified(app* proof_hint, bool success); void diagnose_rup_failure(expr_ref_vector const& clause); From 464d52babed90db7f0bf255057a33bbdae442e2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 12:34:45 -0700 Subject: [PATCH 152/477] fix #6410 regression after introducing beta-redex optimization --- src/smt/theory_array.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 1f842c2ed..4df6ea7e1 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -380,9 +380,8 @@ namespace smt { } else { if (m_final_check_idx % 2 == 1) { - if (assert_delayed_axioms() == FC_CONTINUE) - r = FC_CONTINUE; - else + r = assert_delayed_axioms(); + if (r == FC_DONE) r = mk_interface_eqs_at_final_check(); } else { From cdfab8cb132d2a6379d75529950f5b352396c1fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 14:50:21 -0700 Subject: [PATCH 153/477] wip - add bit-vector validator plugins and logging --- src/sat/smt/CMakeLists.txt | 1 + src/sat/smt/bv_solver.cpp | 85 ++++++++++++++++++++++----- src/sat/smt/bv_solver.h | 16 +++++- src/sat/smt/bv_theory_checker.cpp | 76 +++++++++++++++++++++++++ src/sat/smt/bv_theory_checker.h | 95 +++++++++++++++++++++++++++++++ src/sat/smt/euf_internalize.cpp | 10 ++-- src/sat/smt/euf_proof_checker.cpp | 8 ++- src/sat/smt/euf_solver.h | 4 +- 8 files changed, 272 insertions(+), 23 deletions(-) create mode 100644 src/sat/smt/bv_theory_checker.cpp create mode 100644 src/sat/smt/bv_theory_checker.h diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index cef7f96c4..22fc9963c 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -15,6 +15,7 @@ z3_add_component(sat_smt bv_internalize.cpp bv_invariant.cpp bv_solver.cpp + bv_theory_checker.cpp dt_solver.cpp euf_ackerman.cpp euf_internalize.cpp diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 8ef2c5cd5..c50f7c4e6 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -395,68 +395,123 @@ namespace bv { sat::literal leq1(s().num_vars() + 1, false); sat::literal leq2(s().num_vars() + 2, false); expr_ref eq1(m), eq2(m); + expr* a1 = nullptr, *a2 = nullptr, *b1 = nullptr, *b2 = nullptr; + if (c.m_kind == bv_justification::kind_t::bv2int) { - eq1 = m.mk_eq(c.a->get_expr(), c.b->get_expr()); - eq2 = m.mk_eq(c.a->get_expr(), c.c->get_expr()); - ctx.set_tmp_bool_var(leq1.var(), eq1); - ctx.set_tmp_bool_var(leq2.var(), eq1); + a1 = c.a->get_expr(); + a2 = c.b->get_expr(); + b1 = c.a->get_expr(); + b2 = c.c->get_expr(); } else if (c.m_kind != bv_justification::kind_t::bit2ne) { - expr* e1 = var2expr(c.m_v1); - expr* e2 = var2expr(c.m_v2); - eq1 = m.mk_eq(e1, e2); + a1 = var2expr(c.m_v1); + a2 = var2expr(c.m_v2); + } + + if (a1) { + eq1 = m.mk_eq(a1, a2); ctx.set_tmp_bool_var(leq1.var(), eq1); } + if (b1) { + eq2 = m.mk_eq(b1, b2); + ctx.set_tmp_bool_var(leq2.var(), eq2); + } + + ctx.push(value_trail(m_lit_tail)); + ctx.push(restore_size_trail(m_proof_literals)); + sat::literal_vector lits; switch (c.m_kind) { case bv_justification::kind_t::eq2bit: - lits.push_back(~leq1); lits.push_back(~c.m_antecedent); lits.push_back(c.m_consequent); + m_proof_literals.append(lits); + lits.push_back(~leq1); break; case bv_justification::kind_t::ne2bit: get_antecedents(c.m_consequent, c.to_index(), lits, true); + for (auto& lit : lits) + lit.neg(); lits.push_back(c.m_consequent); + m_proof_literals.append(lits); break; case bv_justification::kind_t::bit2eq: get_antecedents(leq1, c.to_index(), lits, true); for (auto& lit : lits) lit.neg(); + m_proof_literals.append(lits); lits.push_back(leq1); break; case bv_justification::kind_t::bit2ne: get_antecedents(c.m_consequent, c.to_index(), lits, true); + lits.push_back(~c.m_consequent); for (auto& lit : lits) lit.neg(); - lits.push_back(c.m_consequent); + m_proof_literals.append(lits); break; case bv_justification::kind_t::bv2int: get_antecedents(leq1, c.to_index(), lits, true); get_antecedents(leq2, c.to_index(), lits, true); for (auto& lit : lits) lit.neg(); + m_proof_literals.append(lits); lits.push_back(leq1); lits.push_back(leq2); break; } - ctx.get_drat().add(lits, status()); + + m_lit_head = m_lit_tail; + m_lit_tail = m_proof_literals.size(); + proof_hint* ph = new (get_region()) proof_hint(c.m_kind, m_proof_literals, m_lit_head, m_lit_tail, a1, a2, b1, b2); + auto st = sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + ctx.get_drat().add(lits, st); + m_lit_head = m_lit_tail; // TBD, a proper way would be to delete the lemma after use. ctx.set_tmp_bool_var(leq1.var(), nullptr); ctx.set_tmp_bool_var(leq2.var(), nullptr); - } - void solver::asserted(literal l) { - + expr* solver::proof_hint::get_hint(euf::solver& s) const { + ast_manager& m = s.get_manager(); + sort* proof = m.mk_proof_sort(); + expr_ref_vector& args = s.expr_args(); + ptr_buffer sorts; + for (unsigned i = m_lit_head; i < m_lit_tail; ++i) + args.push_back(s.literal2expr(m_proof_literals[i])); + if (m_kind == bv_justification::kind_t::eq2bit) + args.push_back(m.mk_not(m.mk_eq(a1, a2))); + else if (a1) + args.push_back(m.mk_eq(a1, a2)); + if (b1) + args.push_back(m.mk_eq(b1, b2)); + for (auto * arg : args) + sorts.push_back(arg->get_sort()); + symbol th; + switch (m_kind) { + case bv_justification::kind_t::eq2bit: + th = "eq2bit"; break; + case bv_justification::kind_t::ne2bit: + th = "ne2bit"; break; + case bv_justification::kind_t::bit2eq: + th = "bit2eq"; break; + case bv_justification::kind_t::bit2ne: + th = "bit2ne"; break; + case bv_justification::kind_t::bv2int: + th = "bv2int"; break; + } + func_decl* f = m.mk_func_decl(th, sorts.size(), sorts.data(), proof); + return m.mk_app(f, args); + }; + + void solver::asserted(literal l) { atom* a = get_bv2a(l.var()); TRACE("bv", tout << "asserted: " << l << "\n";); if (a) { force_push(); m_prop_queue.push_back(propagation_item(a)); - for (auto p : a->m_bit2occ) { + for (auto p : a->m_bit2occ) del_eq_occurs(p.first, p.second); - } } } diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index 2c8fb4ae9..e4a44e769 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -35,6 +35,9 @@ namespace bv { } }; + + + class solver : public euf::th_euf_solver { typedef rational numeral; typedef euf::theory_var theory_var; @@ -94,8 +97,19 @@ namespace bv { sat::justification mk_ne2bit_justification(unsigned idx, theory_var v1, theory_var v2, sat::literal c, sat::literal a); sat::ext_constraint_idx mk_bv2int_justification(theory_var v1, theory_var v2, euf::enode* a, euf::enode* b, euf::enode* c); void log_drat(bv_justification const& c); + class proof_hint : public euf::th_proof_hint { + bv_justification::kind_t m_kind; + sat::literal_vector& m_proof_literals; + unsigned m_lit_head, m_lit_tail; + expr* a1 = nullptr, * a2 = nullptr, * b1 = nullptr, * b2 = nullptr; + public: + proof_hint(bv_justification::kind_t k, sat::literal_vector& pl, unsigned lh, unsigned lt, expr* a1 = nullptr, expr* a2 = nullptr, expr* b1 = nullptr, expr* b2 = nullptr) : + m_kind(k), m_proof_literals(pl), m_lit_head(lh), m_lit_tail(lt), a1(a1), a2(a2), b1(b1), b2(b2) {} + expr* get_hint(euf::solver& s) const override; + }; + sat::literal_vector m_proof_literals; + unsigned m_lit_head = 0, m_lit_tail = 0; - /** \brief Structure used to store the position of a bitvector variable that contains the true_literal/false_literal. diff --git a/src/sat/smt/bv_theory_checker.cpp b/src/sat/smt/bv_theory_checker.cpp new file mode 100644 index 000000000..9e4418a96 --- /dev/null +++ b/src/sat/smt/bv_theory_checker.cpp @@ -0,0 +1,76 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bv_theory_checker.cpp + +Abstract: + + Plugin for bitvector lemmas + +Author: + + Nikolaj Bjorner (nbjorner) 2022-08-28 + +Notes: + + +--*/ +#pragma once + +#include "sat/smt/euf_solver.h" +#include "sat/smt/bv_theory_checker.h" + + +namespace bv { + + + /** + bv is a generic rule used for internalizing bit-vectors. + It corresponds to the Tseitin of bit-vectors. + + To bypass theory checking we pretend it is trusted. + */ + bool theory_checker::check_bv(app* jst) { return true; } + + /** + Let x, y be bit-vector terms and k be an assignment to constants bit2eq encodes the rule: + + x = k, y = k + ------------ + x = y + */ + bool theory_checker::check_bit2eq(app* jst) { return true; } + + /** + x[i] = false, y[i] = true + ------------------------- + x != y + */ + bool theory_checker::check_bit2ne(app* jst) { return true; } + + /** + x = y + ----------- + x[i] = y[i] + */ + bool theory_checker::check_eq2bit(app* jst) { return true; } + + /** + x != y, x is assigned on all but position i, x[j] = y[j] on other positions. + ---------------------------------------------------------------------------- + x[i] != y[i] + */ + bool theory_checker::check_ne2bit(app* jst) { return true; } + + /** + int2bv(bv2int(x)) = x when int2bv(bv2int(x)) has same sort as x + + n = bv2int(x), n = z + -------------------- + int2bv(z) = x + */ + bool theory_checker::check_bv2int(app* jst) { return true; } + +} diff --git a/src/sat/smt/bv_theory_checker.h b/src/sat/smt/bv_theory_checker.h new file mode 100644 index 000000000..4dda5e7c7 --- /dev/null +++ b/src/sat/smt/bv_theory_checker.h @@ -0,0 +1,95 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bv_theory_checker.h + +Abstract: + + Plugin for bitvector lemmas + +Author: + + Nikolaj Bjorner (nbjorner) 2022-08-28 + +Notes: + + +--*/ +#pragma once + +#include "util/obj_pair_set.h" +#include "ast/ast_trail.h" +#include "ast/ast_util.h" +#include "ast/bv_decl_plugin.h" +#include "sat/smt/euf_proof_checker.h" +#include + + +namespace bv { + + class theory_checker : public euf::theory_checker_plugin { + ast_manager& m; + bv_util bv; + + symbol m_eq2bit = symbol("eq2bit"); + symbol m_ne2bit = symbol("ne2bit"); + symbol m_bit2eq = symbol("bit2eq"); + symbol m_bit2ne = symbol("bit2ne"); + symbol m_bv2int = symbol("bv2int"); + symbol m_bv = symbol("bv"); + + bool check_bv(app* jst); + bool check_bit2eq(app* jst); + bool check_bit2ne(app* jst); + bool check_eq2bit(app* jst); + bool check_ne2bit(app* jst); + bool check_bv2int(app* jst); + + public: + theory_checker(ast_manager& m): + m(m), + bv(m) {} + + bool check(app* jst) override { + if (jst->get_name() == m_bv) + return check_bv(jst); + if (jst->get_name() == m_eq2bit) + return check_eq2bit(jst); + if (jst->get_name() == m_ne2bit) + return check_ne2bit(jst); + if (jst->get_name() == m_bit2eq) + return check_bit2eq(jst); + if (jst->get_name() == m_bit2ne) + return check_bit2ne(jst); + if (jst->get_name() == m_bv2int) + return check_bv2int(jst); + return false; + } + + expr_ref_vector clause(app* jst) override { + expr_ref_vector result(m); + if (jst->get_name() == m_bv) { + for (expr* arg : *jst) + result.push_back(mk_not(m, arg)); + } + else { + for (expr* arg : *jst) + result.push_back(arg); + } + return result; + } + + void register_plugins(euf::theory_checker& pc) override { + pc.register_plugin(m_bv, this); + pc.register_plugin(m_bit2eq, this); + pc.register_plugin(m_bit2ne, this); + pc.register_plugin(m_eq2bit, this); + pc.register_plugin(m_ne2bit, this); + pc.register_plugin(m_bv2int, this); + } + + }; + +} diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 865f58fde..73d059942 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -330,13 +330,13 @@ namespace euf { eqs.push_back(eq); } } - expr_ref fml(m.mk_or(eqs), m); + expr_ref fml = mk_or(eqs); sat::literal dist(si.to_bool_var(e), false); sat::literal some_eq = si.internalize(fml, m_is_redundant); add_root(~dist, ~some_eq); add_root(dist, some_eq); - s().add_clause(~dist, ~some_eq, mk_tseitin_status(~dist, ~some_eq)); - s().add_clause(dist, some_eq, mk_tseitin_status(dist, some_eq)); + s().add_clause(~dist, ~some_eq, mk_distinct_status(~dist, ~some_eq)); + s().add_clause(dist, some_eq, mk_distinct_status(dist, some_eq)); } else if (m.is_eq(e, th, el) && !m.is_iff(e)) { sat::literal lit1 = expr2literal(e); @@ -347,8 +347,8 @@ namespace euf { sat::literal lit2 = expr2literal(e2); add_root(~lit1, lit2); add_root(lit1, ~lit2); - s().add_clause(~lit1, lit2, mk_tseitin_status(~lit1, lit2)); - s().add_clause(lit1, ~lit2, mk_tseitin_status(lit1, ~lit2)); + s().add_clause(~lit1, lit2, mk_distinct_status(~lit1, lit2)); + s().add_clause(lit1, ~lit2, mk_distinct_status(lit1, ~lit2)); } } } diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 9bb2cfbaa..79f7e6880 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -25,6 +25,7 @@ Author: #include "sat/smt/euf_proof_checker.h" #include "sat/smt/arith_theory_checker.h" #include "sat/smt/q_theory_checker.h" +#include "sat/smt/bv_theory_checker.h" #include "sat/smt/distinct_theory_checker.h" #include "sat/smt/tseitin_theory_checker.h" @@ -292,6 +293,7 @@ namespace euf { add_plugin(alloc(distinct::theory_checker, m)); add_plugin(alloc(smt_theory_checker_plugin, m)); add_plugin(alloc(tseitin::theory_checker, m)); + add_plugin(alloc(bv::theory_checker, m)); } theory_checker::~theory_checker() { @@ -341,8 +343,12 @@ namespace euf { for (expr* arg : clause2) literals.mark(arg, true); for (expr* arg : clause1) - if (!literals.is_marked(arg)) + if (!literals.is_marked(arg)) { + if (m.is_not(arg, arg) && m.is_not(arg, arg) && literals.is_marked(arg)) // kludge + continue; + IF_VERBOSE(0, verbose_stream() << mk_bounded_pp(arg, m) << " not in " << clause2 << "\n"); return false; + } // extract negated units for literals in clause2 but not in clause1 // the literals should be rup diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 720053d7d..9983a48dd 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -19,6 +19,7 @@ Author: #include "util/scoped_ptr_vector.h" #include "util/trail.h" #include "ast/ast_translation.h" +#include "ast/ast_util.h" #include "ast/euf/euf_egraph.h" #include "ast/rewriter/th_rewriter.h" #include "tactic/model_converter.h" @@ -391,6 +392,7 @@ namespace euf { void visit_expr(std::ostream& out, expr* e); std::ostream& display_expr(std::ostream& out, expr* e); void on_instantiation(unsigned n, sat::literal const* lits, unsigned k, euf::enode* const* bindings); + expr_ref_vector& expr_args() { m_expr_args.reset(); return m_expr_args; } smt_proof_hint* mk_smt_hint(symbol const& n, literal_vector const& lits, enode_pair_vector const& eqs) { return mk_smt_hint(n, lits.size(), lits.data(), eqs.size(), eqs.data()); } @@ -441,7 +443,7 @@ namespace euf { euf::enode* mk_enode(expr* e, unsigned n, enode* const* args); void set_bool_var2expr(sat::bool_var v, expr* e) { m_bool_var2expr.setx(v, e, nullptr); } expr* bool_var2expr(sat::bool_var v) const { return m_bool_var2expr.get(v, nullptr); } - expr_ref literal2expr(sat::literal lit) const { expr* e = bool_var2expr(lit.var()); return (e && lit.sign()) ? expr_ref(m.mk_not(e), m) : expr_ref(e, m); } + expr_ref literal2expr(sat::literal lit) const { expr* e = bool_var2expr(lit.var()); return (e && lit.sign()) ? expr_ref(mk_not(m, e), m) : expr_ref(e, m); } unsigned generation() const { return m_generation; } sat::literal attach_lit(sat::literal lit, expr* e); From eaf52f4c3265d7dcc85354f697ef1cac684a57bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 14:52:30 -0700 Subject: [PATCH 154/477] fix infinite loop issue in def::operator+, other issues remain though for #6404 The example from #6404 results in an incorrect result. It uses integer division on private variables where MBQI support is new and not tested for substitutions. --- src/math/simplex/model_based_opt.cpp | 34 ++++++++++++++++++++++++---- src/math/simplex/model_based_opt.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index b90851582..7ab246c6e 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -98,11 +98,13 @@ namespace opt { } else if (v1 < v2) { vs.push_back(vs1[i]); - vs.back().m_coeff *= c1; + vs.back().m_coeff *= c1; + ++i; } else { vs.push_back(vs2[j]); - vs.back().m_coeff *= c2; + vs.back().m_coeff *= c2; + ++j; } } result.m_div = c1*m_div; @@ -111,6 +113,26 @@ namespace opt { return result; } + model_based_opt::def model_based_opt::def::substitute(unsigned v, def const& other) const { + def result; + vector const& vs1 = m_vars; + vector const& vs2 = other.m_vars; + rational coeff(0); + for (auto const& [id, c] : vs1) { + if (id == v) { + coeff = c; + break; + } + } + if (coeff == 0) { + return *this; + } + + NOT_IMPLEMENTED_YET(); + result.normalize(); + return result; + } + model_based_opt::def model_based_opt::def::operator/(rational const& r) const { def result(*this); result.m_div *= r; @@ -1418,13 +1440,17 @@ namespace opt { project(v, false); // project internal variables. - - def y_def = project(y, compute_def); def z_def = project(z, compute_def); + def y_def = project(y, compute_def); // may depend on z + if (compute_def) { + result = (y_def * K) + z_def; m_var2value[x] = eval(result); + TRACE("opt", tout << y << " := " << y_def << "\n"; + tout << z << " := " << z_def << "\n"; + tout << x << " := " << result << "\n"); } TRACE("opt", display(tout << "solve_div done v" << x << "\n")); return result; diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 5ba9bd619..8150f945f 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -86,6 +86,7 @@ namespace opt { def operator/(rational const& n) const; def operator*(rational const& n) const; def operator+(rational const& n) const; + def substitute(unsigned v, def const& other) const; void normalize(); }; From 77cbd89420b08db8fb4a276d584c682b6dc7935f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2022 14:57:49 -0700 Subject: [PATCH 155/477] remove once pragma from cpp file Signed-off-by: Nikolaj Bjorner --- src/sat/smt/bv_theory_checker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/smt/bv_theory_checker.cpp b/src/sat/smt/bv_theory_checker.cpp index 9e4418a96..96663c796 100644 --- a/src/sat/smt/bv_theory_checker.cpp +++ b/src/sat/smt/bv_theory_checker.cpp @@ -17,7 +17,6 @@ Notes: --*/ -#pragma once #include "sat/smt/euf_solver.h" #include "sat/smt/bv_theory_checker.h" From 07dd1065dbcc7d1b076c5d2578fd74f808fa9c86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2022 08:34:55 -0700 Subject: [PATCH 156/477] added API to monitor clause inferences See RELEASE_NOTES for more information examples pending. --- RELEASE_NOTES.md | 50 ++++++++++ scripts/update_api.py | 9 +- src/api/api_solver.cpp | 27 ++++++ src/api/c++/z3++.h | 27 +++++- src/api/dotnet/CMakeLists.txt | 1 + src/api/dotnet/OnClause.cs | 102 ++++++++++++++++++++ src/api/python/z3/z3.py | 52 ++++++++-- src/api/z3_api.h | 19 ++++ src/ast/ast.cpp | 8 ++ src/ast/ast.h | 2 + src/ast/ast_ll_pp.cpp | 1 + src/sat/sat_solver.h | 10 +- src/sat/sat_solver/inc_sat_solver.cpp | 4 + src/sat/smt/bv_internalize.cpp | 2 +- src/sat/smt/euf_proof.cpp | 50 ++++++---- src/sat/smt/euf_solver.cpp | 8 ++ src/sat/smt/euf_solver.h | 12 ++- src/sat/smt/q_solver.cpp | 16 +-- src/smt/qi_queue.cpp | 10 ++ src/smt/smt_clause_proof.cpp | 134 +++++++++++++++----------- src/smt/smt_clause_proof.h | 18 +++- src/smt/smt_context.h | 6 ++ src/smt/smt_internalizer.cpp | 6 +- src/smt/smt_justification.cpp | 3 +- src/smt/smt_kernel.cpp | 4 + src/smt/smt_kernel.h | 2 + src/smt/smt_solver.cpp | 4 + src/smt/tactic/smt_tactic_core.cpp | 15 ++- src/solver/combined_solver.cpp | 6 +- src/solver/solver.h | 2 +- src/solver/tactic2solver.cpp | 4 + src/tactic/tactic.h | 4 + src/tactic/tactical.cpp | 4 + src/tactic/user_propagator_base.h | 5 + 34 files changed, 505 insertions(+), 122 deletions(-) create mode 100644 src/api/dotnet/OnClause.cs diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b1fe88e06..0ec6c04b1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,6 +10,56 @@ Version 4.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.12.0 +============== +- add clause logging API. + - The purpose of logging API and self-checking is to enable an array of use cases. + - proof mining (what instantiations did Z3 use)? + - A refresh of the AxiomProfiler could use the logging API. The (brittle) trace feature should be deprecated. + - debugging + - a built-in self certifier implements a custom proof checker for the format used by the new solver (sat.euf=true). + - other potential options: + - integration into certified tool chains + - interpolation + - Z3_register_on_clause (also exposed over C++, Python and .Net) + - it applies to z3's main CDCL(T) core and a new CDCL(T) core (sat.euf=true). + - The added API function allows to register a callback for when clauses are inferred + More precisely, when clauses are assumed (as part of input), deleted, or deduced. + Clauses that are deduced by the CDCL SAT engine using standard inferences are marked as 'rup'. + Clauses that are deduced by theories are marked by default by 'smt', and when more detailed information + is available with proof hints or proof objects. Instantations are considered useful to track so they + are logged using terms of the form (inst (not (forall (x) body)) body[t/x] (bind t)), where + 'inst' is a name of a function that produces a proof term representing the instantiation. +- add options for proof logging, trimming, and checking for the new core. + - sat.smt.proof (symbol) add SMT proof to file (default: ) + - sat.smt.proof.check (bool) check SMT proof while it is created (default: false) + - it applies a custom self-validator. The self-validator comprises of several small checkers and represent a best-effort + validation mechanism. If there are no custom validators associated with inferences, or the custom validators fail to certify + inferences, the self-validator falls back to invoking z3 (SMT) solving on the lemma. + - euf - propagations and conflicts from congruence closure (theory of equality and uninterpreted functions) are checked + based on a proof format that tracks uses of congruence closure and equalities. It only performs union find operations. + - tseitin - clausification steps are checked for Boolean operators. + - farkas, bound, implies_eq - arithmetic inferences that can be justified using a combination of Farkas lemma and cuts are checked. + Note: the arithmetic solver may produce proof hints that the proof checker cannot check. It is mainly a limitation + of the arithmetic solver not pulling relevant information. Ensuring a tight coupling with proof hints and the validator + capabilites is open ended future work and good material for theses. + - bit-vector inferences - are treated as trusted (there is no validation, it always blindly succeeds) + - arrays, datatypes - there is no custom validation for other theories at present. Lemmas are validated using SMT. + - sat.smt.proof.check_rup (bool) apply forward RUP proof checking (default: true) + - this option can incur significant runtime overhead. Effective proof checking relies on first trimming + proofs into a format where dependencies are tracked and then checking relevant inferences. + Turn this option off if you just want to check theory inferences. +- add options to validate proofs offline. It applies to proofs saved when sat.smt.proof is set to a valid file name. + - solver.proof.check (bool) check proof logs (default: true) + - the option sat.smt.proof_check_rup can be used to control what is checked + - solver.proof.save (bool) save proof log into a proof object that can be extracted using (get-proof) (default: false) + - experimental: saves a proof log into a term + - solver.proof.trim (bool) trim the offline proof and print the trimmed proof to the console + - experimental: performs DRUP trimming to reduce the set of hypotheses and inferences relevant to derive the empty clause. +- JS support for Arrays, thanks to Walden Yan +- More portable memory allocation, thanks to Nuno Lopes (avoid custom handling to calculate memory usage) + + Version 4.11.2 ============== - add error handling to fromString method in JavaScript diff --git a/scripts/update_api.py b/scripts/update_api.py index 41a9face5..a9753ec23 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -339,6 +339,10 @@ def Z3_set_error_handler(ctx, hndlr, _elems=Elementaries(_lib.Z3_set_error_handl _elems.Check(ctx) return ceh +def Z3_solver_register_on_clause(ctx, s, user_ctx, on_clause_eh, _elems = Elementaries(_lib.Z3_solver_register_on_clause)): + _elems.f(ctx, s, user_ctx, on_clause_eh) + _elems.Check(ctx) + def Z3_solver_propagate_init(ctx, s, user_ctx, push_eh, pop_eh, fresh_eh, _elems = Elementaries(_lib.Z3_solver_propagate_init)): _elems.f(ctx, s, user_ctx, push_eh, pop_eh, fresh_eh) _elems.Check(ctx) @@ -1315,7 +1319,8 @@ z3_ml_callbacks = frozenset([ 'Z3_solver_propagate_eq', 'Z3_solver_propagate_diseq', 'Z3_solver_propagate_created', - 'Z3_solver_propagate_decide' + 'Z3_solver_propagate_decide', + 'Z3_solver_register_on_clause' ]) def mk_ml(ml_src_dir, ml_output_dir): @@ -1844,6 +1849,7 @@ _error_handler_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint) _lib.Z3_set_error_handler.restype = None _lib.Z3_set_error_handler.argtypes = [ContextObj, _error_handler_type] +Z3_on_clause_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) Z3_push_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p) Z3_pop_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint) Z3_fresh_eh = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) @@ -1855,6 +1861,7 @@ Z3_eq_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_ Z3_created_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) Z3_decide_eh = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p) +_lib.Z3_solver_register_on_clause.restype = None _lib.Z3_solver_propagate_init.restype = None _lib.Z3_solver_propagate_final.restype = None _lib.Z3_solver_propagate_fixed.restype = None diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 963a57666..ab285be06 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -907,6 +907,33 @@ extern "C" { ~api_context_obj() override { dealloc(c); } }; + struct scoped_ast_vector { + Z3_ast_vector_ref* v; + scoped_ast_vector(Z3_ast_vector_ref* v): v(v) { v->inc_ref(); } + ~scoped_ast_vector() { v->dec_ref(); } + }; + + void Z3_API Z3_solver_register_on_clause( + Z3_context c, + Z3_solver s, + void* user_context, + Z3_on_clause_eh on_clause_eh) { + Z3_TRY; + RESET_ERROR_CODE(); + init_solver(c, s); + user_propagator::on_clause_eh_t _on_clause = [=](void* user_ctx, expr* proof, unsigned n, expr* const* _literals) { + Z3_ast_vector_ref * literals = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(literals); + expr_ref pr(proof, mk_c(c)->m()); + scoped_ast_vector _sc(literals); + for (unsigned i = 0; i < n; ++i) + literals->m_ast_vector.push_back(_literals[i]); + on_clause_eh(user_ctx, of_expr(pr.get()), of_ast_vector(literals)); + }; + to_solver_ref(s)->register_on_clause(user_context, _on_clause); + Z3_CATCH; + } + void Z3_API Z3_solver_propagate_init( Z3_context c, Z3_solver s, diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 0275a22e1..553e71287 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -158,7 +158,7 @@ namespace z3 { class context { private: friend class user_propagator_base; - bool m_enable_exceptions; + bool m_enable_exceptions = true; rounding_mode m_rounding_mode; Z3_context m_ctx = nullptr; void init(config & c) { @@ -2670,10 +2670,10 @@ namespace z3 { public: struct simple {}; struct translate {}; - solver(context & c):object(c) { init(Z3_mk_solver(c)); } - solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); } + solver(context & c):object(c) { init(Z3_mk_solver(c)); check_error(); } + solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); check_error(); } solver(context & c, Z3_solver s):object(c) { init(s); } - solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); } + solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); check_error(); } solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); } solver(solver const & s):object(s) { init(s.m_solver); } ~solver() { Z3_solver_dec_ref(ctx(), m_solver); } @@ -4059,6 +4059,25 @@ namespace z3 { return expr(ctx(), r); } + typedef std::function on_clause_eh_t; + + class on_clause { + context& c; + on_clause_eh_t m_on_clause; + + static void _on_clause_eh(void* _ctx, Z3_ast _proof, Z3_ast_vector _literals) { + on_clause* ctx = static_cast(_ctx); + expr_vector lits(ctx->c, _literals); + expr proof(ctx->c, _proof); + ctx->m_on_clause(proof, lits); + } + public: + on_clause(solver& s, on_clause_eh_t& on_clause_eh): c(s.ctx()) { + m_on_clause = on_clause_eh; + Z3_solver_register_on_clause(c, s, this, _on_clause_eh); + c.check_error(); + } + }; class user_propagator_base { diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index b2ba590ce..a9344aa86 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -87,6 +87,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE NativeFuncInterp.cs NativeModel.cs NativeSolver.cs + OnClause.cs Optimize.cs ParamDescrs.cs Params.cs diff --git a/src/api/dotnet/OnClause.cs b/src/api/dotnet/OnClause.cs new file mode 100644 index 000000000..686318928 --- /dev/null +++ b/src/api/dotnet/OnClause.cs @@ -0,0 +1,102 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + OnClause.cs + +Abstract: + + Callback on clause inferences + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-19 + +Notes: + + +--*/ + +using System; +using System.Diagnostics; +using System.Linq; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Microsoft.Z3 +{ + + using Z3_context = System.IntPtr; + using Z3_solver = System.IntPtr; + using voidp = System.IntPtr; + using Z3_ast = System.IntPtr; + using Z3_ast_vector = System.IntPtr; + + + /// + /// OnClause - clause inference callback + /// + public class OnClause : IDisposable + { + /// + /// Delegate type for when clauses are inferred. + /// An inference is a pair comprising of + /// - a proof (hint). A partial (or comprehensive) derivation justifying the inference. + /// - a clause (vector of literals) + /// The life-time of the proof hint and clause vector is limited to the scope of the callback. + /// should the callback want to store hints or clauses it will need to call Dup on the hints + /// and/or extract literals from the clause, respectively. + /// + public delegate void OnClauseEh(Expr proof_hint, ASTVector clause); + + + // access managed objects through a static array. + // thread safety is ignored for now. + GCHandle gch; + Solver solver; + Context ctx; + OnClauseEh on_clause; + + Native.Z3_on_clause_eh on_clause_eh; + + static void _on_clause(voidp ctx, Z3_ast _proof_hint, Z3_ast_vector _clause) + { + var onc = (OnClause)GCHandle.FromIntPtr(ctx).Target; + using var proof_hint = Expr.Create(onc.ctx, _proof_hint); + using var clause = new ASTVector(onc.ctx, _clause); + onc.on_clause(proof_hint, clause); + } + + /// + /// OnClause constructor + /// + public OnClause(Solver s, OnClauseEh onc) + { + gch = GCHandle.Alloc(this); + solver = s; + ctx = solver.Context; + on_clause = onc; + on_clause_eh = _on_clause; + Native.Z3_solver_register_on_clause(ctx.nCtx, solver.NativeObject, GCHandle.ToIntPtr(gch), on_clause_eh); + } + + /// + /// Release private memory. + /// + ~OnClause() + { + Dispose(); + } + + /// + /// Must be called. The object will not be garbage collected automatically even if the context is disposed + /// + public virtual void Dispose() + { + if (!gch.IsAllocated) + return; + gch.Free(); + } + } +} diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index ca3bc6f53..bbe212453 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11301,6 +11301,45 @@ def TransitiveClosure(f): """ return FuncDeclRef(Z3_mk_transitive_closure(f.ctx_ref(), f.ast), f.ctx) +def to_Ast(ptr,): + ast = Ast(ptr) + super(ctypes.c_void_p, ast).__init__(ptr) + return ast + +def to_ContextObj(ptr,): + ctx = ContextObj(ptr) + super(ctypes.c_void_p, ctx).__init__(ptr) + return ctx + +def to_AstVectorObj(ptr,): + v = AstVectorObj(ptr) + super(ctypes.c_void_p, v).__init__(ptr) + return v + +# NB. my-hacky-class only works for a single instance of OnClause +# it should be replaced with a proper correlation between OnClause +# and object references that can be passed over the FFI. +# for UserPropagator we use a global dictionary, which isn't great code. + +_my_hacky_class = None +def on_clause_eh(ctx, p, clause): + onc = _my_hacky_class + p = _to_expr_ref(to_Ast(p), onc.ctx) + clause = AstVector(to_AstVectorObj(clause), onc.ctx) + onc.on_clause(p, clause) + +_on_clause_eh = Z3_on_clause_eh(on_clause_eh) + +class OnClause: + def __init__(self, s, on_clause): + self.s = s + self.ctx = s.ctx + self.on_clause = on_clause + self.idx = 22 + global _my_hacky_class + _my_hacky_class = self + Z3_solver_register_on_clause(self.ctx.ref(), self.s.solver, self.idx, _on_clause_eh) + class PropClosures: def __init__(self): @@ -11358,11 +11397,6 @@ def user_prop_pop(ctx, cb, num_scopes): prop.cb = cb prop.pop(num_scopes) -def to_ContextObj(ptr,): - ctx = ContextObj(ptr) - super(ctypes.c_void_p, ctx).__init__(ptr) - return ctx - def user_prop_fresh(ctx, _new_ctx): _prop_closures.set_threaded() @@ -11377,10 +11411,6 @@ def user_prop_fresh(ctx, _new_ctx): _prop_closures.set(new_prop.id, new_prop) return new_prop.id -def to_Ast(ptr,): - ast = Ast(ptr) - super(ctypes.c_void_p, ast).__init__(ptr) - return ast def user_prop_fixed(ctx, cb, id, value): prop = _prop_closures.get(ctx) @@ -11442,6 +11472,7 @@ _user_prop_eq = Z3_eq_eh(user_prop_eq) _user_prop_diseq = Z3_eq_eh(user_prop_diseq) _user_prop_decide = Z3_decide_eh(user_prop_decide) + def PropagateFunction(name, *sig): """Create a function that gets tracked by user propagator. Every term headed by this function symbol is tracked. @@ -11462,7 +11493,8 @@ def PropagateFunction(name, *sig): dom[i] = sig[i].ast ctx = rng.ctx return FuncDeclRef(Z3_solver_propagate_declare(ctx.ref(), to_symbol(name, ctx), arity, dom, rng.ast), ctx) - + + class UserPropagateBase: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 9955f91be..1100d60dd 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1433,6 +1433,7 @@ Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_as Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb)); Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t)); Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast* t, unsigned* idx, Z3_lbool* phase)); +Z3_DECLARE_CLOSURE(Z3_on_clause_eh, void, (void* ctx, Z3_ast proof_hint, Z3_ast_vector literals)); /** @@ -6877,6 +6878,24 @@ extern "C" { */ void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]); + /** + \brief register a callback to that retrieves assumed, inferred and deleted clauses during search. + + \param c - context. + \param s - solver object. + \param user_context - a context used to maintain state for callbacks. + \param on_clause_eh - a callback that is invoked by when a clause is + - asserted to the CDCL engine (corresponding to an input clause after pre-processing) + - inferred by CDCL(T) using either a SAT or theory conflict/propagation + - deleted by the CDCL(T) engine + + def_API('Z3_solver_register_on_clause', VOID, (_in(CONTEXT), _in(SOLVER), _in(VOID_PTR), _fnptr(Z3_on_clause_eh))) + */ + void Z3_API Z3_solver_register_on_clause( + Z3_context c, + Z3_solver s, + void* user_context, + Z3_on_clause_eh on_clause_eh); /** \brief register a user-properator with the solver. diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f9bdc3414..50b9e5a4d 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1969,6 +1969,14 @@ app * ast_manager::mk_app(family_id fid, decl_kind k, expr * arg1, expr * arg2, return mk_app(fid, k, 0, nullptr, 3, args); } +app * ast_manager::mk_app(symbol const& name, unsigned n, expr* const* args, sort* range) { + ptr_buffer sorts; + for (unsigned i = 0; i < n; ++i) + sorts.push_back(args[i]->get_sort()); + return mk_app(mk_func_decl(name, n, sorts.data(), range), n, args); +} + + sort * ast_manager::mk_sort(symbol const & name, sort_info * info) { unsigned sz = sort::get_obj_size(); void * mem = allocate_node(sz); diff --git a/src/ast/ast.h b/src/ast/ast.h index 511c2cee0..ce9de96d4 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1883,6 +1883,8 @@ public: return mk_app(decl, 3, args); } + app * mk_app(symbol const& name, unsigned n, expr* const* args, sort* range); + app * mk_const(func_decl * decl) { SASSERT(decl->get_arity() == 0); return mk_app(decl, static_cast(0), static_cast(nullptr)); diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index 5de98c644..d04777eb7 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -86,6 +86,7 @@ class ll_printer { default: display_child_ref(n); } + } template diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 64ee209c9..2b341185f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -432,17 +432,17 @@ namespace sat { } void checkpoint() { - if (!m_checkpoint_enabled) return; - if (limit_reached()) { + if (!m_checkpoint_enabled) + return; + if (limit_reached()) throw solver_exception(Z3_CANCELED_MSG); - } - if (memory_exceeded()) { + if (memory_exceeded()) throw solver_exception(Z3_MAX_MEMORY_MSG); - } } void set_par(parallel* p, unsigned id); bool canceled() { return !m_rlimit.inc(); } config const& get_config() const { return m_config; } + void set_drat(bool d) { m_config.m_drat = d; } drat& get_drat() { return m_drat; } drat* get_drat_ptr() { return &m_drat; } void set_incremental(bool b) { m_config.m_incremental = b; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 5c1859258..6fb936435 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -661,6 +661,10 @@ public: return ext; } + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + ensure_euf()->register_on_clause(ctx, on_clause); + } + void user_propagate_init( void* ctx, user_propagator::push_eh_t& push_eh, diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 4cc161829..cffd62acd 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -772,6 +772,6 @@ namespace bv { eqs.push_back(~eq); } TRACE("bv", for (auto l : eqs) tout << mk_bounded_pp(literal2expr(l), m) << " "; tout << "\n";); - s().add_clause(eqs.size(), eqs.data(), sat::status::th(m_is_redundant, get_id())); + add_clause(eqs); } } diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index bfda8aad6..906e6e068 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -25,19 +25,25 @@ namespace euf { if (m_proof_initialized) return; - if (s().get_config().m_drat && - (get_config().m_lemmas2console || - s().get_config().m_smt_proof_check || - s().get_config().m_smt_proof.is_non_empty_string())) { + if (m_on_clause) + s().set_drat(true); + + if (!s().get_config().m_drat) + return; - get_drat().add_theory(get_id(), symbol("euf")); - get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); - TRACE("euf", tout << "init-proof " << s().get_config().m_smt_proof << "\n"); - if (s().get_config().m_smt_proof.is_non_empty_string()) - m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); - get_drat().set_clause_eh(*this); - m_proof_initialized = true; - } + if (!get_config().m_lemmas2console && + !s().get_config().m_smt_proof_check && + !m_on_clause && + !s().get_config().m_smt_proof.is_non_empty_string()) + return; + + get_drat().add_theory(get_id(), symbol("euf")); + get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); + + if (s().get_config().m_smt_proof.is_non_empty_string()) + m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); + get_drat().set_clause_eh(*this); + m_proof_initialized = true; } /** @@ -135,7 +141,6 @@ namespace euf { ast_manager& m = s.get_manager(); func_decl_ref cc(m), cc_comm(m); sort* proof = m.mk_proof_sort(); - ptr_buffer sorts; expr_ref_vector& args = s.m_expr_args; args.reset(); if (m_cc_head < m_cc_tail) { @@ -161,12 +166,8 @@ namespace euf { for (unsigned i = m_cc_head; i < m_cc_tail; ++i) { auto const& [a, b, ts, comm] = s.m_explain_cc[i]; args.push_back(cc_proof(comm, m.mk_eq(a, b))); - } - for (auto * arg : args) - sorts.push_back(arg->get_sort()); - - func_decl* f = m.mk_func_decl(th, sorts.size(), sorts.data(), proof); - return m.mk_app(f, args); + } + return m.mk_app(th, args.size(), args.data(), proof); } smt_proof_hint* solver::mk_smt_clause(symbol const& n, unsigned nl, literal const* lits) { @@ -304,6 +305,17 @@ namespace euf { on_lemma(n, lits, st); on_proof(n, lits, st); on_check(n, lits, st); + on_clause_eh(n, lits, st); + } + + void solver::on_clause_eh(unsigned n, literal const* lits, sat::status st) { + if (!m_on_clause) + return; + m_clause.reset(); + for (unsigned i = 0; i < n; ++i) + m_clause.push_back(literal2expr(lits[i])); + auto hint = status2proof_hint(st); + m_on_clause(m_on_clause_ctx, hint, m_clause.size(), m_clause.data()); } void solver::on_proof(unsigned n, literal const* lits, sat::status st) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 128f6ecc9..df36501dd 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -1113,6 +1113,14 @@ namespace euf { return true; } + void solver::register_on_clause( + void* ctx, + user_propagator::on_clause_eh_t& on_clause) { + m_on_clause_ctx = ctx; + m_on_clause = on_clause; + init_proof(); + } + void solver::user_propagate_init( void* ctx, user_propagator::push_eh_t& push_eh, diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 9983a48dd..d4729dcfe 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -123,8 +123,10 @@ namespace euf { sat::lookahead* m_lookahead = nullptr; ast_manager* m_to_m; sat::sat_internalizer* m_to_si; - scoped_ptr m_ackerman; - user_solver::solver* m_user_propagator = nullptr; + scoped_ptr m_ackerman; + user_propagator::on_clause_eh_t m_on_clause; + void* m_on_clause_ctx = nullptr; + user_solver::solver* m_user_propagator = nullptr; th_solver* m_qsolver = nullptr; unsigned m_generation = 0; std::string m_reason_unknown; @@ -221,6 +223,7 @@ namespace euf { void on_lemma(unsigned n, literal const* lits, sat::status st); void on_proof(unsigned n, literal const* lits, sat::status st); void on_check(unsigned n, literal const* lits, sat::status st); + void on_clause_eh(unsigned n, literal const* lits, sat::status st); std::ostream& display_literals(std::ostream& out, unsigned n, sat::literal const* lits); void display_assume(std::ostream& out, unsigned n, literal const* lits); void display_inferred(std::ostream& out, unsigned n, literal const* lits, expr* proof_hint); @@ -487,6 +490,11 @@ namespace euf { // diagnostics func_decl_ref_vector const& unhandled_functions() { return m_unhandled_functions; } + // clause tracing + void register_on_clause( + void* ctx, + user_propagator::on_clause_eh_t& on_clause); + // user propagator void user_propagate_init( void* ctx, diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 7fd7be97e..a94008074 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -389,26 +389,16 @@ namespace q { expr* q_proof_hint::get_hint(euf::solver& s) const { ast_manager& m = s.get_manager(); expr_ref_vector args(m); - ptr_buffer sorts; expr_ref binding(m); sort* range = m.mk_proof_sort(); - func_decl* d; for (unsigned i = 0; i < m_num_bindings; ++i) args.push_back(m_bindings[i]); - for (expr* arg : args) - sorts.push_back(arg->get_sort()); - d = m.mk_func_decl(symbol("bind"), args.size(), sorts.data(), range); - binding = m.mk_app(d, args); + binding = m.mk_app(symbol("bind"), args.size(), args.data(), range); args.reset(); - sorts.reset(); for (unsigned i = 0; i < m_num_literals; ++i) args.push_back(s.literal2expr(~m_literals[i])); - args.push_back(binding); - for (expr* arg : args) - sorts.push_back(arg->get_sort()); - - d = m.mk_func_decl(symbol("inst"), args.size(), sorts.data(), range); - return m.mk_app(d, args); + args.push_back(binding); + return m.mk_app(symbol("inst"), args.size(), args.data(), range); } } diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index f8fbe739e..a1402839d 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -304,6 +304,16 @@ namespace smt { } m_instances.push_back(pr1); } + else if (m_context.on_clause_active()) { + expr_ref_vector bindings_e(m), args(m); + for (unsigned i = 0; i < num_bindings; ++i) + bindings_e.push_back(bindings[i]->get_expr()); + args.push_back(m.mk_not(q)); + args.push_back(instance); + args.push_back(m.mk_app(symbol("bind"), num_bindings, bindings_e.data(), m.mk_proof_sort())); + pr1 = m.mk_app(symbol("inst"), args.size(), args.data(), m.mk_proof_sort()); + m_instances.push_back(pr1); + } TRACE("qi_queue", tout << mk_pp(lemma, m) << "\n#" << lemma->get_id() << ":=\n" << mk_ll_pp(lemma, m);); m_stats.m_num_instances++; unsigned gen = get_new_gen(q, generation, ent.m_cost); diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index 9722d95c0..a2bc381e4 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -36,91 +36,113 @@ namespace smt { } } - proof* clause_proof::justification2proof(justification* j) { - return (m.proofs_enabled() && j) ? j->mk_proof(ctx.get_cr()) : nullptr; + proof* clause_proof::justification2proof(status st, justification* j) { + proof* r = nullptr; + if (j) + r = j->mk_proof(ctx.get_cr()); + if (r) + return r; + if (!m_on_clause_active) + return nullptr; + switch (st) { + case status::assumption: + return m.mk_const("assumption", m.mk_proof_sort()); + case status::lemma: + return m.mk_const("rup", m.mk_proof_sort()); + case status::th_lemma: + case status::th_assumption: + return m.mk_const("smt", m.mk_proof_sort()); + case status::deleted: + return m.mk_const("del", m.mk_proof_sort()); + } + UNREACHABLE(); + return nullptr; } void clause_proof::add(clause& c) { - if (ctx.get_fparams().m_clause_proof) { - justification* j = c.get_justification(); - proof_ref pr(justification2proof(j), m); - CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); - update(c, kind2st(c.get_kind()), pr); - } + if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + return; + justification* j = c.get_justification(); + auto st = kind2st(c.get_kind()); + proof_ref pr(justification2proof(st, j), m); + CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); + update(c, st, pr); } void clause_proof::add(unsigned n, literal const* lits, clause_kind k, justification* j) { - if (ctx.get_fparams().m_clause_proof) { - proof_ref pr(justification2proof(j), m); - CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); - m_lits.reset(); - for (unsigned i = 0; i < n; ++i) { - m_lits.push_back(ctx.literal2expr(lits[i])); - } - update(kind2st(k), m_lits, pr); - } + if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + return; + auto st = kind2st(k); + proof_ref pr(justification2proof(st, j), m); + CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); + m_lits.reset(); + for (unsigned i = 0; i < n; ++i) + m_lits.push_back(ctx.literal2expr(lits[i])); + update(st, m_lits, pr); } void clause_proof::shrink(clause& c, unsigned new_size) { - if (ctx.get_fparams().m_clause_proof) { - m_lits.reset(); - for (unsigned i = 0; i < new_size; ++i) { - m_lits.push_back(ctx.literal2expr(c[i])); - } - update(status::lemma, m_lits, nullptr); - for (unsigned i = new_size; i < c.get_num_literals(); ++i) { - m_lits.push_back(ctx.literal2expr(c[i])); - } - update(status::deleted, m_lits, nullptr); - } + if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + return; + m_lits.reset(); + for (unsigned i = 0; i < new_size; ++i) + m_lits.push_back(ctx.literal2expr(c[i])); + proof* p = justification2proof(status::lemma, nullptr); + update(status::lemma, m_lits, p); + for (unsigned i = new_size; i < c.get_num_literals(); ++i) + m_lits.push_back(ctx.literal2expr(c[i])); + p = justification2proof(status::deleted, nullptr); + update(status::deleted, m_lits, p); } void clause_proof::add(literal lit, clause_kind k, justification* j) { - if (ctx.get_fparams().m_clause_proof) { - m_lits.reset(); - m_lits.push_back(ctx.literal2expr(lit)); - proof* pr = justification2proof(j); - update(kind2st(k), m_lits, pr); - } + if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + return; + m_lits.reset(); + m_lits.push_back(ctx.literal2expr(lit)); + auto st = kind2st(k); + proof* pr = justification2proof(st, j); + update(st, m_lits, pr); } void clause_proof::add(literal lit1, literal lit2, clause_kind k, justification* j) { - if (ctx.get_fparams().m_clause_proof) { - m_lits.reset(); - m_lits.push_back(ctx.literal2expr(lit1)); - m_lits.push_back(ctx.literal2expr(lit2)); - proof* pr = justification2proof(j); - m_trail.push_back(info(kind2st(k), m_lits, pr)); - } + if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + return; + m_lits.reset(); + m_lits.push_back(ctx.literal2expr(lit1)); + m_lits.push_back(ctx.literal2expr(lit2)); + auto st = kind2st(k); + proof* pr = justification2proof(st, j); + update(st, m_lits, pr); } void clause_proof::del(clause& c) { - update(c, status::deleted, nullptr); + update(c, status::deleted, justification2proof(status::deleted, nullptr)); } void clause_proof::update(status st, expr_ref_vector& v, proof* p) { TRACE("clause_proof", tout << m_trail.size() << " " << st << " " << v << "\n";); - IF_VERBOSE(3, verbose_stream() << st << " " << v << "\n"); - m_trail.push_back(info(st, v, p)); + if (ctx.get_fparams().m_clause_proof) + m_trail.push_back(info(st, v, p)); + if (m_on_clause_eh) + m_on_clause_eh(m_on_clause_ctx, p, v.size(), v.data()); } void clause_proof::update(clause& c, status st, proof* p) { - if (ctx.get_fparams().m_clause_proof) { - m_lits.reset(); - for (literal lit : c) { - m_lits.push_back(ctx.literal2expr(lit)); - } - update(st, m_lits, p); - } + if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + return; + m_lits.reset(); + for (literal lit : c) + m_lits.push_back(ctx.literal2expr(lit)); + update(st, m_lits, p); } proof_ref clause_proof::get_proof(bool inconsistent) { TRACE("context", tout << "get-proof " << ctx.get_fparams().m_clause_proof << "\n";); - if (!ctx.get_fparams().m_clause_proof) { + if (!ctx.get_fparams().m_clause_proof) return proof_ref(m); - } proof_ref_vector ps(m); for (auto& info : m_trail) { expr_ref fact = mk_or(info.m_clause); @@ -143,12 +165,10 @@ namespace smt { break; } } - if (inconsistent) { + if (inconsistent) ps.push_back(m.mk_false()); - } - else { + else ps.push_back(m.mk_const("clause-trail-end", m.mk_bool_sort())); - } return proof_ref(m.mk_clause_trail(ps.size(), ps.data()), m); } diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index e78c9943c..f15d0ffe0 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -28,6 +28,7 @@ Revision History: #include "smt/smt_theory.h" #include "smt/smt_clause.h" +#include "tactic/user_propagator_base.h" namespace smt { class context; @@ -50,14 +51,17 @@ namespace smt { proof_ref m_proof; info(status st, expr_ref_vector& v, proof* p): m_status(st), m_clause(v), m_proof(p, m_clause.m()) {} }; - context& ctx; - ast_manager& m; + context& ctx; + ast_manager& m; expr_ref_vector m_lits; - vector m_trail; + vector m_trail; + bool m_on_clause_active = false; + user_propagator::on_clause_eh_t m_on_clause_eh; + void* m_on_clause_ctx = nullptr; void update(status st, expr_ref_vector& v, proof* p); void update(clause& c, status st, proof* p); status kind2st(clause_kind k); - proof* justification2proof(justification* j); + proof* justification2proof(status st, justification* j); public: clause_proof(context& ctx); void shrink(clause& c, unsigned new_size); @@ -67,6 +71,12 @@ namespace smt { void add(unsigned n, literal const* lits, clause_kind k, justification* j); void del(clause& c); proof_ref get_proof(bool inconsistent); + bool on_clause_active() const { return m_on_clause_active; } + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) { + m_on_clause_eh = on_clause; + m_on_clause_ctx = ctx; + m_on_clause_active = !!m_on_clause_eh; + } }; std::ostream& operator<<(std::ostream& out, clause_proof::status st); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 7ca2e1c63..4a5f64926 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1706,6 +1706,12 @@ namespace smt { void get_units(expr_ref_vector& result); + bool on_clause_active() const { return m_clause_proof.on_clause_active(); } + + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) { + m_clause_proof.register_on_clause(ctx, on_clause); + } + /* * user-propagator */ diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ac433c602..2483b2ca4 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1626,9 +1626,11 @@ namespace smt { } mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); } - else { + else if (pr && on_clause_active()) + // support logging of quantifier instantiations and other more detailed information + mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); + else mk_clause(num_lits, lits, nullptr); - } } void context::mk_root_clause(literal l1, literal l2, proof * pr) { diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index 0124a1810..d2a8aa2e6 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -82,7 +82,8 @@ namespace smt { } proof * unit_resolution_justification::mk_proof(conflict_resolution & cr) { - SASSERT(m_antecedent); + if (!m_antecedent) + return nullptr; ast_manager& m = cr.get_manager(); proof_ref_vector prs(m); proof * pr = cr.get_proof(m_antecedent); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 8f442596c..ae3338f52 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -260,6 +260,10 @@ namespace smt { m_imp->m_kernel.user_propagate_init(ctx, push_eh, pop_eh, fresh_eh); } + void kernel::register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) { + m_imp->m_kernel.register_on_clause(ctx, on_clause); + } + void kernel::user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) { m_imp->m_kernel.user_propagate_register_fixed(fixed_eh); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 4fa840f5e..fa4a48406 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -290,6 +290,8 @@ namespace smt { */ static void collect_param_descrs(param_descrs & d); + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause); + /** \brief initialize a user-propagator "theory" */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 61c6de377..61c7fdda7 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -212,6 +212,10 @@ namespace { return m_context.get_trail(max_level); } + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + m_context.register_on_clause(ctx, on_clause); + } + void user_propagate_init( void* ctx, user_propagator::push_eh_t& push_eh, diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index c45165d79..5527f12f5 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -323,7 +323,13 @@ public: user_propagator::eq_eh_t m_diseq_eh; user_propagator::created_eh_t m_created_eh; user_propagator::decide_eh_t m_decide_eh; - + void* m_on_clause_ctx = nullptr; + user_propagator::on_clause_eh_t m_on_clause_eh; + + void on_clause_delay_init() { + if (m_on_clause_eh) + m_ctx->register_on_clause(m_on_clause_ctx, m_on_clause_eh); + } void user_propagate_delay_init() { if (!m_user_ctx) @@ -349,6 +355,13 @@ public: m_diseq_eh = nullptr; m_created_eh = nullptr; m_decide_eh = nullptr; + m_on_clause_eh = nullptr; + m_on_clause_ctx = nullptr; + } + + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + m_on_clause_ctx = ctx; + m_on_clause_eh = on_clause; } void user_propagate_init( diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 76e6138ab..7b1449637 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -344,7 +344,11 @@ public: else return m_solver2->get_labels(r); } - + + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + switch_inc_mode(); + m_solver2->register_on_clause(ctx, on_clause); + } void user_propagate_init( void* ctx, diff --git a/src/solver/solver.h b/src/solver/solver.h index 8a4bec538..4ffdd5092 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -278,7 +278,7 @@ public: }; virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; - + protected: virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 6e34758e6..b65ffde57 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -84,6 +84,10 @@ public: void set_phase(phase* p) override { } void move_to_front(expr* e) override { } + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + m_tactic->register_on_clause(ctx, on_clause); + } + void user_propagate_init( void* ctx, user_propagator::push_eh_t& push_eh, diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index d919f51ee..0f55ea0fe 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -76,6 +76,10 @@ public: static void checkpoint(ast_manager& m); + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + throw default_exception("tactic does not support clause logging"); + } + void user_propagate_init( void* ctx, user_propagator::push_eh_t& push_eh, diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 25f8365e3..0d1062d78 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -166,6 +166,10 @@ public: return translate_core(m); } + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + m_t2->register_on_clause(ctx, on_clause); + } + void user_propagate_init( void* ctx, user_propagator::push_eh_t& push_eh, diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 18d71b514..68e55be75 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -27,6 +27,7 @@ namespace user_propagator { typedef std::function pop_eh_t; typedef std::function created_eh_t; typedef std::function decide_eh_t; + typedef std::function on_clause_eh_t; class plugin : public decl_plugin { public: @@ -94,6 +95,10 @@ namespace user_propagator { virtual void user_propagate_clear() { } + virtual void register_on_clause(void*, on_clause_eh_t& r) { + throw default_exception("clause logging is only supported on the SMT solver"); + } + }; From b084852397dcf6d117dac347cdf83203bcd2d129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2022 12:12:32 -0700 Subject: [PATCH 157/477] update release notes, fix bug in replay of Boolean variables in new core --- RELEASE_NOTES.md | 104 ++++++++++++++++++++++++-------- src/sat/smt/euf_internalize.cpp | 7 +-- src/sat/smt/euf_solver.cpp | 4 ++ src/sat/smt/euf_solver.h | 2 +- 4 files changed, 87 insertions(+), 30 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0ec6c04b1..b17150867 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -15,49 +15,103 @@ Version 4.12.0 - add clause logging API. - The purpose of logging API and self-checking is to enable an array of use cases. - proof mining (what instantiations did Z3 use)? - - A refresh of the AxiomProfiler could use the logging API. The (brittle) trace feature should be deprecated. + - A refresh of the AxiomProfiler could use the logging API. + The (brittle) trace feature should be deprecated. - debugging - - a built-in self certifier implements a custom proof checker for the format used by the new solver (sat.euf=true). + - a built-in self certifier implements a custom proof checker for + the format used by the new solver (sat.euf=true). - other potential options: - integration into certified tool chains - interpolation - Z3_register_on_clause (also exposed over C++, Python and .Net) - it applies to z3's main CDCL(T) core and a new CDCL(T) core (sat.euf=true). - - The added API function allows to register a callback for when clauses are inferred - More precisely, when clauses are assumed (as part of input), deleted, or deduced. - Clauses that are deduced by the CDCL SAT engine using standard inferences are marked as 'rup'. - Clauses that are deduced by theories are marked by default by 'smt', and when more detailed information - is available with proof hints or proof objects. Instantations are considered useful to track so they - are logged using terms of the form (inst (not (forall (x) body)) body[t/x] (bind t)), where - 'inst' is a name of a function that produces a proof term representing the instantiation. + - The added API function allows to register a callback for when clauses + are inferred. More precisely, when clauses are assumed (as part of input), + deleted, or deduced. + Clauses that are deduced by the CDCL SAT engine using standard + inferences are marked as 'rup'. + Clauses that are deduced by theories are marked by default + by 'smt', and when more detailed information + is available with proof hints or proof objects. + Instantations are considered useful to track so they + are logged using terms of the form + + (inst (not (forall (x) body)) body[t/x] (bind t)), where + + 'inst' is a name of a function that produces a proof term representing + the instantiation. - add options for proof logging, trimming, and checking for the new core. - sat.smt.proof (symbol) add SMT proof to file (default: ) - sat.smt.proof.check (bool) check SMT proof while it is created (default: false) - - it applies a custom self-validator. The self-validator comprises of several small checkers and represent a best-effort - validation mechanism. If there are no custom validators associated with inferences, or the custom validators fail to certify - inferences, the self-validator falls back to invoking z3 (SMT) solving on the lemma. - - euf - propagations and conflicts from congruence closure (theory of equality and uninterpreted functions) are checked - based on a proof format that tracks uses of congruence closure and equalities. It only performs union find operations. + - it applies a custom self-validator. The self-validator comprises of + several small checkers and represent a best-effort validation mechanism. + If there are no custom validators associated with inferences, or the custom + validators fail to certify inferences, the self-validator falls back to + invoking z3 (SMT) solving on the lemma. + - euf - propagations and conflicts from congruence closure + (theory of equality and uninterpreted functions) are checked + based on a proof format that tracks uses of congruence closure and + equalities. It only performs union find operations. - tseitin - clausification steps are checked for Boolean operators. - - farkas, bound, implies_eq - arithmetic inferences that can be justified using a combination of Farkas lemma and cuts are checked. - Note: the arithmetic solver may produce proof hints that the proof checker cannot check. It is mainly a limitation - of the arithmetic solver not pulling relevant information. Ensuring a tight coupling with proof hints and the validator + - farkas, bound, implies_eq - arithmetic inferences that can be justified using + a combination of Farkas lemma and cuts are checked. + Note: the arithmetic solver may produce proof hints that the proof + checker cannot check. It is mainly a limitation + of the arithmetic solver not pulling relevant information. + Ensuring a tight coupling with proof hints and the validator capabilites is open ended future work and good material for theses. - - bit-vector inferences - are treated as trusted (there is no validation, it always blindly succeeds) - - arrays, datatypes - there is no custom validation for other theories at present. Lemmas are validated using SMT. + - bit-vector inferences - are treated as trusted + (there is no validation, it always blindly succeeds) + - arrays, datatypes - there is no custom validation for + other theories at present. Lemmas are validated using SMT. - sat.smt.proof.check_rup (bool) apply forward RUP proof checking (default: true) - - this option can incur significant runtime overhead. Effective proof checking relies on first trimming - proofs into a format where dependencies are tracked and then checking relevant inferences. + - this option can incur significant runtime overhead. + Effective proof checking relies on first trimming proofs into a + format where dependencies are tracked and then checking relevant inferences. Turn this option off if you just want to check theory inferences. -- add options to validate proofs offline. It applies to proofs saved when sat.smt.proof is set to a valid file name. +- add options to validate proofs offline. It applies to proofs + saved when sat.smt.proof is set to a valid file name. - solver.proof.check (bool) check proof logs (default: true) - the option sat.smt.proof_check_rup can be used to control what is checked - - solver.proof.save (bool) save proof log into a proof object that can be extracted using (get-proof) (default: false) + - solver.proof.save (bool) save proof log into a proof object + that can be extracted using (get-proof) (default: false) - experimental: saves a proof log into a term - solver.proof.trim (bool) trim the offline proof and print the trimmed proof to the console - - experimental: performs DRUP trimming to reduce the set of hypotheses and inferences relevant to derive the empty clause. + - experimental: performs DRUP trimming to reduce the set of hypotheses + and inferences relevant to derive the empty clause. - JS support for Arrays, thanks to Walden Yan -- More portable memory allocation, thanks to Nuno Lopes (avoid custom handling to calculate memory usage) +- More portable memory allocation, thanks to Nuno Lopes + (avoid custom handling to calculate memory usage) + +- clause logging and proofs: many open-ended directions. + Many directions and functionality features remain in an open-ended state, + subject to fixes, improvements, and contributions. + We list a few of them here: + - comprehensive efficient self-validators for arithmetic, and other theories + - an efficient proof checker when several theory solvers cooperate in a propagation or + conflict. The theory combination case is currently delegated to the smt solver. + The proper setup for integrating theory lemmas is in principle not complicated, + but the implementation requires some changes. + - external efficient proof validators (based on certified tool chains) + can be integrated over the API. + - dampening repeated clauses: A side-effect of conflict resolution is to + log theory lemmas. It often happens that the theory lemma becomes + the conflict clause, that is then logged as rup. Thus, two clauses are + logged. + - support for online trim so that proofs generated using clause logging can be used for SPACER + - SPACER also would benefit from more robust proof hints for arithmetic + lemmas (bounds and implied equalities are sometimes not logged correctly) + - integration into axiom profiling through online and/or offline interfaces. + - an online interface attaches a callback with a running solver. This is available. + - an offline interface saves a clause proof to a file (currently just + supported for sat.euf) and then reads the file in a separate process + The separate process attaches a callback on inferred clauses. + This is currently not available but a relatively small feature. + - more detailed proof hints for the legacy solver clause logger. + Other than quantifier instantiations, no detailed information is retained for + theory clauses. + - integration of pre-processing proofs with logging proofs. There is + currently no supported bridge to create a end-to-end proof objects. Version 4.11.2 diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 73d059942..337e95ddf 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -159,8 +159,7 @@ namespace euf { v = si.add_bool_var(e); s().set_external(v); s().set_eliminated(v, false); - m_bool_var2expr.reserve(v + 1, nullptr); - m_bool_var2expr[v] = e; + set_bool_var2expr(v, e); m_var_trail.push_back(v); sat::literal lit2 = literal(v, false); th_proof_hint* ph1 = nullptr, * ph2 = nullptr; @@ -189,11 +188,11 @@ namespace euf { return lit; } - m_bool_var2expr[v] = e; - m_var_trail.push_back(v); + set_bool_var2expr(v, e); enode* n = m_egraph.find(e); if (!n) n = mk_enode(e, 0, nullptr); + CTRACE("euf", n->bool_var() != sat::null_bool_var && n->bool_var() != v, display(tout << bpp(n) << " " << n->bool_var() << " vs " << v << "\n")); SASSERT(n->bool_var() == sat::null_bool_var || n->bool_var() == v); m_egraph.set_bool_var(n, v); if (m.is_eq(e) || m.is_or(e) || m.is_and(e) || m.is_not(e)) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index df36501dd..9528310d2 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -672,6 +672,10 @@ namespace euf { else attach_lit(lit, e); } + + for (auto const& [e, v] : replay.m) + if (si.is_bool_op(e)) + si.cache(to_app(e), sat::literal(v, false)); if (relevancy_enabled()) for (auto const& [e, generation, v] : m_reinit) diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index d4729dcfe..554560be8 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -444,7 +444,7 @@ namespace euf { expr_ref mk_eq(euf::enode* n1, euf::enode* n2) { return mk_eq(n1->get_expr(), n2->get_expr()); } euf::enode* e_internalize(expr* e); euf::enode* mk_enode(expr* e, unsigned n, enode* const* args); - void set_bool_var2expr(sat::bool_var v, expr* e) { m_bool_var2expr.setx(v, e, nullptr); } + void set_bool_var2expr(sat::bool_var v, expr* e) { m_var_trail.push_back(v); m_bool_var2expr.setx(v, e, nullptr); } expr* bool_var2expr(sat::bool_var v) const { return m_bool_var2expr.get(v, nullptr); } expr_ref literal2expr(sat::literal lit) const { expr* e = bool_var2expr(lit.var()); return (e && lit.sign()) ? expr_ref(mk_not(m, e), m) : expr_ref(e, m); } unsigned generation() const { return m_generation; } From 4c79e63c1b1a0a653b14d9ddc8190cdd084debf4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2022 12:52:58 -0700 Subject: [PATCH 158/477] Update parse-api.ts --- src/api/js/scripts/parse-api.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/js/scripts/parse-api.ts b/src/api/js/scripts/parse-api.ts index cee61ca29..c3292583a 100644 --- a/src/api/js/scripts/parse-api.ts +++ b/src/api/js/scripts/parse-api.ts @@ -45,6 +45,8 @@ const types = { __proto__: null, // these are function types I can't be bothered to parse + // NSB: They can be extracted automatically from z3_api.h thanks to the use + // of a macro. Z3_error_handler: 'Z3_error_handler', Z3_push_eh: 'Z3_push_eh', Z3_pop_eh: 'Z3_pop_eh', @@ -54,6 +56,7 @@ const types = { Z3_final_eh: 'Z3_final_eh', Z3_created_eh: 'Z3_created_eh', Z3_decide_eh: 'Z3_decide_eh', + Z3_on_clause_eh: 'Z3_on_clause_eh', } as unknown as Record; export type ApiParam = { kind: string; sizeIndex?: number; type: string }; From f6d554118f684a6ae64efce9e91c6ea25d76dcbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Oct 2022 21:14:43 +0100 Subject: [PATCH 159/477] Bump docker/build-push-action from 3.1.1 to 3.2.0 (#6405) --- .github/workflows/docker-image.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 8a669b2d0..abaa26db2 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -41,7 +41,7 @@ jobs: type=edge type=sha,prefix=ubuntu-20.04-bare-z3-sha- - name: Build and push Bare Z3 Docker Image - uses: docker/build-push-action@v3.1.1 + uses: docker/build-push-action@v3.2.0 with: context: . push: true From a90c4f65cff4b7fa965a779b5ae0acb50ca7ed09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2022 13:21:17 -0700 Subject: [PATCH 160/477] increment version per release notes incrementing minor version because the API has a new function. This breaks log replay against old dlls and inclusion against z3++.h. --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 4 ++-- scripts/release.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7093e679f..d79a01da7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.11.3.0 LANGUAGES CXX) +project(Z3 VERSION 4.12.0.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2704a8735..60cbdcc56 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 11, 3, 0) # express a default build version or pick up ci build version + set_version(4, 12, 0, 0) # express a default build version or pick up ci build version # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index ed7c9cb12..55fcb147f 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,7 +1,7 @@ variables: Major: '4' - Minor: '11' - Patch: '3' + Minor: '12' + Patch: '0' AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.DefinitionName) diff --git a/scripts/release.yml b/scripts/release.yml index c48457c1c..53d937b69 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.11.3' + ReleaseVersion: '4.12.0' stages: From 88d10f7fe4513c26b43f0d00d652d76c2d12e5b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2022 13:37:51 -0700 Subject: [PATCH 161/477] add example for monitoring proof logs Signed-off-by: Nikolaj Bjorner --- examples/python/prooflogs.py | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 examples/python/prooflogs.py diff --git a/examples/python/prooflogs.py b/examples/python/prooflogs.py new file mode 100644 index 000000000..265c98d7f --- /dev/null +++ b/examples/python/prooflogs.py @@ -0,0 +1,93 @@ +# This script illustrates uses of proof logs over the Python interface. + +from z3 import * + +example1 = """ +(declare-sort T) + +(declare-fun subtype (T T) Bool) + +;; subtype is reflexive +(assert (forall ((x T)) (subtype x x))) + +;; subtype is antisymmetric +(assert (forall ((x T) (y T)) (=> (and (subtype x y) + (subtype y x)) + (= x y)))) +;; subtype is transitive +(assert (forall ((x T) (y T) (z T)) (=> (and (subtype x y) + (subtype y z)) + (subtype x z)))) +;; subtype has the tree-property +(assert (forall ((x T) (y T) (z T)) (=> (and (subtype x z) + (subtype y z)) + (or (subtype x y) + (subtype y x))))) + +;; now we define a simple example using the axiomatization above. +(declare-const obj-type T) +(declare-const int-type T) +(declare-const real-type T) +(declare-const complex-type T) +(declare-const string-type T) + +;; we have an additional axiom: every type is a subtype of obj-type +(assert (forall ((x T)) (subtype x obj-type))) + +(assert (subtype int-type real-type)) +(assert (subtype real-type complex-type)) +(assert (not (subtype string-type real-type))) +(declare-const root-type T) +(assert (subtype obj-type root-type)) +""" + +def monitor_plain(): + print("Monitor all inferred clauses") + s = Solver() + s.from_string(example1) + onc = OnClause(s, lambda pr, clause : print(pr, clause)) + print(s.check()) + +def log_instance(pr, clause): + if pr.decl().name() == "inst": + q = pr.arg(0).arg(0) # first argument is Not(q) + for ch in pr.children(): + if ch.decl().name() == "bind": + print("Binding") + print(q) + print(ch.children()) + break + +def monitor_instances(): + print("Monitor just quantifier bindings") + s = Solver() + s.from_string(example1) + onc = OnClause(s, log_instance) + print(s.check()) + +def monitor_with_proofs(): + print("Monitor clauses annotated with detailed justifications") + set_param(proof=True) + s = Solver() + s.from_string(example1) + onc = OnClause(s, lambda pr, clause : print(pr, clause)) + print(s.check()) + +def monitor_new_core(): + print("Monitor proof objects from the new core") + set_param("sat.euf", True) + set_param("tactic.default_tactic", "sat") + s = Solver() + s.from_string(example1) + onc = OnClause(s, lambda pr, clause : print(pr, clause)) + print(s.check()) + + +if __name__ == "__main__": + monitor_plain() + monitor_instances() + monitor_new_core() + + +# Monitoring with proofs cannot be done in the same session +# monitor_with_proofs() From f6595c161f73309aeb4df9cc078d21d4909b38db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2022 17:43:56 -0700 Subject: [PATCH 162/477] add examples with proof replay Signed-off-by: Nikolaj Bjorner --- examples/python/proofreplay.py | 113 ++++++++++++++++++++++ src/api/api_solver.cpp | 8 ++ src/cmd_context/cmd_context.h | 1 + src/cmd_context/extra_cmds/proof_cmds.cpp | 39 +++++++- src/cmd_context/extra_cmds/proof_cmds.h | 2 +- src/sat/sat_config.cpp | 3 +- src/sat/sat_config.h | 1 + src/sat/smt/euf_proof.cpp | 3 +- src/sat/smt/euf_proof_checker.cpp | 1 + 9 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 examples/python/proofreplay.py diff --git a/examples/python/proofreplay.py b/examples/python/proofreplay.py new file mode 100644 index 000000000..c8c9ff47e --- /dev/null +++ b/examples/python/proofreplay.py @@ -0,0 +1,113 @@ +# This script illustrates uses of proof replay and proof logs over the Python interface. + +from z3 import * + +example1 = """ +(declare-sort T) + +(declare-fun subtype (T T) Bool) + +;; subtype is reflexive +(assert (forall ((x T)) (subtype x x))) + +;; subtype is antisymmetric +(assert (forall ((x T) (y T)) (=> (and (subtype x y) + (subtype y x)) + (= x y)))) +;; subtype is transitive +(assert (forall ((x T) (y T) (z T)) (=> (and (subtype x y) + (subtype y z)) + (subtype x z)))) +;; subtype has the tree-property +(assert (forall ((x T) (y T) (z T)) (=> (and (subtype x z) + (subtype y z)) + (or (subtype x y) + (subtype y x))))) + +;; now we define a simple example using the axiomatization above. +(declare-const obj-type T) +(declare-const int-type T) +(declare-const real-type T) +(declare-const complex-type T) +(declare-const string-type T) + +;; we have an additional axiom: every type is a subtype of obj-type +(assert (forall ((x T)) (subtype x obj-type))) + +(assert (subtype int-type real-type)) +(assert (subtype real-type complex-type)) +(assert (not (subtype string-type real-type))) +(declare-const root-type T) +(assert (subtype obj-type root-type)) +""" + +if __name__ == "__main__": + print("Solve and log inferences") + print("--------------------------------------------------------") + + # inference logging, replay, and checking is supported for + # the core enabled by setting sat.euf = true. + # setting the default tactic to 'sat' bypasses other tactics that could + # end up using different solvers. + set_param("sat.euf", True) + set_param("tactic.default_tactic", "sat") + + # Set a log file to trace inferences + set_param("sat.smt.proof", "proof_log.smt2") + s = Solver() + s.from_string(example1) + print(s.check()) + print(s.statistics()) + print("Parse the logged inferences and replay them") + print("--------------------------------------------------------") + + # Reset the log file to an invalid (empty) file name. + set_param("sat.smt.proof", "") + + # Turn off proof checking. It is on by default when parsing proof logs. + set_param("solver.proof.check", False) + s = Solver() + onc = OnClause(s, lambda pr, clause : print(pr, clause)) + s.from_file("proof_log.smt2") + + + print("Parse the logged inferences and check them") + print("--------------------------------------------------------") + s = Solver() + + # Now turn on proof checking. It invokes the self-validator. + # The self-validator produces log lines of the form: + # (proofs +tseitin 60 +alldiff 8 +euf 3 +rup 5 +inst 6 -quant 3 -inst 2) + # (verified-smt + # (inst (forall (vars (x T) (y T) (z T)) (or (subtype (:var 2) (:var 1)) ... + # The 'proofs' line summarizes inferences that were self-validated. + # The pair +tseitin 60 indicates that 60 inferences were validated as Tseitin + # encodings. + # The pair -inst 2 indicates that two quantifier instantiations were not self-validated + # They were instead validated using a call to SMT solving. A log for an smt invocation + # is exemplified in the next line. + # Note that the pair +inst 6 indicates that 6 quantifier instantations were validated + # using a syntactic (cheap) check. Some quantifier instantiations based on quantifier elimination + # are not simple substitutions and therefore a simple syntactic check does not suffice. + set_param("solver.proof.check", True) + s.from_file("proof_log.smt2") + + print("Verify and self-validate on the fly") + print("--------------------------------------------------------") + set_param("sat.smt.proof.check", True) + s = Solver() + s.from_string(example1) + print(s.check()) + print(s.statistics()) + + print("Verify and self-validate on the fly, but don't check rup") + print("--------------------------------------------------------") + set_param("sat.smt.proof.check", True) + set_param("sat.smt.proof.check_rup", False) + s = Solver() + s.from_string(example1) + print(s.check()) + print(s.statistics()) + + + diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index ab285be06..2f0780d58 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -931,6 +931,14 @@ extern "C" { on_clause_eh(user_ctx, of_expr(pr.get()), of_ast_vector(literals)); }; to_solver_ref(s)->register_on_clause(user_context, _on_clause); + auto& solver = *to_solver(s); + + if (!solver.m_cmd_context) { + solver.m_cmd_context = alloc(cmd_context, false, &(mk_c(c)->m())); + install_proof_cmds(*solver.m_cmd_context); + init_proof_cmds(*solver.m_cmd_context); + } + solver.m_cmd_context->get_proof_cmds()->register_on_clause(user_context, _on_clause); Z3_CATCH; } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 61e3b2ecc..15b5df0d1 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -99,6 +99,7 @@ public: virtual void end_infer() = 0; virtual void end_deleted() = 0; virtual void updt_params(params_ref const& p) = 0; + virtual void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) = 0; }; diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index e544d353b..bf12157c1 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -227,13 +227,34 @@ class proof_cmds_imp : public proof_cmds { scoped_ptr m_checker; scoped_ptr m_saver; scoped_ptr m_trimmer; + user_propagator::on_clause_eh_t m_on_clause_eh; + void* m_on_clause_ctx = nullptr; + expr_ref m_assumption, m_del; euf::smt_proof_checker& checker() { params_ref p; if (!m_checker) m_checker = alloc(euf::smt_proof_checker, m, p); return *m_checker; } proof_saver& saver() { if (!m_saver) m_saver = alloc(proof_saver, ctx); return *m_saver; } proof_trim& trim() { if (!m_trimmer) m_trimmer = alloc(proof_trim, ctx); return *m_trimmer; } + + expr_ref assumption() { + if (!m_assumption) + m_assumption = m.mk_app(symbol("assumption"), 0, nullptr, m.mk_proof_sort()); + return m_assumption; + } + + expr_ref del() { + if (!m_del) + m_del = m.mk_app(symbol("del"), 0, nullptr, m.mk_proof_sort()); + return m_del; + } public: - proof_cmds_imp(cmd_context& ctx): ctx(ctx), m(ctx.m()), m_lits(m), m_proof_hint(m) { + proof_cmds_imp(cmd_context& ctx): + ctx(ctx), + m(ctx.m()), + m_lits(m), + m_proof_hint(m), + m_assumption(m), + m_del(m) { updt_params(gparams::get_module("solver")); } @@ -251,6 +272,8 @@ public: saver().assume(m_lits); if (m_trim) trim().assume(m_lits); + if (m_on_clause_eh) + m_on_clause_eh(m_on_clause_ctx, assumption(), m_lits.size(), m_lits.data()); m_lits.reset(); m_proof_hint.reset(); } @@ -262,6 +285,8 @@ public: saver().infer(m_lits, m_proof_hint); if (m_trim) trim().infer(m_lits, m_proof_hint); + if (m_on_clause_eh) + m_on_clause_eh(m_on_clause_ctx, m_proof_hint, m_lits.size(), m_lits.data()); m_lits.reset(); m_proof_hint.reset(); } @@ -273,6 +298,8 @@ public: saver().del(m_lits); if (m_trim) trim().del(m_lits); + if (m_on_clause_eh) + m_on_clause_eh(m_on_clause_ctx, del(), m_lits.size(), m_lits.data()); m_lits.reset(); m_proof_hint.reset(); } @@ -285,6 +312,12 @@ public: if (m_trim) trim().updt_params(p); } + + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause_eh) override { + m_on_clause_ctx = ctx; + m_on_clause_eh = on_clause_eh; + } + }; @@ -344,3 +377,7 @@ void install_proof_cmds(cmd_context & ctx) { ctx.insert(alloc(infer_cmd)); ctx.insert(alloc(assume_cmd)); } + +void init_proof_cmds(cmd_context& ctx) { + get(ctx); +} diff --git a/src/cmd_context/extra_cmds/proof_cmds.h b/src/cmd_context/extra_cmds/proof_cmds.h index 9625e93ad..bc2c84d47 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.h +++ b/src/cmd_context/extra_cmds/proof_cmds.h @@ -33,4 +33,4 @@ Notes: class cmd_context; void install_proof_cmds(cmd_context & ctx); - +void init_proof_cmds(cmd_context& ctx); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 2330fe401..32d764658 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -200,8 +200,9 @@ namespace sat { m_smt_proof = p.smt_proof(); m_smt_proof_check = p.smt_proof_check(); m_smt_proof_check_rup = p.smt_proof_check_rup(); + m_drat_disable = p.drat_disable(); m_drat = - !p.drat_disable() && p.threads() == 1 && + !m_drat_disable && p.threads() == 1 && (sp.lemmas2console() || m_drat_check_unsat || m_drat_file.is_non_empty_string() || diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 2d609b1bc..ae19c63ea 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -175,6 +175,7 @@ namespace sat { // drat proofs bool m_drat; + bool m_drat_disable; bool m_drat_binary; symbol m_drat_file; symbol m_smt_proof; diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 906e6e068..742e00cd7 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -25,7 +25,7 @@ namespace euf { if (m_proof_initialized) return; - if (m_on_clause) + if (m_on_clause && !s().get_config().m_drat_disable) s().set_drat(true); if (!s().get_config().m_drat) @@ -39,7 +39,6 @@ namespace euf { get_drat().add_theory(get_id(), symbol("euf")); get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); - if (s().get_config().m_smt_proof.is_non_empty_string()) m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); get_drat().set_clause_eh(*this); diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index 79f7e6880..2d4f67cd2 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -372,6 +372,7 @@ namespace euf { void smt_theory_checker_plugin::register_plugins(theory_checker& pc) { pc.register_plugin(symbol("datatype"), this); pc.register_plugin(symbol("array"), this); + pc.register_plugin(symbol("quant"), this); pc.register_plugin(symbol("fpa"), this); } From 2842c27e92cf0fdc7c0c89dfdae7efb25e92204e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 04:48:13 -0700 Subject: [PATCH 163/477] #6364 --- src/sat/smt/arith_diagnostics.cpp | 8 +------- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/sat_internalizer.h | 1 + src/sat/tactic/goal2sat.cpp | 7 +++++++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 2be19182a..e84646e7b 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -152,7 +152,6 @@ namespace arith { solver& a = dynamic_cast(*s.fid2solver(fid)); char const* name; expr_ref_vector args(m); - sort_ref_vector sorts(m); switch (m_ty) { case hint_type::farkas_h: @@ -182,11 +181,6 @@ namespace arith { args.push_back(arith.mk_int(1)); args.push_back(eq); } - for (expr* arg : args) - sorts.push_back(arg->get_sort()); - sort* range = m.mk_proof_sort(); - func_decl* d = m.mk_func_decl(symbol(name), args.size(), sorts.data(), range); - expr* r = m.mk_app(d, args); - return r; + return m.mk_app(symbol(name), args.size(), args.data(), m.mk_proof_sort()); } } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 9528310d2..2aa46928b 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -674,7 +674,7 @@ namespace euf { } for (auto const& [e, v] : replay.m) - if (si.is_bool_op(e)) + if (si.is_bool_op(e) && !si.is_cached(to_app(e), sat::literal(v, false))) si.cache(to_app(e), sat::literal(v, false)); if (relevancy_enabled()) diff --git a/src/sat/smt/sat_internalizer.h b/src/sat/smt/sat_internalizer.h index e7d0d9b43..5fbf879ae 100644 --- a/src/sat/smt/sat_internalizer.h +++ b/src/sat/smt/sat_internalizer.h @@ -26,6 +26,7 @@ namespace sat { virtual literal internalize(expr* e, bool learned) = 0; virtual bool_var to_bool_var(expr* e) = 0; virtual bool_var add_bool_var(expr* e) = 0; + virtual bool is_cached(app* t, literal l) const = 0; virtual void cache(app* t, literal l) = 0; virtual void uncache(literal l) = 0; virtual void push() = 0; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 038cd337b..a2d94652c 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -276,6 +276,13 @@ struct goal2sat::imp : public sat::sat_internalizer { m_lit2app.insert(l.index(), t); m_cache_trail.push_back(t); } + + bool is_cached(app* t, sat::literal l) const override { + if (!m_app2lit.contains(t)) + return false; + SASSERT(m_app2lit[t] == l); + return true; + } void convert_atom(expr * t, bool root, bool sign) { SASSERT(m.is_bool(t)); From 65ea4925b324adbcf889489568367841a9275180 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 08:37:21 -0700 Subject: [PATCH 164/477] initialization of proof_cmds Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 2f0780d58..a6b2d6605 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -936,8 +936,10 @@ extern "C" { if (!solver.m_cmd_context) { solver.m_cmd_context = alloc(cmd_context, false, &(mk_c(c)->m())); install_proof_cmds(*solver.m_cmd_context); - init_proof_cmds(*solver.m_cmd_context); } + + if (!solver.m_cmd_context->proof_cmds()) + init_proof_cmds(*solver.m_cmd_context); solver.m_cmd_context->get_proof_cmds()->register_on_clause(user_context, _on_clause); Z3_CATCH; } From 2f1514a259842a4891ce803d8cac175ccb9467a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 08:38:23 -0700 Subject: [PATCH 165/477] initialization of proof_cmds Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index a6b2d6605..5edc42157 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -938,7 +938,7 @@ extern "C" { install_proof_cmds(*solver.m_cmd_context); } - if (!solver.m_cmd_context->proof_cmds()) + if (!solver.m_cmd_context->get_proof_cmds()) init_proof_cmds(*solver.m_cmd_context); solver.m_cmd_context->get_proof_cmds()->register_on_clause(user_context, _on_clause); Z3_CATCH; From 6292b06c67e213f03b9746240e44d80043edff5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 08:48:15 -0700 Subject: [PATCH 166/477] ensure that initialization order for euf_solver is aligned Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_solver.cpp | 7 ++-- src/sat/smt/euf_solver.h | 84 ++++++++++++++++++++------------------ 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 2aa46928b..3d4af371f 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -46,14 +46,13 @@ namespace euf { m_trail(), m_rewriter(m), m_unhandled_functions(m), - m_lookahead(nullptr), m_to_m(&m), m_to_si(&si), m_values(m), - m_clause(m), - m_expr_args(m), m_clause_visitor(m), - m_smt_proof_checker(m, p) + m_smt_proof_checker(m, p), + m_clause(m), + m_expr_args(m) { updt_params(p); m_relevancy.set_enabled(get_config().m_relevancy_lvl > 2); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 554560be8..2ac847a56 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -112,39 +112,55 @@ namespace euf { std::function<::solver*(void)> m_mk_solver; ast_manager& m; - sat::sat_internalizer& si; - relevancy m_relevancy; - smt_params m_config; - euf::egraph m_egraph; - trail_stack m_trail; - stats m_stats; - th_rewriter m_rewriter; - func_decl_ref_vector m_unhandled_functions; - sat::lookahead* m_lookahead = nullptr; - ast_manager* m_to_m; - sat::sat_internalizer* m_to_si; - scoped_ptr m_ackerman; - user_propagator::on_clause_eh_t m_on_clause; - void* m_on_clause_ctx = nullptr; - user_solver::solver* m_user_propagator = nullptr; - th_solver* m_qsolver = nullptr; - unsigned m_generation = 0; - std::string m_reason_unknown; - mutable ptr_vector m_todo; + sat::sat_internalizer& si; + relevancy m_relevancy; + smt_params m_config; + euf::egraph m_egraph; + trail_stack m_trail; + stats m_stats; + th_rewriter m_rewriter; + func_decl_ref_vector m_unhandled_functions; + sat::lookahead* m_lookahead = nullptr; + ast_manager* m_to_m = nullptr; + sat::sat_internalizer* m_to_si; + scoped_ptr m_ackerman; + user_propagator::on_clause_eh_t m_on_clause; + void* m_on_clause_ctx = nullptr; + user_solver::solver* m_user_propagator = nullptr; + th_solver* m_qsolver = nullptr; + unsigned m_generation = 0; + std::string m_reason_unknown; + mutable ptr_vector m_todo; - ptr_vector m_bool_var2expr; - ptr_vector m_explain; - euf::cc_justification m_explain_cc; - unsigned m_num_scopes = 0; - unsigned_vector m_var_trail; - svector m_scopes; - scoped_ptr_vector m_solvers; - ptr_vector m_id2solver; + ptr_vector m_bool_var2expr; + ptr_vector m_explain; + euf::cc_justification m_explain_cc; + 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; + // proofs + bool m_proof_initialized = false; + ast_pp_util m_clause_visitor; + bool m_display_all_decls = false; + smt_proof_checker m_smt_proof_checker; + + typedef std::pair expr_pair; + literal_vector m_proof_literals; + svector m_proof_eqs, m_proof_deqs, m_expr_pairs; + unsigned m_lit_head = 0, m_lit_tail = 0, m_cc_head = 0, m_cc_tail = 0; + unsigned m_eq_head = 0, m_eq_tail = 0, m_deq_head = 0, m_deq_tail = 0; + symbol m_euf = symbol("euf"); + symbol m_smt = symbol("smt"); + expr_ref_vector m_clause; + expr_ref_vector m_expr_args; + // internalization bool visit(expr* e) override; @@ -201,24 +217,12 @@ namespace euf { void log_antecedents(literal l, literal_vector const& r, th_proof_hint* hint); void log_justification(literal l, th_explain const& jst); - typedef std::pair expr_pair; - literal_vector m_proof_literals; - svector m_proof_eqs, m_proof_deqs, m_expr_pairs; - unsigned m_lit_head = 0, m_lit_tail = 0, m_cc_head = 0, m_cc_tail = 0; - unsigned m_eq_head = 0, m_eq_tail = 0, m_deq_head = 0, m_deq_tail = 0; - symbol m_euf = symbol("euf"); - symbol m_smt = symbol("smt"); - expr_ref_vector m_clause; - expr_ref_vector m_expr_args; eq_proof_hint* mk_hint(symbol const& th, literal lit, literal_vector const& r); - bool m_proof_initialized = false; + void init_proof(); - ast_pp_util m_clause_visitor; - bool m_display_all_decls = false; - smt_proof_checker m_smt_proof_checker; void on_clause(unsigned n, literal const* lits, sat::status st) override; void on_lemma(unsigned n, literal const* lits, sat::status st); void on_proof(unsigned n, literal const* lits, sat::status st); From fc304618284ba31d2fd167bbc97377e0bfb108d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 09:09:06 -0700 Subject: [PATCH 167/477] unused variables Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/proof_cmds.cpp | 9 ++++----- src/math/simplex/model_based_opt.cpp | 2 +- src/muz/base/dl_rule_subsumption_index.h | 4 ++-- src/muz/spacer/spacer_cluster.cpp | 1 + src/muz/spacer/spacer_convex_closure.cpp | 1 + src/muz/spacer/spacer_sem_matcher.cpp | 2 +- src/muz/transforms/dl_mk_slice.cpp | 4 +++- src/sat/smt/euf_solver.cpp | 2 -- src/shell/drat_frontend.cpp | 1 - src/smt/theory_str.cpp | 4 ++-- src/test/dl_relation.cpp | 2 +- src/test/simplifier.cpp | 5 +++++ 12 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/cmd_context/extra_cmds/proof_cmds.cpp b/src/cmd_context/extra_cmds/proof_cmds.cpp index bf12157c1..9c9b9ed62 100644 --- a/src/cmd_context/extra_cmds/proof_cmds.cpp +++ b/src/cmd_context/extra_cmds/proof_cmds.cpp @@ -57,10 +57,9 @@ Proof checker for clauses created during search. * Replay proof entierly, then walk backwards extracting reduced proof. */ class proof_trim { - cmd_context& ctx; - ast_manager& m; - sat::proof_trim trim; - euf::theory_checker m_checker; + ast_manager& m; + sat::proof_trim trim; + euf::theory_checker m_checker; vector m_clauses; bool_vector m_is_infer; symbol m_rup; @@ -88,7 +87,7 @@ class proof_trim { public: proof_trim(cmd_context& ctx): - ctx(ctx), + // ctx(ctx), m(ctx.m()), trim(gparams::get_module("sat"), m.limit()), m_checker(m) { diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 7ab246c6e..cb3a5be4d 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -116,7 +116,7 @@ namespace opt { model_based_opt::def model_based_opt::def::substitute(unsigned v, def const& other) const { def result; vector const& vs1 = m_vars; - vector const& vs2 = other.m_vars; + // vector const& vs2 = other.m_vars; rational coeff(0); for (auto const& [id, c] : vs1) { if (id == v) { diff --git a/src/muz/base/dl_rule_subsumption_index.h b/src/muz/base/dl_rule_subsumption_index.h index 9c29683b3..3783be3dc 100644 --- a/src/muz/base/dl_rule_subsumption_index.h +++ b/src/muz/base/dl_rule_subsumption_index.h @@ -29,7 +29,7 @@ namespace datalog { typedef obj_hashtable app_set; ast_manager & m; - context & m_context; + // context & m_context; rule_ref_vector m_ref_holder; @@ -42,7 +42,7 @@ namespace datalog { public: rule_subsumption_index(context & ctx) : m(ctx.get_manager()), - m_context(ctx), + // m_context(ctx), m_ref_holder(ctx.get_rule_manager()) {} ~rule_subsumption_index() { diff --git a/src/muz/spacer/spacer_cluster.cpp b/src/muz/spacer/spacer_cluster.cpp index 13ef17c26..b03562b12 100644 --- a/src/muz/spacer/spacer_cluster.cpp +++ b/src/muz/spacer/spacer_cluster.cpp @@ -381,6 +381,7 @@ void lemma_cluster_finder::cluster(lemma_ref &lemma) { for (const lemma_ref &l : neighbours) { SASSERT(cluster->can_contain(l)); bool added = cluster->add_lemma(l, false); + (void)added; CTRACE("cluster_stats", added, tout << "Added neighbour lemma\n" << mk_and(l->get_cube()) << "\n";); } diff --git a/src/muz/spacer/spacer_convex_closure.cpp b/src/muz/spacer/spacer_convex_closure.cpp index 476821643..2c11642c5 100644 --- a/src/muz/spacer/spacer_convex_closure.cpp +++ b/src/muz/spacer/spacer_convex_closure.cpp @@ -261,6 +261,7 @@ bool convex_closure::infer_div_pred(const vector &data, rational &m, }); SASSERT(data.size() > 1); SASSERT(is_sorted(data)); + (void)is_sorted; m = rational(2); diff --git a/src/muz/spacer/spacer_sem_matcher.cpp b/src/muz/spacer/spacer_sem_matcher.cpp index b0eeb51a3..8a79662a9 100644 --- a/src/muz/spacer/spacer_sem_matcher.cpp +++ b/src/muz/spacer/spacer_sem_matcher.cpp @@ -84,7 +84,7 @@ bool sem_matcher::operator()(expr * e1, expr * e2, substitution & s, bool &pos) top = false; if (n1->get_decl() != n2->get_decl()) { - expr *e1 = nullptr, *e2 = nullptr, *e3 = nullptr, *e4 = nullptr, *e5 = nullptr; + expr *e1 = nullptr, *e2 = nullptr; rational val1, val2; // x<=y == !(x>y) diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index 834bb41ef..25888cb68 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -260,7 +260,9 @@ namespace datalog { rm(ctx.get_rule_manager()), m_pinned_rules(rm), m_pinned_exprs(m), - m_unifier(ctx) {} + m_unifier(ctx) { + (void)m_ctx; + } void insert(rule* orig_rule, rule* slice_rule, unsigned sz, unsigned const* renaming) { m_rule2slice.insert(orig_rule, slice_rule); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 3d4af371f..5086dea98 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -232,7 +232,6 @@ namespace euf { auto* ext = sat::constraint_base::to_extension(idx); th_proof_hint* hint = nullptr; bool has_theory = false; - bool has_nested_theory = false; if (ext == this) get_antecedents(l, constraint::from_idx(idx), r, probing); else { @@ -250,7 +249,6 @@ namespace euf { sat::literal lit = sat::null_literal; ext->get_antecedents(lit, idx, r, probing); has_theory = true; - has_nested_theory = true; } } m_egraph.end_explain(); diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index b0b711ef0..7484684f2 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -18,7 +18,6 @@ Copyright (c) 2020 Microsoft Corporation class drup_checker { sat::drat& m_drat; sat::literal_vector m_units; - bool m_check_inputs = false; void add_units() { auto const& units = m_drat.units(); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 955241efd..1e12f8bd3 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -2470,10 +2470,8 @@ namespace smt { TRACE("str", tout << "SKIP: both concats are already in the same equivalence class" << std::endl;); } else { expr_ref_vector items(m); - int pos = 0; for (auto itor : resolvedMap) { items.push_back(ctx.mk_eq_atom(itor.first, itor.second)); - pos += 1; } expr_ref premise(mk_and(items), m); expr_ref conclusion(ctx.mk_eq_atom(node, resultAst), m); @@ -4539,6 +4537,7 @@ namespace smt { and_item.push_back(ctx.mk_eq_atom(mk_strlen(m), m_autil.mk_add(mk_strlen(str1Ast), mk_strlen(commonVar)) )); pos += 1; + (void)pos; // addItems[0] = mk_length(t, commonVar); // addItems[1] = mk_length(t, str2Ast); @@ -6439,6 +6438,7 @@ namespace smt { expr_ref arg2_eq (ctx.mk_eq_atom(arg2, suffixAst), m); and_items.push_back(arg2_eq); and_count += 1; + (void) and_count; arrangement_disjunction.push_back(mk_and(and_items)); } diff --git a/src/test/dl_relation.cpp b/src/test/dl_relation.cpp index 9969ada2f..1646350f2 100644 --- a/src/test/dl_relation.cpp +++ b/src/test/dl_relation.cpp @@ -247,7 +247,7 @@ namespace datalog { { relation_base* b1 = br.mk_full(nullptr, sig); relation_base* b2 = br.mk_full(nullptr, sig); - unsigned x0x3[2] = { 0, 3 }; + // unsigned x0x3[2] = { 0, 3 }; unsigned x1x3[2] = { 1, 3 }; unsigned x2x3[2] = { 2, 3 }; scoped_ptr id1 = br.mk_filter_identical_fn(*b1, 2, x1x3); diff --git a/src/test/simplifier.cpp b/src/test/simplifier.cpp index d716a1268..7bfa72db8 100644 --- a/src/test/simplifier.cpp +++ b/src/test/simplifier.cpp @@ -93,6 +93,7 @@ static void test_datatypes() { int_list = Z3_mk_list_sort(ctx, Z3_mk_string_symbol(ctx, "int_list"), int_ty, &nil_decl, &is_nil_decl, &cons_decl, &is_cons_decl, &head_decl, &tail_decl); + (void) int_list; nil = Z3_mk_app(ctx, nil_decl, 0, nullptr); Z3_ast a = Z3_simplify(ctx, Z3_mk_app(ctx, is_nil_decl, 1, &nil)); @@ -166,6 +167,7 @@ static void test_array() { Z3_ast n4 = Z3_mk_numeral(ctx, "4", i); Z3_ast s1 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"s1"), i); Z3_ast s2 = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx,"s2"), i); + (void) s2; Z3_ast c1 = Z3_mk_const_array(ctx, i, n1); Z3_ast x1 = Z3_mk_store(ctx, Z3_mk_store(ctx, c1, n2, n3), n1, n4); @@ -175,6 +177,7 @@ static void test_array() { Z3_ast xs[4] = { x1, x2, x3, x4}; Z3_ast exy = Z3_mk_eq(ctx, x2, x1); Z3_ast rxy = Z3_simplify(ctx, exy); + (void)rxy; TRACE("simplifier", tout << Z3_ast_to_string(ctx, rxy) << "\n";); TRACE("simplifier", tout << Z3_ast_to_string(ctx, Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3))) << "\n";); @@ -195,6 +198,8 @@ static void test_array() { Z3_ast sel1 = Z3_mk_select(ctx, x1, n1); Z3_ast sel2 = Z3_mk_select(ctx, x1, n4); + (void)sel1; + (void)sel2; TRACE("simplifier", tout << Z3_ast_to_string(ctx, Z3_simplify(ctx, sel1)) << "\n"; From 5976978062c96178e7402d6c09d2d43fb1e978df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 09:11:15 -0700 Subject: [PATCH 168/477] move std functions up for potential alignment issues Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_solver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 2ac847a56..5e12324a4 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -111,6 +111,7 @@ namespace euf { } std::function<::solver*(void)> m_mk_solver; + user_propagator::on_clause_eh_t m_on_clause; ast_manager& m; sat::sat_internalizer& si; relevancy m_relevancy; @@ -124,7 +125,6 @@ namespace euf { ast_manager* m_to_m = nullptr; sat::sat_internalizer* m_to_si; scoped_ptr m_ackerman; - user_propagator::on_clause_eh_t m_on_clause; void* m_on_clause_ctx = nullptr; user_solver::solver* m_user_propagator = nullptr; th_solver* m_qsolver = nullptr; From edad727cd5458fa6b5cea6754cbfbbd302a1ded7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 13:14:54 -0700 Subject: [PATCH 169/477] #6364 ensure substitutions are applied to eliminate internal variables from results --- src/math/simplex/model_based_opt.cpp | 82 ++++++++++++++++++++++------ src/math/simplex/model_based_opt.h | 5 +- src/test/model_based_opt.cpp | 20 +++++++ 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index cb3a5be4d..ac7e89d5b 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -113,10 +113,16 @@ namespace opt { return result; } - model_based_opt::def model_based_opt::def::substitute(unsigned v, def const& other) const { - def result; + /** + a1*x1 + a2*x2 + a3*x3 + coeff1 / c1 + x2 |-> b1*x1 + b4*x4 + ceoff2 / c2 + ------------------------------------------------------------------------ + (a1*x1 + a2*((b1*x1 + b4*x4 + coeff2) / c2) + a3*x3 + coeff1) / c1 + ------------------------------------------------------------------------ + (c2*a1*x1 + a2*b1*x1 + a2*b4*x4 + c2*a3*x3 + c2*coeff1 + coeff2) / c1*c2 + */ + void model_based_opt::def::substitute(unsigned v, def const& other) { vector const& vs1 = m_vars; - // vector const& vs2 = other.m_vars; rational coeff(0); for (auto const& [id, c] : vs1) { if (id == v) { @@ -124,13 +130,46 @@ namespace opt { break; } } - if (coeff == 0) { - return *this; - } + if (coeff == 0) + return; - NOT_IMPLEMENTED_YET(); - result.normalize(); - return result; + rational c1 = m_div; + rational c2 = other.m_div; + + vector const& vs2 = other.m_vars; + vector vs; + unsigned i = 0, j = 0; + while (i < vs1.size() || j < vs2.size()) { + unsigned v1 = UINT_MAX, v2 = UINT_MAX; + if (i < vs1.size()) v1 = vs1[i].m_id; + if (j < vs2.size()) v2 = vs2[j].m_id; + if (v1 == v) + ++i; + else if (v1 == v2) { + vs.push_back(vs1[i]); + vs.back().m_coeff *= c2; + vs.back().m_coeff += coeff * vs2[j].m_coeff; + ++i; ++j; + if (vs.back().m_coeff.is_zero()) + vs.pop_back(); + } + else if (v1 < v2) { + vs.push_back(vs1[i]); + vs.back().m_coeff *= c2; + ++i; + } + else { + vs.push_back(vs2[j]); + vs.back().m_coeff *= coeff; + ++j; + } + } + m_div *= other.m_div; + m_coeff *= c2; + m_coeff += coeff*other.m_coeff; + m_vars.reset(); + m_vars.append(vs); + normalize(); } model_based_opt::def model_based_opt::def::operator/(rational const& r) const { @@ -1436,15 +1475,20 @@ namespace opt { } - for (unsigned v : vs) - project(v, false); - + for (unsigned v : vs) { + def v_def = project(v, false); + if (compute_def) + eliminate(v, v_def); + } + // project internal variables. def z_def = project(z, compute_def); def y_def = project(y, compute_def); // may depend on z - if (compute_def) { + z_def.substitute(y, y_def); + eliminate(y, y_def); + eliminate(z, z_def); result = (y_def * K) + z_def; m_var2value[x] = eval(result); @@ -1650,14 +1694,20 @@ namespace opt { TRACE("opt", display(tout << "solved v" << x << "\n")); return result; } + + void model_based_opt::eliminate(unsigned v, def const& new_def) { + for (auto & d : m_result) + d.substitute(v, new_def); + } vector model_based_opt::project(unsigned num_vars, unsigned const* vars, bool compute_def) { - vector result; + m_result.reset(); for (unsigned i = 0; i < num_vars; ++i) { - result.push_back(project(vars[i], compute_def)); + m_result.push_back(project(vars[i], compute_def)); + eliminate(vars[i], m_result.back()); TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n");); } - return result; + return m_result; } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 8150f945f..35516283d 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -86,7 +86,7 @@ namespace opt { def operator/(rational const& n) const; def operator*(rational const& n) const; def operator+(rational const& n) const; - def substitute(unsigned v, def const& other) const; + void substitute(unsigned v, def const& other); void normalize(); }; @@ -101,6 +101,9 @@ namespace opt { unsigned_vector m_lub, m_glb, m_divides, m_mod, m_div; unsigned_vector m_above, m_below; unsigned_vector m_retired_rows; + vector m_result; + + void eliminate(unsigned v, def const& d); bool invariant(); bool invariant(unsigned index, row const& r); diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index b307f85e4..e2dc74db0 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -392,9 +392,29 @@ static void test11() { } +static void test12() { + opt::model_based_opt::def d1, d2, d3, d4; + typedef opt::model_based_opt::var var; + d1.m_vars.push_back(var(1, rational(4))); + d1.m_vars.push_back(var(2, rational(3))); + d1.m_vars.push_back(var(3, rational(5))); + d1.m_coeff = rational(8); + d1.m_div = rational(7); + std::cout << d1 << "\n"; + d2.m_vars.push_back(var(3, rational(2))); + d2.m_vars.push_back(var(4, rational(2))); + d2.m_div = rational(3); + d2.m_coeff = rational(5); + std::cout << d2 << "\n"; + d1.substitute(2, d2); + std::cout << d1 << "\n"; +} + // test with mix of upper and lower bounds void tst_model_based_opt() { + test12(); + return; test10(); check_random_ineqs(); test1(); From 354bc504009f2cc08f15ebc2c4f89f9ebdec530d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 13:15:43 -0700 Subject: [PATCH 170/477] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ffc50c1ba..b73251f44 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ src/api/js/node_modules/ src/api/js/build/ src/api/js/**/*.__GENERATED__.* debug/* +examples/python/z3 out/** *.bak From 6d6752b2aadcae4b65b6d230496370c8dae2835b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 16:39:43 -0700 Subject: [PATCH 171/477] #6364 --- .gitignore | 1 + src/sat/smt/q_mbi.cpp | 16 ++++++++++++---- src/sat/smt/q_model_fixer.cpp | 2 +- src/sat/smt/q_theory_checker.cpp | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index b73251f44..17465d9ae 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ src/api/js/build/ src/api/js/**/*.__GENERATED__.* debug/* examples/python/z3 +examples/python/libz3.dll out/** *.bak diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 4530e9f93..cda05ee28 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -125,7 +125,11 @@ namespace q { } if (m.is_model_value(e)) return expr_ref(m.mk_model_value(0, e->get_sort()), m); - return expr_ref(e, m); + + expr_ref e1 = m_model->unfold_as_array(e); + if (e1 == e) + return e1; + return replace_model_value(e1); } expr_ref mbqi::choose_term(euf::enode* r) { @@ -355,8 +359,8 @@ namespace q { for (app* v : vars) { expr_ref term(m); expr_ref val = (*m_model)(v); - val = m_model->unfold_as_array(val); term = replace_model_value(val); + TRACE("euf", tout << "replaced model value " << term << "\nfrom\n" << val << "\n"); rep.insert(v, term); if (ctx.use_drat()) m_defs.push_back(mbp::def(expr_ref(v, m), term)); @@ -407,10 +411,13 @@ namespace q { auto* n = nodes[i]; expr* e = n->get_expr(); expr* val = ctx.node2value(n); - if (val && e->get_sort() == srt && !m.is_value(e) && !visited.is_marked(val)) { + if (val && e->get_sort() == srt && + !m.is_value(e) && + !visited.is_marked(val)) { visited.mark(val); + expr_ref value = replace_model_value(val); veqs.push_back(m.mk_eq(v, e)); - meqs.push_back(m.mk_eq(v, val)); + meqs.push_back(m.mk_eq(v, value)); --bound; } } @@ -473,6 +480,7 @@ namespace q { expr_ref _term = subst(e, qb.vars); app_ref term(to_app(_term), m); expr_ref value = (*m_model)(term); + value = replace_model_value(value); expr* s = m_model_fixer.invert_app(term, value); rep.insert(term, s); expr_ref eq(m.mk_eq(term, s), m); diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index 37e2424ce..38f38ee0a 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -253,7 +253,7 @@ namespace q { euf::enode* r = nullptr; auto& v2r = ctx.values2root(); TRACE("q", - tout << "invert-app " << mk_pp(t, m) << " = " << mk_pp(value, m) << "\n"; + tout << "invert-app " << mk_pp(t, m) << " =\n" << mk_pp(value, m) << "\n"; if (v2r.find(value, r)) tout << "inverse " << mk_pp(r->get_expr(), m) << "\n"; /*ctx.display(tout); */ diff --git a/src/sat/smt/q_theory_checker.cpp b/src/sat/smt/q_theory_checker.cpp index be246dd3c..9f31325b5 100644 --- a/src/sat/smt/q_theory_checker.cpp +++ b/src/sat/smt/q_theory_checker.cpp @@ -24,7 +24,7 @@ namespace q { expr_ref_vector theory_checker::clause(app* jst) { expr_ref_vector result(m); for (expr* arg : *jst) - if (!is_bind(arg)) + if (m.is_bool(arg)) result.push_back(mk_not(m, arg)); return result; } From c1b355f34269581963d7003b709512d8fedc71c8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 17:48:17 -0700 Subject: [PATCH 172/477] #6364 throttle on upwards propagation of default was too restrictive --- src/sat/smt/array_axioms.cpp | 4 ++++ src/sat/smt/array_solver.cpp | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 2c08b3e69..901344293 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -625,6 +625,10 @@ namespace array { return change; } + /** + * For every occurrence of as-array(f) and every occurrence of f(t) + * add equality select(as-array(f), t) = f(t) + */ bool solver::add_as_array_eqs(euf::enode* n) { func_decl* f = nullptr; bool change = false; diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index f66c2a183..2d3d13d3a 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -216,8 +216,7 @@ namespace array { d.m_has_default = true; for (euf::enode* lambda : d.m_lambdas) push_axiom(default_axiom(lambda)); - if (should_prop_upward(d)) - propagate_parent_default(v); + propagate_parent_default(v); } void solver::propagate_select_axioms(var_data const& d, euf::enode* lambda) { @@ -255,7 +254,7 @@ namespace array { return; ctx.push(reset_flag_trail(d.m_prop_upward)); d.m_prop_upward = true; - if (should_prop_upward(d)) + if (should_prop_upward(d)) propagate_parent_select_axioms(v); set_prop_upward(d); } From 842e8057bc669c03dbc472993bc44a3901c00de8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2022 17:49:15 -0700 Subject: [PATCH 173/477] log also quantifier generation (besides binding) We add also logging for quantifier generation. It is auxiliary information that is of use for diagnostics (axiom profiler). --- src/sat/smt/q_clause.h | 5 +++-- src/sat/smt/q_ematch.cpp | 10 +++++----- src/sat/smt/q_ematch.h | 2 +- src/sat/smt/q_mbi.cpp | 2 +- src/sat/smt/q_solver.cpp | 12 ++++++++---- src/sat/smt/q_solver.h | 8 +++++--- src/smt/qi_queue.cpp | 4 ++++ 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/sat/smt/q_clause.h b/src/sat/smt/q_clause.h index e1e31b199..aedb0bc4c 100644 --- a/src/sat/smt/q_clause.h +++ b/src/sat/smt/q_clause.h @@ -125,12 +125,13 @@ namespace q { struct justification { expr* m_lhs, * m_rhs; bool m_sign; + unsigned m_generation; unsigned m_num_ex; size_t** m_explain; clause& m_clause; euf::enode* const* m_binding; - justification(lit const& l, clause& c, euf::enode* const* b, unsigned n, size_t** ev) : - m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_num_ex(n), m_explain(ev), m_clause(c), m_binding(b) {} + justification(lit const& l, clause& c, euf::enode* const* b, unsigned generation, unsigned n, size_t** ev) : + m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_generation(generation), m_num_ex(n), m_explain(ev), m_clause(c), m_binding(b) {} 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 2c5ab80ae..9335c576b 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -104,7 +104,7 @@ namespace q { * is created to ensure the justification trail is well-founded * during conflict resolution. */ - sat::ext_justification_idx ematch::mk_justification(unsigned idx, clause& c, euf::enode* const* b) { + sat::ext_justification_idx ematch::mk_justification(unsigned idx, unsigned generation, clause& c, euf::enode* const* b) { void* mem = ctx.get_region().allocate(justification::get_obj_size()); sat::constraint_base::initialize(mem, &m_qs); bool sign = false; @@ -129,7 +129,7 @@ namespace q { size_t** ev = static_cast(ctx.get_region().allocate(sizeof(size_t*) * m_explain.size())); for (unsigned i = m_explain.size(); i-- > 0; ) ev[i] = m_explain[i]; - auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b, m_explain.size(), ev); + auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b, generation, m_explain.size(), ev); return constraint->to_index(); } @@ -363,7 +363,7 @@ namespace q { if (!is_owned) binding = copy_nodes(c, binding); - auto j_idx = mk_justification(idx, c, binding); + auto j_idx = mk_justification(idx, max_generation, c, binding); if (is_owned) propagate(ev == l_false, idx, j_idx); @@ -387,7 +387,7 @@ namespace q { m_qs.log_instantiation(lits, &j); euf::th_proof_hint* ph = nullptr; if (ctx.use_drat()) - ph = q_proof_hint::mk(ctx, lits, j.m_clause.num_decls(), j.m_binding); + ph = q_proof_hint::mk(ctx, j.m_generation, lits, j.m_clause.num_decls(), j.m_binding); m_qs.add_clause(lits, ph); } @@ -414,7 +414,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())); + ctx.propagate(lit, mk_justification(UINT_MAX, b.m_max_generation, c, b.nodes())); m_qs.log_instantiation(~c.m_literal, lit); } diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index 834c8740d..c04107b3b 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -97,7 +97,7 @@ namespace q { ptr_vector m_explain; euf::cc_justification m_explain_cc; - sat::ext_justification_idx mk_justification(unsigned idx, clause& c, euf::enode* const* b); + sat::ext_justification_idx mk_justification(unsigned idx, unsigned generation, clause& c, euf::enode* const* b); void ensure_ground_enodes(expr* e); void ensure_ground_enodes(clause const& c); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index cda05ee28..2c9b87c13 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -71,7 +71,7 @@ namespace q { for (auto const& [qlit, fml, inst, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ~ctx.mk_literal(fml); - auto* ph = ctx.use_drat()? q_proof_hint::mk(ctx, ~qlit, lit, inst.size(), inst.data()) : nullptr; + auto* ph = ctx.use_drat()? q_proof_hint::mk(ctx, generation, ~qlit, lit, inst.size(), inst.data()) : nullptr; m_qs.add_clause(~qlit, lit, ph); m_qs.log_instantiation(~qlit, lit); } diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index a94008074..ae37b7f07 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -364,10 +364,10 @@ namespace q { } } - q_proof_hint* q_proof_hint::mk(euf::solver& s, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings) { + q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned generation, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings) { SASSERT(n > 0); auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, lits.size())); - q_proof_hint* ph = new (mem) q_proof_hint(n, lits.size()); + q_proof_hint* ph = new (mem) q_proof_hint(generation, n, lits.size()); for (unsigned i = 0; i < n; ++i) ph->m_bindings[i] = bindings[i]->get_expr(); for (unsigned i = 0; i < lits.size(); ++i) @@ -375,10 +375,10 @@ namespace q { return ph; } - q_proof_hint* q_proof_hint::mk(euf::solver& s, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings) { + q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned generation, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings) { SASSERT(n > 0); auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, 2)); - q_proof_hint* ph = new (mem) q_proof_hint(n, 2); + q_proof_hint* ph = new (mem) q_proof_hint(generation, n, 2); for (unsigned i = 0; i < n; ++i) ph->m_bindings[i] = bindings[i]; ph->m_literals[0] = l1; @@ -390,6 +390,9 @@ namespace q { ast_manager& m = s.get_manager(); expr_ref_vector args(m); expr_ref binding(m); + arith_util a(m); + expr_ref gen(a.mk_int(m_generation), m); + expr* gens[1] = { gen.get() }; sort* range = m.mk_proof_sort(); for (unsigned i = 0; i < m_num_bindings; ++i) args.push_back(m_bindings[i]); @@ -398,6 +401,7 @@ namespace q { for (unsigned i = 0; i < m_num_literals; ++i) args.push_back(s.literal2expr(~m_literals[i])); args.push_back(binding); + args.push_back(m.mk_app(symbol("gen"), 1, gens, range)); return m.mk_app(symbol("inst"), args.size(), args.data(), range); } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 3a95a00be..153cdc774 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -30,19 +30,21 @@ namespace euf { namespace q { struct q_proof_hint : public euf::th_proof_hint { + unsigned m_generation; unsigned m_num_bindings; unsigned m_num_literals; sat::literal* m_literals; expr* m_bindings[0]; - q_proof_hint(unsigned b, unsigned l) { + q_proof_hint(unsigned g, unsigned b, unsigned l) { + m_generation = g; m_num_bindings = b; m_num_literals = l; m_literals = reinterpret_cast(m_bindings + m_num_bindings); } static size_t get_obj_size(unsigned num_bindings, unsigned num_lits) { return sizeof(q_proof_hint) + num_bindings*sizeof(expr*) + num_lits*sizeof(sat::literal); } - static q_proof_hint* mk(euf::solver& s, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings); - static q_proof_hint* mk(euf::solver& s, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings); + static q_proof_hint* mk(euf::solver& s, unsigned generation, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings); + static q_proof_hint* mk(euf::solver& s, unsigned generation, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings); expr* get_hint(euf::solver& s) const override; }; diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index a1402839d..b3e8429b4 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -306,11 +306,15 @@ namespace smt { } else if (m_context.on_clause_active()) { expr_ref_vector bindings_e(m), args(m); + arith_util a(m); + expr_ref gen(a.mk_int(generation), m); + expr* gens[1] = { gen.get() }; for (unsigned i = 0; i < num_bindings; ++i) bindings_e.push_back(bindings[i]->get_expr()); args.push_back(m.mk_not(q)); args.push_back(instance); args.push_back(m.mk_app(symbol("bind"), num_bindings, bindings_e.data(), m.mk_proof_sort())); + args.push_back(m.mk_app(symbol("gen"), 1, gens, m.mk_proof_sort())); pr1 = m.mk_app(symbol("inst"), args.size(), args.data(), m.mk_proof_sort()); m_instances.push_back(pr1); } From 31914d8ecf8145510776802c018f134d02a21888 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Oct 2022 03:47:57 -0700 Subject: [PATCH 174/477] simplify purified expressions --- src/qe/mbp/mbp_term_graph.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qe/mbp/mbp_term_graph.cpp b/src/qe/mbp/mbp_term_graph.cpp index 4709c8c72..624febffd 100644 --- a/src/qe/mbp/mbp_term_graph.cpp +++ b/src/qe/mbp/mbp_term_graph.cpp @@ -24,6 +24,7 @@ Notes: #include "ast/ast_util.h" #include "ast/for_each_expr.h" #include "ast/occurs.h" +#include "ast/rewriter/th_rewriter.h" #include "model/model_evaluator.h" #include "qe/mbp/mbp_term_graph.h" @@ -583,6 +584,7 @@ namespace mbp { ast_manager &m; u_map m_term2app; u_map m_root2rep; + th_rewriter m_rewriter; model_ref m_model; expr_ref_vector m_pinned; // tracks expr in the maps @@ -609,7 +611,7 @@ namespace mbp { } TRACE("qe_verbose", tout << *ch << " -> " << mk_pp(e, m) << "\n";); } - expr* pure = m.mk_app(a->get_decl(), kids.size(), kids.data()); + expr_ref pure = m_rewriter.mk_app(a->get_decl(), kids.size(), kids.data()); m_pinned.push_back(pure); add_term2app(t, pure); return pure; @@ -940,7 +942,7 @@ namespace mbp { } public: - projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} + projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_rewriter(m), m_pinned(m) {} void add_term2app(term const& t, expr* a) { m_term2app.insert(t.get_id(), a); From ad5fa9433f486b088e9459b85ba69510fcf2b8c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Oct 2022 09:25:45 -0700 Subject: [PATCH 175/477] add experiment with quot-rem encoding experiment seeks to determine whether quot-rem encoding can substitute the division circuit encoding. A first test suggests it makes no difference. --- src/smt/theory_bv.cpp | 10 +++++++--- src/solver/assertions/asserted_formulas.cpp | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index f195e0c9d..922eafcf6 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -24,6 +24,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "util/stats.h" +#define ENABLE_QUOT_REM_ENCODING 0 namespace smt { @@ -898,8 +899,11 @@ namespace smt { case OP_BSUB: internalize_sub(term); return true; case OP_BMUL: internalize_mul(term); return true; case OP_BSDIV_I: internalize_sdiv(term); return true; +#if ENABLE_QUOT_REM_ENCODING + case OP_BUDIV_I: internalize_udiv_quot_rem(term); return true; +#else case OP_BUDIV_I: internalize_udiv(term); return true; - // case OP_BUDIV_I: internalize_udiv_quot_rem(term); return true; +#endif case OP_BSREM_I: internalize_srem(term); return true; case OP_BUREM_I: internalize_urem(term); return true; case OP_BSMOD_I: internalize_smod(term); return true; @@ -1394,7 +1398,7 @@ namespace smt { ctx.mark_as_relevant(n->get_arg(0)); assert_int2bv_axiom(n); } -#if 0 +#if ENABLE_QUOT_REM_ENCODING else if (m_util.is_bv_udivi(n)) { ctx.mark_as_relevant(n->get_arg(0)); ctx.mark_as_relevant(n->get_arg(1)); @@ -1994,7 +1998,7 @@ namespace smt { return true; } -#if 0 +#if ENABLE_QUOT_REM_ENCODING void theory_bv::internalize_udiv_quot_rem(app* n) { process_args(n); mk_enode(n); diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 630d73945..90c84e7ee 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -332,8 +332,8 @@ bool asserted_formulas::invoke(simplify_fmls& s) { IF_VERBOSE(10000, verbose_stream() << "total size: " << get_total_size() << "\n";); TRACE("reduce_step_ll", ast_mark visited; display_ll(tout, visited);); CASSERT("well_sorted",check_well_sorted()); + TRACE("after_reduce", display(tout << s.id() << "\n");); if (inconsistent() || canceled()) { - TRACE("after_reduce", display(tout);); TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); return false; } From 53adc2afeef10eaf5f780a790f6070775058da73 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Oct 2022 15:24:44 -0700 Subject: [PATCH 176/477] update debugging information for new core --- src/sat/smt/arith_solver.cpp | 34 +++++----------------------------- src/sat/smt/euf_model.cpp | 12 ++++++++---- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index f7e3f6293..eb0af0c69 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -561,6 +561,9 @@ namespace arith { void solver::dbg_finalize_model(model& mdl) { if (m_not_handled) return; + + // this is already handled in general in euf_model.cpp + return; bool found_bad = false; for (unsigned v = 0; v < get_num_vars(); ++v) { if (!is_bool(v)) @@ -583,35 +586,8 @@ namespace arith { if (!found_bad && value == get_phase(n->bool_var())) continue; - TRACE("arith", - ptr_vector nodes; - expr_mark marks; - nodes.push_back(n->get_expr()); - for (unsigned i = 0; i < nodes.size(); ++i) { - expr* r = nodes[i]; - if (marks.is_marked(r)) - continue; - marks.mark(r); - if (is_app(r)) - for (expr* arg : *to_app(r)) - nodes.push_back(arg); - expr_ref rval(m); - expr_ref mval = mdl(r); - if (ctx.get_egraph().find(r)) - rval = mdl(ctx.get_egraph().find(r)->get_root()->get_expr()); - tout << r->get_id() << ": " << mk_bounded_pp(r, m, 1) << " := " << mval; - if (rval != mval) tout << " " << rval; - tout << "\n"; - }); - TRACE("arith", - tout << eval << " " << value << " " << ctx.bpp(n) << "\n"; - tout << mdl << "\n"; - s().display(tout);); - IF_VERBOSE(0, - verbose_stream() << eval << " " << value << " " << ctx.bpp(n) << "\n"; - verbose_stream() << n->bool_var() << " " << n->value() << " " << get_phase(n->bool_var()) << " " << ctx.bpp(n) << "\n"; - verbose_stream() << *b << "\n";); - IF_VERBOSE(0, ctx.display_validation_failure(verbose_stream(), mdl, n)); + TRACE("arith", ctx.display_validation_failure(tout << *b << "\n", mdl, n)); + IF_VERBOSE(0, ctx.display_validation_failure(verbose_stream() << *b << "\n", mdl, n)); UNREACHABLE(); } } diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index c22c46322..54a3d63d8 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -287,17 +287,20 @@ namespace euf { nodes.push_back(n); for (unsigned i = 0; i < nodes.size(); ++i) { euf::enode* r = nodes[i]; - if (r->is_marked1()) + if (!r || r->is_marked1()) continue; r->mark1(); - for (auto* arg : euf::enode_args(r)) - nodes.push_back(arg); + if (is_app(r->get_expr())) + for (auto* arg : *r->get_app()) + nodes.push_back(get_enode(arg)); expr_ref val = mdl(r->get_expr()); expr_ref sval(m); th_rewriter rw(m); rw(val, sval); expr_ref mval = mdl(r->get_root()->get_expr()); if (mval != sval) { + if (r->bool_var() != sat::null_bool_var) + out << "b" << r->bool_var() << " "; out << bpp(r) << " :=\neval: " << sval << "\nmval: " << mval << "\n"; continue; } @@ -309,7 +312,8 @@ namespace euf { out << bpp(r) << " :=\neval: " << sval << "\nmval: " << bval << "\n"; } for (euf::enode* r : nodes) - r->unmark1(); + if (r) + r->unmark1(); out << mdl << "\n"; } From 7eee7914bd50885159f52d941f4a9296db69b980 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Oct 2022 15:26:00 -0700 Subject: [PATCH 177/477] align format of quantifier instantiation with new core So far the format is (forall ((x Int)) body) (not (body[t/x])) The alternative could be the clause (not (forall ((x Int)) body)) body[t/x] they just better be consistent between engines --- src/smt/qi_queue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index b3e8429b4..cb28f87f8 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -311,8 +311,8 @@ namespace smt { expr* gens[1] = { gen.get() }; for (unsigned i = 0; i < num_bindings; ++i) bindings_e.push_back(bindings[i]->get_expr()); - args.push_back(m.mk_not(q)); - args.push_back(instance); + args.push_back(q); + args.push_back(mk_not(m, instance)); args.push_back(m.mk_app(symbol("bind"), num_bindings, bindings_e.data(), m.mk_proof_sort())); args.push_back(m.mk_app(symbol("gen"), 1, gens, m.mk_proof_sort())); pr1 = m.mk_app(symbol("inst"), args.size(), args.data(), m.mk_proof_sort()); From e3a44254c9b9a50a7769a7482674e0103052ecb0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 22 Oct 2022 11:18:16 -0700 Subject: [PATCH 178/477] fix #6415 --- src/qe/mbp/mbp_arith.cpp | 6 ++-- src/qe/qe_mbi.cpp | 73 +++++++++++++++++++++++++++++++++++++--- src/qe/qe_mbi.h | 6 ++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index a886a5a70..9956a6d2e 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -407,9 +407,9 @@ namespace mbp { TRACE("qe", for (auto const& [v, t] : result) tout << v << " := " << t << "\n"; - for (auto* f : fmls) - tout << mk_pp(f, m) << " := " << eval(f) << "\n"; - tout << "fmls:" << fmls << "\n";); + for (auto* f : fmls) + tout << mk_pp(f, m) << " := " << eval(f) << "\n"; + tout << "fmls:" << fmls << "\n";); return true; } diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index dea1b11c0..81b7211bf 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -30,6 +30,7 @@ Notes: #include "ast/ast_util.h" #include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include "ast/for_each_expr.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/rewriter/bool_rewriter.h" @@ -117,6 +118,12 @@ namespace qe { return all_shared; } + void mbi_plugin::validate_interpolant(expr* itp) { + for (expr* e : subterms::ground(expr_ref(itp, m))) + if (!is_shared(e)) + IF_VERBOSE(0, verbose_stream() << "non-shared subterm " << mk_bounded_pp(e, m) << "\n"); + } + // ------------------------------- // prop_mbi @@ -209,12 +216,10 @@ namespace qe { lits.reset(); IF_VERBOSE(10, verbose_stream() << "atoms: " << m_atoms << "\n"); for (expr* e : m_atoms) { - if (mdl->is_true(e)) { + if (mdl->is_true(e)) lits.push_back(e); - } - else if (mdl->is_false(e)) { + else if (mdl->is_false(e)) lits.push_back(m.mk_not(e)); - } } TRACE("qe", tout << "atoms from model: " << lits << "\n";); solver_ref dual = m_dual_solver->translate(m, m_dual_solver->get_params()); @@ -262,6 +267,64 @@ namespace qe { return avars; } + /*** + Arithmetic projection is not guaranteed to remove non-shared variables + when there are expressions with if-then-else constructs. + For these cases we apply model refinement to the literals: non-shared + sub-expressions are replaced by model values. + */ + void uflia_mbi::fix_non_shared(model& mdl, expr_ref_vector& lits) { + th_rewriter rewrite(m); + expr_ref_vector trail(m); + obj_map cache; + ptr_vector todo, args; + expr* f = nullptr; + todo.append(lits.size(), lits.data()); + while (!todo.empty()) { + expr* e = todo.back(); + if (cache.contains(e)) { + todo.pop_back(); + continue; + } + if (!is_app(e)) { + cache.insert(e, e); + todo.pop_back(); + continue; + } + args.reset(); + unsigned sz = todo.size(); + bool diff = false; + func_decl* fn = to_app(e)->get_decl(); + if (!is_shared(fn)) { + expr_ref val = mdl(e); + cache.insert(e, val); + trail.push_back(val); + todo.pop_back(); + continue; + } + for (expr* arg : *to_app(e)) { + if (cache.find(arg, f)) { + args.push_back(f); + diff |= f != arg; + } + else + todo.push_back(arg); + } + if (sz < todo.size()) + continue; + todo.pop_back(); + if (!diff) { + cache.insert(e, e); + continue; + } + f = rewrite.mk_app(to_app(e)->get_decl(), args.size(), args.data()); + trail.push_back(f); + cache.insert(e, f); + } + for (unsigned i = 0; i < lits.size(); ++i) + lits[i] = cache[lits.get(i)]; + } + vector uflia_mbi::arith_project(model_ref& mdl, app_ref_vector& avars, expr_ref_vector& lits) { mbp::arith_project_plugin ap(m); ap.set_check_purified(false); @@ -269,6 +332,7 @@ namespace qe { bool ok = ap.project(*mdl.get(), avars, lits, defs); (void)ok; CTRACE("qe", !ok, tout << "projection failure ignored!!!!\n"); + fix_non_shared(*mdl, lits); return defs; } @@ -522,6 +586,7 @@ namespace qe { break; case l_false: itp = mk_or(itps); + a.validate_interpolant(itp); return l_false; case l_undef: return l_undef; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 70c0f98bb..93f7df88d 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -100,6 +100,11 @@ namespace qe { */ lbool check(expr_ref_vector& lits, model_ref& mdl); + /** + * \brief validate interpolant that it only uses shared symbols. + */ + void validate_interpolant(expr* itp); + }; class prop_mbi_plugin : public mbi_plugin { @@ -131,6 +136,7 @@ namespace qe { void split_arith(expr_ref_vector const& lits, expr_ref_vector& alits, expr_ref_vector& uflits); + void fix_non_shared(model& mdl, expr_ref_vector& lits); public: uflia_mbi(solver* s, solver* emptySolver); mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override; From 071a1447e33e2d9be3e217b10f4aba2648126536 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2022 11:03:00 -0700 Subject: [PATCH 179/477] fix #6418 --- src/qe/qe_mbi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 81b7211bf..48a7928be 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -317,9 +317,9 @@ namespace qe { cache.insert(e, e); continue; } - f = rewrite.mk_app(to_app(e)->get_decl(), args.size(), args.data()); - trail.push_back(f); - cache.insert(e, f); + expr_ref val = rewrite.mk_app(to_app(e)->get_decl(), args.size(), args.data()); + trail.push_back(val); + cache.insert(e, val); } for (unsigned i = 0; i < lits.size(); ++i) lits[i] = cache[lits.get(i)]; From 4a1d76cf49cddf177f9e4ad503c26e170aa0e9f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2022 11:03:51 -0700 Subject: [PATCH 180/477] #6418 - add best-effort for nested and/or (from ite literals) --- src/qe/mbp/mbp_arith.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index 9956a6d2e..e97eb4ef7 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -155,6 +155,35 @@ namespace mbp { } SASSERT(found_eq); } + else if (m.is_and(lit) && !is_not) { + fmls.append(to_app(lit)->get_num_args(), to_app(lit)->get_args()); + return true; + } + else if (m.is_or(lit) && is_not) { + for (expr* arg : *to_app(lit)) + fmls.push_back(mk_not(m, arg)); + return true; + } + else if (m.is_or(lit) && !is_not) { + for (expr* arg : *to_app(lit)) { + if (eval.is_true(arg)) { + fmls.push_back(arg); + return true; + } + } + TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); + return false; + } + else if (m.is_and(lit) && is_not) { + for (expr* arg : *to_app(lit)) { + if (eval.is_false(arg)) { + fmls.push_back(mk_not(m, arg)); + return true; + } + } + TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); + return false; + } else { TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); return false; From ddbca68270f68839553790f9cc4ba933e606ec6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2022 11:05:09 -0700 Subject: [PATCH 181/477] minor formatting update --- src/sat/sat_solver.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 15bc20a58..3012a840e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -601,18 +601,17 @@ namespace sat { clause * r = alloc_clause(num_lits, lits, st.is_redundant()); SASSERT(!st.is_redundant() || r->is_learned()); bool reinit = attach_nary_clause(*r, st.is_sat() && st.is_redundant()); - if (reinit || has_variables_to_reinit(*r)) push_reinit_stack(*r); - if (st.is_redundant()) { + + if (reinit || has_variables_to_reinit(*r)) + push_reinit_stack(*r); + if (st.is_redundant()) m_learned.push_back(r); - } - else { + else m_clauses.push_back(r); - } if (m_config.m_drat) m_drat.add(*r, st); - for (literal l : *r) { + for (literal l : *r) m_touched[l.var()] = m_touch_index; - } return r; } From 6393ed78d7434e6be1a0a372d5110cba532979b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2022 11:05:33 -0700 Subject: [PATCH 182/477] remove useless log --- src/sat/tactic/goal2sat.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index a2d94652c..c819403d7 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -509,7 +509,6 @@ struct goal2sat::imp : public sat::sat_internalizer { m_result_stack.shrink(old_sz); m_result_stack.push_back(l); - TRACE("goal2sat", tout << m_result_stack << "\n";); } } From c8e1e180eaa566b1b8a27df9a9f4c81132f7ffc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2022 11:05:50 -0700 Subject: [PATCH 183/477] prefix Boolean variables in log with b --- src/sat/smt/euf_internalize.cpp | 2 +- src/sat/smt/euf_solver.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 337e95ddf..c0b2540ea 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -174,7 +174,7 @@ namespace euf { lit = lit2; } - TRACE("euf", tout << "attach v" << v << " " << mk_bounded_pp(e, m) << "\n";); + TRACE("euf", tout << "attach b" << v << " " << mk_bounded_pp(e, m) << "\n";); m_bool_var2expr.reserve(v + 1, nullptr); if (m_bool_var2expr[v] && m_egraph.find(e)) { if (m_egraph.find(e)->bool_var() != v) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 5086dea98..149e3b1a2 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -647,10 +647,10 @@ namespace euf { 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";); + TRACE("euf", for (auto const& kv : replay.m) tout << "b" << kv.m_value << "\n";); for (auto const& [e, generation, v] : m_reinit) { scoped_generation _sg(*this, generation); - TRACE("euf", tout << "replay: " << v << " " << e->get_id() << " " << mk_bounded_pp(e, m) << " " << si.is_bool_op(e) << "\n";); + TRACE("euf", tout << "replay: b" << v << " #" << e->get_id() << " " << mk_bounded_pp(e, m) << " " << si.is_bool_op(e) << "\n";); sat::literal lit; if (si.is_bool_op(e)) lit = literal(replay.m[e], false); From 5c7eaec566f3db02026163142ced0b4be9556365 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2022 00:38:31 -0700 Subject: [PATCH 184/477] #6364 - remove option of redundant clauses from internalization gc-ing definitions leads to unsoundness when they are not replayed. Instead of attempting to replay definitions theory internalization is irredundant by default. This is also the old solver behavior where TH_LEMMA is essentially never used, but is valid for top-level theory lemmas. --- src/sat/smt/arith_internalize.cpp | 8 +++---- src/sat/smt/arith_solver.cpp | 5 ++--- src/sat/smt/arith_solver.h | 4 ++-- src/sat/smt/array_internalize.cpp | 10 ++++----- src/sat/smt/array_solver.h | 4 ++-- src/sat/smt/bv_internalize.cpp | 28 ++++++++++++------------ src/sat/smt/bv_solver.cpp | 4 ++-- src/sat/smt/bv_solver.h | 4 ++-- src/sat/smt/dt_solver.cpp | 10 ++++----- src/sat/smt/dt_solver.h | 4 ++-- src/sat/smt/euf_ackerman.cpp | 4 +--- src/sat/smt/euf_internalize.cpp | 36 +++++++++++++++---------------- src/sat/smt/euf_proof.cpp | 6 +++--- src/sat/smt/euf_solver.cpp | 30 +++++++++++++------------- src/sat/smt/euf_solver.h | 4 ++-- src/sat/smt/fpa_solver.cpp | 10 ++++----- src/sat/smt/fpa_solver.h | 4 ++-- src/sat/smt/pb_internalize.cpp | 9 ++++---- src/sat/smt/pb_solver.h | 4 ++-- src/sat/smt/q_solver.cpp | 6 +++--- src/sat/smt/q_solver.h | 4 ++-- src/sat/smt/recfun_solver.cpp | 10 ++++----- src/sat/smt/recfun_solver.h | 4 ++-- src/sat/smt/sat_internalizer.h | 2 +- src/sat/smt/sat_th.cpp | 13 ++++------- src/sat/smt/sat_th.h | 15 ++++++------- src/sat/smt/user_solver.cpp | 16 +++++++------- src/sat/smt/user_solver.h | 4 ++-- src/sat/tactic/goal2sat.cpp | 18 +++++++--------- 29 files changed, 133 insertions(+), 147 deletions(-) diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 30eab0b53..04a3ae4ef 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -20,9 +20,8 @@ Author: namespace arith { - sat::literal solver::internalize(expr* e, bool sign, bool root, bool learned) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { init_internalize(); - flet _is_learned(m_is_redundant, learned); internalize_atom(e); literal lit = ctx.expr2literal(e); if (sign) @@ -30,9 +29,8 @@ namespace arith { return lit; } - void solver::internalize(expr* e, bool redundant) { + void solver::internalize(expr* e) { init_internalize(); - flet _is_learned(m_is_redundant, redundant); if (m.is_bool(e)) internalize_atom(e); else @@ -247,7 +245,7 @@ namespace arith { ctx.push(push_back_vector(m_idiv_terms)); m_idiv_terms.push_back(n); app_ref mod(a.mk_mod(n1, n2), m); - internalize(mod, m_is_redundant); + internalize(mod); st.to_ensure_var().push_back(n1); st.to_ensure_var().push_back(n2); } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index eb0af0c69..a658315e3 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -952,7 +952,6 @@ namespace arith { sat::check_result solver::check() { force_push(); m_model_is_initialized = false; - flet _is_learned(m_is_redundant, true); IF_VERBOSE(12, verbose_stream() << "final-check " << lp().get_status() << "\n"); SASSERT(lp().ax_is_correct()); @@ -1174,7 +1173,7 @@ namespace arith { for (auto const& c : core) m_core2.push_back(~c); m_core2.push_back(lit); - add_clause(m_core2, pma); + add_redundant(m_core2, pma); } else { auto* jst = euf::th_explain::propagate(*this, core, eqs, lit, pma); @@ -1215,7 +1214,7 @@ namespace arith { for (literal& c : m_core) c.neg(); - add_clause(m_core, explain(hint_type::farkas_h)); + add_redundant(m_core, explain(hint_type::farkas_h)); } bool solver::is_infeasible() const { diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 3d3f1ddd7..775fecd70 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -504,8 +504,8 @@ namespace arith { void finalize_model(model& mdl) override { DEBUG_CODE(dbg_finalize_model(mdl);); } void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override; bool add_dep(euf::enode* n, top_sort& dep) override; - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; void eq_internalized(euf::enode* n) override; void apply_sort_cnstr(euf::enode* n, sort* s) override {} bool is_shared(theory_var v) const override; diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 4df4f3a50..c7517f5a4 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -20,9 +20,9 @@ Author: namespace array { - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { SASSERT(m.is_bool(e)); - if (!visit_rec(m, e, sign, root, redundant)) { + if (!visit_rec(m, e, sign, root)) { TRACE("array", tout << mk_pp(e, m) << "\n";); return sat::null_literal; } @@ -32,8 +32,8 @@ namespace array { return lit; } - void solver::internalize(expr* e, bool redundant) { - visit_rec(m, e, false, false, redundant); + void solver::internalize(expr* e) { + visit_rec(m, e, false, false); } euf::theory_var solver::mk_var(euf::enode* n) { @@ -66,7 +66,7 @@ namespace array { if (visited(e)) return true; if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { - ctx.internalize(e, m_is_redundant); + ctx.internalize(e); euf::enode* n = expr2enode(e); ensure_var(n); return true; diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 5c2708842..4f100d694 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -296,8 +296,8 @@ namespace array { bool include_func_interp(func_decl* f) const override { return a.is_ext(f); } void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override; bool add_dep(euf::enode* n, top_sort& dep) override; - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; euf::theory_var mk_var(euf::enode* n) override; void apply_sort_cnstr(euf::enode* n, sort* s) override; bool is_shared(theory_var v) const override; diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index cffd62acd..99d2a34ae 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -99,10 +99,10 @@ namespace bv { get_var(n); } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { force_push(); SASSERT(m.is_bool(e)); - if (!visit_rec(m, e, sign, root, redundant)) + if (!visit_rec(m, e, sign, root)) return sat::null_literal; sat::literal lit = expr2literal(e); if (sign) @@ -110,14 +110,14 @@ namespace bv { return lit; } - void solver::internalize(expr* e, bool redundant) { + void solver::internalize(expr* e) { force_push(); - visit_rec(m, e, false, false, redundant); + visit_rec(m, e, false, false); } bool solver::visit(expr* e) { if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { - ctx.internalize(e, m_is_redundant); + ctx.internalize(e); return true; } m_stack.push_back(sat::eframe(e)); @@ -246,7 +246,7 @@ namespace bv { for (unsigned i = 0; i < bv_size; i++) { expr_ref b2b(bv.mk_bit2bool(e, i), m); m_bits[v].push_back(sat::null_literal); - sat::literal lit = ctx.internalize(b2b, false, false, m_is_redundant); + sat::literal lit = ctx.internalize(b2b, false, false); TRACE("bv", tout << "add-bit: " << lit << " " << literal2expr(lit) << "\n";); if (m_bits[v].back() == sat::null_literal) m_bits[v].back() = lit; @@ -344,7 +344,7 @@ namespace bv { SASSERT(bits.size() == m_bits[v].size()); unsigned i = 0; for (expr* bit : bits) { - sat::literal lit = ctx.internalize(bit, false, false, m_is_redundant); + sat::literal lit = ctx.internalize(bit, false, false); TRACE("bv", tout << "set " << m_bits[v][i] << " == " << lit << "\n";); add_clause(~lit, m_bits[v][i]); add_clause(lit, ~m_bits[v][i]); @@ -353,7 +353,7 @@ namespace bv { return; } for (expr* bit : bits) - add_bit(v, ctx.internalize(bit, false, false, m_is_redundant)); + add_bit(v, ctx.internalize(bit, false, false)); for (expr* bit : bits) get_var(expr2enode(bit)); SASSERT(get_bv_size(n) == bits.size()); @@ -371,7 +371,7 @@ namespace bv { sat::literal solver::mk_true() { if (m_true == sat::null_literal) { ctx.push(value_trail(m_true)); - m_true = ctx.internalize(m.mk_true(), false, true, false); + m_true = ctx.internalize(m.mk_true(), false, true); s().assign_unit(m_true); } return m_true; @@ -493,7 +493,7 @@ namespace bv { m_bb.mk_sle(arg1_bits.size(), arg1_bits.data(), arg2_bits.data(), le); else m_bb.mk_ule(arg1_bits.size(), arg1_bits.data(), arg2_bits.data(), le); - literal def = ctx.internalize(le, false, false, m_is_redundant); + literal def = ctx.internalize(le, false, false); if (Negated) def.neg(); add_def(def, expr2literal(n)); @@ -598,7 +598,7 @@ namespace bv { get_arg_bits(n, 1, arg2_bits); expr_ref out(m); fn(arg1_bits.size(), arg1_bits.data(), arg2_bits.data(), out); - sat::literal def = ctx.internalize(out, false, false, m_is_redundant); + sat::literal def = ctx.internalize(out, false, false); add_def(def, expr2literal(n)); } @@ -753,12 +753,11 @@ namespace bv { return; if (v1 > v2) std::swap(v1, v2); - flet _red(m_is_redundant, true); ++m_stats.m_ackerman; expr* o1 = var2expr(v1); expr* o2 = var2expr(v2); expr_ref oe = mk_var_eq(v1, v2); - literal oeq = ctx.internalize(oe, false, false, m_is_redundant); + literal oeq = ctx.internalize(oe, false, false); unsigned sz = m_bits[v1].size(); TRACE("bv", tout << "ackerman-eq: " << s().scope_lvl() << " " << oe << "\n";); literal_vector eqs; @@ -772,6 +771,7 @@ namespace bv { eqs.push_back(~eq); } TRACE("bv", for (auto l : eqs) tout << mk_bounded_pp(literal2expr(l), m) << " "; tout << "\n";); - add_clause(eqs); + euf::th_proof_hint* ph = ctx.mk_smt_clause(name(), eqs.size(), eqs.data()); + s().mk_clause(eqs, sat::status::th(true, m.get_basic_family_id(), ph)); } } diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index c50f7c4e6..f103f876a 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -168,7 +168,7 @@ namespace bv { TRACE("bv", tout << "found new diseq axiom\n" << pp(v1) << pp(v2);); m_stats.m_num_diseq_static++; expr_ref eq(m.mk_eq(var2expr(v1), var2expr(v2)), m); - add_unit(~ctx.internalize(eq, false, false, m_is_redundant)); + add_unit(~ctx.internalize(eq, false, false)); } std::ostream& solver::display(std::ostream& out, theory_var v) const { @@ -464,7 +464,7 @@ namespace bv { m_lit_head = m_lit_tail; m_lit_tail = m_proof_literals.size(); proof_hint* ph = new (get_region()) proof_hint(c.m_kind, m_proof_literals, m_lit_head, m_lit_tail, a1, a2, b1, b2); - auto st = sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + auto st = sat::status::th(false, m.get_basic_family_id(), ph); ctx.get_drat().add(lits, st); m_lit_head = m_lit_tail; // TBD, a proper way would be to delete the lemma after use. diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index e4a44e769..dc9cd1456 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -385,8 +385,8 @@ namespace bv { std::function& pb) override { return false; } bool to_formulas(std::function& l2e, expr_ref_vector& fmls) override { return false; } - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; void eq_internalized(euf::enode* n) override; euf::theory_var mk_var(euf::enode* n) override; void apply_sort_cnstr(euf::enode * n, sort * s) override; diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index a87f8770b..56a224d36 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -804,8 +804,8 @@ namespace dt { } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { - if (!visit_rec(m, e, sign, root, redundant)) + sat::literal solver::internalize(expr* e, bool sign, bool root) { + if (!visit_rec(m, e, sign, root)) return sat::null_literal; auto lit = ctx.expr2literal(e); if (sign) @@ -813,15 +813,15 @@ namespace dt { return lit; } - void solver::internalize(expr* e, bool redundant) { - visit_rec(m, e, false, false, redundant); + void solver::internalize(expr* e) { + visit_rec(m, e, false, false); } bool solver::visit(expr* e) { if (visited(e)) return true; if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { - ctx.internalize(e, m_is_redundant); + ctx.internalize(e); if (is_datatype(e)) mk_var(expr2enode(e)); return true; diff --git a/src/sat/smt/dt_solver.h b/src/sat/smt/dt_solver.h index 4e2524f6b..51a7679fd 100644 --- a/src/sat/smt/dt_solver.h +++ b/src/sat/smt/dt_solver.h @@ -154,8 +154,8 @@ namespace dt { void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override; bool add_dep(euf::enode* n, top_sort& dep) override; bool include_func_interp(func_decl* f) const override; - sat::literal internalize(expr* e, bool sign, bool root, bool redundant) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; euf::theory_var mk_var(euf::enode* n) override; void apply_sort_cnstr(euf::enode* n, sort* s) override; bool is_shared(theory_var v) const override { return false; } diff --git a/src/sat/smt/euf_ackerman.cpp b/src/sat/smt/euf_ackerman.cpp index 19b1a28de..906120314 100644 --- a/src/sat/smt/euf_ackerman.cpp +++ b/src/sat/smt/euf_ackerman.cpp @@ -189,7 +189,6 @@ namespace euf { } void ackerman::add_cc(expr* _a, expr* _b) { - flet _is_redundant(ctx.m_is_redundant, true); app* a = to_app(_a); app* b = to_app(_b); TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << "\n";); @@ -213,7 +212,6 @@ namespace euf { void ackerman::add_eq(expr* a, expr* b, expr* c) { if (a == c || b == c) return; - flet _is_redundant(ctx.m_is_redundant, true); sat::literal lits[3]; expr_ref eq1(ctx.mk_eq(a, c), m); expr_ref eq2(ctx.mk_eq(b, c), m); @@ -223,7 +221,7 @@ namespace euf { lits[1] = ~ctx.mk_literal(eq2); lits[2] = ctx.mk_literal(eq3); th_proof_hint* ph = ctx.mk_tc_proof_hint(lits); - ctx.s().mk_clause(3, lits, sat::status::th(true, m.get_basic_family_id(), ph)); + ctx.s().add_clause(3, lits, sat::status::th(true, m.get_basic_family_id(), ph)); } } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index c0b2540ea..e2b116ea2 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -34,28 +34,28 @@ Notes: namespace euf { - void solver::internalize(expr* e, bool redundant) { + void solver::internalize(expr* e) { if (get_enode(e)) return; if (si.is_bool_op(e)) - attach_lit(si.internalize(e, redundant), e); + attach_lit(si.internalize(e), e); else if (auto* ext = expr2solver(e)) - ext->internalize(e, redundant); + ext->internalize(e); else - visit_rec(m, e, false, false, redundant); + visit_rec(m, e, false, false); SASSERT(m_egraph.find(e)); } sat::literal solver::mk_literal(expr* e) { expr_ref _e(e, m); bool is_not = m.is_not(e, e); - sat::literal lit = internalize(e, false, false, m_is_redundant); + sat::literal lit = internalize(e, false, false); if (is_not) lit.neg(); return lit; } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { euf::enode* n = get_enode(e); if (n) { if (m.is_bool(e)) { @@ -67,14 +67,14 @@ namespace euf { return sat::null_literal; } if (si.is_bool_op(e)) { - sat::literal lit = attach_lit(si.internalize(e, redundant), e); + sat::literal lit = attach_lit(si.internalize(e), e); if (sign) lit.neg(); return lit; } if (auto* ext = expr2solver(e)) - return ext->internalize(e, sign, root, redundant); - if (!visit_rec(m, e, sign, root, redundant)) { + return ext->internalize(e, sign, root); + if (!visit_rec(m, e, sign, root)) { TRACE("euf", tout << "visit-rec\n";); return sat::null_literal; } @@ -89,13 +89,13 @@ namespace euf { th_solver* s = nullptr; if (n && !si.is_bool_op(e) && (s = expr2solver(e), s && euf::null_theory_var == n->get_th_var(s->get_id()))) { // ensure that theory variables are attached in shared contexts. See notes (*) - s->internalize(e, false); + s->internalize(e); return true; } if (n) return true; if (si.is_bool_op(e)) { - attach_lit(si.internalize(e, m_is_redundant), e); + attach_lit(si.internalize(e), e); return true; } if (is_app(e) && to_app(e)->get_num_args() > 0) { @@ -103,7 +103,7 @@ namespace euf { return false; } if (auto* s = expr2solver(e)) - s->internalize(e, m_is_redundant); + s->internalize(e); else attach_node(mk_enode(e, 0, nullptr)); return true; @@ -118,7 +118,7 @@ namespace euf { return false; SASSERT(!get_enode(e)); if (auto* s = expr2solver(e)) - s->internalize(e, m_is_redundant); + s->internalize(e); else attach_node(mk_enode(e, num, m_args.data())); return true; @@ -167,8 +167,8 @@ namespace euf { ph1 = mk_smt_hint(symbol("tseitin"), ~lit, lit2); ph2 = mk_smt_hint(symbol("tseitin"), lit, ~lit2); } - s().mk_clause(~lit, lit2, sat::status::th(m_is_redundant, m.get_basic_family_id(), ph1)); - s().mk_clause(lit, ~lit2, sat::status::th(m_is_redundant, m.get_basic_family_id(), ph2)); + s().mk_clause(~lit, lit2, sat::status::th(false, m.get_basic_family_id(), ph1)); + s().mk_clause(lit, ~lit2, sat::status::th(false, m.get_basic_family_id(), ph2)); add_aux(~lit, lit2); add_aux(lit, ~lit2); lit = lit2; @@ -258,7 +258,7 @@ namespace euf { } pb_util pb(m); expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.data(), 2), m); - sat::literal lit = si.internalize(at_least2, m_is_redundant); + sat::literal lit = si.internalize(at_least2); s().add_clause(lit, mk_distinct_status(lit)); } } @@ -331,7 +331,7 @@ namespace euf { } expr_ref fml = mk_or(eqs); sat::literal dist(si.to_bool_var(e), false); - sat::literal some_eq = si.internalize(fml, m_is_redundant); + sat::literal some_eq = si.internalize(fml); add_root(~dist, ~some_eq); add_root(dist, some_eq); s().add_clause(~dist, ~some_eq, mk_distinct_status(~dist, ~some_eq)); @@ -461,7 +461,7 @@ namespace euf { euf::enode* solver::e_internalize(expr* e) { euf::enode* n = m_egraph.find(e); if (!n) { - internalize(e, m_is_redundant); + internalize(e); n = m_egraph.find(e); } return n; diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 742e00cd7..a8a9523fd 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -238,12 +238,12 @@ namespace euf { sat::status solver::mk_tseitin_status(unsigned n, sat::literal const* lits) { th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("tseitin"), n, lits) : nullptr; - return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + return sat::status::th(false, m.get_basic_family_id(), ph); } sat::status solver::mk_distinct_status(unsigned n, sat::literal const* lits) { th_proof_hint* ph = use_drat() ? mk_smt_hint(symbol("alldiff"), n, lits) : nullptr; - return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + return sat::status::th(false, m.get_basic_family_id(), ph); } expr* smt_proof_hint::get_hint(euf::solver& s) const { @@ -294,7 +294,7 @@ namespace euf { lits.push_back(jst.lit_consequent()); if (jst.eq_consequent().first != nullptr) lits.push_back(add_lit(jst.eq_consequent())); - get_drat().add(lits, sat::status::th(m_is_redundant, jst.ext().get_id(), jst.get_pragma())); + get_drat().add(lits, sat::status::th(false, jst.ext().get_id(), jst.get_pragma())); for (unsigned i = s().num_vars(); i < nv; ++i) set_tmp_bool_var(i, nullptr); } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 149e3b1a2..737148cd7 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -655,14 +655,14 @@ namespace euf { if (si.is_bool_op(e)) lit = literal(replay.m[e], false); else - lit = si.internalize(e, false); + lit = si.internalize(e); VERIFY(lit.var() == v); if (!m_egraph.find(e) && !m.is_iff(e) && !m.is_or(e) && !m.is_and(e) && !m.is_not(e) && !m.is_implies(e) && !m.is_xor(e)) { ptr_buffer args; if (is_app(e)) for (expr* arg : *to_app(e)) args.push_back(e_internalize(arg)); - internalize(e, true); + internalize(e); if (!m_egraph.find(e)) mk_enode(e, args.size(), args.data()); } @@ -692,10 +692,10 @@ namespace euf { disable_relevancy(e); return; } - auto lit = si.internalize(e, true); + auto lit = si.internalize(e); switch (to_app(e)->get_decl_kind()) { case OP_NOT: { - auto lit2 = si.internalize(to_app(e)->get_arg(0), true); + auto lit2 = si.internalize(to_app(e)->get_arg(0)); add_aux(lit, lit2); add_aux(~lit, ~lit2); break; @@ -705,8 +705,8 @@ namespace euf { 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); + auto lit1 = si.internalize(to_app(e)->get_arg(0)); + auto lit2 = si.internalize(to_app(e)->get_arg(1)); add_aux(~lit, ~lit1, lit2); add_aux(~lit, lit1, ~lit2); add_aux(lit, lit1, lit2); @@ -716,7 +716,7 @@ namespace euf { case OP_OR: { sat::literal_vector lits; for (expr* arg : *to_app(e)) - lits.push_back(si.internalize(arg, true)); + lits.push_back(si.internalize(arg)); for (auto lit2 : lits) add_aux(~lit2, lit); lits.push_back(~lit); @@ -726,7 +726,7 @@ namespace euf { case OP_AND: { sat::literal_vector lits; for (expr* arg : *to_app(e)) - lits.push_back(~si.internalize(arg, true)); + lits.push_back(~si.internalize(arg)); for (auto nlit2 : lits) add_aux(~lit, ~nlit2); lits.push_back(lit); @@ -740,9 +740,9 @@ namespace euf { add_aux(~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); + auto lit1 = si.internalize(to_app(e)->get_arg(0)); + auto lit2 = si.internalize(to_app(e)->get_arg(1)); + auto lit3 = si.internalize(to_app(e)->get_arg(2)); add_aux(~lit, ~lit1, lit2); add_aux(~lit, lit1, lit3); add_aux(lit, ~lit1, ~lit2); @@ -754,8 +754,8 @@ namespace euf { 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); + auto lit1 = si.internalize(to_app(e)->get_arg(0)); + auto lit2 = si.internalize(to_app(e)->get_arg(1)); add_aux(lit, ~lit1, lit2); add_aux(lit, lit1, ~lit2); add_aux(~lit, lit1, lit2); @@ -767,8 +767,8 @@ namespace euf { 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); + auto lit1 = si.internalize(to_app(e)->get_arg(0)); + auto lit2 = si.internalize(to_app(e)->get_arg(1)); add_aux(~lit, ~lit1, lit2); add_aux(lit, lit1); add_aux(lit, ~lit2); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 5e12324a4..beb0809fb 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -439,8 +439,8 @@ namespace euf { bool to_formulas(std::function& l2e, expr_ref_vector& fmls) override; // internalize - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool learned) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; sat::literal mk_literal(expr* e); void attach_th_var(enode* n, th_solver* th, theory_var v) { m_egraph.add_th_var(n, v, th->get_id()); } void attach_node(euf::enode* n); diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 4a5795953..1de72d80b 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -95,9 +95,9 @@ namespace fpa { TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(n->get_expr(), m) << " := " << v << "\n";); } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { SASSERT(m.is_bool(e)); - if (!visit_rec(m, e, sign, root, redundant)) + if (!visit_rec(m, e, sign, root)) return sat::null_literal; sat::literal lit = expr2literal(e); if (sign) @@ -105,8 +105,8 @@ namespace fpa { return lit; } - void solver::internalize(expr* e, bool redundant) { - visit_rec(m, e, false, false, redundant); + void solver::internalize(expr* e) { + visit_rec(m, e, false, false); } bool solver::visited(expr* e) { @@ -118,7 +118,7 @@ namespace fpa { if (visited(e)) return true; if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { - ctx.internalize(e, m_is_redundant); + ctx.internalize(e); return true; } m_stack.push_back(sat::eframe(e)); diff --git a/src/sat/smt/fpa_solver.h b/src/sat/smt/fpa_solver.h index 38abb399d..1473ec463 100644 --- a/src/sat/smt/fpa_solver.h +++ b/src/sat/smt/fpa_solver.h @@ -59,8 +59,8 @@ namespace fpa { bool use_diseqs() const override { return true; } void new_diseq_eh(euf::th_eq const& eq) override; - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; void apply_sort_cnstr(euf::enode* n, sort* s) override; std::ostream& display(std::ostream& out) const override; diff --git a/src/sat/smt/pb_internalize.cpp b/src/sat/smt/pb_internalize.cpp index eae1bbe5a..af25e7a92 100644 --- a/src/sat/smt/pb_internalize.cpp +++ b/src/sat/smt/pb_internalize.cpp @@ -22,12 +22,11 @@ Author: namespace pb { - void solver::internalize(expr* e, bool redundant) { - internalize(e, false, false, redundant); + void solver::internalize(expr* e) { + internalize(e, false, false); } - literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { - flet _redundant(m_is_redundant, redundant); + literal solver::internalize(expr* e, bool sign, bool root) { if (m_pb.is_pb(e)) { sat::literal lit = internalize_pb(e, sign, root); if (m_ctx && !root && lit != sat::null_literal) @@ -84,7 +83,7 @@ namespace pb { void solver::convert_pb_args(app* t, literal_vector& lits) { for (expr* arg : *t) { - lits.push_back(si.internalize(arg, m_is_redundant)); + lits.push_back(si.internalize(arg)); s().set_external(lits.back().var()); } } diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h index 09c0e47e0..f6a0c049e 100644 --- a/src/sat/smt/pb_solver.h +++ b/src/sat/smt/pb_solver.h @@ -402,8 +402,8 @@ namespace pb { bool is_blocked(literal l, sat::ext_constraint_idx idx) override; bool check_model(sat::model const& m) const override; - literal internalize(expr* e, bool sign, bool root, bool redundant) override; - void internalize(expr* e, bool redundant) override; + literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; bool to_formulas(std::function& l2e, expr_ref_vector& fmls) override; euf::th_solver* clone(euf::solver& ctx) override; diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index ae37b7f07..26c99180b 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -53,7 +53,7 @@ namespace q { if (!m_flat.find(q, q_flat)) { if (expand(q)) { for (expr* e : m_expanded) { - sat::literal lit = ctx.internalize(e, l.sign(), false, false); + sat::literal lit = ctx.internalize(e, l.sign(), false); add_clause(~l, lit); } return; @@ -62,7 +62,7 @@ namespace q { } if (is_ground(q_flat->get_expr())) { - auto lit = ctx.internalize(q_flat->get_expr(), l.sign(), false, false); + auto lit = ctx.internalize(q_flat->get_expr(), l.sign(), false); add_clause(~l, lit); } else { @@ -163,7 +163,7 @@ namespace q { m_mbqi.init_search(); } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool learned) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { SASSERT(is_forall(e) || is_exists(e)); sat::bool_var v = ctx.get_si().add_bool_var(e); sat::literal lit = ctx.attach_lit(sat::literal(v, false), e); diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 153cdc774..d0581f852 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -95,8 +95,8 @@ namespace q { void collect_statistics(statistics& st) const override; euf::th_solver* clone(euf::solver& ctx) override; bool unit_propagate() override; - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override { internalize(e, false, false, redundant); } + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override { internalize(e, false, false); } euf::theory_var mk_var(euf::enode* n) override; void init_search() override; void finalize_model(model& mdl) override; diff --git a/src/sat/smt/recfun_solver.cpp b/src/sat/smt/recfun_solver.cpp index c88138d3f..aef957034 100644 --- a/src/sat/smt/recfun_solver.cpp +++ b/src/sat/smt/recfun_solver.cpp @@ -232,10 +232,10 @@ namespace recfun { ctx.push(push_back_vector>(m_propagation_queue)); } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { force_push(); SASSERT(m.is_bool(e)); - if (!visit_rec(m, e, sign, root, redundant)) { + if (!visit_rec(m, e, sign, root)) { TRACE("array", tout << mk_pp(e, m) << "\n";); return sat::null_literal; } @@ -245,9 +245,9 @@ namespace recfun { return lit; } - void solver::internalize(expr* e, bool redundant) { + void solver::internalize(expr* e) { force_push(); - visit_rec(m, e, false, false, redundant); + visit_rec(m, e, false, false); } bool solver::visited(expr* e) { @@ -259,7 +259,7 @@ namespace recfun { if (visited(e)) return true; if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { - ctx.internalize(e, m_is_redundant); + ctx.internalize(e); return true; } m_stack.push_back(sat::eframe(e)); diff --git a/src/sat/smt/recfun_solver.h b/src/sat/smt/recfun_solver.h index 4e41a35a9..21d75623f 100644 --- a/src/sat/smt/recfun_solver.h +++ b/src/sat/smt/recfun_solver.h @@ -101,8 +101,8 @@ namespace recfun { void collect_statistics(statistics& st) const override; euf::th_solver* clone(euf::solver& ctx) override; bool unit_propagate() override; - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; bool add_dep(euf::enode* n, top_sort& dep) override; void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override; bool is_shared(euf::theory_var v) const override { return true; } diff --git a/src/sat/smt/sat_internalizer.h b/src/sat/smt/sat_internalizer.h index 5fbf879ae..5be20c4e0 100644 --- a/src/sat/smt/sat_internalizer.h +++ b/src/sat/smt/sat_internalizer.h @@ -23,7 +23,7 @@ namespace sat { public: virtual ~sat_internalizer() = default; virtual bool is_bool_op(expr* e) const = 0; - virtual literal internalize(expr* e, bool learned) = 0; + virtual literal internalize(expr* e) = 0; virtual bool_var to_bool_var(expr* e) = 0; virtual bool_var add_bool_var(expr* e) = 0; virtual bool is_cached(app* t, literal l) const = 0; diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 81fd7e384..17d167829 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -21,9 +21,8 @@ Author: namespace euf { - bool th_internalizer::visit_rec(ast_manager& m, expr* a, bool sign, bool root, bool redundant) { + bool th_internalizer::visit_rec(ast_manager& m, expr* a, bool sign, bool root) { IF_VERBOSE(110, verbose_stream() << "internalize: " << mk_pp(a, m) << "\n"); - flet _is_learned(m_is_redundant, redundant); svector::scoped_stack _sc(m_stack); unsigned sz = m_stack.size(); visit(a); @@ -125,15 +124,11 @@ namespace euf { pop_core(n); } - sat::status th_euf_solver::mk_status(th_proof_hint const* ps) { - return sat::status::th(m_is_redundant, get_id(), ps); - } - bool th_euf_solver::add_unit(sat::literal lit, th_proof_hint const* ps) { if (ctx.use_drat() && !ps) ps = ctx.mk_smt_clause(name(), 1, &lit); bool was_true = is_true(lit); - ctx.s().add_clause(1, &lit, mk_status(ps)); + ctx.s().add_clause(1, &lit, sat::status::th(false, get_id(), ps)); ctx.add_root(lit); return !was_true; } @@ -161,7 +156,7 @@ namespace euf { return add_clause(4, lits, ps); } - bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps) { + bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps, bool is_redundant) { if (ctx.use_drat() && !ps) ps = ctx.mk_smt_clause(name(), n, lits); @@ -169,7 +164,7 @@ namespace euf { for (unsigned i = 0; i < n; ++i) was_true |= is_true(lits[i]); ctx.add_root(n, lits); - s().add_clause(n, lits, mk_status(ps)); + s().add_clause(n, lits, sat::status::th(is_redundant, get_id(), ps)); return !was_true; } diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index d64b65635..a3b81a08d 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -30,9 +30,8 @@ namespace euf { protected: euf::enode_vector m_args; svector m_stack; - bool m_is_redundant{ false }; - bool visit_rec(ast_manager& m, expr* e, bool sign, bool root, bool redundant); + bool visit_rec(ast_manager& m, expr* e, bool sign, bool root); virtual bool visit(expr* e) { return false; } virtual bool visited(expr* e) { return false; } @@ -41,9 +40,9 @@ namespace euf { public: virtual ~th_internalizer() = default; - virtual sat::literal internalize(expr* e, bool sign, bool root, bool redundant) = 0; + virtual sat::literal internalize(expr* e, bool sign, bool root) = 0; - virtual void internalize(expr* e, bool redundant) = 0; + virtual void internalize(expr* e) = 0; /** @@ -135,7 +134,7 @@ namespace euf { virtual bool is_beta_redex(euf::enode* p, euf::enode* n) const { return false; } - sat::status status() const { return sat::status::th(m_is_redundant, get_id()); } + sat::status status() const { return sat::status::th(false, get_id()); } }; @@ -155,8 +154,6 @@ namespace euf { sat::literal expr2literal(expr* e) const; region& get_region(); - - sat::status mk_status(th_proof_hint const* ps = nullptr); bool add_unit(sat::literal lit, th_proof_hint const* ps = nullptr); bool add_units(sat::literal_vector const& lits); bool add_clause(sat::literal lit, th_proof_hint const* ps = nullptr) { return add_unit(lit, ps); } @@ -164,9 +161,11 @@ namespace euf { bool add_clause(sat::literal a, sat::literal b, sat::literal c, th_proof_hint const* ps = nullptr); bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d, th_proof_hint const* ps = nullptr); bool add_clause(sat::literal_vector const& lits, th_proof_hint const* ps = nullptr) { return add_clause(lits.size(), lits.data(), ps); } - bool add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps = nullptr); + bool add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps, bool is_redundant = false); void add_equiv(sat::literal a, sat::literal b); void add_equiv_and(sat::literal a, sat::literal_vector const& bs); + bool add_redundant(sat::literal_vector const& lits, th_proof_hint const* ps) { return add_clause(lits.size(), lits.data(), ps, true); } + bool add_redundant(unsigned n, sat::literal* lits, th_proof_hint const* ps); bool is_true(sat::literal lit); diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 5c98a6fac..99e4eeeb1 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -30,7 +30,7 @@ namespace user_solver { void solver::add_expr(expr* e) { force_push(); - ctx.internalize(e, false); + ctx.internalize(e); euf::enode* n = expr2enode(e); if (is_attached_to_var(n)) return; @@ -63,7 +63,7 @@ namespace user_solver { return; } force_push(); - ctx.internalize(e, false); + ctx.internalize(e); m_next_split_expr = e; m_next_split_idx = idx; m_next_split_phase = phase; @@ -162,7 +162,7 @@ namespace user_solver { } void solver::propagate_consequence(prop_info const& prop) { - sat::literal lit = ctx.internalize(prop.m_conseq, false, false, true); + sat::literal lit = ctx.internalize(prop.m_conseq, false, false); if (s().value(lit) != l_true) { s().assign(lit, mk_justification(m_qhead)); ++m_stats.m_num_propagations; @@ -250,8 +250,8 @@ namespace user_solver { return result; } - sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { - if (!visit_rec(m, e, sign, root, redundant)) { + sat::literal solver::internalize(expr* e, bool sign, bool root) { + if (!visit_rec(m, e, sign, root)) { TRACE("array", tout << mk_pp(e, m) << "\n";); return sat::null_literal; } @@ -263,15 +263,15 @@ namespace user_solver { return lit; } - void solver::internalize(expr* e, bool redundant) { - visit_rec(m, e, false, false, redundant); + void solver::internalize(expr* e) { + visit_rec(m, e, false, false); } bool solver::visit(expr* e) { if (visited(e)) return true; if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { - ctx.internalize(e, m_is_redundant); + ctx.internalize(e); return true; } m_stack.push_back(sat::eframe(e)); diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index 28528b9a1..cb1c6fe94 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -154,8 +154,8 @@ namespace user_solver { bool unit_propagate() override; void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector & r, bool probing) override; void collect_statistics(statistics& st) const override; - sat::literal internalize(expr* e, bool sign, bool root, bool learned) override; - void internalize(expr* e, bool redundant) override; + sat::literal internalize(expr* e, bool sign, bool root) override; + void internalize(expr* e) override; std::ostream& display(std::ostream& out) const override; std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override; std::ostream& display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const override; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index c819403d7..403cee684 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -75,7 +75,6 @@ struct goal2sat::imp : public sat::sat_internalizer { func_decl_ref_vector m_unhandled_funs; bool m_default_external; bool m_euf = false; - bool m_is_redundant = false; bool m_top_level = false; sat::literal_vector aig_lits; @@ -133,7 +132,7 @@ struct goal2sat::imp : public sat::sat_internalizer { } sat::status mk_status(euf::th_proof_hint* ph = nullptr) const { - return sat::status::th(m_is_redundant, m.get_basic_family_id(), ph); + return sat::status::th(false, m.get_basic_family_id(), ph); } bool relevancy_enabled() { @@ -179,7 +178,7 @@ struct goal2sat::imp : public sat::sat_internalizer { TRACE("goal2sat", tout << "mk_root_clause: "; for (unsigned i = 0; i < n; i++) tout << lits[i] << " "; tout << "\n";); if (relevancy_enabled()) ensure_euf()->add_root(n, lits); - m_solver.add_clause(n, lits, m_is_redundant ? mk_status(ph) : sat::status::input()); + m_solver.add_clause(n, lits, ph ? mk_status(ph) : sat::status::input()); } sat::bool_var add_var(bool is_ext, expr* n) { @@ -688,7 +687,7 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::literal lit; { flet _top(m_top_level, false); - lit = euf->internalize(e, sign, root, m_is_redundant); + lit = euf->internalize(e, sign, root); } if (lit == sat::null_literal) return; @@ -711,7 +710,7 @@ struct goal2sat::imp : public sat::sat_internalizer { th = dynamic_cast(ext); SASSERT(th); } - auto lit = th->internalize(t, sign, root, m_is_redundant); + auto lit = th->internalize(t, sign, root); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); if (lit == sat::null_literal) return; @@ -780,12 +779,11 @@ struct goal2sat::imp : public sat::sat_internalizer { } }; - void process(expr* n, bool is_root, bool redundant) { + void process(expr* n, bool is_root) { TRACE("goal2sat", tout << "process-begin " << mk_bounded_pp(n, m, 2) << " root: " << is_root << " result-stack: " << m_result_stack.size() << " frame-stack: " << m_frame_stack.size() << "\n";); - flet _is_redundant(m_is_redundant, redundant); scoped_stack _sc(*this, is_root); unsigned sz = m_frame_stack.size(); if (visit(n, is_root, false)) @@ -836,14 +834,14 @@ struct goal2sat::imp : public sat::sat_internalizer { << " result-stack: " << m_result_stack.size() << "\n";); } - sat::literal internalize(expr* n, bool redundant) override { + sat::literal internalize(expr* n) override { bool is_not = m.is_not(n, n); flet _top(m_top_level, false); unsigned sz = m_result_stack.size(); (void)sz; SASSERT(n->get_ref_count() > 0); TRACE("goal2sat", tout << "internalize " << mk_bounded_pp(n, m, 2) << "\n";); - process(n, false, redundant); + process(n, false); 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";); @@ -889,7 +887,7 @@ struct goal2sat::imp : public sat::sat_internalizer { flet _top(m_top_level, true); VERIFY(m_result_stack.empty()); TRACE("goal2sat", tout << "assert: " << mk_bounded_pp(n, m, 3) << "\n";); - process(n, true, m_is_redundant); + process(n, true); CTRACE("goal2sat", !m_result_stack.empty(), tout << m_result_stack << "\n";); SASSERT(m_result_stack.empty()); } From a24b5a64e1ecd9a1a3fb5945b05b2ae9ebb91fd7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2022 00:48:57 -0700 Subject: [PATCH 185/477] #6364 proviso for ignore int --- src/sat/smt/arith_solver.cpp | 2 +- src/sat/smt/euf_model.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index a658315e3..8be98edfb 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -609,7 +609,7 @@ namespace arith { else if (v != euf::null_theory_var) { rational r = get_value(v); TRACE("arith", tout << mk_pp(o, m) << " v" << v << " := " << r << "\n";); - SASSERT("integer variables should have integer values: " && (!a.is_int(o) || r.is_int() || m.limit().is_canceled())); + SASSERT("integer variables should have integer values: " && (ctx.get_config().m_arith_ignore_int || !a.is_int(o) || r.is_int() || m.limit().is_canceled())); if (a.is_int(o) && !r.is_int()) r = floor(r); value = a.mk_numeral(r, o->get_sort()); diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 54a3d63d8..eef873afa 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -320,6 +320,8 @@ namespace euf { void solver::validate_model(model& mdl) { if (!m_unhandled_functions.empty()) return; + if (get_config().m_arith_ignore_int) + return; for (auto* s : m_solvers) if (s && s->has_unhandled()) return; From 4431fd17ced051e9a676ee05b14e2edd2c8c773b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 24 Oct 2022 10:09:56 +0100 Subject: [PATCH 186/477] memory_manager: add support for MacOS & Windows to the new size tracking system --- src/util/memory_manager.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index a2c8e31a4..290881ba5 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -16,10 +16,17 @@ Copyright (c) 2015 Microsoft Corporation #ifdef __GLIBC__ # include # define HAS_MALLOC_USABLE_SIZE -#endif -#ifdef __FreeBSD__ +#elif defined(__APPLE__) +# include +# define HAS_MALLOC_USABLE_SIZE +# define malloc_usable_size malloc_size +#elif defined(__FreeBSD__) # include # define HAS_MALLOC_USABLE_SIZE +#elif defined(_WINDOWS) +# include +# define HAS_MALLOC_USABLE_SIZE +# define malloc_usable_size _msize #endif // The following two function are automatically generated by the mk_make.py script. From cb3c86736cbd41a368e175327efbf315a1317e09 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 24 Oct 2022 10:23:50 +0100 Subject: [PATCH 187/477] fix build --- src/sat/smt/xor_solver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/xor_solver.h b/src/sat/smt/xor_solver.h index 3da30c580..615d83991 100644 --- a/src/sat/smt/xor_solver.h +++ b/src/sat/smt/xor_solver.h @@ -23,9 +23,9 @@ namespace xr { th_solver* clone(euf::solver& ctx) override; - sat::literal internalize(expr* e, bool sign, bool root, bool redundant) override { UNREACHABLE(); return sat::null_literal; } + sat::literal internalize(expr* e, bool sign, bool root) override { UNREACHABLE(); return sat::null_literal; } - void internalize(expr* e, bool redundant) override { UNREACHABLE(); } + void internalize(expr* e) override { UNREACHABLE(); } void asserted(sat::literal l) override; From 280887cc5aa8c8ea46a8e1781772033331268aea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2022 08:32:03 -0700 Subject: [PATCH 188/477] remove deprecated theory aware drat functionality it is handled by the on-clause callback that is owned by the smt solver. --- src/sat/sat_drat.cpp | 16 +--------------- src/sat/sat_drat.h | 35 ----------------------------------- src/sat/smt/euf_proof.cpp | 2 -- src/sat/smt/euf_solver.cpp | 2 -- 4 files changed, 1 insertion(+), 54 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 647f8681c..beda1b901 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -57,17 +57,8 @@ namespace sat { } std::ostream& drat::pp(std::ostream& out, status st) const { - if (st.is_redundant()) - out << "l"; - else if (st.is_deleted()) + if (st.is_deleted()) out << "d"; - else if (st.is_asserted()) - out << "a"; - else if (st.is_input()) - out << "i"; - - if (!st.is_sat()) - out << " " << m_theory[st.get_th()]; return out; } @@ -102,11 +93,6 @@ namespace sat { } } - if (!st.is_sat()) { - for (char ch : m_theory[st.get_th()]) - buffer[len++] = ch; - buffer[len++] = ' '; - } for (unsigned i = 0; i < n; ++i) { literal lit = c[i]; unsigned v = lit.var(); diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 452b69701..7c39f5f41 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -17,39 +17,6 @@ Notes: For DIMACS input it produces DRAT proofs. - For SMT extensions are as follows: - - Input assertion: - i * 0 - - Assertion (true modulo a theory): - a [] * 0 - The if no theory id is given, the assertion is a tautology - modulo Tseitin converison. Theory ids track whether the - tautology is modulo a theory. - Assertions are irredundant. - - Bridge from ast-node to boolean variable: - b 0 - - Definition of an expression (ast-node): - e * 0 - - Redundant clause (theory lemma if theory id is given) - [r []] * 0 - - Declaration of an auxiliary function: - f 0 - - Garbage collection of a Boolean variable: - g 0 - - Available theories are: - - euf The theory lemma should be a consequence of congruence closure. - - ba TBD (need to also log cardinality and pb constraints) - - Life times of theory lemmas is TBD. When they are used for conflict resolution - they are only used for the next lemma. --*/ #pragma once @@ -89,7 +56,6 @@ namespace sat { svector> m_units; vector m_watches; svector m_assignment; - vector m_theory; bool m_inconsistent = false; bool m_check_unsat = false; bool m_check_sat = false; @@ -135,7 +101,6 @@ namespace sat { void updt_config(); - void add_theory(int id, symbol const& s) { m_theory.setx(id, s.str(), std::string()); } void add(); void add(literal l, bool learned); void add(literal l1, literal l2, status st); diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index a8a9523fd..877375246 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -37,8 +37,6 @@ namespace euf { !s().get_config().m_smt_proof.is_non_empty_string()) return; - get_drat().add_theory(get_id(), symbol("euf")); - get_drat().add_theory(m.get_basic_family_id(), symbol("bool")); if (s().get_config().m_smt_proof.is_non_empty_string()) m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); get_drat().set_clause_eh(*this); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 737148cd7..7b02509ee 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -149,8 +149,6 @@ namespace euf { void solver::add_solver(th_solver* th) { family_id fid = th->get_id(); - if (use_drat()) - s().get_drat().add_theory(fid, th->name()); th->set_solver(m_solver); th->push_scopes(s().num_scopes() + s().num_user_scopes()); m_solvers.push_back(th); From e1a00f4917535e1edbdd212a20530051216120e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2022 16:13:24 -0700 Subject: [PATCH 189/477] remove unused experimental feature - diff --- src/ast/array_decl_plugin.cpp | 16 ------- src/ast/array_decl_plugin.h | 6 --- src/sat/smt/array_axioms.cpp | 73 ------------------------------- src/sat/smt/array_internalize.cpp | 10 ----- src/sat/smt/array_solver.cpp | 3 -- src/sat/smt/array_solver.h | 10 +---- 6 files changed, 1 insertion(+), 117 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 5e9356865..7c2b357c2 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -529,19 +529,6 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return nullptr; } return mk_array_ext(arity, domain, parameters[0].get_int()); - case OP_ARRAY_MAXDIFF: - case OP_ARRAY_MINDIFF: { - if (num_parameters != 0) - m_manager->raise_exception("min/maxdiff don't take any parameters"); - if (arity != 2 || domain[0] != domain[1] || !is_array_sort(domain[0]) || 1 != get_array_arity(domain[0])) - m_manager->raise_exception("min/maxdiff don't take two arrays of same sort and with integer index"); - sort* idx = get_array_domain(domain[0], 0); - arith_util arith(*m_manager); - if (!arith.is_int(idx)) - m_manager->raise_exception("min/maxdiff take integer index domain"); - return m_manager->mk_func_decl(k == OP_ARRAY_MAXDIFF ? symbol("maxdiff") : symbol("mindiff"), - arity, domain, arith.mk_int(), func_decl_info(m_family_id, k)); - } case OP_ARRAY_DEFAULT: return mk_default(arity, domain); case OP_SET_UNION: @@ -603,9 +590,6 @@ void array_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("as-array", OP_AS_ARRAY)); op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT)); - op_names.push_back(builtin_name("mindiff", OP_ARRAY_MINDIFF)); - op_names.push_back(builtin_name("maxdiff", OP_ARRAY_MAXDIFF)); - #if 0 op_names.push_back(builtin_name("set-has-size", OP_SET_HAS_SIZE)); op_names.push_back(builtin_name("card", OP_SET_CARD)); diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index fdad692ac..83d541097 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -45,8 +45,6 @@ enum array_op_kind { OP_ARRAY_EXT, OP_ARRAY_DEFAULT, OP_ARRAY_MAP, - OP_ARRAY_MAXDIFF, - OP_ARRAY_MINDIFF, OP_SET_UNION, OP_SET_INTERSECT, OP_SET_DIFFERENCE, @@ -161,8 +159,6 @@ public: bool is_complement(expr* n) const { return is_app_of(n, m_fid, OP_SET_COMPLEMENT); } bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); } bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); } - bool is_maxdiff(expr const* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAXDIFF); } - bool is_mindiff(expr const* n) const { return is_app_of(n, m_fid, OP_ARRAY_MINDIFF); } bool is_set_has_size(expr* e) const { return is_app_of(e, m_fid, OP_SET_HAS_SIZE); } bool is_set_card(expr* e) const { return is_app_of(e, m_fid, OP_SET_CARD); } bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); } @@ -189,8 +185,6 @@ public: bool is_store_ext(expr* e, expr_ref& a, expr_ref_vector& args, expr_ref& value); MATCH_BINARY(is_subset); - MATCH_BINARY(is_maxdiff); - MATCH_BINARY(is_mindiff); }; class array_util : public array_recognizers { diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 901344293..ff60bf675 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -66,10 +66,6 @@ namespace array { return assert_default(r); case axiom_record::kind_t::is_extensionality: return assert_extensionality(r.n->get_expr(), r.select->get_expr()); - case axiom_record::kind_t::is_diff: - return assert_diff(r.n->get_app()); - case axiom_record::kind_t::is_diffselect: - return assert_diff_select(r.n->get_app(), r.select->get_app()); case axiom_record::kind_t::is_congruence: return assert_congruent_axiom(r.n->get_expr(), r.select->get_expr()); default: @@ -278,54 +274,6 @@ namespace array { return add_clause(lit1, ~lit2); } - /** - * a = b or default(a) != default(b) or a[md(a,b)] != b[md(a,b)] - */ - bool solver::assert_diff(expr* md) { - expr* x = nullptr, *y = nullptr; - VERIFY(a.is_maxdiff(md, x, y) || a.is_mindiff(md, x, y)); - expr* args1[2] = { x, md }; - expr* args2[2] = { y, md }; - literal eq = eq_internalize(x, y); - literal eq_default = eq_internalize(a.mk_default(x), a.mk_default(y)); - literal eq_md = eq_internalize(a.mk_select(2, args1), a.mk_select(2, args2)); - return add_clause(eq, ~eq_default, ~eq_md); - } - - /** - * a = b and a[i] != c[i] => i <= md(b, c) or default(b) != default(c) - * a = c and a[i] != b[i] => i <= md(b, c) or default(b) != default(c) - * where ai = a[i], md = md(b, c) - */ - bool solver::assert_diff_select(app* md, app* ai) { - SASSERT(a.is_select(ai)); - SASSERT(ai->get_num_args() == 2); - expr* A = ai->get_arg(0); - expr* i = ai->get_arg(1); - expr* B = md->get_arg(0); - expr* C = md->get_arg(1); - literal eq_default = eq_internalize(a.mk_default(B), a.mk_default(C)); - arith_util autil(m); - literal ineq = mk_literal(a.is_maxdiff(md) ? autil.mk_le(i, md) : autil.mk_le(md, i)); - bool is_new = false; - if (ctx.get_enode(A)->get_root() == ctx.get_enode(B)->get_root()) { - literal eq_ab = eq_internalize(A, B); - expr* args[2] = { C, i }; - literal eq_select = eq_internalize(ai, a.mk_select(2, args)); - if (add_clause(~eq_ab, eq_select, ineq, ~eq_default)) - is_new = true; - } - - if (ctx.get_enode(A)->get_root() == ctx.get_enode(C)->get_root()) { - literal eq_ac = eq_internalize(A, C); - expr* args[2] = { B, i }; - literal eq_select = eq_internalize(ai, a.mk_select(2, args)); - if (add_clause(~eq_ac, eq_select, ineq, ~eq_default)) - is_new = true; - } - return is_new; - } - bool solver::is_map_combinator(expr* map) const { return a.is_map(map) || a.is_union(map) || a.is_intersect(map) || a.is_difference(map) || a.is_complement(map); } @@ -738,26 +686,5 @@ namespace array { return false; } - bool solver::add_diff_select_axioms() { - bool added = false; - - auto add_diff_select = [&](euf::enode* md, euf::enode* a) { - var_data const& d = get_var_data(find(get_th_var(a))); - for (euf::enode* select : d.m_parent_selects) { - if (assert_diff_select(md->get_app(), select->get_app())) - added = true; - } - }; - for (euf::enode* md : m_minmaxdiffs) { - euf::enode* a = md->get_arg(0); - euf::enode* b = md->get_arg(1); - add_diff_select(md, a); - add_diff_select(md, b); - } - return added; - } - - - } diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index c7517f5a4..d5a1dd2c5 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -115,12 +115,6 @@ namespace array { SASSERT(is_array(n->get_arg(0))); push_axiom(extensionality_axiom(n->get_arg(0), n->get_arg(1))); break; - case OP_ARRAY_MINDIFF: - case OP_ARRAY_MAXDIFF: - push_axiom(diff_axiom(n)); - m_minmaxdiffs.push_back(n); - ctx.push(push_back_vector(m_minmaxdiffs)); - break; case OP_ARRAY_DEFAULT: add_parent_default(find(n->get_arg(0))); break; @@ -176,10 +170,6 @@ namespace array { break; case OP_ARRAY_EXT: break; - case OP_ARRAY_MINDIFF: - case OP_ARRAY_MAXDIFF: - // todo - break; case OP_ARRAY_DEFAULT: set_prop_upward(find(n->get_arg(0))); break; diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index 2d3d13d3a..7a8f31f1e 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -101,9 +101,6 @@ namespace array { else if (!turn[idx] && add_interface_equalities()) return sat::check_result::CR_CONTINUE; } - - if (add_diff_select_axioms()) - return sat::check_result::CR_CONTINUE; if (m_delay_qhead < m_axiom_trail.size()) return sat::check_result::CR_CONTINUE; diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 4f100d694..c63eedaca 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -84,8 +84,6 @@ namespace array { is_store, is_select, is_extensionality, - is_diff, - is_diffselect, is_default, is_congruence }; @@ -95,7 +93,7 @@ namespace array { is_applied }; kind_t m_kind; - state_t m_state { state_t::is_new }; + state_t m_state = state_t::is_new; euf::enode* n; euf::enode* select; axiom_record(kind_t k, euf::enode* n, euf::enode* select = nullptr) : m_kind(k), n(n), select(select) {} @@ -166,9 +164,6 @@ namespace array { axiom_record store_axiom(euf::enode* n) { return axiom_record(axiom_record::kind_t::is_store, n); } axiom_record extensionality_axiom(euf::enode* x, euf::enode* y) { return axiom_record(axiom_record::kind_t::is_extensionality, x, y); } axiom_record congruence_axiom(euf::enode* a, euf::enode* b) { return axiom_record(axiom_record::kind_t::is_congruence, a, b); } - axiom_record diff_axiom(euf::enode* md) { return axiom_record(axiom_record::kind_t::is_diff, md); } - euf::enode_vector m_minmaxdiffs; - axiom_record diff_select_axiom(euf::enode* md, euf::enode* ai) { return axiom_record(axiom_record::kind_t::is_diffselect, md, ai); } scoped_ptr m_constraint; @@ -181,15 +176,12 @@ namespace array { bool assert_select_map_axiom(app* select, app* map); bool assert_select_lambda_axiom(app* select, expr* lambda); bool assert_extensionality(expr* e1, expr* e2); - bool assert_diff(expr* md); - bool assert_diff_select(app* ai, app* md); bool assert_default_map_axiom(app* map); bool assert_default_const_axiom(app* cnst); bool assert_default_store_axiom(app* store); bool assert_congruent_axiom(expr* e1, expr* e2); bool add_delayed_axioms(); bool add_as_array_eqs(euf::enode* n); - bool add_diff_select_axioms(); expr_ref apply_map(app* map, unsigned n, expr* const* args); bool is_map_combinator(expr* e) const; From c672c3a250adf0512784d4a7d3504bbd8c70c696 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2022 09:39:11 -0700 Subject: [PATCH 190/477] fix regression introduced in #6143 --- src/sat/sat_simplifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 97405fb32..b456db243 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -2000,7 +2000,7 @@ namespace sat { m_elim_counter -= num_pos * num_neg + before_lits; for (auto & c1 : m_pos_cls) { - if (c1.was_removed()) + if (c1.was_removed() && !c1.contains(pos_l)) continue; for (auto & c2 : m_neg_cls) { m_new_cls.reset(); From 09a2ba4931601def7e9711f0b2194edf0428b3b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2022 10:28:25 -0700 Subject: [PATCH 191/477] remove artificial usage of function, it causes another compiler warning to refer to a function without arguments. --- src/muz/spacer/spacer_convex_closure.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/spacer/spacer_convex_closure.cpp b/src/muz/spacer/spacer_convex_closure.cpp index 2c11642c5..476821643 100644 --- a/src/muz/spacer/spacer_convex_closure.cpp +++ b/src/muz/spacer/spacer_convex_closure.cpp @@ -261,7 +261,6 @@ bool convex_closure::infer_div_pred(const vector &data, rational &m, }); SASSERT(data.size() > 1); SASSERT(is_sorted(data)); - (void)is_sorted; m = rational(2); From c62c5e9d23b1955bb493df0e2a01af981e05ea4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2022 10:29:48 -0700 Subject: [PATCH 192/477] add opportunistic, missing, bv rewrites - x >> x logical = 0 - ~x = -1 -x - x * (y << z) = (x * y) << z --- src/ast/rewriter/bv_rewriter.cpp | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 516248e24..4740a954c 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -911,6 +911,11 @@ br_status bv_rewriter::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) { return BR_REWRITE2; } + if (arg1 == arg2) { + result = mk_numeral(0, bv_size); + return BR_DONE; + } + return BR_FAILED; } @@ -2250,10 +2255,10 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re br_status st = mk_mul_core(num_args, args, result); if (st != BR_FAILED && st != BR_DONE) return st; - expr * x; - expr * y; + expr* x, * y, * z, * u; if (st == BR_FAILED && num_args == 2) { - x = args[0]; y = args[1]; + x = args[0]; + y = args[1]; } else if (st == BR_DONE && is_mul(result) && to_app(result)->get_num_args() == 2) { x = to_app(result)->get_arg(0); @@ -2262,7 +2267,25 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re else { return st; } - + // ~x = -1 - x + unsigned sz = m_util.get_bv_size(x); + if (m_util.is_bv_not(x, z)) { + result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(-1, sz), z), y); + return BR_REWRITE3; + } + if (m_util.is_bv_not(y, z)) { + result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(-1, sz), z), x); + return BR_REWRITE3; + } + // shl(z, u) * x = shl(x * z, u) + if (m_util.is_bv_shl(x, z, u)) { + result = m_util.mk_bv_shl(m_util.mk_bv_mul(z, y), u); + return BR_REWRITE2; + } + if (m_util.is_bv_shl(y, z, u)) { + result = m_util.mk_bv_shl(m_util.mk_bv_mul(z, x), u); + return BR_REWRITE2; + } if (m_mul2concat) { numeral v; unsigned bv_size; From 154fed7783a878cd10524e0f67bd8a31bbf9ef9c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2022 10:30:18 -0700 Subject: [PATCH 193/477] introduce globally visible macro for controlling use of ternary, turn them off --- src/sat/sat_drat.cpp | 2 ++ src/sat/sat_gc.cpp | 6 ++++-- src/sat/sat_justification.h | 12 +++++++++++- src/sat/sat_proof_trim.cpp | 6 ++++++ src/sat/sat_solver.cpp | 27 ++++++++++++++++++++++++--- src/sat/sat_types.h | 2 ++ src/sat/smt/pb_solver.cpp | 6 ++++++ 7 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index beda1b901..306ff2493 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -445,8 +445,10 @@ namespace sat { return false; case justification::BINARY: return contains(c, j.get_literal()); +#if ENABLE_TERNARY case justification::TERNARY: return contains(c, j.get_literal1(), j.get_literal2()); +#endif case justification::CLAUSE: return contains(s.get_clause(j)); default: diff --git a/src/sat/sat_gc.cpp b/src/sat/sat_gc.cpp index ba89ed76f..c8d6ebe7a 100644 --- a/src/sat/sat_gc.cpp +++ b/src/sat/sat_gc.cpp @@ -20,8 +20,6 @@ Revision History: #include "sat/sat_solver.h" -#define ENABLE_TERNARY true - namespace sat { // ----------------------- @@ -180,6 +178,7 @@ namespace sat { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :strategy " << st_name << " :deleted " << (sz - new_sz) << ")\n";); } +#if ENABLE_TERNARY bool solver::can_delete3(literal l1, literal l2, literal l3) const { if (value(l1) == l_true && value(l2) == l_false && @@ -193,16 +192,19 @@ namespace sat { } return true; } +#endif bool solver::can_delete(clause const & c) const { if (c.on_reinit_stack()) return false; +#if ENABLE_TERNARY if (ENABLE_TERNARY && c.size() == 3) { return can_delete3(c[0],c[1],c[2]) && can_delete3(c[1],c[0],c[2]) && can_delete3(c[2],c[0],c[1]); } +#endif literal l0 = c[0]; if (value(l0) != l_true) return true; diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index aa551e86c..1fc97a38c 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -22,7 +22,11 @@ namespace sat { class justification { public: - enum kind { NONE = 0, BINARY = 1, TERNARY = 2, CLAUSE = 3, EXT_JUSTIFICATION = 4}; + enum kind { NONE = 0, BINARY = 1, +#if ENABLE_TERNARY + TERNARY = 2, +#endif + CLAUSE = 3, EXT_JUSTIFICATION = 4}; private: unsigned m_level; size_t m_val1; @@ -32,7 +36,9 @@ namespace sat { public: justification(unsigned lvl):m_level(lvl), m_val1(0), m_val2(NONE) {} explicit justification(unsigned lvl, literal l):m_level(lvl), m_val1(l.to_uint()), m_val2(BINARY) {} +#if ENABLE_TERNARY justification(unsigned lvl, literal l1, literal l2):m_level(lvl), m_val1(l1.to_uint()), m_val2(TERNARY + (l2.to_uint() << 3)) {} +#endif explicit justification(unsigned lvl, clause_offset cls_off):m_level(lvl), m_val1(cls_off), m_val2(CLAUSE) {} static justification mk_ext_justification(unsigned lvl, ext_justification_idx idx) { return justification(lvl, idx, EXT_JUSTIFICATION); } @@ -45,9 +51,11 @@ namespace sat { bool is_binary_clause() const { return m_val2 == BINARY; } literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(val1()); } +#if ENABLE_TERNARY bool is_ternary_clause() const { return get_kind() == TERNARY; } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(val1()); } literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); } +#endif bool is_clause() const { return m_val2 == CLAUSE; } clause_offset get_clause_offset() const { return m_val1; } @@ -65,9 +73,11 @@ namespace sat { case justification::BINARY: out << "binary " << j.get_literal(); break; +#if ENABLE_TERNARY case justification::TERNARY: out << "ternary " << j.get_literal1() << " " << j.get_literal2(); break; +#endif case justification::CLAUSE: out << "clause"; break; diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index 0554eae1d..4c4b9ecaf 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -125,8 +125,10 @@ namespace sat { in_coi |= m_in_coi.contains(lit.index()); else if (js.is_binary_clause()) in_coi = m_in_coi.contains(js.get_literal().index()); +#if ENABLE_TERNARY else if (js.is_ternary_clause()) in_coi = m_in_coi.contains(js.get_literal1().index()) || m_in_coi.contains(js.get_literal2().index()); +#endif else UNREACHABLE(); // approach does not work for external justifications @@ -224,10 +226,12 @@ namespace sat { case justification::BINARY: add_dependency(j.get_literal()); break; +#if ENABLE_TERNARY case justification::TERNARY: add_dependency(j.get_literal1()); add_dependency(j.get_literal2()); break; +#endif case justification::CLAUSE: for (auto lit : s.get_clause(j)) if (s.value(lit) == l_false) @@ -258,11 +262,13 @@ namespace sat { m_clause.push_back(l); m_clause.push_back(j.get_literal()); break; +#if ENABLE_TERNARY case justification::TERNARY: m_clause.push_back(l); m_clause.push_back(j.get_literal1()); m_clause.push_back(j.get_literal2()); break; +#endif case justification::CLAUSE: s.get_clause(j).mark_used(); IF_VERBOSE(3, verbose_stream() << "add core " << s.get_clause(j) << "\n"); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3012a840e..eae0b8f73 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -37,7 +37,6 @@ Revision History: # include #endif -#define ENABLE_TERNARY true namespace sat { @@ -576,6 +575,7 @@ namespace sat { return reinit; } +#if ENABLE_TERNARY bool solver::propagate_ter_clause(clause& c) { bool reinit = false; if (value(c[1]) == l_false && value(c[2]) == l_false) { @@ -595,6 +595,7 @@ namespace sat { } return reinit; } +#endif clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, sat::status st) { m_stats.m_mk_clause++; @@ -1061,7 +1062,7 @@ namespace sat { bool solver::propagate_literal(literal l, bool update) { literal l1, l2; - lbool val1, val2; + bool keep; unsigned curr_level = lvl(l); TRACE("sat_propagate", tout << "propagating: " << l << "@" << curr_level << " " << m_justification[l.var()] << "\n"; ); @@ -1099,7 +1100,9 @@ namespace sat { *it2 = *it; it2++; break; - case watched::TERNARY: +#if ENABLE_TERNARY + case watched::TERNARY: { + lbool val1, val2; l1 = it->get_literal1(); l2 = it->get_literal2(); val1 = value(l1); @@ -1120,6 +1123,8 @@ namespace sat { *it2 = *it; it2++; break; + } +#endif case watched::CLAUSE: { if (value(it->get_blocked_literal()) == l_true) { TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n"; @@ -2497,10 +2502,12 @@ namespace sat { case justification::BINARY: process_antecedent(~(js.get_literal()), num_marks); break; +#if ENABLE_TERNARY case justification::TERNARY: process_antecedent(~(js.get_literal1()), num_marks); process_antecedent(~(js.get_literal2()), num_marks); break; +#endif case justification::CLAUSE: { clause & c = get_clause(js); unsigned i = 0; @@ -2679,11 +2686,13 @@ namespace sat { SASSERT(consequent != null_literal); process_antecedent_for_unsat_core(~(js.get_literal())); break; +#if ENABLE_TERNARY case justification::TERNARY: SASSERT(consequent != null_literal); process_antecedent_for_unsat_core(~(js.get_literal1())); process_antecedent_for_unsat_core(~(js.get_literal2())); break; +#endif case justification::CLAUSE: { clause & c = get_clause(js); unsigned i = 0; @@ -2820,10 +2829,12 @@ namespace sat { case justification::BINARY: level = update_max_level(js.get_literal(), level, unique_max); return level; +#if ENABLE_TERNARY case justification::TERNARY: level = update_max_level(js.get_literal1(), level, unique_max); level = update_max_level(js.get_literal2(), level, unique_max); return level; +#endif case justification::CLAUSE: for (literal l : get_clause(js)) level = update_max_level(l, level, unique_max); @@ -3175,6 +3186,7 @@ namespace sat { return false; } break; +#if ENABLE_TERNARY case justification::TERNARY: if (!process_antecedent_for_minimization(~(js.get_literal1())) || !process_antecedent_for_minimization(~(js.get_literal2()))) { @@ -3182,6 +3194,7 @@ namespace sat { return false; } break; +#endif case justification::CLAUSE: { clause & c = get_clause(js); unsigned i = 0; @@ -3337,10 +3350,12 @@ namespace sat { case justification::BINARY: update_lrb_reasoned(js.get_literal()); break; +#if ENABLE_TERNARY case justification::TERNARY: update_lrb_reasoned(js.get_literal1()); update_lrb_reasoned(js.get_literal2()); break; +#endif case justification::CLAUSE: { clause & c = get_clause(js); for (literal l : c) { @@ -3686,6 +3701,7 @@ namespace sat { } else { clause & c = *(cw.get_clause()); +#if ENABLE_TERNARY if (ENABLE_TERNARY && c.size() == 3) { if (propagate_ter_clause(c) && !at_base_lvl()) m_clauses_to_reinit[j++] = cw; @@ -3695,6 +3711,7 @@ namespace sat { c.set_reinit_stack(false); continue; } +#endif detach_clause(c); attach_clause(c, reinit); if (reinit && !at_base_lvl()) @@ -3961,10 +3978,12 @@ namespace sat { case justification::BINARY: out << "binary " << js.get_literal() << "@" << lvl(js.get_literal()); break; +#if ENABLE_TERNARY case justification::TERNARY: out << "ternary " << js.get_literal1() << "@" << lvl(js.get_literal1()) << " "; out << js.get_literal2() << "@" << lvl(js.get_literal2()); break; +#endif case justification::CLAUSE: { out << "("; bool first = true; @@ -4624,12 +4643,14 @@ namespace sat { if (!check_domain(lit, ~js.get_literal())) return false; s |= m_antecedents.find(js.get_literal().var()); break; +#if ENABLE_TERNARY case justification::TERNARY: if (!check_domain(lit, ~js.get_literal1()) || !check_domain(lit, ~js.get_literal2())) return false; s |= m_antecedents.find(js.get_literal1().var()); s |= m_antecedents.find(js.get_literal2().var()); break; +#endif case justification::CLAUSE: { clause & c = get_clause(js); for (literal l : c) { diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 4e119a2ae..7c4e4fb73 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -34,6 +34,8 @@ class params_ref; class reslimit; class statistics; +#define ENABLE_TERNARY false + namespace sat { #define SAT_VB_LVL 10 diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 1c762cb3f..d1f101582 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -690,6 +690,7 @@ namespace pb { inc_coeff(consequent, offset); process_antecedent(js.get_literal(), offset); break; +#if ENABLE_TERNARY case sat::justification::TERNARY: inc_bound(offset); SASSERT (consequent != sat::null_literal); @@ -697,6 +698,7 @@ namespace pb { process_antecedent(js.get_literal1(), offset); process_antecedent(js.get_literal2(), offset); break; +#endif case sat::justification::CLAUSE: { inc_bound(offset); sat::clause & c = s().get_clause(js); @@ -1017,6 +1019,7 @@ namespace pb { inc_coeff(consequent, 1); process_antecedent(js.get_literal()); break; +#if ENABLE_TERNARY case sat::justification::TERNARY: SASSERT(consequent != sat::null_literal); round_to_one(consequent.var()); @@ -1025,6 +1028,7 @@ namespace pb { process_antecedent(js.get_literal1()); process_antecedent(js.get_literal2()); break; +#endif case sat::justification::CLAUSE: { sat::clause & c = s().get_clause(js); unsigned i = 0; @@ -3472,6 +3476,7 @@ namespace pb { ineq.push(lit, offset); ineq.push(js.get_literal(), offset); break; +#if ENABLE_TERNARY case sat::justification::TERNARY: SASSERT(lit != sat::null_literal); ineq.reset(offset); @@ -3479,6 +3484,7 @@ namespace pb { ineq.push(js.get_literal1(), offset); ineq.push(js.get_literal2(), offset); break; +#endif case sat::justification::CLAUSE: { ineq.reset(offset); sat::clause & c = s().get_clause(js); From a4ece21461505f84dc361f2acc45ad9c57618d96 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2022 10:44:23 -0700 Subject: [PATCH 194/477] toggle enable-ternary to true --- src/sat/sat_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 7c4e4fb73..d2e2ffc94 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -34,7 +34,7 @@ class params_ref; class reslimit; class statistics; -#define ENABLE_TERNARY false +#define ENABLE_TERNARY true namespace sat { #define SAT_VB_LVL 10 From 1720addc4e4a6cd67eb7cbe1f972a742cd9fd54f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 26 Oct 2022 18:22:55 +0100 Subject: [PATCH 195/477] remove a bunch of string copies in the API thanks to C++20 --- src/api/api_datalog.cpp | 3 +-- src/api/api_opt.cpp | 3 +-- src/api/api_params.cpp | 4 ++-- src/api/api_parsers.cpp | 9 +++------ src/api/api_solver.cpp | 3 +-- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 19b488239..8f436bf8a 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -395,8 +395,7 @@ extern "C" { Z3_string s) { Z3_TRY; LOG_Z3_fixedpoint_from_string(c, d, s); - std::string str(s); - std::istringstream is(str); + std::istringstream is(s); RETURN_Z3(Z3_fixedpoint_from_stream(c, d, is)); Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index ebbe1a3db..5854bdaca 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -383,8 +383,7 @@ extern "C" { Z3_string s) { Z3_TRY; //LOG_Z3_optimize_from_string(c, d, s); - std::string str(s); - std::istringstream is(str); + std::istringstream is(s); Z3_optimize_from_stream(c, d, is, nullptr); Z3_CATCH; } diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index 1454525d6..2d0770903 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -116,7 +116,7 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; to_params(p)->m_params.display(buffer); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } @@ -208,7 +208,7 @@ extern "C" { buffer << to_param_descrs_ptr(p)->get_param_name(i); } buffer << ")"; - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 00fe1cd8b..2510d5e17 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -157,8 +157,7 @@ extern "C" { Z3_ast_vector Z3_API Z3_parser_context_from_string(Z3_context c, Z3_parser_context pc, Z3_string str) { Z3_TRY; LOG_Z3_parser_context_from_string(c, pc, str); - std::string s(str); - std::istringstream is(s); + std::istringstream is(str); auto& ctx = to_parser_context(pc)->ctx; Z3_ast_vector r = Z3_parser_context_parse_stream(c, ctx, false, is); RETURN_Z3(r); @@ -202,8 +201,7 @@ extern "C" { Z3_func_decl const decls[]) { Z3_TRY; LOG_Z3_parse_smtlib2_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - std::string s(str); - std::istringstream is(s); + std::istringstream is(str); Z3_ast_vector r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); RETURN_Z3(r); Z3_CATCH_RETURN(nullptr); @@ -243,8 +241,7 @@ extern "C" { ctx->set_solver_factory(mk_smt_strategic_solver_factory()); } scoped_ptr& ctx = mk_c(c)->cmd(); - std::string s(str); - std::istringstream is(s); + std::istringstream is(str); ctx->set_regular_stream(ous); ctx->set_diagnostic_stream(ous); cmd_context::scoped_redirect _redirect(*ctx); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 5edc42157..94d72462f 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -318,8 +318,7 @@ extern "C" { void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string c_str) { Z3_TRY; LOG_Z3_solver_from_string(c, s, c_str); - std::string str(c_str); - std::istringstream is(str); + std::istringstream is(c_str); if (is_dimacs_string(c_str)) { solver_from_dimacs_stream(c, s, is); } From 2258b9b9b60c613f58fa23b48c763ebfe471fcd3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Oct 2022 12:06:02 -0700 Subject: [PATCH 196/477] #6423 --- src/sat/smt/euf_internalize.cpp | 11 ++++++++++- src/sat/smt/pb_pb.cpp | 5 +++-- src/sat/smt/pb_solver.cpp | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index e2b116ea2..9f747090a 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -224,6 +224,14 @@ namespace euf { return; } + // check if it is trivial + expr_mark visited; + for (expr* arg : *e) { + if (visited.is_marked(arg)) + return; + visited.mark(arg); + } + static const unsigned distinct_max_args = 32; if (sz <= distinct_max_args) { sat::literal_vector lits; @@ -248,7 +256,8 @@ namespace euf { func_decl_ref g(m.mk_fresh_func_decl("dist-g", "", 1, &u_ptr, srt), m); expr_ref a(m.mk_fresh_const("a", u), m); expr_ref_vector eqs(m); - for (expr* arg : *e) { + + for (expr* arg : *e) { expr_ref fapp(m.mk_app(f, arg), m); expr_ref gapp(m.mk_app(g, fapp.get()), m); expr_ref eq = mk_eq(gapp, arg); diff --git a/src/sat/smt/pb_pb.cpp b/src/sat/smt/pb_pb.cpp index 1c016311e..6665e19f0 100644 --- a/src/sat/smt/pb_pb.cpp +++ b/src/sat/smt/pb_pb.cpp @@ -39,6 +39,8 @@ namespace pb { m_max_sum(0) { for (unsigned i = 0; i < size(); ++i) { m_wlits[i] = wlits[i]; + if (wlits[i].first > k) + m_wlits[i].first = k; } update_max_sum(); } @@ -47,9 +49,8 @@ namespace pb { m_max_sum = 0; for (unsigned i = 0; i < size(); ++i) { m_wlits[i].first = std::min(k(), m_wlits[i].first); - if (m_max_sum + m_wlits[i].first < m_max_sum) { + if (m_max_sum + m_wlits[i].first < m_max_sum) throw default_exception("addition of pb coefficients overflows"); - } m_max_sum += m_wlits[i].first; } } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index d1f101582..c3e43bfbe 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -1354,7 +1354,6 @@ namespace pb { si(si), m_pb(m), m_lookahead(nullptr), m_constraint_id(0), m_ba(*this), m_sort(m_ba) { - TRACE("pb", tout << this << "\n";); m_num_propagations_since_pop = 0; } @@ -1432,6 +1431,7 @@ namespace pb { } if (!c->well_formed()) IF_VERBOSE(0, verbose_stream() << *c << "\n"); + SASSERT(c->well_formed()); VERIFY(c->well_formed()); if (m_solver && m_solver->get_config().m_drat) { auto * out = s().get_drat().out(); From 5352a0106dfc8a432f1835fc241523879d8cd9d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Oct 2022 12:20:55 -0700 Subject: [PATCH 197/477] fix #6426 --- src/ast/rewriter/bv_rewriter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 4740a954c..b677b2197 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2270,11 +2270,13 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re // ~x = -1 - x unsigned sz = m_util.get_bv_size(x); if (m_util.is_bv_not(x, z)) { - result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(-1, sz), z), y); + numeral p = rational(2).expt(sz) - 1; + result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(p, sz), z), y); return BR_REWRITE3; } if (m_util.is_bv_not(y, z)) { - result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(-1, sz), z), x); + numeral p = rational(2).expt(sz) - 1; + result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(p, sz), z), x); return BR_REWRITE3; } // shl(z, u) * x = shl(x * z, u) From fe1b4bf5ce9f059571698f3c588a094f254405d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Oct 2022 23:43:17 -0700 Subject: [PATCH 198/477] disable ternary, fixes to propagation, make bv_rewrites for multiplier n-ary --- src/ast/bv_decl_plugin.h | 1 + src/ast/rewriter/bv_rewriter.cpp | 61 +++++++++----- src/ast/rewriter/bv_rewriter.h | 1 + src/sat/sat_cleaner.cpp | 2 + src/sat/sat_gc.cpp | 2 +- src/sat/sat_integrity_checker.cpp | 9 +- src/sat/sat_simplifier.cpp | 2 + src/sat/sat_solver.cpp | 132 +++++++++++++++++++----------- src/sat/sat_solver.h | 4 + src/sat/sat_types.h | 2 +- src/sat/sat_watched.cpp | 4 + src/sat/sat_watched.h | 14 +++- 12 files changed, 159 insertions(+), 75 deletions(-) diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 60efc73a9..1cb17900f 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -447,6 +447,7 @@ public: app * mk_bv_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BADD, arg1, arg2); } app * mk_bv_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BSUB, arg1, arg2); } app * mk_bv_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BMUL, arg1, arg2); } + app * mk_bv_mul(unsigned n, expr* const* args) const { return m_manager.mk_app(get_fid(), OP_BMUL, n, args); } app * mk_bv_udiv(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BUDIV, arg1, arg2); } app * mk_bv_udiv_i(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BUDIV_I, arg1, arg2); } app * mk_bv_udiv0(expr * arg) const { return m_manager.mk_app(get_fid(), OP_BUDIV0, arg); } diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index b677b2197..a04436e63 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2251,11 +2251,49 @@ bool bv_rewriter::is_zero_bit(expr * x, unsigned idx) { return false; } +br_status bv_rewriter::mk_mul_hoist(unsigned num_args, expr * const * args, expr_ref & result) { + if (num_args <= 1) + return BR_FAILED; + expr* z = nullptr, *u = nullptr; + for (unsigned i = 0; i < num_args; ++i) { + // ~x = -1 - x + if (m_util.is_bv_not(args[i], z)) { + unsigned sz = m_util.get_bv_size(z); + ptr_vector new_args(num_args, args); + rational p = rational(2).expt(sz) - 1; + new_args[i] = m_util.mk_bv_sub(mk_numeral(p, sz), z); + result = m_util.mk_bv_mul(num_args, new_args.data()); + return BR_REWRITE3; + } + // shl(z, u) * x = shl(x * z, u) + if (m_util.is_bv_shl(args[i], z, u)) { + ptr_vector new_args(num_args, args); + new_args[i] = z; + result = m_util.mk_bv_mul(num_args, new_args.data()); + result = m_util.mk_bv_shl(result, u); + return BR_REWRITE2; + } + } + return BR_FAILED; +} + br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result) { br_status st = mk_mul_core(num_args, args, result); if (st != BR_FAILED && st != BR_DONE) return st; - expr* x, * y, * z, * u; + if (st == BR_DONE && is_mul(result)) { + st = mk_mul_hoist(to_app(result)->get_num_args(), to_app(result)->get_args(), result); + if (st != BR_FAILED) + return st; + st = BR_DONE; + } + if (st == BR_FAILED) { + st = mk_mul_hoist(num_args, args, result); + if (st != BR_FAILED) + return st; + } + + expr* x, * y; if (st == BR_FAILED && num_args == 2) { x = args[0]; y = args[1]; @@ -2267,27 +2305,6 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re else { return st; } - // ~x = -1 - x - unsigned sz = m_util.get_bv_size(x); - if (m_util.is_bv_not(x, z)) { - numeral p = rational(2).expt(sz) - 1; - result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(p, sz), z), y); - return BR_REWRITE3; - } - if (m_util.is_bv_not(y, z)) { - numeral p = rational(2).expt(sz) - 1; - result = m_util.mk_bv_mul(m_util.mk_bv_sub(mk_numeral(p, sz), z), x); - return BR_REWRITE3; - } - // shl(z, u) * x = shl(x * z, u) - if (m_util.is_bv_shl(x, z, u)) { - result = m_util.mk_bv_shl(m_util.mk_bv_mul(z, y), u); - return BR_REWRITE2; - } - if (m_util.is_bv_shl(y, z, u)) { - result = m_util.mk_bv_shl(m_util.mk_bv_mul(z, x), u); - return BR_REWRITE2; - } if (m_mul2concat) { numeral v; unsigned bv_size; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 23ae67277..703e668b6 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -100,6 +100,7 @@ class bv_rewriter : public poly_rewriter { br_status mk_bv_mul(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_mul(2, args, result); } br_status mk_bv_add(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result); + br_status mk_mul_hoist(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result); diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 74ddbdbdb..bbdedab86 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -64,7 +64,9 @@ namespace sat { } TRACE("cleanup_bug", tout << "keeping: " << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";); break; +#if ENABLE_TERNARY case watched::TERNARY: +#endif case watched::CLAUSE: // skip break; diff --git a/src/sat/sat_gc.cpp b/src/sat/sat_gc.cpp index c8d6ebe7a..ab9bc8857 100644 --- a/src/sat/sat_gc.cpp +++ b/src/sat/sat_gc.cpp @@ -198,7 +198,7 @@ namespace sat { if (c.on_reinit_stack()) return false; #if ENABLE_TERNARY - if (ENABLE_TERNARY && c.size() == 3) { + if (c.size() == 3) { return can_delete3(c[0],c[1],c[2]) && can_delete3(c[1],c[0],c[2]) && diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 3453884a4..a6086d8a7 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -27,10 +27,12 @@ namespace sat { s(_s) { } +#if ENABLE_TERNARY // for ternary clauses static bool contains_watched(watch_list const & wlist, literal l1, literal l2) { return wlist.contains(watched(l1, l2)); } +#endif // for nary clauses static bool contains_watched(watch_list const & wlist, clause const & c, clause_offset cls_off) { @@ -63,6 +65,7 @@ namespace sat { if (c.frozen()) return true; +#if ENABLE_TERNARY if (c.size() == 3) { CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n"; tout << "watch_list:\n"; @@ -71,8 +74,10 @@ namespace sat { VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1])); + return true; } - else { +#endif + { if (s.value(c[0]) == l_false || s.value(c[1]) == l_false) { bool on_prop_stack = false; for (unsigned i = s.m_qhead; i < s.m_trail.size(); i++) { @@ -169,11 +174,13 @@ namespace sat { tout << "\n";); VERIFY(find_binary_watch(s.get_wlist(~(w.get_literal())), l)); break; +#if ENABLE_TERNARY case watched::TERNARY: VERIFY(!s.was_eliminated(w.get_literal1().var())); VERIFY(!s.was_eliminated(w.get_literal2().var())); VERIFY(w.get_literal1().index() < w.get_literal2().index()); break; +#endif case watched::CLAUSE: VERIFY(!s.get_clause(w.get_clause_offset()).was_removed()); break; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b456db243..b0faaf6c9 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -269,7 +269,9 @@ namespace sat { watch_list::iterator end2 = wlist.end(); for (; it2 != end2; ++it2) { switch (it2->get_kind()) { +#if ENABLE_TERNARY case watched::TERNARY: +#endif case watched::CLAUSE: // consume break; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index eae0b8f73..56dcdf0df 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -372,15 +372,15 @@ namespace sat { } void solver::del_clause(clause& c) { - if (!c.is_learned()) { + if (!c.is_learned()) m_stats.m_non_learned_generation++; - } - if (c.frozen()) { + + if (c.frozen()) --m_num_frozen; - } - if (!c.was_removed() && m_config.m_drat && !m_drat.is_cleaned(c)) { + + if (!c.was_removed() && m_config.m_drat && !m_drat.is_cleaned(c)) m_drat.del(c); - } + dealloc_clause(&c); if (m_searching) m_stats.m_del_clause++; @@ -448,10 +448,10 @@ namespace sat { if (redundant && m_par) m_par->share_clause(*this, lits[0], lits[1]); return nullptr; +#if ENABLE_TERNARY case 3: - if (ENABLE_TERNARY) return mk_ter_clause(lits, st); - Z3_fallthrough; +#endif default: return mk_nary_clause(num_lits, lits, st); } @@ -545,6 +545,7 @@ namespace sat { m_clauses_to_reinit.push_back(clause_wrapper(l1, l2)); } +#if ENABLE_TERNARY clause * solver::mk_ter_clause(literal * lits, sat::status st) { VERIFY(ENABLE_TERNARY); m_stats.m_mk_ter_clause++; @@ -575,7 +576,6 @@ namespace sat { return reinit; } -#if ENABLE_TERNARY bool solver::propagate_ter_clause(clause& c) { bool reinit = false; if (value(c[1]) == l_false && value(c[2]) == l_false) { @@ -664,9 +664,11 @@ namespace sat { void solver::attach_clause(clause & c, bool & reinit) { SASSERT(c.size() > 2); reinit = false; +#if ENABLE_TERNARY if (ENABLE_TERNARY && c.size() == 3) reinit = attach_ter_clause(c, c.is_learned() ? sat::status::redundant() : sat::status::asserted()); else +#endif reinit = attach_nary_clause(c, c.is_learned() && !c.on_reinit_stack()); } @@ -914,11 +916,14 @@ namespace sat { if (m_config.m_drat) m_drat.del(l1, l2); } - void solver::detach_clause(clause & c) { - if (ENABLE_TERNARY && c.size() == 3) + void solver::detach_clause(clause& c) { +#if ENABLE_TERNARY + if (c.size() == 3) { detach_ter_clause(c); - else - detach_nary_clause(c); + return; + } +#endif + detach_nary_clause(c); } void solver::detach_nary_clause(clause & c) { @@ -927,11 +932,13 @@ namespace sat { erase_clause_watch(get_wlist(~c[1]), cls_off); } +#if ENABLE_TERNARY void solver::detach_ter_clause(clause & c) { erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]); erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]); erase_ternary_watch(get_wlist(~c[2]), c[0], c[1]); } +#endif // ----------------------- // @@ -1060,6 +1067,22 @@ namespace sat { return r; } + void solver::propagate_clause(clause& c, bool update, unsigned assign_level, clause_offset cls_off) { + unsigned glue; + SASSERT(value(c[0]) == l_undef); + m_stats.m_propagate++; + c.mark_used(); + assign_core(c[0], justification(assign_level, cls_off)); + if (update && c.is_learned() && c.glue() > 2 && num_diff_levels_below(c.size(), c.begin(), c.glue() - 1, glue)) + c.set_glue(glue); \ + } + + void solver::set_watch(clause& c, unsigned idx, clause_offset cls_off) { + std::swap(c[1], c[idx]); + DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); + m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); + } + bool solver::propagate_literal(literal l, bool update) { literal l1, l2; @@ -1139,6 +1162,8 @@ namespace sat { if (c[0] == not_l) std::swap(c[0], c[1]); CTRACE("propagate_bug", c[1] != not_l, tout << "l: " << l << " " << c << "\n";); + + if (c.was_removed() || c.size() == 1 || c[1] != not_l) { // Remark: this method may be invoked when the watch lists are not in a consistent state, // and may contain dead/removed clauses, or clauses with removed literals. @@ -1155,58 +1180,65 @@ namespace sat { break; } VERIFY(c[1] == not_l); - literal* l_it = c.begin() + 2; - literal* l_end = c.end(); + + unsigned undef_index = 0; unsigned assign_level = curr_level; unsigned max_index = 1; - for (; l_it != l_end; ++l_it) { - if (value(*l_it) != l_false) { - c[1] = *l_it; - *l_it = not_l; - DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); - m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); + unsigned num_undef = 0; + unsigned sz = c.size(); + + for (unsigned i = 2; i < sz && num_undef <= 1; ++i) { + literal lit = c[i]; + switch (value(lit)) { + case l_true: + it2->set_clause(lit, cls_off); + it2++; goto end_clause_case; - } - } - SASSERT(value(c[0]) == l_false || value(c[0]) == l_undef); - if (assign_level != scope_lvl()) { - for (unsigned i = 2; i < c.size(); ++i) { - unsigned level = lvl(c[i]); + case l_undef: + undef_index = i; + ++num_undef; + break; + case l_false: { + unsigned level = lvl(lit); if (level > assign_level) { assign_level = level; max_index = i; } + break; } - IF_VERBOSE(20, verbose_stream() << "lower assignment level " << assign_level << " scope: " << scope_lvl() << "\n"); + } + } + + if (value(c[0]) == l_false) + assign_level = std::max(assign_level, lvl(c[0])); + + if (undef_index != 0) { + set_watch(c, undef_index, cls_off); + if (value(c[0]) == l_false && num_undef == 1) { + std::swap(c[0], c[1]); + propagate_clause(c, update, assign_level, cls_off); + } + goto end_clause_case; } if (value(c[0]) == l_false) { - assign_level = std::max(assign_level, lvl(c[0])); c.mark_used(); CONFLICT_CLEANUP(); set_conflict(justification(assign_level, cls_off)); return false; } - else { - if (max_index != 1) { - IF_VERBOSE(20, verbose_stream() << "swap watch for: " << c[1] << " " << c[max_index] << "\n"); - std::swap(c[1], c[max_index]); - m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); - } - else { - *it2 = *it; - it2++; - } - m_stats.m_propagate++; - c.mark_used(); - assign_core(c[0], justification(assign_level, cls_off)); - if (update && c.is_learned() && c.glue() > 2) { - unsigned glue; - if (num_diff_levels_below(c.size(), c.begin(), c.glue() - 1, glue)) { - c.set_glue(glue); - } - } + + // value(c[0]) == l_undef + + if (max_index != 1) { + IF_VERBOSE(20, verbose_stream() << "swap watch for: " << c[1] << " " << c[max_index] << "\n"); + set_watch(c, max_index, cls_off); } + else { + *it2 = *it; + it2++; + } + propagate_clause(c, update, assign_level, cls_off); end_clause_case: break; } @@ -3425,6 +3457,7 @@ namespace sat { unmark_lit(~l2); } } +#if ENABLE_TERNARY else if (w.is_ternary_clause()) { literal l2 = w.get_literal1(); literal l3 = w.get_literal2(); @@ -3437,6 +3470,7 @@ namespace sat { unmark_lit(~l2); } } +#endif else { // May miss some binary/ternary clauses, but that is ok. // I sort the watch lists at every simplification round. @@ -3581,7 +3615,7 @@ namespace sat { auto cleanup_watch = [&](literal lit) { for (auto const& w : get_wlist(lit)) { - IF_VERBOSE(0, verbose_stream() << "cleanup: " << lit << " " << w.is_binary_clause() << "\n"); + IF_VERBOSE(1, verbose_stream() << "cleanup: " << lit << " " << w.is_binary_clause() << "\n"); } }; for (bool_var v : m_vars_to_free) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 2b341185f..88c404c7c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -305,9 +305,11 @@ namespace sat { void mk_bin_clause(literal l1, literal l2, sat::status st); void mk_bin_clause(literal l1, literal l2, bool learned) { mk_bin_clause(l1, l2, learned ? sat::status::redundant() : sat::status::asserted()); } bool propagate_bin_clause(literal l1, literal l2); +#if ENABLE_TERNARY clause * mk_ter_clause(literal * lits, status st); bool attach_ter_clause(clause & c, status st); bool propagate_ter_clause(clause& c); +#endif clause * mk_nary_clause(unsigned num_lits, literal * lits, status st); bool has_variables_to_reinit(clause const& c) const; bool has_variables_to_reinit(literal l1, literal l2) const; @@ -480,6 +482,8 @@ namespace sat { bool should_propagate() const; bool propagate_core(bool update); bool propagate_literal(literal l, bool update); + void propagate_clause(clause& c, bool update, unsigned assign_level, clause_offset cls_off); + void set_watch(clause& c, unsigned idx, clause_offset cls_off); // ----------------------- // diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index d2e2ffc94..7c4e4fb73 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -34,7 +34,7 @@ class params_ref; class reslimit; class statistics; -#define ENABLE_TERNARY true +#define ENABLE_TERNARY false namespace sat { #define SAT_VB_LVL 10 diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 8811a4e74..dedbf45f0 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -71,6 +71,7 @@ namespace sat { VERIFY(found); } +#if ENABLE_TERNARY void erase_ternary_watch(watch_list& wlist, literal l1, literal l2) { watched w(l1, l2); watch_list::iterator it = wlist.begin(), end = wlist.end(); @@ -96,6 +97,7 @@ namespace sat { } #endif } +#endif void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist) { watch_list::iterator end = wlist.end(); @@ -118,9 +120,11 @@ namespace sat { if (w.is_learned()) out << "*"; break; +#if ENABLE_TERNARY case watched::TERNARY: out << "(" << w.get_literal1() << " " << w.get_literal2() << ")"; break; +#endif case watched::CLAUSE: out << "(" << w.get_blocked_literal() << " " << *(ca.get_clause(w.get_clause_offset())) << ")"; break; diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 3e27f53c0..7e88c8c51 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -40,7 +40,11 @@ namespace sat { class watched { public: enum kind { - BINARY = 0, TERNARY, CLAUSE, EXT_CONSTRAINT + BINARY = 0, +#if ENABLE_TERNARY + TERNARY, +#endif + CLAUSE, EXT_CONSTRAINT }; private: size_t m_val1; @@ -55,6 +59,7 @@ namespace sat { SASSERT(learned || is_binary_non_learned_clause()); } +#if ENABLE_TERNARY watched(literal l1, literal l2) { SASSERT(l1 != l2); if (l1.index() > l2.index()) @@ -65,6 +70,7 @@ namespace sat { SASSERT(get_literal1() == l1); SASSERT(get_literal2() == l2); } +#endif unsigned val2() const { return m_val2; } @@ -95,9 +101,11 @@ namespace sat { void set_learned(bool l) { if (l) m_val2 |= 4u; else m_val2 &= ~4u; SASSERT(is_learned() == l); } +#if ENABLE_TERNARY bool is_ternary_clause() const { return get_kind() == TERNARY; } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); } +#endif bool is_clause() const { return get_kind() == CLAUSE; } clause_offset get_clause_offset() const { SASSERT(is_clause()); return static_cast(m_val1); } @@ -117,7 +125,9 @@ namespace sat { }; static_assert(0 <= watched::BINARY && watched::BINARY <= 3, ""); +#if ENABLE_TERNARY static_assert(0 <= watched::TERNARY && watched::TERNARY <= 3, ""); +#endif static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 3, ""); static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3, ""); @@ -125,8 +135,10 @@ namespace sat { bool operator()(watched const & w1, watched const & w2) const { if (w2.is_binary_clause()) return false; if (w1.is_binary_clause()) return true; +#if ENABLE_TERNARY if (w2.is_ternary_clause()) return false; if (w1.is_ternary_clause()) return true; +#endif return false; } }; From 1fae3aa152478c06c611c48e4782c4099957bc5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2022 11:22:57 -0700 Subject: [PATCH 199/477] rename set-flat to set-flat-and-or to allow to differentiate parameters --- src/ast/proofs/proof_utils.h | 2 +- src/ast/rewriter/bit_blaster/bit_blaster.h | 2 +- .../rewriter/bit_blaster/bit_blaster_rewriter.cpp | 2 +- src/ast/rewriter/bool_rewriter.cpp | 4 ++-- src/ast/rewriter/bool_rewriter.h | 12 ++++++------ src/model/model_evaluator.cpp | 2 +- src/sat/smt/bv_solver.cpp | 2 +- src/tactic/arith/pb2bv_tactic.cpp | 2 +- src/tactic/core/tseitin_cnf_tactic.cpp | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index 2e3406e10..cc1744d4e 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -106,7 +106,7 @@ public: { ast_manager &m = args.get_manager(); bool_rewriter brwr(m); - brwr.set_flat(false); + brwr.set_flat_and_or(false); if (m.is_or(decl)) { mk_or_core(args, res); } diff --git a/src/ast/rewriter/bit_blaster/bit_blaster.h b/src/ast/rewriter/bit_blaster/bit_blaster.h index ca034337f..39b6de673 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster.h @@ -59,7 +59,7 @@ class bit_blaster : public bit_blaster_tpl { public: bit_blaster(ast_manager & m, bit_blaster_params const & params); bit_blaster_params const & get_params() const { return this->m_params; } - void set_flat(bool f) { m_rw.set_flat(f); } + void set_flat_and_or(bool f) { m_rw.set_flat_and_or(f); } }; diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 13e6a3511..801ebf4b5 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -75,7 +75,7 @@ public: bit_blaster_tpl(blaster_cfg(m_rewriter, m_util)), m_rewriter(m), m_util(m) { - m_rewriter.set_flat(false); + m_rewriter.set_flat_and_or(false); m_rewriter.set_elim_and(true); } diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index fb2b0795b..80495853a 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -24,7 +24,7 @@ Notes: void bool_rewriter::updt_params(params_ref const & _p) { bool_rewriter_params p(_p); - m_flat = p.flat(); + m_flat_and_or = p.flat(); m_elim_and = p.elim_and(); m_elim_ite = p.elim_ite(); m_local_ctx = p.local_ctx(); @@ -555,7 +555,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ result = arg; \ return true; \ } \ - if (m_flat && m().is_or(arg)) { \ + if (m_flat_and_or && m().is_or(arg)) { \ unsigned sz = to_app(arg)->get_num_args(); \ for (unsigned j = 0; j < sz; j++) { \ expr * arg_arg = to_app(arg)->get_arg(j); \ diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index 5820026b7..a25a0f8a3 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -50,7 +50,7 @@ Notes: */ class bool_rewriter { ast_manager & m_manager; - bool m_flat; + bool m_flat_and_or; bool m_local_ctx; bool m_elim_and; bool m_blast_distinct; @@ -83,8 +83,8 @@ public: family_id get_fid() const { return m().get_basic_family_id(); } bool is_eq(expr * t) const { return m().is_eq(t); } - bool flat() const { return m_flat; } - void set_flat(bool f) { m_flat = f; } + bool flat_and_or() const { return m_flat_and_or; } + void set_flat_and_or(bool f) { m_flat_and_or = f; } bool elim_and() const { return m_elim_and; } void set_elim_and(bool f) { m_elim_and = f; } void reset_local_ctx_cost() { m_local_ctx_cost = 0; } @@ -111,7 +111,7 @@ public: mk_and_as_or(num_args, args, result); return BR_DONE; } - else if (m_flat) { + else if (m_flat_and_or) { return mk_flat_and_core(num_args, args, result); } else { @@ -119,7 +119,7 @@ public: } } br_status mk_or_core(unsigned num_args, expr * const * args, expr_ref & result) { - return m_flat ? + return m_flat_and_or ? mk_flat_or_core(num_args, args, result) : mk_nflat_or_core(num_args, args, result); } @@ -234,7 +234,7 @@ public: struct bool_rewriter_cfg : public default_rewriter_cfg { bool_rewriter m_r; - bool flat_assoc(func_decl * f) const { return m_r.flat() && (m_r.m().is_and(f) || m_r.m().is_or(f)); } + bool flat_assoc(func_decl * f) const { return m_r.flat_and_or() && (m_r.m().is_and(f) || m_r.m().is_or(f)); } bool rewrite_patterns() const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = nullptr; diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 843345a46..0c2a09e78 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -86,7 +86,7 @@ struct evaluator_cfg : public default_rewriter_cfg { m_dt(m), m_pinned(m) { bool flat = true; - m_b_rw.set_flat(flat); + m_b_rw.set_flat_and_or(flat); m_a_rw.set_flat(flat); m_bv_rw.set_flat(flat); m_bv_rw.set_mkbv2num(true); diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index f103f876a..a5a35878e 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -55,7 +55,7 @@ namespace bv { m_ackerman(*this), m_bb(m, get_config()), m_find(*this) { - m_bb.set_flat(false); + m_bb.set_flat_and_or(false); } bool solver::is_fixed(euf::theory_var v, expr_ref& val, sat::literal_vector& lits) { diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 2d405895f..c418115a9 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -866,7 +866,7 @@ private: m_used_dependencies(m), m_rw(*this) { updt_params(p); - m_b_rw.set_flat(false); // no flattening otherwise will blowup the memory + m_b_rw.set_flat_and_or(false); // no flattening otherwise will blowup the memory m_b_rw.set_elim_and(true); } diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index c141aaa3b..eec05b604 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -116,7 +116,7 @@ class tseitin_cnf_tactic : public tactic { m_rw(_m), m_num_aux_vars(0) { updt_params(p); - m_rw.set_flat(false); + m_rw.set_flat_and_or(false); } void updt_params(params_ref const & p) { From a409a4a6775aa5ec97654ec038b01f918063cbf6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2022 20:10:55 -0700 Subject: [PATCH 200/477] enforce flat within QF_BV tactic, cap in-processing var-elim loops --- src/ast/rewriter/seq_rewriter.h | 2 +- src/ast/rewriter/th_rewriter.cpp | 2 +- src/sat/sat_simplifier.cpp | 4 +++- src/tactic/core/solve_eqs_tactic.cpp | 19 +++++++++---------- src/tactic/smtlogics/qfbv_tactic.cpp | 1 + 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index cb00938d7..26dc00675 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -354,7 +354,7 @@ class seq_rewriter { public: seq_rewriter(ast_manager & m, params_ref const & p = params_ref()): - m_util(m), m_autil(m), m_br(m), m_re2aut(m), m_op_cache(m), m_es(m), + m_util(m), m_autil(m), m_br(m, p), m_re2aut(m), m_op_cache(m), m_es(m), m_lhs(m), m_rhs(m), m_coalesce_chars(true) { } ast_manager & m() const { return m_util.get_manager(); } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index f7ac45ff5..96b69dbc3 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -850,7 +850,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { m_f_rw(m, p), m_dl_rw(m), m_pb_rw(m), - m_seq_rw(m), + m_seq_rw(m, p), m_char_rw(m), m_rec_rw(m), m_a_util(m), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b0faaf6c9..b67ef6a2a 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -229,6 +229,7 @@ namespace sat { } } + unsigned count = 0; do { if (m_subsumption) subsume(); @@ -240,8 +241,9 @@ namespace sat { return; if (!m_subsumption || m_sub_counter < 0) break; + ++count; } - while (!m_sub_todo.empty()); + while (!m_sub_todo.empty() && count < 20); bool vars_eliminated = m_num_elim_vars > m_old_num_elim_vars; if (m_need_cleanup || vars_eliminated) { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 30e4a8c4b..a7b206d5b 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -36,6 +36,7 @@ class solve_eqs_tactic : public tactic { ast_manager & m_manager; expr_replacer * m_r; + params_ref m_params; bool m_r_owner; arith_util m_a_util; obj_map m_num_occs; @@ -80,7 +81,8 @@ class solve_eqs_tactic : public tactic { ast_manager & m() const { return m_manager; } void updt_params(params_ref const & p) { - tactic_params tp(p); + m_params.append(p); + tactic_params tp(m_params); m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); m_theory_solver = p.get_bool("theory_solver", tp.solve_eqs_theory_solver()); m_max_occs = p.get_uint("solve_eqs_max_occs", tp.solve_eqs_max_occs()); @@ -702,8 +704,8 @@ class solve_eqs_tactic : public tactic { if (m_produce_proofs) return; unsigned size = g.size(); - hoist_rewriter_star rw(m()); - th_rewriter thrw(m()); + hoist_rewriter_star rw(m(), m_params); + th_rewriter thrw(m(), m_params); expr_ref tmp(m()), tmp2(m()); TRACE("solve_eqs", g.display(tout);); @@ -1082,15 +1084,13 @@ class solve_eqs_tactic : public tactic { }; imp * m_imp; - params_ref m_params; public: - solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner): - m_params(p) { + solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner) { m_imp = alloc(imp, m, p, r, owner); } tactic * translate(ast_manager & m) override { - return alloc(solve_eqs_tactic, m, m_params, mk_expr_simp_replacer(m, m_params), true); + return alloc(solve_eqs_tactic, m, m_imp->m_params, mk_expr_simp_replacer(m, m_imp->m_params), true); } ~solve_eqs_tactic() override { @@ -1100,8 +1100,7 @@ public: char const* name() const override { return "solve_eqs"; } void updt_params(params_ref const & p) override { - m_params.append(p); - m_imp->updt_params(m_params); + m_imp->updt_params(p); } void collect_param_descrs(param_descrs & r) override { @@ -1126,7 +1125,7 @@ public: bool owner = m_imp->m_r_owner; m_imp->m_r_owner = false; // stole replacer - imp * d = alloc(imp, m, m_params, r, owner); + imp * d = alloc(imp, m, m_imp->m_params, r, owner); d->m_num_eliminated_vars = num_elim_vars; std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index b242d86cf..1366b701e 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -86,6 +86,7 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat params_ref local_ctx_p = p; local_ctx_p.set_bool("local_ctx", true); + local_ctx_p.set_bool("flat", false); params_ref solver_p; solver_p.set_bool("preprocess", false); // preprocessor of smt::context is not needed. From 91cdc082c47008c916f35d7d1b7f662a2e21e0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Facundo=20Dom=C3=ADnguez?= Date: Fri, 28 Oct 2022 17:57:22 -0300 Subject: [PATCH 201/477] Optimize calls to Z3_eval_smtlib2_string (#6422) * Allow reseting the stream of smt2::scanner * Put the parser of parse_smt2_commands in the cmd_context * Move parser streams to cmd_context * Move parser fields from cmd_context to api::context * Move forward declarations from cmd_context.h to api_context.h * Change parse_smt2_commands_with_parser to use *& instead of ** * Add tests for Z3_eval_smtlib2_string * Don't reuse the streams in Z3_eval_smtlib2_string * Fix indentation * Add back unnecessary deleted line Co-authored-by: Nuno Lopes --- src/api/api_context.cpp | 2 + src/api/api_context.h | 18 ++++++ src/api/api_parsers.cpp | 3 +- src/parsers/smt2/smt2parser.cpp | 14 +++++ src/parsers/smt2/smt2parser.h | 9 ++- src/parsers/smt2/smt2scanner.cpp | 18 ++++-- src/parsers/smt2/smt2scanner.h | 3 +- src/test/smt2print_parse.cpp | 96 +++++++++++++++++++++++++++++++- 8 files changed, 154 insertions(+), 9 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 6d9af74a0..cef63621d 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -149,6 +149,8 @@ namespace api { context::~context() { + if (m_parser) + smt2::free_parser(m_parser); m_last_obj = nullptr; flush_objects(); for (auto& kv : m_allocated_objects) { diff --git a/src/api/api_context.h b/src/api/api_context.h index 3bc0d4403..a3f027dd5 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -50,6 +50,11 @@ namespace realclosure { class manager; }; +namespace smt2 { + class parser; + void free_parser(parser*); +}; + namespace api { class seq_expr_solver : public expr_solver { @@ -233,6 +238,19 @@ namespace api { void check_sorts(ast * n); + + // ------------------------------------------------ + // + // State reused by calls to Z3_eval_smtlib2_string + // + // ------------------------------------------------ + // + // The m_parser field is reused by all calls of Z3_eval_smtlib2_string using this context. + // It is an optimization to save the cost of recreating these objects on each invocation. + // + // See https://github.com/Z3Prover/z3/pull/6422 for the motivation + smt2::parser* m_parser = nullptr; + // ------------------------ // // Polynomial manager & caches diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 2510d5e17..899750ef7 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -246,7 +246,8 @@ extern "C" { ctx->set_diagnostic_stream(ous); cmd_context::scoped_redirect _redirect(*ctx); try { - if (!parse_smt2_commands(*ctx.get(), is)) { + // See api::context::m_parser for a motivation about the reuse of the parser + if (!parse_smt2_commands_with_parser(mk_c(c)->m_parser, *ctx.get(), is)) { SET_ERROR_CODE(Z3_PARSER_ERROR, ous.str()); RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 45a9a9cc9..9f61d48ca 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -3105,6 +3105,10 @@ namespace smt2 { } + void reset_input(std::istream & is, bool interactive) { + m_scanner.reset_input(is, interactive); + } + sexpr_ref parse_sexpr_ref() { m_num_bindings = 0; m_num_open_paren = 0; @@ -3204,6 +3208,8 @@ namespace smt2 { } } }; + + void free_parser(parser * p) { dealloc(p); } }; bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) { @@ -3211,6 +3217,14 @@ bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, return p(); } +bool parse_smt2_commands_with_parser(class smt2::parser *& p, cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) { + if (p) + p->reset_input(is, interactive); + else + p = alloc(smt2::parser, ctx, is, interactive, ps, filename); + 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); diff --git a/src/parsers/smt2/smt2parser.h b/src/parsers/smt2/smt2parser.h index ad8f040b4..30089b7a2 100644 --- a/src/parsers/smt2/smt2parser.h +++ b/src/parsers/smt2/smt2parser.h @@ -20,7 +20,14 @@ Revision History: #include "cmd_context/cmd_context.h" -bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref(), char const * filename = nullptr); +namespace smt2 { + class parser; + void free_parser(parser * p); +} + +bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & ps = params_ref(), char const * filename = nullptr); + +bool parse_smt2_commands_with_parser(class smt2::parser *& p, cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & ps = params_ref(), char const * filename = nullptr); sexpr_ref parse_sexpr(cmd_context& ctx, std::istream& is, params_ref const& ps, char const* filename); diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 2027698eb..2fb45db3b 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -27,8 +27,8 @@ namespace smt2 { if (m_at_eof) throw scanner_exception("unexpected end of file"); if (m_interactive) { - m_curr = m_stream.get(); - if (m_stream.eof()) + m_curr = m_stream->get(); + if (m_stream->eof()) m_at_eof = true; } else if (m_bpos < m_bend) { @@ -36,8 +36,8 @@ namespace smt2 { m_bpos++; } else { - m_stream.read(m_buffer, SCANNER_BUFFER_SIZE); - m_bend = static_cast(m_stream.gcount()); + m_stream->read(m_buffer, SCANNER_BUFFER_SIZE); + m_bend = static_cast(m_stream->gcount()); m_bpos = 0; if (m_bpos == m_bend) { m_at_eof = true; @@ -281,7 +281,7 @@ namespace smt2 { m_bv_size(UINT_MAX), m_bpos(0), m_bend(0), - m_stream(stream), + m_stream(&stream), m_cache_input(false) { @@ -390,5 +390,13 @@ namespace smt2 { return m_cache_result.begin(); } + void scanner::reset_input(std::istream & stream, bool interactive) { + m_stream = &stream; + m_interactive = interactive; + m_at_eof = false; + m_bpos = 0; + m_bend = 0; + next(); + } }; diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index 5fb59c7cd..dd1aa04c0 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -49,7 +49,7 @@ namespace smt2 { unsigned m_bpos; unsigned m_bend; svector m_string; - std::istream& m_stream; + std::istream* m_stream; bool m_cache_input; svector m_cache; @@ -99,6 +99,7 @@ namespace smt2 { void stop_caching() { m_cache_input = false; } unsigned cache_size() const { return m_cache.size(); } void reset_cache() { m_cache.reset(); } + void reset_input(std::istream & stream, bool interactive = false); char const * cached_str(unsigned begin, unsigned end); }; diff --git a/src/test/smt2print_parse.cpp b/src/test/smt2print_parse.cpp index 81b7ba1e9..ed674de8b 100644 --- a/src/test/smt2print_parse.cpp +++ b/src/test/smt2print_parse.cpp @@ -64,6 +64,98 @@ void test_parseprint(char const* spec) { Z3_del_context(ctx); } +void test_eval(Z3_context ctx, Z3_string spec, bool shouldFail) { + std::cout << "spec:\n" << spec << "\n"; + + Z3_string resp; + bool failed = false; + try { + resp = Z3_eval_smtlib2_string(ctx, spec); + } + catch (std::runtime_error& e) { + resp = e.what(); + failed = true; + } + + std::cout << "response:\n" << resp << "\n"; + + if (shouldFail != failed) { + if (shouldFail) + throw std::runtime_error("should have failed"); + else + throw std::runtime_error("should have succeeded"); + } +} + +void throwError(Z3_context c, Z3_error_code e) { + throw std::runtime_error(Z3_get_error_msg(c, e)); +} + +void test_repeated_eval() { + // Z3_eval_smtlib2_string reuses the parser and the scanner + // when called repeteadly on the same context. + // + // These tests rehearse that earlier calls do not interfere + // with the result of later calls if the SMT queries are independent. + + char const* spec1 = + "(push)\n" + "(declare-datatypes (T) ((list (nil) (cons (car T) (cdr list)))))\n" + "(declare-const x Int)\n" + "(declare-const l (list Int))\n" + "(declare-fun f ((list Int)) Bool)\n" + "(assert (f (cons x l)))\n" + "(check-sat)\n" + "(pop)\n"; + + char const* spec2 = + "(push)\n" + "(declare-const a (Array Int Int))\n" + "(declare-const b (Array (Array Int Int) Bool))\n" + "(assert (select b a))\n" + "(assert (= b ((as const (Array (Array Int Int) Bool)) true)))\n" + "(assert (= b (store b a true)))\n" + "(declare-const b1 (Array Bool Bool))\n" + "(declare-const b2 (Array Bool Bool))\n" + "(assert (= ((as const (Array Bool Bool)) false) ((_ map and) b1 b2)))\n" + "(check-sat)\n" + "(pop)\n"; + + char const* spec3 = + "(push)\n" + "(declare-const a@ (Array Int Int))\n" + "(declare-const b (Array (Array Int Int) Bool))\n" + "(assert (select b a))\n" + "(check-sat)\n" + "(pop)\n"; + + char const* spec4 = + "(push)\n" + "(declare-const a (Array Int Int))\n" + "(declare-const b# (Array (Array Int Int) Bool))\n" + "(assert (select b a))\n" + "(check-sat)\n" + "(pop)\n"; + + Z3_context ctx = Z3_mk_context(nullptr); + Z3_set_error_handler(ctx, throwError); + std::cout << "testing Z3_eval_smtlib2_string\n"; + + test_eval(ctx, spec1, false); + std::cout << "successful call after successful call\n"; + test_eval(ctx, spec2, false); + std::cout << "failing call after successful call\n"; + test_eval(ctx, spec3, true); + std::cout << "failing call after failing call\n"; + test_eval(ctx, spec4, true); + std::cout << "successful call after failing call\n"; + test_eval(ctx, spec1, false); + + std::cout << "done evaluating\n"; + + Z3_del_context(ctx); +} + void tst_smt2print_parse() { // test basic datatypes @@ -126,6 +218,8 @@ void tst_smt2print_parse() { test_parseprint(spec6); - // Test ? + // Test ? + + test_repeated_eval(); } From 0e651eee0457b525677ed3a23bbc1df353122ff8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Oct 2022 14:12:28 -0700 Subject: [PATCH 202/477] #6421 --- src/opt/opt_solver.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 64bf389bf..ee91b06a4 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -287,7 +287,9 @@ namespace opt { bool ok = bound_value(i, val); if (l_true != m_context.check(0, nullptr)) return false; - m_context.get_model(m_last_model); + m_context.get_model(m_last_model); + if (!m_last_model) + return false; update_objective(); return ok; }; @@ -299,7 +301,9 @@ namespace opt { TRACE("opt", tout << "updated\n";); m_last_model = nullptr; m_context.get_model(m_last_model); - if (!has_shared || val == current_objective_value(i)) + if (!m_last_model) + return false; + else if (!has_shared || val == current_objective_value(i)) m_models.set(i, m_last_model.get()); else if (!check_bound()) return false; From 0da0fa2b2761f9cec1a9c1ce9837c14eaa4252e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 29 Oct 2022 13:42:57 -0700 Subject: [PATCH 203/477] #6429 --- src/math/simplex/model_based_opt.cpp | 2 +- src/qe/mbp/mbp_arith.cpp | 38 ++++++++++++++++------------ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index ac7e89d5b..9e7ac75ce 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1299,7 +1299,7 @@ namespace opt { def result; unsigned_vector div_rows(_div_rows), mod_rows(_mod_rows); SASSERT(!div_rows.empty() || !mod_rows.empty()); - TRACE("opt", display(tout << "solve_div " << x << "\n")); + TRACE("opt", display(tout << "solve_div v" << x << "\n")); rational K(1); for (unsigned ri : div_rows) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index e97eb4ef7..5d9d3c19c 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -421,15 +421,23 @@ namespace mbp { mbo.display(tout);); vector defs = mbo.project(real_vars.size(), real_vars.data(), compute_def); + vector rows; + u_map def_vars; mbo.get_live_rows(rows); - rows2fmls(rows, index2expr, fmls); + for (row const& r : rows) { + if (r.m_type == opt::t_mod) + def_vars.insert(r.m_id, r); + else if (r.m_type == opt::t_div) + def_vars.insert(r.m_id, r); + } + rows2fmls(def_vars, rows, index2expr, fmls); TRACE("qe", mbo.display(tout << "mbo result\n"); for (auto const& d : defs) tout << "def: " << d << "\n"; tout << fmls << "\n";); if (compute_def) - optdefs2mbpdef(defs, index2expr, real_vars, result); + optdefs2mbpdef(def_vars, defs, index2expr, real_vars, result); if (m_apply_projection && !apply_projection(eval, result, fmls)) return false; @@ -442,7 +450,7 @@ namespace mbp { return true; } - void optdefs2mbpdef(vector const& defs, ptr_vector const& index2expr, unsigned_vector const& real_vars, vector& result) { + void optdefs2mbpdef(u_map const& def_vars, vector const& defs, ptr_vector const& index2expr, unsigned_vector const& real_vars, vector& result) { SASSERT(defs.size() == real_vars.size()); for (unsigned i = 0; i < defs.size(); ++i) { auto const& d = defs[i]; @@ -450,8 +458,12 @@ namespace mbp { bool is_int = a.is_int(x); expr_ref_vector ts(m); expr_ref t(m); - for (var const& v : d.m_vars) - ts.push_back(var2expr(index2expr, v)); + for (var const& v : d.m_vars) { + t = id2expr(def_vars, index2expr, v.m_id); + if (v.m_coeff != 1) + t = a.mk_mul(a.mk_numeral(v.m_coeff, a.is_int(t)), t); + ts.push_back(t); + } if (!d.m_coeff.is_zero()) ts.push_back(a.mk_numeral(d.m_coeff, is_int)); if (ts.empty()) @@ -492,7 +504,8 @@ namespace mbp { t = a.mk_int(mod(r.m_coeff, r.m_mod)); return t; } - ts.push_back(a.mk_int(r.m_coeff)); + if (r.m_coeff != 0) + ts.push_back(a.mk_int(r.m_coeff)); t = mk_add(ts); t = a.mk_mod(t, a.mk_int(r.m_mod)); return t; @@ -501,7 +514,8 @@ namespace mbp { t = a.mk_int(div(r.m_coeff, r.m_mod)); return t; } - ts.push_back(a.mk_int(r.m_coeff)); + if (r.m_coeff != 0) + ts.push_back(a.mk_int(r.m_coeff)); t = mk_add(ts); t = a.mk_idiv(t, a.mk_int(r.m_mod)); return t; @@ -513,15 +527,7 @@ namespace mbp { } } - void rows2fmls(vector const& rows, ptr_vector const& index2expr, expr_ref_vector& fmls) { - - u_map def_vars; - for (row const& r : rows) { - if (r.m_type == opt::t_mod) - def_vars.insert(r.m_id, r); - else if (r.m_type == opt::t_div) - def_vars.insert(r.m_id, r); - } + void rows2fmls(u_map& def_vars, vector const& rows, ptr_vector const& index2expr, expr_ref_vector& fmls) { for (row const& r : rows) { expr_ref t(m), s(m), val(m); From 9fc4015c46360058ad4b4fcccc7fee076ca5c74c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 30 Oct 2022 03:57:39 -0700 Subject: [PATCH 204/477] remove ternary clause optimization Removing ternary clause optimization from sat_solver simplifies special case handling of ternary clauses throughout the sat solver and dependent solvers (pb_solver). Benchmarking on QF_BV suggests the ternary clause optimization does not have any effect. While removing ternary clause optimization two bugs in unit propagation were also uncovered: it missed propagations when the only a single undef literal remained in the non-watched literals and it did not update blocked literals in cases where it could in the watch list. These performance bugs were for general clauses, ternary clause propagation did not miss propagations (and don't use blocked literals), but fixing these issues for general clauses appear to have made ternary clause optimization irrelevant based on what was measured. --- src/sat/sat_cleaner.cpp | 3 - src/sat/sat_drat.cpp | 4 - src/sat/sat_gc.cpp | 24 ---- src/sat/sat_integrity_checker.cpp | 26 ---- src/sat/sat_justification.h | 21 +--- src/sat/sat_proof_trim.cpp | 17 --- src/sat/sat_simplifier.cpp | 3 - src/sat/sat_solver.cpp | 197 ++---------------------------- src/sat/sat_solver.h | 6 - src/sat/sat_types.h | 2 - src/sat/sat_watched.cpp | 33 ----- src/sat/sat_watched.h | 38 +----- src/sat/smt/pb_solver.cpp | 28 ----- 13 files changed, 16 insertions(+), 386 deletions(-) diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index bbdedab86..8da933fb2 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -64,9 +64,6 @@ namespace sat { } TRACE("cleanup_bug", tout << "keeping: " << ~to_literal(l_idx) << " " << it2->get_literal() << "\n";); break; -#if ENABLE_TERNARY - case watched::TERNARY: -#endif case watched::CLAUSE: // skip break; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 306ff2493..46a608151 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -445,10 +445,6 @@ namespace sat { return false; case justification::BINARY: return contains(c, j.get_literal()); -#if ENABLE_TERNARY - case justification::TERNARY: - return contains(c, j.get_literal1(), j.get_literal2()); -#endif case justification::CLAUSE: return contains(s.get_clause(j)); default: diff --git a/src/sat/sat_gc.cpp b/src/sat/sat_gc.cpp index ab9bc8857..a655956db 100644 --- a/src/sat/sat_gc.cpp +++ b/src/sat/sat_gc.cpp @@ -178,33 +178,9 @@ namespace sat { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :strategy " << st_name << " :deleted " << (sz - new_sz) << ")\n";); } -#if ENABLE_TERNARY - bool solver::can_delete3(literal l1, literal l2, literal l3) const { - if (value(l1) == l_true && - value(l2) == l_false && - value(l3) == l_false) { - justification const& j = m_justification[l1.var()]; - if (j.is_ternary_clause()) { - watched w1(l2, l3); - watched w2(j.get_literal1(), j.get_literal2()); - return w1 != w2; - } - } - return true; - } -#endif - bool solver::can_delete(clause const & c) const { if (c.on_reinit_stack()) return false; -#if ENABLE_TERNARY - if (c.size() == 3) { - return - can_delete3(c[0],c[1],c[2]) && - can_delete3(c[1],c[0],c[2]) && - can_delete3(c[2],c[0],c[1]); - } -#endif literal l0 = c[0]; if (value(l0) != l_true) return true; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index a6086d8a7..223e58677 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -26,13 +26,6 @@ namespace sat { integrity_checker::integrity_checker(solver const & _s): s(_s) { } - -#if ENABLE_TERNARY - // for ternary clauses - static bool contains_watched(watch_list const & wlist, literal l1, literal l2) { - return wlist.contains(watched(l1, l2)); - } -#endif // for nary clauses static bool contains_watched(watch_list const & wlist, clause const & c, clause_offset cls_off) { @@ -65,18 +58,6 @@ namespace sat { if (c.frozen()) return true; -#if ENABLE_TERNARY - if (c.size() == 3) { - CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n"; - tout << "watch_list:\n"; - s.display_watch_list(tout, s.get_wlist(~c[0])); - tout << "\n";); - VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); - VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); - VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1])); - return true; - } -#endif { if (s.value(c[0]) == l_false || s.value(c[1]) == l_false) { bool on_prop_stack = false; @@ -174,13 +155,6 @@ namespace sat { tout << "\n";); VERIFY(find_binary_watch(s.get_wlist(~(w.get_literal())), l)); break; -#if ENABLE_TERNARY - case watched::TERNARY: - VERIFY(!s.was_eliminated(w.get_literal1().var())); - VERIFY(!s.was_eliminated(w.get_literal2().var())); - VERIFY(w.get_literal1().index() < w.get_literal2().index()); - break; -#endif case watched::CLAUSE: VERIFY(!s.get_clause(w.get_clause_offset()).was_removed()); break; diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index 1fc97a38c..f83173aa7 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -22,11 +22,7 @@ namespace sat { class justification { public: - enum kind { NONE = 0, BINARY = 1, -#if ENABLE_TERNARY - TERNARY = 2, -#endif - CLAUSE = 3, EXT_JUSTIFICATION = 4}; + enum kind { NONE = 0, BINARY = 1, CLAUSE = 2, EXT_JUSTIFICATION = 3}; private: unsigned m_level; size_t m_val1; @@ -36,9 +32,7 @@ namespace sat { public: justification(unsigned lvl):m_level(lvl), m_val1(0), m_val2(NONE) {} explicit justification(unsigned lvl, literal l):m_level(lvl), m_val1(l.to_uint()), m_val2(BINARY) {} -#if ENABLE_TERNARY - justification(unsigned lvl, literal l1, literal l2):m_level(lvl), m_val1(l1.to_uint()), m_val2(TERNARY + (l2.to_uint() << 3)) {} -#endif + explicit justification(unsigned lvl, clause_offset cls_off):m_level(lvl), m_val1(cls_off), m_val2(CLAUSE) {} static justification mk_ext_justification(unsigned lvl, ext_justification_idx idx) { return justification(lvl, idx, EXT_JUSTIFICATION); } @@ -51,12 +45,6 @@ namespace sat { bool is_binary_clause() const { return m_val2 == BINARY; } literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(val1()); } -#if ENABLE_TERNARY - bool is_ternary_clause() const { return get_kind() == TERNARY; } - literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(val1()); } - literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); } -#endif - bool is_clause() const { return m_val2 == CLAUSE; } clause_offset get_clause_offset() const { return m_val1; } @@ -73,11 +61,6 @@ namespace sat { case justification::BINARY: out << "binary " << j.get_literal(); break; -#if ENABLE_TERNARY - case justification::TERNARY: - out << "ternary " << j.get_literal1() << " " << j.get_literal2(); - break; -#endif case justification::CLAUSE: out << "clause"; break; diff --git a/src/sat/sat_proof_trim.cpp b/src/sat/sat_proof_trim.cpp index 4c4b9ecaf..df55aecd7 100644 --- a/src/sat/sat_proof_trim.cpp +++ b/src/sat/sat_proof_trim.cpp @@ -125,10 +125,6 @@ namespace sat { in_coi |= m_in_coi.contains(lit.index()); else if (js.is_binary_clause()) in_coi = m_in_coi.contains(js.get_literal().index()); -#if ENABLE_TERNARY - else if (js.is_ternary_clause()) - in_coi = m_in_coi.contains(js.get_literal1().index()) || m_in_coi.contains(js.get_literal2().index()); -#endif else UNREACHABLE(); // approach does not work for external justifications @@ -226,12 +222,6 @@ namespace sat { case justification::BINARY: add_dependency(j.get_literal()); break; -#if ENABLE_TERNARY - case justification::TERNARY: - add_dependency(j.get_literal1()); - add_dependency(j.get_literal2()); - break; -#endif case justification::CLAUSE: for (auto lit : s.get_clause(j)) if (s.value(lit) == l_false) @@ -262,13 +252,6 @@ namespace sat { m_clause.push_back(l); m_clause.push_back(j.get_literal()); break; -#if ENABLE_TERNARY - case justification::TERNARY: - m_clause.push_back(l); - m_clause.push_back(j.get_literal1()); - m_clause.push_back(j.get_literal2()); - break; -#endif case justification::CLAUSE: s.get_clause(j).mark_used(); IF_VERBOSE(3, verbose_stream() << "add core " << s.get_clause(j) << "\n"); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b67ef6a2a..9ba536091 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -271,9 +271,6 @@ namespace sat { watch_list::iterator end2 = wlist.end(); for (; it2 != end2; ++it2) { switch (it2->get_kind()) { -#if ENABLE_TERNARY - case watched::TERNARY: -#endif case watched::CLAUSE: // consume break; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 56dcdf0df..eea3a2475 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -448,10 +448,6 @@ namespace sat { if (redundant && m_par) m_par->share_clause(*this, lits[0], lits[1]); return nullptr; -#if ENABLE_TERNARY - case 3: - return mk_ter_clause(lits, st); -#endif default: return mk_nary_clause(num_lits, lits, st); } @@ -545,58 +541,6 @@ namespace sat { m_clauses_to_reinit.push_back(clause_wrapper(l1, l2)); } -#if ENABLE_TERNARY - clause * solver::mk_ter_clause(literal * lits, sat::status st) { - VERIFY(ENABLE_TERNARY); - m_stats.m_mk_ter_clause++; - clause * r = alloc_clause(3, lits, st.is_redundant()); - bool reinit = attach_ter_clause(*r, st); - if (reinit || has_variables_to_reinit(*r)) push_reinit_stack(*r); - if (st.is_redundant()) - m_learned.push_back(r); - else - m_clauses.push_back(r); - for (literal l : *r) { - m_touched[l.var()] = m_touch_index; - } - return r; - } - - bool solver::attach_ter_clause(clause & c, sat::status st) { - VERIFY(ENABLE_TERNARY); - bool reinit = false; - if (m_config.m_drat) m_drat.add(c, st); - TRACE("sat_verbose", tout << c << "\n";); - SASSERT(!c.was_removed()); - m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); - m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); - m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); - if (!at_base_lvl()) - reinit = propagate_ter_clause(c); - return reinit; - } - - bool solver::propagate_ter_clause(clause& c) { - bool reinit = false; - if (value(c[1]) == l_false && value(c[2]) == l_false) { - m_stats.m_ter_propagate++; - assign(c[0], justification(std::max(lvl(c[1]), lvl(c[2])), c[1], c[2])); - reinit = !c.is_learned(); - } - else if (value(c[0]) == l_false && value(c[2]) == l_false) { - m_stats.m_ter_propagate++; - assign(c[1], justification(std::max(lvl(c[0]), lvl(c[2])), c[0], c[2])); - reinit = !c.is_learned(); - } - else if (value(c[0]) == l_false && value(c[1]) == l_false) { - m_stats.m_ter_propagate++; - assign(c[2], justification(std::max(lvl(c[0]), lvl(c[1])), c[0], c[1])); - reinit = !c.is_learned(); - } - return reinit; - } -#endif - clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, sat::status st) { m_stats.m_mk_clause++; clause * r = alloc_clause(num_lits, lits, st.is_redundant()); @@ -663,13 +607,7 @@ namespace sat { void solver::attach_clause(clause & c, bool & reinit) { SASSERT(c.size() > 2); - reinit = false; -#if ENABLE_TERNARY - if (ENABLE_TERNARY && c.size() == 3) - reinit = attach_ter_clause(c, c.is_learned() ? sat::status::redundant() : sat::status::asserted()); - else -#endif - reinit = attach_nary_clause(c, c.is_learned() && !c.on_reinit_stack()); + reinit = attach_nary_clause(c, c.is_learned() && !c.on_reinit_stack()); } void solver::set_learned(clause& c, bool redundant) { @@ -917,12 +855,6 @@ namespace sat { } void solver::detach_clause(clause& c) { -#if ENABLE_TERNARY - if (c.size() == 3) { - detach_ter_clause(c); - return; - } -#endif detach_nary_clause(c); } @@ -932,14 +864,6 @@ namespace sat { erase_clause_watch(get_wlist(~c[1]), cls_off); } -#if ENABLE_TERNARY - void solver::detach_ter_clause(clause & c) { - erase_ternary_watch(get_wlist(~c[0]), c[1], c[2]); - erase_ternary_watch(get_wlist(~c[1]), c[0], c[2]); - erase_ternary_watch(get_wlist(~c[2]), c[0], c[1]); - } -#endif - // ----------------------- // // Basic @@ -1123,31 +1047,6 @@ namespace sat { *it2 = *it; it2++; break; -#if ENABLE_TERNARY - case watched::TERNARY: { - lbool val1, val2; - l1 = it->get_literal1(); - l2 = it->get_literal2(); - val1 = value(l1); - val2 = value(l2); - if (val1 == l_false && val2 == l_undef) { - m_stats.m_ter_propagate++; - assign_core(l2, justification(std::max(curr_level, lvl(l1)), l1, not_l)); - } - else if (val1 == l_undef && val2 == l_false) { - m_stats.m_ter_propagate++; - assign_core(l1, justification(std::max(curr_level, lvl(l2)), l2, not_l)); - } - else if (val1 == l_false && val2 == l_false) { - CONFLICT_CLEANUP(); - set_conflict(justification(std::max(curr_level, lvl(l1)), l1, not_l), ~l2); - return false; - } - *it2 = *it; - it2++; - break; - } -#endif case watched::CLAUSE: { if (value(it->get_blocked_literal()) == l_true) { TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n"; @@ -2534,12 +2433,6 @@ namespace sat { case justification::BINARY: process_antecedent(~(js.get_literal()), num_marks); break; -#if ENABLE_TERNARY - case justification::TERNARY: - process_antecedent(~(js.get_literal1()), num_marks); - process_antecedent(~(js.get_literal2()), num_marks); - break; -#endif case justification::CLAUSE: { clause & c = get_clause(js); unsigned i = 0; @@ -2718,13 +2611,6 @@ namespace sat { SASSERT(consequent != null_literal); process_antecedent_for_unsat_core(~(js.get_literal())); break; -#if ENABLE_TERNARY - case justification::TERNARY: - SASSERT(consequent != null_literal); - process_antecedent_for_unsat_core(~(js.get_literal1())); - process_antecedent_for_unsat_core(~(js.get_literal2())); - break; -#endif case justification::CLAUSE: { clause & c = get_clause(js); unsigned i = 0; @@ -2861,12 +2747,6 @@ namespace sat { case justification::BINARY: level = update_max_level(js.get_literal(), level, unique_max); return level; -#if ENABLE_TERNARY - case justification::TERNARY: - level = update_max_level(js.get_literal1(), level, unique_max); - level = update_max_level(js.get_literal2(), level, unique_max); - return level; -#endif case justification::CLAUSE: for (literal l : get_clause(js)) level = update_max_level(l, level, unique_max); @@ -3218,15 +3098,6 @@ namespace sat { return false; } break; -#if ENABLE_TERNARY - case justification::TERNARY: - if (!process_antecedent_for_minimization(~(js.get_literal1())) || - !process_antecedent_for_minimization(~(js.get_literal2()))) { - reset_unmark(old_size); - return false; - } - break; -#endif case justification::CLAUSE: { clause & c = get_clause(js); unsigned i = 0; @@ -3382,12 +3253,6 @@ namespace sat { case justification::BINARY: update_lrb_reasoned(js.get_literal()); break; -#if ENABLE_TERNARY - case justification::TERNARY: - update_lrb_reasoned(js.get_literal1()); - update_lrb_reasoned(js.get_literal2()); - break; -#endif case justification::CLAUSE: { clause & c = get_clause(js); for (literal l : c) { @@ -3457,20 +3322,6 @@ namespace sat { unmark_lit(~l2); } } -#if ENABLE_TERNARY - else if (w.is_ternary_clause()) { - literal l2 = w.get_literal1(); - literal l3 = w.get_literal2(); - if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) { - // eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3 - unmark_lit(~l3); - } - else if (is_marked_lit(~l2) && is_marked_lit(l3) && l0 != ~l2) { - // eliminate ~l2 from lemma because we have the clause l \/ l2 \/ l3 - unmark_lit(~l2); - } - } -#endif else { // May miss some binary/ternary clauses, but that is ok. // I sort the watch lists at every simplification round. @@ -3735,17 +3586,6 @@ namespace sat { } else { clause & c = *(cw.get_clause()); -#if ENABLE_TERNARY - if (ENABLE_TERNARY && c.size() == 3) { - if (propagate_ter_clause(c) && !at_base_lvl()) - m_clauses_to_reinit[j++] = cw; - else if (has_variables_to_reinit(c) && !at_base_lvl()) - m_clauses_to_reinit[j++] = cw; - else - c.set_reinit_stack(false); - continue; - } -#endif detach_clause(c); attach_clause(c, reinit); if (reinit && !at_base_lvl()) @@ -4012,12 +3852,6 @@ namespace sat { case justification::BINARY: out << "binary " << js.get_literal() << "@" << lvl(js.get_literal()); break; -#if ENABLE_TERNARY - case justification::TERNARY: - out << "ternary " << js.get_literal1() << "@" << lvl(js.get_literal1()) << " "; - out << js.get_literal2() << "@" << lvl(js.get_literal2()); - break; -#endif case justification::CLAUSE: { out << "("; bool first = true; @@ -4677,24 +4511,14 @@ namespace sat { if (!check_domain(lit, ~js.get_literal())) return false; s |= m_antecedents.find(js.get_literal().var()); break; -#if ENABLE_TERNARY - case justification::TERNARY: - if (!check_domain(lit, ~js.get_literal1()) || - !check_domain(lit, ~js.get_literal2())) return false; - s |= m_antecedents.find(js.get_literal1().var()); - s |= m_antecedents.find(js.get_literal2().var()); - break; -#endif case justification::CLAUSE: { clause & c = get_clause(js); for (literal l : c) { if (l != lit) { - if (check_domain(lit, ~l) && all_found) { - s |= m_antecedents.find(l.var()); - } - else { - all_found = false; - } + if (check_domain(lit, ~l) && all_found) + s |= m_antecedents.find(l.var()); + else + all_found = false; } } break; @@ -4729,12 +4553,11 @@ namespace sat { bool solver::extract_fixed_consequences1(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { index_set s; - if (m_antecedents.contains(lit.var())) { + if (m_antecedents.contains(lit.var())) return true; - } - if (assumptions.contains(lit)) { - s.insert(lit.index()); - } + + if (assumptions.contains(lit)) + s.insert(lit.index()); else { if (!extract_assumptions(lit, s)) { SASSERT(!m_todo_antecedents.empty()); @@ -4806,7 +4629,7 @@ namespace sat { clause_vector const & cs = *(vs[i]); for (clause* cp : cs) { clause & c = *cp; - if (ENABLE_TERNARY && c.size() == 3) + if (c.size() == 3) num_ter++; else num_cls++; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 88c404c7c..2e53e4620 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -305,11 +305,6 @@ namespace sat { void mk_bin_clause(literal l1, literal l2, sat::status st); void mk_bin_clause(literal l1, literal l2, bool learned) { mk_bin_clause(l1, l2, learned ? sat::status::redundant() : sat::status::asserted()); } bool propagate_bin_clause(literal l1, literal l2); -#if ENABLE_TERNARY - clause * mk_ter_clause(literal * lits, status st); - bool attach_ter_clause(clause & c, status st); - bool propagate_ter_clause(clause& c); -#endif clause * mk_nary_clause(unsigned num_lits, literal * lits, status st); bool has_variables_to_reinit(clause const& c) const; bool has_variables_to_reinit(literal l1, literal l2) const; @@ -345,7 +340,6 @@ namespace sat { void detach_bin_clause(literal l1, literal l2, bool learned); void detach_clause(clause & c); void detach_nary_clause(clause & c); - void detach_ter_clause(clause & c); void push_reinit_stack(clause & c); void push_reinit_stack(literal l1, literal l2); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 7c4e4fb73..4e119a2ae 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -34,8 +34,6 @@ class params_ref; class reslimit; class statistics; -#define ENABLE_TERNARY false - namespace sat { #define SAT_VB_LVL 10 diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index dedbf45f0..5573212f5 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -71,34 +71,6 @@ namespace sat { VERIFY(found); } -#if ENABLE_TERNARY - void erase_ternary_watch(watch_list& wlist, literal l1, literal l2) { - watched w(l1, l2); - watch_list::iterator it = wlist.begin(), end = wlist.end(); - watch_list::iterator it2 = it; - bool found = false; - for (; it != end; ++it) { - if (!found && w == *it) { - found = true; - } - else { - *it2 = *it; - ++it2; - } - } - wlist.set_end(it2); -#if 0 - VERIFY(found); - for (watched const& w2 : wlist) { - if (w2 == w) { - std::cout << l1 << " " << l2 << "\n"; - } - //VERIFY(w2 != w); - } -#endif - } -#endif - void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist) { watch_list::iterator end = wlist.end(); for (; it != end; ++it, ++it2) @@ -120,11 +92,6 @@ namespace sat { if (w.is_learned()) out << "*"; break; -#if ENABLE_TERNARY - case watched::TERNARY: - out << "(" << w.get_literal1() << " " << w.get_literal2() << ")"; - break; -#endif case watched::CLAUSE: out << "(" << w.get_blocked_literal() << " " << *(ca.get_clause(w.get_clause_offset())) << ")"; break; diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 7e88c8c51..6d91434db 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -40,11 +40,7 @@ namespace sat { class watched { public: enum kind { - BINARY = 0, -#if ENABLE_TERNARY - TERNARY, -#endif - CLAUSE, EXT_CONSTRAINT + BINARY = 0, CLAUSE, EXT_CONSTRAINT }; private: size_t m_val1; @@ -59,18 +55,6 @@ namespace sat { SASSERT(learned || is_binary_non_learned_clause()); } -#if ENABLE_TERNARY - watched(literal l1, literal l2) { - SASSERT(l1 != l2); - if (l1.index() > l2.index()) - std::swap(l1, l2); - m_val1 = l1.to_uint(); - m_val2 = static_cast(TERNARY) + (l2.to_uint() << 2); - SASSERT(is_ternary_clause()); - SASSERT(get_literal1() == l1); - SASSERT(get_literal2() == l2); - } -#endif unsigned val2() const { return m_val2; } @@ -101,11 +85,6 @@ namespace sat { void set_learned(bool l) { if (l) m_val2 |= 4u; else m_val2 &= ~4u; SASSERT(is_learned() == l); } -#if ENABLE_TERNARY - bool is_ternary_clause() const { return get_kind() == TERNARY; } - literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } - literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); } -#endif bool is_clause() const { return get_kind() == CLAUSE; } clause_offset get_clause_offset() const { SASSERT(is_clause()); return static_cast(m_val1); } @@ -124,21 +103,14 @@ namespace sat { bool operator!=(watched const & w) const { return !operator==(w); } }; - static_assert(0 <= watched::BINARY && watched::BINARY <= 3, ""); -#if ENABLE_TERNARY - static_assert(0 <= watched::TERNARY && watched::TERNARY <= 3, ""); -#endif - static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 3, ""); - static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3, ""); + static_assert(0 <= watched::BINARY && watched::BINARY <= 2, ""); + static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 2, ""); + static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 2, ""); struct watched_lt { bool operator()(watched const & w1, watched const & w2) const { if (w2.is_binary_clause()) return false; if (w1.is_binary_clause()) return true; -#if ENABLE_TERNARY - if (w2.is_ternary_clause()) return false; - if (w1.is_ternary_clause()) return true; -#endif return false; } }; @@ -148,8 +120,6 @@ namespace sat { watched* find_binary_watch(watch_list & wlist, literal l); watched const* find_binary_watch(watch_list const & wlist, literal l); bool erase_clause_watch(watch_list & wlist, clause_offset c); - void erase_ternary_watch(watch_list & wlist, literal l1, literal l2); - void set_ternary_learned(watch_list& wlist, literal l1, literal l2, bool learned); class clause_allocator; std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist, extension* ext); diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index c3e43bfbe..424b20d4e 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -690,15 +690,6 @@ namespace pb { inc_coeff(consequent, offset); process_antecedent(js.get_literal(), offset); break; -#if ENABLE_TERNARY - case sat::justification::TERNARY: - inc_bound(offset); - SASSERT (consequent != sat::null_literal); - inc_coeff(consequent, offset); - process_antecedent(js.get_literal1(), offset); - process_antecedent(js.get_literal2(), offset); - break; -#endif case sat::justification::CLAUSE: { inc_bound(offset); sat::clause & c = s().get_clause(js); @@ -1019,16 +1010,6 @@ namespace pb { inc_coeff(consequent, 1); process_antecedent(js.get_literal()); break; -#if ENABLE_TERNARY - case sat::justification::TERNARY: - SASSERT(consequent != sat::null_literal); - round_to_one(consequent.var()); - inc_bound(1); - inc_coeff(consequent, 1); - process_antecedent(js.get_literal1()); - process_antecedent(js.get_literal2()); - break; -#endif case sat::justification::CLAUSE: { sat::clause & c = s().get_clause(js); unsigned i = 0; @@ -3476,15 +3457,6 @@ namespace pb { ineq.push(lit, offset); ineq.push(js.get_literal(), offset); break; -#if ENABLE_TERNARY - case sat::justification::TERNARY: - SASSERT(lit != sat::null_literal); - ineq.reset(offset); - ineq.push(lit, offset); - ineq.push(js.get_literal1(), offset); - ineq.push(js.get_literal2(), offset); - break; -#endif case sat::justification::CLAUSE: { ineq.reset(offset); sat::clause & c = s().get_clause(js); From 1646a41b2f2ffd319138036e4debd3282b6ff10e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 08:44:55 -0700 Subject: [PATCH 205/477] minor fixes - ensure mk_extract performs simplification to distribute over extract and removing extract if the range is the entire bit-vector - ensure bool_rewriter simplifeis disjunctions when applicable. --- src/ast/euf/euf_egraph.cpp | 4 ++++ src/ast/euf/euf_etable.cpp | 2 -- src/ast/justified_expr.h | 11 +++++------ src/ast/rewriter/bool_rewriter.cpp | 2 +- src/ast/rewriter/mk_extract_proc.cpp | 7 +++++++ src/ast/rewriter/th_rewriter.h | 1 + src/tactic/core/solve_eqs_tactic.cpp | 7 ++----- src/tactic/core/solve_eqs_tactic.h | 3 +-- src/tactic/core/symmetry_reduce_tactic.cpp | 5 +++-- 9 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 6034d8428..c8605b297 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -904,6 +904,10 @@ template void euf::egraph::explain_todo(ptr_vector& justifications, cc_j template void euf::egraph::explain_eq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); template unsigned euf::egraph::explain_diseq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); +template void euf::egraph::explain(ptr_vector& justifications, cc_justification*); +template void euf::egraph::explain_todo(ptr_vector& justifications, cc_justification*); +template void euf::egraph::explain_eq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); +template unsigned euf::egraph::explain_diseq(ptr_vector& justifications, cc_justification*, enode* a, enode* b); #if 0 diff --git a/src/ast/euf/euf_etable.cpp b/src/ast/euf/euf_etable.cpp index cfc99e4a0..e007297ef 100644 --- a/src/ast/euf/euf_etable.cpp +++ b/src/ast/euf/euf_etable.cpp @@ -201,8 +201,6 @@ namespace euf { enode_bool_pair etable::insert(enode * n) { // it doesn't make sense to insert a constant. SASSERT(n->num_args() > 0); - SASSERT(!m_manager.is_and(n->get_expr())); - SASSERT(!m_manager.is_or(n->get_expr())); enode * n_prime; void * t = get_table(n); switch (static_cast(GET_TAG(t))) { diff --git a/src/ast/justified_expr.h b/src/ast/justified_expr.h index 786061065..a599ff5a1 100644 --- a/src/ast/justified_expr.h +++ b/src/ast/justified_expr.h @@ -33,8 +33,7 @@ public: justified_expr(justified_expr const& other): m(other.m), m_fml(other.m_fml), - m_proof(other.m_proof) - { + m_proof(other.m_proof) { m.inc_ref(m_fml); m.inc_ref(m_proof); } @@ -42,8 +41,7 @@ public: justified_expr(justified_expr && other) noexcept : m(other.m), m_fml(nullptr), - m_proof(nullptr) - { + m_proof(nullptr) { std::swap(m_fml, other.m_fml); std::swap(m_proof, other.m_proof); } @@ -51,10 +49,11 @@ public: ~justified_expr() { m.dec_ref(m_fml); m.dec_ref(m_proof); - m_fml = nullptr; - m_proof = nullptr; + m_fml = nullptr; + m_proof = nullptr; } expr* get_fml() const { return m_fml; } + proof* get_proof() const { return m_proof; } }; diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 80495853a..1964e6528 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -290,7 +290,7 @@ br_status bool_rewriter::mk_flat_or_core(unsigned num_args, expr * const * args, ast_lt lt; std::sort(flat_args.begin(), flat_args.end(), lt); } - result = m().mk_or(flat_args); + result = mk_or_app(flat_args.size(), flat_args.data()); } return BR_DONE; } diff --git a/src/ast/rewriter/mk_extract_proc.cpp b/src/ast/rewriter/mk_extract_proc.cpp index be61047a4..cc18ae176 100644 --- a/src/ast/rewriter/mk_extract_proc.cpp +++ b/src/ast/rewriter/mk_extract_proc.cpp @@ -32,8 +32,15 @@ mk_extract_proc::~mk_extract_proc() { } app * mk_extract_proc::operator()(unsigned high, unsigned low, expr * arg) { + unsigned l, h; + while (m_util.is_extract(arg, l, h, arg)) { + low += l; + high += l; + } ast_manager & m = m_util.get_manager(); sort * s = arg->get_sort(); + if (low == 0 && high + 1 == m_util.get_bv_size(arg) && is_app(arg)) + return to_app(arg); if (m_low == low && m_high == high && m_domain == s) return m.mk_app(m_f_cached, arg); // m_f_cached has a reference to m_domain, so, I don't need to inc_ref m_domain diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index 271500551..e432678a4 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -47,6 +47,7 @@ public: expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings); expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args); + expr_ref mk_app(func_decl* f, ptr_vector const& args) { return mk_app(f, args.size(), args.data()); } bool reduce_quantifier(quantifier * old_q, expr * new_body, diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index a7b206d5b..5a076aa0f 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -1141,9 +1141,6 @@ public: }; -tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replacer * r) { - if (r == nullptr) - return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true)); - else - return clean(alloc(solve_eqs_tactic, m, p, r, false)); +tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true)); } diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index d986b0dbf..d65a33046 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -21,9 +21,8 @@ Revision History: #include "util/params.h" class ast_manager; class tactic; -class expr_replacer; -tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref(), expr_replacer * r = nullptr); +tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()); /* ADD_TACTIC("solve-eqs", "eliminate variables by solving equations.", "mk_solve_eqs_tactic(m, p)") diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 9aa4c9448..e94e83679 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -25,6 +25,7 @@ Notes: #include "ast/rewriter/expr_replacer.h" #include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" class symmetry_reduce_tactic : public tactic { class imp; @@ -608,12 +609,12 @@ private: return (j == A.size())?0:A[j]; } - app* mk_member(app* t, term_set const& C) { + expr* mk_member(app* t, term_set const& C) { expr_ref_vector eqs(m()); for (unsigned i = 0; i < C.size(); ++i) { eqs.push_back(m().mk_eq(t, C[i])); } - return m().mk_or(eqs.size(), eqs.data()); + return mk_or(m(), eqs.size(), eqs.data()); } }; From e57674490f37d027a500d30b272e3e337d637049 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 08:51:30 -0700 Subject: [PATCH 206/477] adding simplifiers layer simplifiers layer is a common substrate for global non-incremental and incremental processing. The first two layers are new, but others are to be ported form tactics. - bv::slice - rewrites equations to cut-dice-slice bit-vector extractions until they align. It creates opportunities for rewriting portions of bit-vectors to common sub-expressions, including values. - euf::completion - generalizes the KB simplifcation from asserted formulas to use the E-graph to establish a global and order-independent canonization. The interface dependent_expr_simplifier is amenable to forming tactics. Plugins for asserted-formulas is also possible but not yet realized. --- scripts/mk_project.py | 3 +- src/CMakeLists.txt | 3 +- src/ast/simplifiers/CMakeLists.txt | 8 + src/ast/simplifiers/bv_slice.cpp | 207 +++++++++++++ src/ast/simplifiers/bv_slice.h | 55 ++++ src/ast/simplifiers/dependent_expr.h | 75 +++++ src/ast/simplifiers/dependent_expr_state.h | 86 ++++++ src/ast/simplifiers/euf_completion.cpp | 330 +++++++++++++++++++++ src/ast/simplifiers/euf_completion.h | 63 ++++ src/tactic/CMakeLists.txt | 1 + src/tactic/bv/CMakeLists.txt | 2 + src/tactic/bv/bv_slice_tactic.h | 29 ++ src/tactic/core/CMakeLists.txt | 2 + src/tactic/core/euf_completion_tactic.cpp | 32 ++ src/tactic/core/euf_completion_tactic.h | 29 ++ src/tactic/dependent_expr_state_tactic.h | 101 +++++++ 16 files changed, 1024 insertions(+), 2 deletions(-) create mode 100644 src/ast/simplifiers/CMakeLists.txt create mode 100644 src/ast/simplifiers/bv_slice.cpp create mode 100644 src/ast/simplifiers/bv_slice.h create mode 100644 src/ast/simplifiers/dependent_expr.h create mode 100644 src/ast/simplifiers/dependent_expr_state.h create mode 100644 src/ast/simplifiers/euf_completion.cpp create mode 100644 src/ast/simplifiers/euf_completion.h create mode 100644 src/tactic/bv/bv_slice_tactic.h create mode 100644 src/tactic/core/euf_completion_tactic.cpp create mode 100644 src/tactic/core/euf_completion_tactic.h create mode 100644 src/tactic/dependent_expr_state_tactic.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 60cbdcc56..9c4cda4a1 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -31,10 +31,11 @@ def init_project_def(): add_lib('nlsat', ['polynomial', 'sat']) add_lib('lp', ['util', 'nlsat', 'grobner', 'interval', 'smt_params'], 'math/lp') add_lib('rewriter', ['ast', 'polynomial', 'automata', 'params'], 'ast/rewriter') + add_lib('simplifiers', ['euf', 'rewriter'], 'ast/simplifiers') add_lib('macros', ['rewriter'], 'ast/macros') add_lib('normal_forms', ['rewriter'], 'ast/normal_forms') add_lib('model', ['rewriter', 'macros']) - add_lib('tactic', ['ast', 'model']) + add_lib('tactic', ['ast', 'model', 'simplifiers']) add_lib('substitution', ['ast', 'rewriter'], 'ast/substitution') add_lib('parser_util', ['ast'], 'parsers/util') add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b96638944..ad6fbcdb2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,9 +49,10 @@ add_subdirectory(ast/rewriter) add_subdirectory(ast/normal_forms) add_subdirectory(ast/macros) add_subdirectory(model) +add_subdirectory(ast/euf) +add_subdirectory(ast/simplifiers) add_subdirectory(tactic) add_subdirectory(ast/substitution) -add_subdirectory(ast/euf) add_subdirectory(smt/params) add_subdirectory(parsers/util) add_subdirectory(math/grobner) diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt new file mode 100644 index 000000000..650410415 --- /dev/null +++ b/src/ast/simplifiers/CMakeLists.txt @@ -0,0 +1,8 @@ +z3_add_component(simplifiers + SOURCES + euf_completion.cpp + bv_slice.cpp + COMPONENT_DEPENDENCIES + euf + rewriter +) diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp new file mode 100644 index 000000000..f39fa932e --- /dev/null +++ b/src/ast/simplifiers/bv_slice.cpp @@ -0,0 +1,207 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bv_slice.cpp + +Abstract: + + simplifier for extracting bit-vector ranges + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/simplifiers/bv_slice.h" + +namespace bv { + + void slice::reduce() { + process_eqs(); + apply_subst(); + advance_qhead(m_fmls.size()); + } + + void slice::process_eqs() { + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + auto const [f, d] = m_fmls[i](); + process_eq(f); + } + } + + void slice::process_eq(expr* e) { + expr* x, * y; + if (!m.is_eq(e, x, y)) + return; + if (!m_bv.is_bv(x)) + return; + m_xs.reset(); + m_ys.reset(); + get_concats(x, m_xs); + get_concats(y, m_ys); + slice_eq(); + } + + void slice::slice_eq() { + unsigned i = m_xs.size(), j = m_ys.size(); + unsigned offx = 0, offy = 0; + while (0 < i) { + SASSERT(0 < j); + expr* x = m_xs[i - 1]; // least significant bits are last + expr* y = m_ys[j - 1]; + SASSERT(offx == 0 || offy == 0); + unsigned szx = m_bv.get_bv_size(x); + unsigned szy = m_bv.get_bv_size(y); + SASSERT(offx < szx); + SASSERT(offy < szy); + if (szx - offx == szy - offy) { + register_slice(offx, szx - 1, x); + register_slice(offy, szy - 1, y); + --i; + --j; + offx = 0; + offy = 0; + } + else if (szx - offx < szy - offy) { + register_slice(offx, szx - 1, x); + register_slice(offy, offy + szx - offx - 1, y); + offy += szx - offx; + offx = 0; + --i; + } + else { + register_slice(offy, szy - 1, y); + register_slice(offx, offx + szy - offy - 1, x); + offx += szy - offy; + offy = 0; + --j; + } + } + } + + void slice::register_slice(unsigned lo, unsigned hi, expr* x) { + SASSERT(lo <= hi && hi < m_bv.get_bv_size(x)); + unsigned l, h; + while (m_bv.is_extract(x, l, h, x)) { + // x[l:h][lo:hi] = x[l+lo:l+hi] + hi += l; + lo += l; + SASSERT(lo <= hi && hi < m_bv.get_bv_size(x)); + } + unsigned sz = m_bv.get_bv_size(x); + if (hi - lo + 1 == sz) + return; + SASSERT(0 < lo || hi + 1 < sz); + auto& b = m_boundaries.insert_if_not_there(x, uint_set()); + + struct remove_set : public trail { + uint_set& b; + unsigned i; + remove_set(uint_set& b, unsigned i) :b(b), i(i) {} + void undo() override { + b.remove(i); + } + }; + if (lo > 0 && !b.contains(lo)) { + b.insert(lo); + if (m_num_scopes > 0) + m_trail.push(remove_set(b, lo)); + } + if (hi + 1 < sz && !b.contains(hi + 1)) { + b.insert(hi + 1); + if (m_num_scopes > 0) + m_trail.push(remove_set(b, hi+ 1)); + } + } + + expr* slice::mk_extract(unsigned hi, unsigned lo, expr* x) { + unsigned l, h; + while (m_bv.is_extract(x, l, h, x)) { + lo += l; + hi += l; + } + if (lo == 0 && hi + 1 == m_bv.get_bv_size(x)) + return x; + else + return m_bv.mk_extract(hi, lo, x); + } + + void slice::apply_subst() { + if (m_boundaries.empty()) + return; + expr_ref_vector cache(m), pin(m); + ptr_vector todo, args; + expr* c; + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + auto const [f, d] = m_fmls[i](); + todo.push_back(f); + pin.push_back(f); + while (!todo.empty()) { + expr* e = todo.back(); + c = cache.get(e->get_id(), nullptr); + if (c) { + todo.pop_back(); + continue; + } + if (!is_app(e)) { + cache.setx(e->get_id(), e); + todo.pop_back(); + continue; + } + args.reset(); + unsigned sz = todo.size(); + bool change = false; + for (expr* arg : *to_app(e)) { + c = cache.get(arg->get_id(), nullptr); + if (c) { + args.push_back(c); + change |= c != arg; + SASSERT(c->get_sort() == arg->get_sort()); + } + else + todo.push_back(arg); + } + if (sz == todo.size()) { + todo.pop_back(); + if (change) + cache.setx(e->get_id(), m_rewriter.mk_app(to_app(e)->get_decl(), args)); + else + cache.setx(e->get_id(), e); + SASSERT(e->get_sort() == cache.get(e->get_id())->get_sort()); + uint_set b; + if (m_boundaries.find(e, b)) { + expr* r = cache.get(e->get_id()); + expr_ref_vector xs(m); + unsigned lo = 0; + for (unsigned hi : b) { + xs.push_back(mk_extract(hi - 1, lo, r)); + lo = hi; + } + xs.push_back(mk_extract(m_bv.get_bv_size(r) - 1, lo, r)); + xs.reverse(); + expr_ref xc(m_bv.mk_concat(xs), m); + cache.setx(e->get_id(), xc); + SASSERT(e->get_sort() == xc->get_sort()); + } + } + } + c = cache.get(f->get_id()); + if (c != f) + m_fmls.update(i, dependent_expr(m, c, d)); + } + } + + void slice::get_concats(expr* x, ptr_vector& xs) { + while (m_bv.is_concat(x)) { + xs.append(to_app(x)->get_num_args(), to_app(x)->get_args()); + x = xs.back(); + xs.pop_back(); + } + xs.push_back(x); + } +} diff --git a/src/ast/simplifiers/bv_slice.h b/src/ast/simplifiers/bv_slice.h new file mode 100644 index 000000000..cc0f48cfc --- /dev/null +++ b/src/ast/simplifiers/bv_slice.h @@ -0,0 +1,55 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bv_slice.h + +Abstract: + + simplifier for extracting bit-vector ranges + It rewrites a state using bit-vector slices. + Slices are extracted from bit-vector equality assertions + in the style of (but not fully implementing a full slicing) + Bjorner & Pichora, TACAS 1998 and Brutomesso et al 2008. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + +#pragma once + +#include "util/uint_set.h" +#include "ast/bv_decl_plugin.h" +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" + + +namespace bv { + + class slice : public dependent_expr_simplifier { + bv_util m_bv; + th_rewriter m_rewriter; + obj_map m_boundaries; + ptr_vector m_xs, m_ys; + + expr* mk_extract(unsigned hi, unsigned lo, expr* x); + void process_eqs(); + void process_eq(expr* e); + void slice_eq(); + void register_slice(unsigned lo, unsigned hi, expr* x); + void apply_subst(); + void get_concats(expr* x, ptr_vector& xs); + + public: + + slice(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_bv(m), m_rewriter(m) {} + + void push() override { dependent_expr_simplifier::push(); } + void pop(unsigned n) override { dependent_expr_simplifier::pop(n); } + void reduce() override; + }; +} diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h new file mode 100644 index 000000000..9d6d8625e --- /dev/null +++ b/src/ast/simplifiers/dependent_expr.h @@ -0,0 +1,75 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + dependent_expr.h + +Abstract: + + Container class for dependent expressions. + They represent how assertions are tracked in goals. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ +#pragma once + +#include "ast/ast.h" + +class dependent_expr { + ast_manager& m; + expr* m_fml; + expr_dependency* m_dep; +public: + dependent_expr(ast_manager& m, expr* fml, expr_dependency* d): + m(m), + m_fml(fml), + m_dep(d) { + SASSERT(fml); + m.inc_ref(fml); + m.inc_ref(d); + } + + dependent_expr& operator=(dependent_expr const& other) { + SASSERT(&m == &other.m); + if (this != &other) { + m.inc_ref(other.m_fml); + m.inc_ref(other.m_dep); + m.dec_ref(m_fml); + m.dec_ref(m_dep); + m_fml = other.m_fml; + m_dep = other.m_dep; + } + return *this; + } + + dependent_expr(dependent_expr const& other): + m(other.m), + m_fml(other.m_fml), + m_dep(other.m_dep) { + m.inc_ref(m_fml); + m.inc_ref(m_dep); + } + + dependent_expr(dependent_expr && other) noexcept : + m(other.m), + m_fml(nullptr), + m_dep(nullptr) { + std::swap(m_fml, other.m_fml); + std::swap(m_dep, other.m_dep); + } + + ~dependent_expr() { + m.dec_ref(m_fml); + m.dec_ref(m_dep); + m_fml = nullptr; + m_dep = nullptr; + } + + std::tuple operator()() const { + return { m_fml, m_dep }; + } +}; diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h new file mode 100644 index 000000000..5156d1126 --- /dev/null +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -0,0 +1,86 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + dependent_expr_state.h + +Abstract: + + abstraction for simplification of depenent expression states. + A dependent_expr_state is an interface to a set of dependent expressions. + Dependent expressions are formulas together with a set of dependencies that are coarse grained + proof hints or justifications for them. Input assumptions can be self-justified. + + The dependent_expr_simplifier implements main services: + - push, pop - that scope the local state + - reduce - to process formulas in a dependent_expr_state between the current value of m_qhead and the size() + of the depdenent_expr_state + + A dependent expr_simplifier can be used to: + - to build a tactic + - for incremental pre-processing + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + +#pragma once + +#include "util/trail.h" +#include "util/statistics.h" +#include "util/params.h" +#include "ast/simplifiers/dependent_expr.h" + +/** + abstract interface to state updated by simplifiers. + */ +class dependent_expr_state { +public: + virtual unsigned size() const = 0; + virtual dependent_expr const& operator[](unsigned i) = 0; + virtual void update(unsigned i, dependent_expr const& j) = 0; + virtual bool inconsistent() = 0; +}; + +/** + Shared interface of simplifiers. + */ +class dependent_expr_simplifier { +protected: + ast_manager& m; + dependent_expr_state& m_fmls; + unsigned m_qhead = 0; // pointer into last processed formula in m_fmls + unsigned m_num_scopes = 0; + trail_stack m_trail; + void advance_qhead(unsigned sz) { if (m_num_scopes > 0) m_trail.push(value_trail(m_qhead)); m_qhead = sz; } +public: + dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s) {} + virtual ~dependent_expr_simplifier() {} + virtual void push() { m_num_scopes++; m_trail.push_scope(); } + virtual void pop(unsigned n) { m_num_scopes -= n; m_trail.pop_scope(n); } + virtual void reduce() = 0; + virtual void collect_statistics(statistics& st) const {} + virtual void reset_statistics() {} + virtual void updt_params(params_ref const& p) {} +}; + +/** + Factory interface for creating simplifiers. + The use of a factory allows delaying the creation of the dependent_expr_state + argument until the point where the expression simplifier is created. + This is used in tactics where the dependent_expr_state is a reference to the + new tactic. + + Alternatively have a clone method on dependent_expr_simplifier. + */ +class dependent_expr_simplifier_factory { + unsigned m_ref = 0; +public: + virtual dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) = 0; + virtual ~dependent_expr_simplifier_factory() {} + void inc_ref() { ++m_ref; } + void dec_ref() { if (--m_ref == 0) dealloc(this); } +}; diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp new file mode 100644 index 000000000..068f6598e --- /dev/null +++ b/src/ast/simplifiers/euf_completion.cpp @@ -0,0 +1,330 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + euf_completion.cpp + +Abstract: + + Ground completion for equalities + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +Notes: + +Create a congruence closure of E. +Select _simplest_ term in each equivalence class. A term is _simplest_ +if it is smallest in a well-order, such as a ground Knuth-Bendix order. +A basic approach is terms that are of smallest depth, are values can be chosen as simplest. +Ties between equal-depth terms can be resolved arbitrarily. + + +Algorithm for extracting canonical form from an E-graph: + +* Compute function canon(t) that maps every term in E to a canonical, least with respect to well-order relative to the congruence closure. + That is, terms that are equal modulo the congruence closure have the same canonical representative. + +* Each f(t) = g(s) in E: + * add f(canon(t)) = canon(f(t)), g(canon(s)) = canon(g(s)) where canon(f(t)) = canon(g(s)) by construction. + +* Each other g(t) in E: + * add g(canon(t)) to E. + * Note that canon(g(t)) = true because g(t) = true is added to congruence closure of E. +* We claim the new formula is equivalent. +* The dependencies for each rewrite can be computed by following the equality justification data-structure. + + +--*/ + +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/euf/euf_egraph.h" +#include "ast/simplifiers/euf_completion.h" + +namespace euf { + + completion::completion(ast_manager& m, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_egraph(m), + m_canonical(m), + m_eargs(m), + m_deps(m), + m_rewriter(m) { + m_tt = m_egraph.mk(m.mk_true(), 0, 0, nullptr); + m_ff = m_egraph.mk(m.mk_false(), 0, 0, nullptr); + } + + void completion::reduce() { + ++m_epoch; + add_egraph(); + map_canonical(); + read_egraph(); + } + + void completion::add_egraph() { + m_nodes.reset(); + unsigned sz = m_fmls.size(); + expr* x, *y; + for (unsigned i = m_qhead; i < sz; ++i) { + auto [f,d] = m_fmls[i](); + auto* n = mk_enode(f); + if (m.is_eq(f, x, y)) + m_egraph.merge(n->get_arg(0), n->get_arg(1), d); + if (m.is_not(f, x)) + m_egraph.merge(n->get_arg(0), m_ff, d); + else + m_egraph.merge(n, m_tt, d); + } + m_egraph.propagate(); + } + + void completion::read_egraph() { + + if (m_egraph.inconsistent()) { + auto* d = explain_conflict(); + dependent_expr de(m, m.mk_false(), d); + m_fmls.update(0, de); + return; + } + + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + auto [f, d] = m_fmls[i](); + auto* n = m_egraph.find(f); + SASSERT(n); + + expr_dependency_ref dep(d, m); + expr_ref g = canonize_fml(f, dep); + if (g != f) { + m_fmls.update(i, dependent_expr(m, g, dep)); + m_stats.m_num_rewrites++; + IF_VERBOSE(10, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); + } + CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); + } + advance_qhead(m_fmls.size()); + } + + enode* completion::mk_enode(expr* e) { + m_todo.push_back(e); + enode* n; + while (!m_todo.empty()) { + e = m_todo.back(); + if (m_egraph.find(e)) { + m_todo.pop_back(); + continue; + } + if (!is_app(e)) { + m_nodes.push_back(m_egraph.mk(e, 0, 0, nullptr)); + m_todo.pop_back(); + continue; + } + m_args.reset(); + unsigned sz = m_todo.size(); + for (expr* arg : *to_app(e)) { + n = m_egraph.find(arg); + if (n) + m_args.push_back(n); + else + m_todo.push_back(arg); + } + if (sz == m_todo.size()) { + m_nodes.push_back(m_egraph.mk(e, 0, m_args.size(), m_args.data())); + m_todo.pop_back(); + } + } + return m_egraph.find(e); + } + + expr_ref completion::canonize_fml(expr* f, expr_dependency_ref& d) { + + expr* x, * y; + if (m.is_eq(f, x, y)) { + expr_ref x1 = canonize(x, d); + expr_ref y1 = canonize(y, d); + + if (x == x1 && y == y1) + return expr_ref(f, m); + if (x1 == y1) + return expr_ref(m.mk_true(), m); + else { + expr* c = get_canonical(x, d); + if (c == x1) + return expr_ref(m.mk_eq(y1, c), m); + else if (c == y1) + return expr_ref(m.mk_eq(x1, c), m); + else + return expr_ref(m.mk_and(m.mk_eq(x1, c), m.mk_eq(y1, c)), m); + } + } + + if (m.is_not(f, x)) { + expr_ref x1 = canonize(x, d); + return expr_ref(mk_not(m, x1), m); + } + + return canonize(f, d); + } + + expr_ref completion::canonize(expr* f, expr_dependency_ref& d) { + if (!is_app(f)) + return expr_ref(f, m); // todo could normalize ground expressions under quantifiers + + m_eargs.reset(); + bool change = false; + for (expr* arg : *to_app(f)) { + m_eargs.push_back(get_canonical(arg, d)); + change = arg != m_eargs.back(); + } + + if (!change) + return expr_ref(f, m); + else + return expr_ref(m_rewriter.mk_app(to_app(f)->get_decl(), m_eargs.size(), m_eargs.data()), m); + } + + expr* completion::get_canonical(expr* f, expr_dependency_ref& d) { + enode* n = m_egraph.find(f); + enode* r = n->get_root(); + d = m.mk_join(d, explain_eq(n, r)); + d = m.mk_join(d, m_deps.get(r->get_id(), nullptr)); + return m_canonical.get(r->get_id()); + } + + expr* completion::get_canonical(enode* n) { + if (m_epochs.get(n->get_id(), 0) == m_epoch) + return m_canonical.get(n->get_id()); + else + return nullptr; + } + + void completion::set_canonical(enode* n, expr* e) { + class vtrail : public trail { + expr_ref_vector& c; + unsigned idx; + expr_ref old_value; + public: + vtrail(expr_ref_vector& c, unsigned idx) : + c(c), idx(idx), old_value(c.get(idx), c.m()) { + } + + void undo() override { + c[idx] = old_value; + old_value = nullptr; + } + }; + if (m_num_scopes > 0) + m_trail.push(vtrail(m_canonical, n->get_id())); + m_canonical.setx(n->get_id(), e); + m_epochs.setx(n->get_id(), m_epoch, 0); + } + + expr_dependency* completion::explain_eq(enode* a, enode* b) { + if (a == b) + return nullptr; + ptr_vector just; + m_egraph.begin_explain(); + m_egraph.explain_eq(just, nullptr, a, b); + m_egraph.end_explain(); + expr_dependency* d = nullptr; + for (expr_dependency* d2 : just) + d = m.mk_join(d, d2); + return d; + } + + expr_dependency* completion::explain_conflict() { + ptr_vector just; + m_egraph.begin_explain(); + m_egraph.explain(just, nullptr); + m_egraph.end_explain(); + expr_dependency* d = nullptr; + for (expr_dependency* d2 : just) + d = m.mk_join(d, d2); + return d; + } + + void completion::collect_statistics(statistics& st) const { + st.update("euf-completion-rewrites", m_stats.m_num_rewrites); + } + + void completion::map_canonical() { + m_todo.reset(); + enode_vector roots; + for (unsigned i = 0; i < m_nodes.size(); ++i) { + enode* n = m_nodes[i]->get_root(); + if (n->is_marked1()) + continue; + n->mark1(); + roots.push_back(n); + enode* rep = nullptr; + for (enode* k : enode_class(n)) + if (!rep || m.is_value(k->get_expr()) || get_depth(rep->get_expr()) > get_depth(k->get_expr())) + rep = k; + m_reps.setx(n->get_id(), rep, nullptr); + + TRACE("euf_completion", tout << "rep " << m_egraph.bpp(n) << " -> " << m_egraph.bpp(rep) << "\n"; + for (enode* k : enode_class(n)) tout << m_egraph.bpp(k) << "\n";); + m_todo.push_back(n->get_expr()); + for (enode* arg : enode_args(n)) { + arg = arg->get_root(); + if (!arg->is_marked1()) + m_nodes.push_back(arg); + } + } + for (enode* r : roots) + r->unmark1(); + + // explain dependencies when no nodes are marked. + // explain_eq uses both mark1 and mark2 on e-nodes so + // we cannot call it inside the previous loop where mark1 is used + // to track which roots have been processed. + for (enode* r : roots) { + enode* rep = m_reps[r->get_id()]; + auto* d = explain_eq(r, rep); + m_deps.setx(r->get_id(), d); + } + expr_ref new_expr(m); + while (!m_todo.empty()) { + expr* e = m_todo.back(); + enode* n = m_egraph.find(e); + SASSERT(n->is_root()); + enode* rep = m_reps[n->get_id()]; + if (get_canonical(n)) + m_todo.pop_back(); + else if (get_depth(rep->get_expr()) == 0 || !is_app(rep->get_expr())) { + set_canonical(n, rep->get_expr()); + m_todo.pop_back(); + } + else { + m_eargs.reset(); + unsigned sz = m_todo.size(); + bool new_arg = false; + expr_dependency* d = m_deps.get(n->get_id(), nullptr); + for (enode* arg : enode_args(rep)) { + enode* rarg = arg->get_root(); + expr* c = get_canonical(rarg); + if (c) { + m_eargs.push_back(c); + new_arg |= c != arg->get_expr(); + d = m.mk_join(d, m_deps.get(rarg->get_id(), nullptr)); + } + else + m_todo.push_back(rarg->get_expr()); + } + if (sz == m_todo.size()) { + m_todo.pop_back(); + if (new_arg) + new_expr = m_rewriter.mk_app(to_app(rep->get_expr())->get_decl(), m_eargs.size(), m_eargs.data()); + else + new_expr = rep->get_expr(); + set_canonical(n, new_expr); + m_deps.setx(n->get_id(), d); + } + } + } + } +} + + diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h new file mode 100644 index 000000000..9e293ca0e --- /dev/null +++ b/src/ast/simplifiers/euf_completion.h @@ -0,0 +1,63 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + euf_completion.h + +Abstract: + + Ground completion for equalities + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/euf/euf_egraph.h" +#include "ast/rewriter/th_rewriter.h" + +namespace euf { + + class completion : public dependent_expr_simplifier { + + struct stats { + unsigned m_num_rewrites = 0; + void reset() { memset(this, 0, sizeof(*this)); } + }; + + egraph m_egraph; + enode* m_tt, *m_ff; + ptr_vector m_todo; + enode_vector m_args, m_reps, m_nodes; + expr_ref_vector m_canonical, m_eargs; + expr_dependency_ref_vector m_deps; + unsigned m_epoch = 0; + unsigned_vector m_epochs; + th_rewriter m_rewriter; + stats m_stats; + + enode* mk_enode(expr* e); + void add_egraph(); + void map_canonical(); + void read_egraph(); + expr_ref canonize(expr* f, expr_dependency_ref& dep); + expr_ref canonize_fml(expr* f, expr_dependency_ref& dep); + expr* get_canonical(expr* f, expr_dependency_ref& d); + expr* get_canonical(enode* n); + void set_canonical(enode* n, expr* e); + expr_dependency* explain_eq(enode* a, enode* b); + expr_dependency* explain_conflict(); + public: + completion(ast_manager& m, dependent_expr_state& fmls); + void push() override { m_egraph.push(); dependent_expr_simplifier::push(); } + void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_egraph.pop(n); } + void reduce() override; + void collect_statistics(statistics& st) const override; + void reset_statistics() override { m_stats.reset(); } + }; +} diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index 114e4f849..b9b4394d9 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -17,6 +17,7 @@ z3_add_component(tactic COMPONENT_DEPENDENCIES ast model + simplifiers TACTIC_HEADERS probe.h tactic.h diff --git a/src/tactic/bv/CMakeLists.txt b/src/tactic/bv/CMakeLists.txt index e9f0927d5..653571265 100644 --- a/src/tactic/bv/CMakeLists.txt +++ b/src/tactic/bv/CMakeLists.txt @@ -8,6 +8,7 @@ z3_add_component(bv_tactics bv_bound_chk_tactic.cpp bv_bounds_tactic.cpp bv_size_reduction_tactic.cpp + bv_slice_tactic.cpp dt2bv_tactic.cpp elim_small_bv_tactic.cpp max_bv_sharing_tactic.cpp @@ -21,6 +22,7 @@ z3_add_component(bv_tactics bv_bound_chk_tactic.h bv_bounds_tactic.h bv_size_reduction_tactic.h + bv_slice_tactic.h bvarray2uf_tactic.h dt2bv_tactic.h elim_small_bv_tactic.h diff --git a/src/tactic/bv/bv_slice_tactic.h b/src/tactic/bv/bv_slice_tactic.h new file mode 100644 index 000000000..23ed16680 --- /dev/null +++ b/src/tactic/bv/bv_slice_tactic.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + bv_slice_tactic.h + +Abstract: + + Tactic for simplifying with bit-vector slices + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ +#pragma once + +#include "util/params.h" +class ast_manager; +class tactic; + +tactic * mk_bv_slice_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("bv-slice", "simplify using bit-vector slices.", "mk_bv_slice_tactic(m, p)") +*/ + + diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index a247c7b20..e57510d4f 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -10,6 +10,7 @@ z3_add_component(core_tactics dom_simplify_tactic.cpp elim_term_ite_tactic.cpp elim_uncnstr_tactic.cpp + euf_completion_tactic.cpp injectivity_tactic.cpp nnf_tactic.cpp occf_tactic.cpp @@ -38,6 +39,7 @@ z3_add_component(core_tactics dom_simplify_tactic.h elim_term_ite_tactic.h elim_uncnstr_tactic.h + euf_completion_tactic.h injectivity_tactic.h nnf_tactic.h occf_tactic.h diff --git a/src/tactic/core/euf_completion_tactic.cpp b/src/tactic/core/euf_completion_tactic.cpp new file mode 100644 index 000000000..bdd940f17 --- /dev/null +++ b/src/tactic/core/euf_completion_tactic.cpp @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + euf_completion_tactic.cpp + +Abstract: + + Tactic for simplifying with equations. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ + +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/euf_completion.h" +#include "tactic/core/euf_completion_tactic.h" + +class euf_completion_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(euf::completion, m, s); + } +}; + +tactic * mk_euf_completion_tactic(ast_manager& m, params_ref const& p) { + return alloc(dependent_expr_state_tactic, m, p, alloc(euf_completion_tactic_factory), "euf-completion"); +} diff --git a/src/tactic/core/euf_completion_tactic.h b/src/tactic/core/euf_completion_tactic.h new file mode 100644 index 000000000..36511bbe3 --- /dev/null +++ b/src/tactic/core/euf_completion_tactic.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + euf_completion_tactic.h + +Abstract: + + Tactic for simplifying with equations. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ +#pragma once + +#include "util/params.h" +class ast_manager; +class tactic; + +tactic * mk_euf_completion_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("euf-completion", "simplify using equalities.", "mk_euf_completion_tactic(m, p)") +*/ + + diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h new file mode 100644 index 000000000..c62125459 --- /dev/null +++ b/src/tactic/dependent_expr_state_tactic.h @@ -0,0 +1,101 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + dependent_expr_state_tactic.h + +Abstract: + + The dependent_expr_state_tactic creates a tactic from a dependent_expr_simplifier. + It relies on a factory for building simplifiers. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ +#include "tactic/tactic.h" +#include "ast/simplifiers/dependent_expr_state.h" + +class dependent_expr_state_tactic : public tactic, public dependent_expr_state { + ast_manager& m; + params_ref m_params; + std::string m_name; + ref m_factory; + scoped_ptr m_simp; + goal_ref m_goal; + dependent_expr m_dep; + + void init() { + if (!m_simp) + m_simp = m_factory->mk(m, m_params, *this); + } + +public: + + dependent_expr_state_tactic(ast_manager& m, params_ref const& p, dependent_expr_simplifier_factory* f, char const* name): + m(m), + m_params(p), + m_name(name), + m_factory(f), + m_simp(f->mk(m, p, *this)), + m_dep(m, m.mk_true(), nullptr) + {} + + /** + * size(), [](), update() and inconsisent() implement the abstract interface of dependent_expr_state + */ + unsigned size() const override { return m_goal->size(); } + + dependent_expr const& operator[](unsigned i) override { + m_dep = dependent_expr(m, m_goal->form(i), m_goal->dep(i)); + return m_dep; + } + void update(unsigned i, dependent_expr const& j) override { + auto [f, d] = j(); + m_goal->update(i, f, nullptr, d); + } + + bool inconsistent() override { + return m_goal->inconsistent(); + } + + char const* name() const override { return m_name.c_str(); } + + void updt_params(params_ref const & p) override { + m_params.append(p); + init(); + m_simp->updt_params(m_params); + } + + tactic * translate(ast_manager & m) override { + return alloc(dependent_expr_state_tactic, m, m_params, m_factory.get(), name()); + } + + void operator()(goal_ref const & in, + goal_ref_buffer & result) override { + if (in->proofs_enabled()) + throw tactic_exception("tactic does not support low level proofs"); + init(); + tactic_report report(name(), *in); + m_goal = in.get(); + m_simp->reduce(); + m_goal->inc_depth(); + result.push_back(in.get()); + } + + void cleanup() override { + } + + void collect_statistics(statistics & st) const override { + if (m_simp) + m_simp->collect_statistics(st); + } + + void reset_statistics() override { + if (m_simp) + m_simp->reset_statistics(); + } +}; + From 41b87b4c42382eedd96cc757a6bfcb9b6e3363f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 08:51:43 -0700 Subject: [PATCH 207/477] Create bv_slice_tactic.cpp missing file --- src/tactic/bv/bv_slice_tactic.cpp | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/tactic/bv/bv_slice_tactic.cpp diff --git a/src/tactic/bv/bv_slice_tactic.cpp b/src/tactic/bv/bv_slice_tactic.cpp new file mode 100644 index 000000000..040068e39 --- /dev/null +++ b/src/tactic/bv/bv_slice_tactic.cpp @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bv_slice_tactic.cpp + +Abstract: + + Tactic for simplifying with bit-vector slices + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ + +#include "ast/simplifiers/bv_slice.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "tactic/bv/bv_slice_tactic.h" + + +class bv_slice_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(bv::slice, m, s); + } +}; + +tactic* mk_bv_slice_tactic(ast_manager& m, params_ref const& p) { + return alloc(dependent_expr_state_tactic, m, p, alloc(bv_slice_factory), "bv-slice"); +} From 0d97d2214c53bb71d091b78455ad90304df9bcd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 09:37:55 -0700 Subject: [PATCH 208/477] adding virtual destructor Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/dependent_expr_state.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 5156d1126..e67aa56cc 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -39,6 +39,7 @@ Author: */ class dependent_expr_state { public: + virtual ~dependent_expr_state() {} virtual unsigned size() const = 0; virtual dependent_expr const& operator[](unsigned i) = 0; virtual void update(unsigned i, dependent_expr const& j) = 0; From ae707ffff7b3a4e4f33c4dae114362a2709d4376 Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Wed, 2 Nov 2022 18:02:29 +0100 Subject: [PATCH 209/477] Added 64-bit "1" counting (#6434) * Memory leak in .NET user-propagator The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically * Throw an exception if variable passed to decide is already assigned instead of running in an assertion violation * Added 64-bit "1" counting --- src/util/util.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/util/util.h b/src/util/util.h index f08558f37..9d129f9a7 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -103,6 +103,7 @@ unsigned uint64_log2(uint64_t v); static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits"); // Return the number of 1 bits in v. +// see e.g. http://en.wikipedia.org/wiki/Hamming_weight static inline unsigned get_num_1bits(unsigned v) { #ifdef __GNUC__ return __builtin_popcount(v); @@ -122,6 +123,25 @@ static inline unsigned get_num_1bits(unsigned v) { #endif } +static inline unsigned get_num_1bits(uint64_t v) { +#ifdef __GNUC__ + return __builtin_popcountll(v); +#else +#ifdef Z3DEBUG + unsigned c; + uint64_t v1 = v; + for (c = 0; v1; c++) { + v1 &= v1 - 1; + } +#endif + v = v - (v >> 1) & 0x5555555555555555; + v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333); + v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F; + uint64_t r = (v * 0x0101010101010101) >> 56; + SASSERT(c == r); +#endif +} + // Remark: on gcc, the operators << and >> do not produce zero when the second argument >= 64. // So, I'm using the following two definitions to fix the problem static inline uint64_t shift_right(uint64_t x, uint64_t y) { From df71e834280c493ec2d2cc2a621ad21435787736 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 17:32:09 -0700 Subject: [PATCH 210/477] remove incorrect assertion Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/euf_completion.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 068f6598e..e5b328d7f 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -92,8 +92,6 @@ namespace euf { for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { auto [f, d] = m_fmls[i](); - auto* n = m_egraph.find(f); - SASSERT(n); expr_dependency_ref dep(d, m); expr_ref g = canonize_fml(f, dep); From 6790f18132041040ffaa098b853afa57637c6ddf Mon Sep 17 00:00:00 2001 From: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Thu, 3 Nov 2022 11:34:52 +0100 Subject: [PATCH 211/477] Added limit to "visit" to allow detecting multiple visits (#6435) * Memory leak in .NET user-propagator The user-propagator object has to be manually disposed (IDisposable), otherwise it stays in memory forever, as it cannot be garbage collected automatically * Throw an exception if variable passed to decide is already assigned instead of running in an assertion violation * Added limit to "visit" to allow detecting multiple visits * Putting visit in a separate class (Reason: We will probably need two of them in the sat::solver) * Bugfix --- src/sat/sat_gc.cpp | 4 ++-- src/sat/sat_lut_finder.cpp | 12 ++++++------ src/sat/sat_solver.cpp | 32 +++++++------------------------ src/sat/sat_solver.h | 13 ++++--------- src/sat/sat_xor_finder.cpp | 12 ++++++------ src/sat/smt/pb_solver.cpp | 8 ++++---- src/util/visit_helper.h | 39 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 68 insertions(+), 52 deletions(-) create mode 100644 src/util/visit_helper.h diff --git a/src/sat/sat_gc.cpp b/src/sat/sat_gc.cpp index a655956db..69e91c745 100644 --- a/src/sat/sat_gc.cpp +++ b/src/sat/sat_gc.cpp @@ -406,9 +406,9 @@ namespace sat { auto gc_watch = [&](literal lit) { auto& wl1 = get_wlist(lit); for (auto w : get_wlist(lit)) { - if (w.is_binary_clause() && w.get_literal().var() < max_var && !is_visited(w.get_literal())) { + if (w.is_binary_clause() && w.get_literal().var() < max_var && !m_visited.is_visited(w.get_literal())) { m_aux_literals.push_back(w.get_literal()); - mark_visited(w.get_literal()); + m_visited.mark_visited(w.get_literal()); } } wl1.reset(); diff --git a/src/sat/sat_lut_finder.cpp b/src/sat/sat_lut_finder.cpp index 5459ab2a4..26ec80143 100644 --- a/src/sat/sat_lut_finder.cpp +++ b/src/sat/sat_lut_finder.cpp @@ -70,7 +70,7 @@ namespace sat { for (literal l : m_clause) { m_vars.push_back(l.var()); m_var_position[l.var()] = i; - s.mark_visited(l.var()); + s.m_visited.mark_visited(l.var()); mask |= (l.sign() << (i++)); } m_clauses_to_remove.reset(); @@ -91,7 +91,7 @@ namespace sat { // TBD: replace by BIG // loop over binary clauses in watch list for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_lut(~l, w.get_literal())) { add_lut(); return; @@ -100,7 +100,7 @@ namespace sat { } l.neg(); for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_lut(~l, w.get_literal())) { add_lut(); return; @@ -124,8 +124,8 @@ namespace sat { } bool lut_finder::extract_lut(literal l1, literal l2) { - SASSERT(s.is_visited(l1.var())); - SASSERT(s.is_visited(l2.var())); + SASSERT(s.m_visited.is_visited(l1.var())); + SASSERT(s.m_visited.is_visited(l2.var())); m_missing.reset(); unsigned mask = 0; for (unsigned i = 0; i < m_vars.size(); ++i) { @@ -144,7 +144,7 @@ namespace sat { bool lut_finder::extract_lut(clause& c2) { for (literal l : c2) { - if (!s.is_visited(l.var())) + if (!s.m_visited.is_visited(l.var())) return false; } if (c2.size() == m_vars.size()) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index eea3a2475..f97a08001 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3441,10 +3441,10 @@ namespace sat { for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; ) { clause_wrapper const& cw = m_clauses_to_reinit[i]; for (unsigned j = cw.size(); j-- > 0; ) - mark_visited(cw[j].var()); + m_visited.mark_visited(cw[j].var()); } for (literal lit : m_lemma) - mark_visited(lit.var()); + m_visited.mark_visited(lit.var()); auto is_active = [&](bool_var v) { return value(v) != l_undef && lvl(v) <= new_lvl; @@ -3452,7 +3452,7 @@ namespace sat { for (unsigned i = old_num_vars; i < sz; ++i) { bool_var v = m_active_vars[i]; - if (is_external(v) || is_visited(v) || is_active(v)) { + if (is_external(v) || m_visited.is_visited(v) || is_active(v)) { m_vars_to_reinit.push_back(v); m_active_vars[j++] = v; m_var_scope[v] = new_lvl; @@ -4697,10 +4697,10 @@ namespace sat { bool solver::all_distinct(literal_vector const& lits) { init_visited(); for (literal l : lits) { - if (is_visited(l.var())) { + if (m_visited.is_visited(l.var())) { return false; } - mark_visited(l.var()); + m_visited.mark_visited(l.var()); } return true; } @@ -4708,30 +4708,12 @@ namespace sat { bool solver::all_distinct(clause const& c) { init_visited(); for (literal l : c) { - if (is_visited(l.var())) { + if (m_visited.is_visited(l.var())) { return false; } - mark_visited(l.var()); + m_visited.mark_visited(l.var()); } return true; } - void solver::init_ts(unsigned n, svector& v, unsigned& ts) { - if (v.empty()) - ts = 0; - - ts++; - if (ts == 0) { - ts = 1; - v.reset(); - } - while (v.size() < n) - v.push_back(0); - } - - void solver::init_visited() { - init_ts(2 * num_vars(), m_visited, m_visited_ts); - } - - }; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 2e53e4620..b75950f88 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -28,6 +28,7 @@ Revision History: #include "util/rlimit.h" #include "util/scoped_ptr_vector.h" #include "util/scoped_limit_trail.h" +#include "util/visit_helper.h" #include "sat/sat_types.h" #include "sat/sat_clause.h" #include "sat/sat_watched.h" @@ -176,8 +177,7 @@ namespace sat { std::string m_reason_unknown; bool m_trim = false; - svector m_visited; - unsigned m_visited_ts; + visit_helper m_visited; struct scope { unsigned m_trail_lim; @@ -342,13 +342,8 @@ namespace sat { void detach_nary_clause(clause & c); void push_reinit_stack(clause & c); void push_reinit_stack(literal l1, literal l2); - - void init_ts(unsigned n, svector& v, unsigned& ts); - void init_visited(); - void mark_visited(literal l) { m_visited[l.index()] = m_visited_ts; } - void mark_visited(bool_var v) { mark_visited(literal(v, false)); } - bool is_visited(bool_var v) const { return is_visited(literal(v, false)); } - bool is_visited(literal l) const { return m_visited[l.index()] == m_visited_ts; } + + void init_visited(unsigned lim = 1) { m_visited.init_visited(num_vars(), lim); } bool all_distinct(literal_vector const& lits); bool all_distinct(clause const& cl); diff --git a/src/sat/sat_xor_finder.cpp b/src/sat/sat_xor_finder.cpp index dbe08d96c..0a20f4782 100644 --- a/src/sat/sat_xor_finder.cpp +++ b/src/sat/sat_xor_finder.cpp @@ -62,7 +62,7 @@ namespace sat { unsigned mask = 0, i = 0; for (literal l : c) { m_var_position[l.var()] = i; - s.mark_visited(l.var()); + s.m_visited.mark_visited(l.var()); parity ^= !l.sign(); mask |= (!l.sign() << (i++)); } @@ -84,7 +84,7 @@ namespace sat { } // loop over binary clauses in watch list for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_xor(parity, c, ~l, w.get_literal())) { add_xor(parity, c); return; @@ -93,7 +93,7 @@ namespace sat { } l.neg(); for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_xor(parity, c, ~l, w.get_literal())) { add_xor(parity, c); return; @@ -122,8 +122,8 @@ namespace sat { } bool xor_finder::extract_xor(bool parity, clause& c, literal l1, literal l2) { - SASSERT(s.is_visited(l1.var())); - SASSERT(s.is_visited(l2.var())); + SASSERT(s.m_visited.is_visited(l1.var())); + SASSERT(s.m_visited.is_visited(l2.var())); m_missing.reset(); unsigned mask = 0; for (unsigned i = 0; i < c.size(); ++i) { @@ -144,7 +144,7 @@ namespace sat { bool xor_finder::extract_xor(bool parity, clause& c, clause& c2) { bool parity2 = false; for (literal l : c2) { - if (!s.is_visited(l.var())) return false; + if (!s.m_visited.is_visited(l.var())) return false; parity2 ^= !l.sign(); } if (c2.size() == c.size() && parity2 != parity) { diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 424b20d4e..5b2d851d3 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -2709,10 +2709,10 @@ namespace pb { } void solver::init_visited() { s().init_visited(); } - void solver::mark_visited(literal l) { s().mark_visited(l); } - void solver::mark_visited(bool_var v) { s().mark_visited(v); } - bool solver::is_visited(bool_var v) const { return s().is_visited(v); } - bool solver::is_visited(literal l) const { return s().is_visited(l); } + void solver::mark_visited(literal l) { s().m_visited.mark_visited(l); } + void solver::mark_visited(bool_var v) { s().m_visited.mark_visited(v); } + bool solver::is_visited(bool_var v) const { return s().m_visited.is_visited(v); } + bool solver::is_visited(literal l) const { return s().m_visited.is_visited(l); } void solver::cleanup_clauses() { if (m_clause_removed) { diff --git a/src/util/visit_helper.h b/src/util/visit_helper.h new file mode 100644 index 000000000..1a0d4f5b9 --- /dev/null +++ b/src/util/visit_helper.h @@ -0,0 +1,39 @@ +#pragma once +#include "sat_literal.h" + +class visit_helper { + + unsigned_vector m_visited; + unsigned m_visited_begin = 0; + unsigned m_visited_end = 0; + + void init_ts(unsigned n, unsigned lim = 1) { + SASSERT(lim > 0); + if (m_visited_end >= m_visited_end + lim) { // overflow + m_visited_begin = 0; + m_visited_end = lim; + m_visited.reset(); + } + else { + m_visited_begin = m_visited_end; + m_visited_end = m_visited_end + lim; + } + while (m_visited.size() < n) + m_visited.push_back(0); + } + +public: + + void init_visited(unsigned num_vars, unsigned lim = 1) { + init_ts(2 * num_vars, lim); + } + void mark_visited(sat::literal l) { m_visited[l.index()] = m_visited_begin + 1; } + void mark_visited(sat::bool_var v) { mark_visited(sat::literal(v, false)); } + void inc_visited(sat::literal l) { + m_visited[l.index()] = std::min(m_visited_end, std::max(m_visited_begin, m_visited[l.index()]) + 1); + } + void inc_visited(sat::bool_var v) { inc_visited(sat::literal(v, false)); } + bool is_visited(sat::bool_var v) const { return is_visited(sat::literal(v, false)); } + bool is_visited(sat::literal l) const { return m_visited[l.index()] > m_visited_begin; } + unsigned num_visited(unsigned i) { return std::max(m_visited_begin, m_visited[i]) - m_visited_begin; } +}; \ No newline at end of file From e1417597688c8cd5057971316977db4841489b7d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 15:59:08 -0700 Subject: [PATCH 212/477] init solve_eqs --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/solve_eqs.cpp | 116 +++++++++++++++++++++++++++++ src/ast/simplifiers/solve_eqs.h | 75 +++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 src/ast/simplifiers/solve_eqs.cpp create mode 100644 src/ast/simplifiers/solve_eqs.h diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index 650410415..d07220fb5 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -2,6 +2,7 @@ z3_add_component(simplifiers SOURCES euf_completion.cpp bv_slice.cpp + solve_eqs.cpp COMPONENT_DEPENDENCIES euf rewriter diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp new file mode 100644 index 000000000..77808c142 --- /dev/null +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -0,0 +1,116 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + solve_eqs.cpp + +Abstract: + + simplifier for solving equations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + + +#include "ast/simplifiers/solve_eqs.h" + + +namespace euf { + + + void solve_eqs::init() { + + } + + // initialize graph that maps variable ids to next ids + void solve_eqs::extract_dep_graph(dep_eq_vector& eqs) { + m_var2id.reset(); + m_id2var.reset(); + m_next.reset(); + unsigned sz = 0; + for (auto const& [v, t, d] : eqs) + sz = std::max(sz, v->get_id()); + m_var2id.resize(sz + 1, UINT_MAX); + for (auto const& [v, t, d] : eqs) { + if (is_var(v)) + continue; + m_var2id[v->get_id()] = m_id2var.size(); + m_id2var.push_back(v); + } + m_next.resize(m_id2var.size()); + + for (auto const& [v, t, d] : eqs) + m_next[var2id(v)].push_back(t); + } + + void solve_eqs::add_subst(app* v, expr* term) { + + } + + /** + * Build a substitution while assigning levels to terms. + * The substitution is well-formed when variables are replaced with terms whose + * Free variables have higher levels. + */ + void solve_eqs::extract_subst() { + m_var2level.reset(); + m_var2level.resize(m_id2var.size(), UINT_MAX); + auto is_explored = [&](unsigned id) { + return m_var2level[id] != UINT_MAX; + }; + auto is_safe = [&](unsigned lvl, expr* t) { + for (auto* e : subterms::all(expr_ref(t, m))) + if (is_var(e) && m_var2level[var2id(e)] < lvl) + return false; + }; + + unsigned init_level = UINT_MAX; + for (unsigned id = 0; id < m_id2var.size(); ++id) { + if (is_explored(id)) + continue; + // initialize current level to have enough room to assign different levels to all variables. + init_level -= m_id2var.size() + 1; + unsigned curr_level = init_level; + todo.push_back(id); + while (!todo.empty()) { + unsigned j = todo.back(); + todo.pop_back(); + if (is_explored(j)) + continue; + m_var2level[id] = curr_level++; + for (expr* t : m_next[j]) { + if (!is_safe(curr_level, t)) + continue; + add_subst(m_id2var[j], t); + for (auto* e : subterms::all(expr_ref(t, m))) + if (is_var(e) && !is_explored(var2id(e))) + todo.push_back(var2id(e)); + break; + } + } + } + } + + void solve_eqs::extract_subst(dep_eq_vector& eqs, dep_eq_vector& subst) { + + } + + void solve_eqs::apply_subst() { + + } + + void solve_eqs::reduce() { + init(); + dep_eq_vector eqs, subst; + get_eqs(eqs); + extract_subst(eqs, subst); + apply_subst(); + advance_qhead(m_fmls.size()); + } + +} diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h new file mode 100644 index 000000000..936816bc4 --- /dev/null +++ b/src/ast/simplifiers/solve_eqs.h @@ -0,0 +1,75 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + solve_eqs.h + +Abstract: + + simplifier for solving equations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" + + +namespace euf { + + struct dependent_eq { + app* var; + expr_ref term; + expr_dependency* dep; + dependent_eq(app* var, expr_ref& term, expr_dependency* d) : var(var), term(term), dep(d) {} + }; + + typedef vector dep_eq_vector; + + class extract_eq { + pulic: + virtual ~extract_eq() {} + virtual void get_eqs(depdendent_expr const& e, dep_eq_vector& eqs) = 0; + }; + + class solve_eqs : public dependent_expr_simplifier { + th_rewriter m_rewriter; + scoped_ptr_vector m_extract_plugins; + unsigned_vector m_var2id; + ptr_vector m_id2var; + vector m_next; + + void init(); + + bool is_var(expr* v) const; + unsigned var2id(expr* v) const { return m_var2id[v->get_id()]; } + + void get_eqs(dep_eq_vector& eqs) { + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) + get_eqs(m_fmls[i](), eqs); + } + + void get_eqs(dependent_expr const& f, dep_eq_vector& eqs) { + for (auto* ex : m_extract_plugins) + ex->get_eqs(f, eqs); + } + + void extract_subst(dep_eq_vector& eqs, dep_eq_vector& subst); + void apply_subst(); + + public: + + solve_eqs(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_rewriter(m) {} + + void push() override { dependent_expr_simplifier::push(); } + void pop(unsigned n) override { dependent_expr_simplifier::pop(n); } + void reduce() override; + }; +} From c0f483528dd6ee2de51f02e5c4c0814552060d06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 17:31:25 -0700 Subject: [PATCH 213/477] working on solve_eqs --- src/ast/simplifiers/solve_eqs.cpp | 149 +++++++++++++++++++++++++----- src/ast/simplifiers/solve_eqs.h | 23 +++-- 2 files changed, 141 insertions(+), 31 deletions(-) diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 77808c142..a47a05cee 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -16,16 +16,69 @@ Author: --*/ - +#include "util/trace.h" +#include "ast/ast_util.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/solve_eqs.h" namespace euf { + class basic_extract_eq : public extract_eq { + ast_manager& m; + public: + basic_extract_eq(ast_manager& m) : m(m) {} + void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) { + auto [f, d] = e(); + expr* x, * y; + if (m.is_eq(f, x, y)) { + if (is_uninterp_const(x)) + eqs.push_back(dependent_eq(to_app(x), expr_ref(y, m), d)); + if (is_uninterp_const(y)) + eqs.push_back(dependent_eq(to_app(y), expr_ref(x, m), d)); + } + expr* c, * th, * el, * x1, * y1, * x2, * y2; + if (m.is_ite(f, c, th, el)) { + if (m.is_eq(th, x1, y1) && m.is_eq(el, x2, y2)) { + if (x1 == y2 && is_uninterp_const(x1)) + std::swap(x2, y2); + if (x2 == y2 && is_uninterp_const(x2)) + std::swap(x2, y2), std::swap(x1, y1); + if (x2 == y1 && is_uninterp_const(x2)) + std::swap(x1, y1); + if (x1 == x2 && is_uninterp_const(x1)) + eqs.push_back(dependent_eq(to_app(x1), expr_ref(m.mk_ite(c, y1, y2), m), d)); + } + } + if (is_uninterp_const(f)) + eqs.push_back(dependent_eq(to_app(f), expr_ref(m.mk_true(), m), d)); + if (m.is_not(f, x) && is_uninterp_const(x)) + eqs.push_back(dependent_eq(to_app(x), expr_ref(m.mk_false(), m), d)); + } + }; - void solve_eqs::init() { + class arith_extract_eq : public extract_eq { + ast_manager& m; + arith_util a; +#if 0 + void solve_eq(expr* f, expr_depedency* d) { - } + } +#endif + public: + arith_extract_eq(ast_manager& m) : m(m), a(m) {} + void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) { +#if 0 + auto [f, d] = e(); + expr* x, * y; + if (m.is_eq(f, x, y) && a.is_int_real(x)) + ; +#endif + } + }; // initialize graph that maps variable ids to next ids void solve_eqs::extract_dep_graph(dep_eq_vector& eqs) { @@ -44,12 +97,8 @@ namespace euf { } m_next.resize(m_id2var.size()); - for (auto const& [v, t, d] : eqs) - m_next[var2id(v)].push_back(t); - } - - void solve_eqs::add_subst(app* v, expr* term) { - + for (auto const& eq : eqs) + m_next[var2id(eq.var)].push_back(eq); } /** @@ -58,22 +107,30 @@ namespace euf { * Free variables have higher levels. */ void solve_eqs::extract_subst() { - m_var2level.reset(); - m_var2level.resize(m_id2var.size(), UINT_MAX); + m_id2level.reset(); + m_id2level.resize(m_id2var.size(), UINT_MAX); + m_subst_ids.reset(); + m_subst = alloc(expr_substitution, m, false, false); + auto is_explored = [&](unsigned id) { - return m_var2level[id] != UINT_MAX; + return m_id2level[id] != UINT_MAX; }; + auto is_safe = [&](unsigned lvl, expr* t) { for (auto* e : subterms::all(expr_ref(t, m))) - if (is_var(e) && m_var2level[var2id(e)] < lvl) + if (is_var(e) && m_id2level[var2id(e)] < lvl) return false; + return true; }; unsigned init_level = UINT_MAX; + unsigned_vector todo; for (unsigned id = 0; id < m_id2var.size(); ++id) { if (is_explored(id)) continue; // initialize current level to have enough room to assign different levels to all variables. + if (init_level < m_id2var.size() + 1) + return; init_level -= m_id2var.size() + 1; unsigned curr_level = init_level; todo.push_back(id); @@ -82,12 +139,14 @@ namespace euf { todo.pop_back(); if (is_explored(j)) continue; - m_var2level[id] = curr_level++; - for (expr* t : m_next[j]) { + m_id2level[id] = curr_level++; + for (auto const& eq : m_next[j]) { + auto const& [v, t, d] = eq; if (!is_safe(curr_level, t)) continue; - add_subst(m_id2var[j], t); - for (auto* e : subterms::all(expr_ref(t, m))) + m_next[j][0] = eq; + m_subst_ids.push_back(id); + for (expr* e : subterms::all(expr_ref(t, m))) if (is_var(e) && !is_explored(var2id(e))) todo.push_back(var2id(e)); break; @@ -96,19 +155,65 @@ namespace euf { } } - void solve_eqs::extract_subst(dep_eq_vector& eqs, dep_eq_vector& subst) { + void solve_eqs::add_subst(dependent_eq const& eq) { + m_subst->insert(eq.var, eq.term, nullptr, eq.dep); + } + void solve_eqs::normalize() { + scoped_ptr rp = mk_default_expr_replacer(m, true); + m_subst->reset(); + rp->set_substitution(m_subst.get()); + + std::sort(m_subst_ids.begin(), m_subst_ids.end(), [&](unsigned u, unsigned v) { return m_id2level[u] > m_id2level[v]; }); + + expr_dependency_ref new_dep(m); + expr_ref new_def(m); + proof_ref new_pr(m); + + for (unsigned id : m_subst_ids) { + // checkpoint(); + auto const& [v, def, dep] = m_next[id][0]; + rp->operator()(def, new_def, new_pr, new_dep); + // m_num_steps += rp->get_num_steps() + 1; + new_dep = m.mk_join(dep, new_dep); + m_subst->insert(v, new_def, new_pr, new_dep); + // we updated the substitution, but we don't need to reset rp + // because all cached values there do not depend on v. + } + + TRACE("solve_eqs", + tout << "after normalizing variables\n"; + for (unsigned id : m_subst_ids) { + auto const& eq = m_next[id][0]; + expr* def = nullptr; + proof* pr = nullptr; + expr_dependency* dep = nullptr; + m_subst->find(eq.var, def, pr, dep); + tout << mk_pp(eq.var, m) << "\n----->\n" << mk_pp(def, m) << "\n\n"; + }); } void solve_eqs::apply_subst() { - + scoped_ptr rp = mk_default_expr_replacer(m, true); + rp->set_substitution(m_subst.get()); + expr_ref new_f(m); + proof_ref new_pr(m); + expr_dependency_ref new_dep(m); + for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { + auto [f, d] = m_fmls[i](); + rp->operator()(f, new_f, new_pr, new_dep); + if (new_f == f) + continue; + new_dep = m.mk_join(d, new_dep); + m_fmls.update(i, dependent_expr(m, new_f, new_dep)); + } } void solve_eqs::reduce() { - init(); - dep_eq_vector eqs, subst; + dep_eq_vector eqs; get_eqs(eqs); - extract_subst(eqs, subst); + extract_dep_graph(eqs); + extract_subst(); apply_subst(); advance_qhead(m_fmls.size()); } diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 936816bc4..55cad7e67 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -20,6 +20,8 @@ Author: #include "ast/simplifiers/dependent_expr_state.h" #include "ast/rewriter/th_rewriter.h" +#include "ast/expr_substitution.h" +#include "util/scoped_ptr_vector.h" namespace euf { @@ -34,34 +36,37 @@ namespace euf { typedef vector dep_eq_vector; class extract_eq { - pulic: + public: virtual ~extract_eq() {} - virtual void get_eqs(depdendent_expr const& e, dep_eq_vector& eqs) = 0; + virtual void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) = 0; }; class solve_eqs : public dependent_expr_simplifier { th_rewriter m_rewriter; scoped_ptr_vector m_extract_plugins; - unsigned_vector m_var2id; + unsigned_vector m_var2id, m_id2level, m_subst_ids; ptr_vector m_id2var; - vector m_next; + vector m_next; + scoped_ptr m_subst; - void init(); + void add_subst(dependent_eq const& eq); - bool is_var(expr* v) const; + bool is_var(expr* e) const { return e->get_id() < m_var2id.size() && m_var2id[e->get_id()] != UINT_MAX; } unsigned var2id(expr* v) const { return m_var2id[v->get_id()]; } void get_eqs(dep_eq_vector& eqs) { for (unsigned i = m_qhead; i < m_fmls.size(); ++i) - get_eqs(m_fmls[i](), eqs); + get_eqs(m_fmls[i], eqs); } void get_eqs(dependent_expr const& f, dep_eq_vector& eqs) { - for (auto* ex : m_extract_plugins) + for (extract_eq* ex : m_extract_plugins) ex->get_eqs(f, eqs); } - void extract_subst(dep_eq_vector& eqs, dep_eq_vector& subst); + void extract_subst(); + void extract_dep_graph(dep_eq_vector& eqs); + void normalize(); void apply_subst(); public: From 6841ba3e57cc01839830025f53a3891cbe2928f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2022 20:14:49 -0700 Subject: [PATCH 214/477] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 17465d9ae..936f977aa 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,4 @@ CMakeSettings.json *.swp .DS_Store dbg/** +*.wsp From 070c5c624a7148aba6e5b56a1283984796dc5fab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 03:33:31 -0700 Subject: [PATCH 215/477] wip - converting the equation solver as a simplifier --- src/ast/arith_decl_plugin.h | 3 + src/ast/simplifiers/CMakeLists.txt | 3 +- src/ast/simplifiers/extract_eqs.cpp | 239 ++++++++++++++++++++++++++++ src/ast/simplifiers/extract_eqs.h | 47 ++++++ src/ast/simplifiers/solve_eqs.cpp | 74 +++------ src/ast/simplifiers/solve_eqs.h | 22 +-- 6 files changed, 316 insertions(+), 72 deletions(-) create mode 100644 src/ast/simplifiers/extract_eqs.cpp create mode 100644 src/ast/simplifiers/extract_eqs.h diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 781996662..0c77867d4 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -453,6 +453,9 @@ public: app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(arith_family_id, OP_MUL, arg1, arg2); } app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(arith_family_id, OP_MUL, arg1, arg2, arg3); } app * mk_mul(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(arith_family_id, OP_MUL, num_args, args); } + app * mk_mul(ptr_buffer const& args) const { return mk_mul(args.size(), args.data()); } + app * mk_mul(ptr_vector const& args) const { return mk_mul(args.size(), args.data()); } + app * mk_mul(expr_ref_vector const& args) const { return mk_mul(args.size(), args.data()); } app * mk_uminus(expr * arg) const { return m_manager.mk_app(arith_family_id, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(arith_family_id, OP_IDIV, arg1, arg2); } diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index d07220fb5..a260dd3b7 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -1,7 +1,8 @@ z3_add_component(simplifiers SOURCES - euf_completion.cpp bv_slice.cpp + euf_completion.cpp + extract_eqs.cpp solve_eqs.cpp COMPONENT_DEPENDENCIES euf diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp new file mode 100644 index 000000000..99be4268c --- /dev/null +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -0,0 +1,239 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + extract_eqs.cpp + +Abstract: + + simplifier for solving equations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + +#include "ast/ast_util.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/simplifiers/extract_eqs.h" + + +namespace euf { + + class basic_extract_eq : public extract_eq { + ast_manager& m; + + public: + basic_extract_eq(ast_manager& m) : m(m) {} + + void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { + auto [f, d] = e(); + expr* x, * y; + if (m.is_eq(f, x, y)) { + if (is_uninterp_const(x)) + eqs.push_back(dependent_eq(to_app(x), expr_ref(y, m), d)); + if (is_uninterp_const(y)) + eqs.push_back(dependent_eq(to_app(y), expr_ref(x, m), d)); + } + expr* c, * th, * el, * x1, * y1, * x2, * y2; + if (m.is_ite(f, c, th, el)) { + if (m.is_eq(th, x1, y1) && m.is_eq(el, x2, y2)) { + if (x1 == y2 && is_uninterp_const(x1)) + std::swap(x2, y2); + if (x2 == y2 && is_uninterp_const(x2)) + std::swap(x2, y2), std::swap(x1, y1); + if (x2 == y1 && is_uninterp_const(x2)) + std::swap(x1, y1); + if (x1 == x2 && is_uninterp_const(x1)) + eqs.push_back(dependent_eq(to_app(x1), expr_ref(m.mk_ite(c, y1, y2), m), d)); + } + } + if (is_uninterp_const(f)) + eqs.push_back(dependent_eq(to_app(f), expr_ref(m.mk_true(), m), d)); + if (m.is_not(f, x) && is_uninterp_const(x)) + eqs.push_back(dependent_eq(to_app(x), expr_ref(m.mk_false(), m), d)); + } + }; + + class arith_extract_eq : public extract_eq { + ast_manager& m; + arith_util a; + expr_ref_vector m_args; + expr_sparse_mark m_nonzero; + + + // solve u mod r1 = y -> u = r1*mod!1 + y + void solve_mod(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + expr* u, * z; + rational r1, r2; + if (!a.is_mod(x, u, z)) + return; + if (!a.is_numeral(z, r1)) + return; + if (r1 <= 0) + return; + expr_ref term(m); + term = a.mk_add(a.mk_mul(z, m.mk_fresh_const("mod", a.mk_int())), y); + solve_eq(u, term, d, eqs); + } + + /*** + * Solve + * x + Y = Z -> x = Z - Y + * -1*x + Y = Z -> x = Y - Z + * a*x + Y = Z -> x = (Z - Y)/a for is-real(x) + */ + void solve_add(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + if (!a.is_add(x)) + return; + expr* u, * z; + rational r; + expr_ref term(m); + unsigned i = 0; + auto mk_term = [&](unsigned i) { + term = y; + unsigned j = 0; + for (expr* arg2 : *to_app(x)) { + if (i != j) + term = a.mk_sub(term, arg2); + ++j; + } + }; + for (expr* arg : *to_app(x)) { + if (is_uninterp_const(arg)) { + mk_term(i); + eqs.push_back(dependent_eq(to_app(arg), term, d)); + } + else if (a.is_mul(arg, u, z) && a.is_numeral(u, r) && is_uninterp_const(z)) { + if (r == -1) { + mk_term(i); + term = a.mk_uminus(term); + eqs.push_back(dependent_eq(to_app(z), term, d)); + } + else if (a.is_real(arg) && r != 0) { + mk_term(i); + term = a.mk_div(term, u); + eqs.push_back(dependent_eq(to_app(z), term, d)); + } + } + else if (a.is_real(arg) && a.is_mul(arg)) { + unsigned j = 0; + for (expr* xarg : *to_app(arg)) { + ++j; + if (!is_uninterp_const(xarg)) + continue; + unsigned k = 0; + bool nonzero = true; + for (expr* yarg : *to_app(arg)) { + ++k; + nonzero = k == j || m_nonzero.is_marked(yarg) || (a.is_numeral(yarg, r) && r != 0); + if (!nonzero) + break; + } + if (!nonzero) + continue; + + k = 0; + ptr_buffer args; + for (expr* yarg : *to_app(arg)) { + ++k; + if (k != j) + args.push_back(yarg); + } + mk_term(i); + term = a.mk_div(term, a.mk_mul(args.size(), args.data())); + eqs.push_back(dependent_eq(to_app(xarg), term, d)); + } + } + ++i; + } + } + + /*** + * Solve for x * Y = Z, where Y != 0 -> x = Z / Y + */ + void solve_mul(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + if (!a.is_mul(x)) + return; + rational r; + expr_ref term(m); + unsigned i = 0; + for (expr* arg : *to_app(x)) { + ++i; + if (!is_uninterp_const(arg)) + continue; + unsigned j = 0; + bool nonzero = true; + for (expr* arg2 : *to_app(x)) { + ++j; + nonzero = j == i || m_nonzero.is_marked(arg2) || (a.is_numeral(arg2, r) && r != 0); + if (!nonzero) + break; + } + if (!nonzero) + continue; + ptr_buffer args; + j = 0; + for (expr* arg2 : *to_app(x)) { + ++j; + if (j != i) + args.push_back(arg2); + } + term = a.mk_div(y, a.mk_mul(args)); + eqs.push_back(dependent_eq(to_app(arg), term, d)); + } + } + + void add_pos(expr* f) { + expr* lhs = nullptr, * rhs = nullptr; + rational val; + if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_neg()) + m_nonzero.mark(lhs); + else if (a.is_ge(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_pos()) + m_nonzero.mark(lhs); + else if (m.is_not(f, f)) { + if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && !val.is_neg()) + m_nonzero.mark(lhs); + else if (a.is_ge(f, lhs, rhs) && a.is_numeral(rhs, val) && !val.is_pos()) + m_nonzero.mark(lhs); + else if (m.is_eq(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_zero()) + m_nonzero.mark(lhs); + } + } + + void solve_eq(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + solve_add(x, y, d, eqs); + solve_mod(x, y, d, eqs); + solve_mul(x, y, d, eqs); + } + + public: + arith_extract_eq(ast_manager& m) : m(m), a(m), m_args(m) {} + void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { + auto [f, d] = e(); + expr* x, * y; + if (m.is_eq(f, x, y) && a.is_int_real(x)) { + solve_eq(x, y, d, eqs); + solve_eq(y, x, d, eqs); + } + } + + void pre_process(dependent_expr_state& fmls) override { + m_nonzero.reset(); + for (unsigned i = 0; i < fmls.size(); ++i) { + auto [f, d] = fmls[i](); + add_pos(f); + } + } + }; + + void register_extract_eqs(ast_manager& m, scoped_ptr_vector& ex) { + ex.push_back(alloc(arith_extract_eq, m)); + ex.push_back(alloc(basic_extract_eq, m)); + } +} diff --git a/src/ast/simplifiers/extract_eqs.h b/src/ast/simplifiers/extract_eqs.h new file mode 100644 index 000000000..e6c81bb20 --- /dev/null +++ b/src/ast/simplifiers/extract_eqs.h @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + extract_eqs.h + +Abstract: + + simplifier for solving equations + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_substitution.h" +#include "util/scoped_ptr_vector.h" + + +namespace euf { + + struct dependent_eq { + app* var; + expr_ref term; + expr_dependency* dep; + dependent_eq(app* var, expr_ref& term, expr_dependency* d) : var(var), term(term), dep(d) {} + }; + + typedef vector dep_eq_vector; + + class extract_eq { + public: + virtual ~extract_eq() {} + virtual void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) = 0; + virtual void pre_process(dependent_expr_state& fmls) {} + }; + + void register_extract_eqs(ast_manager& m, scoped_ptr_vector& ex); + +} diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index a47a05cee..d9fbf9664 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -27,59 +27,6 @@ Author: namespace euf { - class basic_extract_eq : public extract_eq { - ast_manager& m; - public: - basic_extract_eq(ast_manager& m) : m(m) {} - void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) { - auto [f, d] = e(); - expr* x, * y; - if (m.is_eq(f, x, y)) { - if (is_uninterp_const(x)) - eqs.push_back(dependent_eq(to_app(x), expr_ref(y, m), d)); - if (is_uninterp_const(y)) - eqs.push_back(dependent_eq(to_app(y), expr_ref(x, m), d)); - } - expr* c, * th, * el, * x1, * y1, * x2, * y2; - if (m.is_ite(f, c, th, el)) { - if (m.is_eq(th, x1, y1) && m.is_eq(el, x2, y2)) { - if (x1 == y2 && is_uninterp_const(x1)) - std::swap(x2, y2); - if (x2 == y2 && is_uninterp_const(x2)) - std::swap(x2, y2), std::swap(x1, y1); - if (x2 == y1 && is_uninterp_const(x2)) - std::swap(x1, y1); - if (x1 == x2 && is_uninterp_const(x1)) - eqs.push_back(dependent_eq(to_app(x1), expr_ref(m.mk_ite(c, y1, y2), m), d)); - } - } - if (is_uninterp_const(f)) - eqs.push_back(dependent_eq(to_app(f), expr_ref(m.mk_true(), m), d)); - if (m.is_not(f, x) && is_uninterp_const(x)) - eqs.push_back(dependent_eq(to_app(x), expr_ref(m.mk_false(), m), d)); - } - }; - - class arith_extract_eq : public extract_eq { - ast_manager& m; - arith_util a; -#if 0 - void solve_eq(expr* f, expr_depedency* d) { - - } -#endif - public: - arith_extract_eq(ast_manager& m) : m(m), a(m) {} - void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) { -#if 0 - auto [f, d] = e(); - expr* x, * y; - if (m.is_eq(f, x, y) && a.is_int_real(x)) - ; -#endif - } - }; - // initialize graph that maps variable ids to next ids void solve_eqs::extract_dep_graph(dep_eq_vector& eqs) { m_var2id.reset(); @@ -210,6 +157,11 @@ namespace euf { } void solve_eqs::reduce() { + + for (extract_eq* ex : m_extract_plugins) + ex->pre_process(m_fmls); + + // TODO add a loop. dep_eq_vector eqs; get_eqs(eqs); extract_dep_graph(eqs); @@ -218,4 +170,20 @@ namespace euf { advance_qhead(m_fmls.size()); } + solve_eqs::solve_eqs(ast_manager& m, dependent_expr_state& fmls) : + dependent_expr_simplifier(m, fmls), m_rewriter(m) { + register_extract_eqs(m, m_extract_plugins); + } + + void solve_eqs::updt_params(params_ref const& p) { + // TODO +#if 0 + tactic_params tp(m_params); + m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); + m_theory_solver = p.get_bool("theory_solver", tp.solve_eqs_theory_solver()); + m_max_occs = p.get_uint("solve_eqs_max_occs", tp.solve_eqs_max_occs()); + m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); +#endif + } + } diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 55cad7e67..942498a52 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -18,29 +18,13 @@ Author: #pragma once -#include "ast/simplifiers/dependent_expr_state.h" #include "ast/rewriter/th_rewriter.h" #include "ast/expr_substitution.h" #include "util/scoped_ptr_vector.h" - +#include "ast/simplifiers/extract_eqs.h" namespace euf { - struct dependent_eq { - app* var; - expr_ref term; - expr_dependency* dep; - dependent_eq(app* var, expr_ref& term, expr_dependency* d) : var(var), term(term), dep(d) {} - }; - - typedef vector dep_eq_vector; - - class extract_eq { - public: - virtual ~extract_eq() {} - virtual void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) = 0; - }; - class solve_eqs : public dependent_expr_simplifier { th_rewriter m_rewriter; scoped_ptr_vector m_extract_plugins; @@ -71,10 +55,12 @@ namespace euf { public: - solve_eqs(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_rewriter(m) {} + solve_eqs(ast_manager& m, dependent_expr_state& fmls); void push() override { dependent_expr_simplifier::push(); } void pop(unsigned n) override { dependent_expr_simplifier::pop(n); } void reduce() override; + + void updt_params(params_ref const& p) override; }; } From 90490cb22f2600dd45826ba7070c97e091077298 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 03:54:39 -0700 Subject: [PATCH 216/477] make visited_helper independent of literals re-introduce shorthands in sat::solver for visited and have them convert literals to unsigned. --- src/sat/sat_gc.cpp | 4 ++-- src/sat/sat_lut_finder.cpp | 8 +++---- src/sat/sat_solver.cpp | 14 ++++++------ src/sat/sat_solver.h | 6 +++++- src/sat/sat_xor_finder.cpp | 8 +++---- src/sat/smt/pb_solver.cpp | 8 +++---- src/util/visit_helper.h | 44 +++++++++++++++++++++++--------------- 7 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/sat/sat_gc.cpp b/src/sat/sat_gc.cpp index 69e91c745..a655956db 100644 --- a/src/sat/sat_gc.cpp +++ b/src/sat/sat_gc.cpp @@ -406,9 +406,9 @@ namespace sat { auto gc_watch = [&](literal lit) { auto& wl1 = get_wlist(lit); for (auto w : get_wlist(lit)) { - if (w.is_binary_clause() && w.get_literal().var() < max_var && !m_visited.is_visited(w.get_literal())) { + if (w.is_binary_clause() && w.get_literal().var() < max_var && !is_visited(w.get_literal())) { m_aux_literals.push_back(w.get_literal()); - m_visited.mark_visited(w.get_literal()); + mark_visited(w.get_literal()); } } wl1.reset(); diff --git a/src/sat/sat_lut_finder.cpp b/src/sat/sat_lut_finder.cpp index 26ec80143..60143f91c 100644 --- a/src/sat/sat_lut_finder.cpp +++ b/src/sat/sat_lut_finder.cpp @@ -70,7 +70,7 @@ namespace sat { for (literal l : m_clause) { m_vars.push_back(l.var()); m_var_position[l.var()] = i; - s.m_visited.mark_visited(l.var()); + s.mark_visited(l.var()); mask |= (l.sign() << (i++)); } m_clauses_to_remove.reset(); @@ -91,7 +91,7 @@ namespace sat { // TBD: replace by BIG // loop over binary clauses in watch list for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_lut(~l, w.get_literal())) { add_lut(); return; @@ -100,7 +100,7 @@ namespace sat { } l.neg(); for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_lut(~l, w.get_literal())) { add_lut(); return; @@ -144,7 +144,7 @@ namespace sat { bool lut_finder::extract_lut(clause& c2) { for (literal l : c2) { - if (!s.m_visited.is_visited(l.var())) + if (!s.is_visited(l.var())) return false; } if (c2.size() == m_vars.size()) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f97a08001..14e7e9775 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3441,10 +3441,10 @@ namespace sat { for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; ) { clause_wrapper const& cw = m_clauses_to_reinit[i]; for (unsigned j = cw.size(); j-- > 0; ) - m_visited.mark_visited(cw[j].var()); + mark_visited(cw[j].var()); } for (literal lit : m_lemma) - m_visited.mark_visited(lit.var()); + mark_visited(lit.var()); auto is_active = [&](bool_var v) { return value(v) != l_undef && lvl(v) <= new_lvl; @@ -3452,7 +3452,7 @@ namespace sat { for (unsigned i = old_num_vars; i < sz; ++i) { bool_var v = m_active_vars[i]; - if (is_external(v) || m_visited.is_visited(v) || is_active(v)) { + if (is_external(v) || is_visited(v) || is_active(v)) { m_vars_to_reinit.push_back(v); m_active_vars[j++] = v; m_var_scope[v] = new_lvl; @@ -4697,10 +4697,10 @@ namespace sat { bool solver::all_distinct(literal_vector const& lits) { init_visited(); for (literal l : lits) { - if (m_visited.is_visited(l.var())) { + if (is_visited(l.var())) { return false; } - m_visited.mark_visited(l.var()); + mark_visited(l.var()); } return true; } @@ -4708,10 +4708,10 @@ namespace sat { bool solver::all_distinct(clause const& c) { init_visited(); for (literal l : c) { - if (m_visited.is_visited(l.var())) { + if (is_visited(l.var())) { return false; } - m_visited.mark_visited(l.var()); + mark_visited(l.var()); } return true; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b75950f88..982a84307 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -343,7 +343,11 @@ namespace sat { void push_reinit_stack(clause & c); void push_reinit_stack(literal l1, literal l2); - void init_visited(unsigned lim = 1) { m_visited.init_visited(num_vars(), lim); } + void init_visited(unsigned lim = 1) { m_visited.init_visited(2 * num_vars(), lim); } + bool is_visited(sat::bool_var v) const { return is_visited(literal(v, false)); } + bool is_visited(literal lit) const { return m_visited.is_visited(lit.index()); } + void mark_visited(literal lit) { m_visited.mark_visited(lit.index()); } + void mark_visited(bool_var v) { mark_visited(literal(v, false)); } bool all_distinct(literal_vector const& lits); bool all_distinct(clause const& cl); diff --git a/src/sat/sat_xor_finder.cpp b/src/sat/sat_xor_finder.cpp index 0a20f4782..a34d1b7ad 100644 --- a/src/sat/sat_xor_finder.cpp +++ b/src/sat/sat_xor_finder.cpp @@ -62,7 +62,7 @@ namespace sat { unsigned mask = 0, i = 0; for (literal l : c) { m_var_position[l.var()] = i; - s.m_visited.mark_visited(l.var()); + s.mark_visited(l.var()); parity ^= !l.sign(); mask |= (!l.sign() << (i++)); } @@ -84,7 +84,7 @@ namespace sat { } // loop over binary clauses in watch list for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_xor(parity, c, ~l, w.get_literal())) { add_xor(parity, c); return; @@ -93,7 +93,7 @@ namespace sat { } l.neg(); for (watched const & w : s.get_wlist(l)) { - if (w.is_binary_clause() && s.m_visited.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { + if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) { if (extract_xor(parity, c, ~l, w.get_literal())) { add_xor(parity, c); return; @@ -144,7 +144,7 @@ namespace sat { bool xor_finder::extract_xor(bool parity, clause& c, clause& c2) { bool parity2 = false; for (literal l : c2) { - if (!s.m_visited.is_visited(l.var())) return false; + if (!s.is_visited(l.var())) return false; parity2 ^= !l.sign(); } if (c2.size() == c.size() && parity2 != parity) { diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 5b2d851d3..424b20d4e 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -2709,10 +2709,10 @@ namespace pb { } void solver::init_visited() { s().init_visited(); } - void solver::mark_visited(literal l) { s().m_visited.mark_visited(l); } - void solver::mark_visited(bool_var v) { s().m_visited.mark_visited(v); } - bool solver::is_visited(bool_var v) const { return s().m_visited.is_visited(v); } - bool solver::is_visited(literal l) const { return s().m_visited.is_visited(l); } + void solver::mark_visited(literal l) { s().mark_visited(l); } + void solver::mark_visited(bool_var v) { s().mark_visited(v); } + bool solver::is_visited(bool_var v) const { return s().is_visited(v); } + bool solver::is_visited(literal l) const { return s().is_visited(l); } void solver::cleanup_clauses() { if (m_clause_removed) { diff --git a/src/util/visit_helper.h b/src/util/visit_helper.h index 1a0d4f5b9..a11d7bdc6 100644 --- a/src/util/visit_helper.h +++ b/src/util/visit_helper.h @@ -1,5 +1,21 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + visit_helper.h + +Abstract: + + Routine for marking and counting visited occurrences + +Author: + + Clemens Eisenhofer 2022-11-03 + +--*/ #pragma once -#include "sat_literal.h" + class visit_helper { @@ -7,7 +23,9 @@ class visit_helper { unsigned m_visited_begin = 0; unsigned m_visited_end = 0; - void init_ts(unsigned n, unsigned lim = 1) { +public: + + void init_visited(unsigned n, unsigned lim = 1) { SASSERT(lim > 0); if (m_visited_end >= m_visited_end + lim) { // overflow m_visited_begin = 0; @@ -18,22 +36,14 @@ class visit_helper { m_visited_begin = m_visited_end; m_visited_end = m_visited_end + lim; } - while (m_visited.size() < n) - m_visited.push_back(0); + while (m_visited.size() < n) + m_visited.push_back(0); } -public: - - void init_visited(unsigned num_vars, unsigned lim = 1) { - init_ts(2 * num_vars, lim); + void mark_visited(unsigned v) { m_visited[v] = m_visited_begin + 1; } + void inc_visited(unsigned v) { + m_visited[v] = std::min(m_visited_end, std::max(m_visited_begin, m_visited[v]) + 1); } - void mark_visited(sat::literal l) { m_visited[l.index()] = m_visited_begin + 1; } - void mark_visited(sat::bool_var v) { mark_visited(sat::literal(v, false)); } - void inc_visited(sat::literal l) { - m_visited[l.index()] = std::min(m_visited_end, std::max(m_visited_begin, m_visited[l.index()]) + 1); - } - void inc_visited(sat::bool_var v) { inc_visited(sat::literal(v, false)); } - bool is_visited(sat::bool_var v) const { return is_visited(sat::literal(v, false)); } - bool is_visited(sat::literal l) const { return m_visited[l.index()] > m_visited_begin; } - unsigned num_visited(unsigned i) { return std::max(m_visited_begin, m_visited[i]) - m_visited_begin; } + bool is_visited(unsigned v) const { return m_visited[v] > m_visited_begin; } + unsigned num_visited(unsigned v) { return std::max(m_visited_begin, m_visited[v]) - m_visited_begin; } }; \ No newline at end of file From 7b12a5c5a8b2ace6551fe084c0b766bab52e40b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 04:49:20 -0700 Subject: [PATCH 217/477] build fix --- src/ast/expr_substitution.h | 1 + src/ast/simplifiers/extract_eqs.h | 2 +- src/ast/simplifiers/solve_eqs.cpp | 35 ++++++++++++++++++++++++---- src/ast/simplifiers/solve_eqs.h | 13 +++++++++++ src/tactic/core/solve_eqs_tactic.cpp | 10 ++------ 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index bbd1c0e8e..6d4b1b618 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -45,6 +45,7 @@ public: unsigned size() const { return m_subst.size(); } void insert(expr * s, expr * def, proof * def_pr = nullptr, expr_dependency * def_dep = nullptr); void erase(expr * s); + expr* find(expr* s) { proof* pr; expr* def; VERIFY(find(s, def, pr)); SASSERT(def); return def; } bool find(expr * s, expr * & def, proof * & def_pr); bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep); bool contains(expr * s); diff --git a/src/ast/simplifiers/extract_eqs.h b/src/ast/simplifiers/extract_eqs.h index e6c81bb20..29c136028 100644 --- a/src/ast/simplifiers/extract_eqs.h +++ b/src/ast/simplifiers/extract_eqs.h @@ -30,7 +30,7 @@ namespace euf { app* var; expr_ref term; expr_dependency* dep; - dependent_eq(app* var, expr_ref& term, expr_dependency* d) : var(var), term(term), dep(d) {} + dependent_eq(app* var, expr_ref const& term, expr_dependency* d) : var(var), term(term), dep(d) {} }; typedef vector dep_eq_vector; diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index d9fbf9664..38100fcdc 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -20,7 +20,7 @@ Author: #include "ast/ast_util.h" #include "ast/for_each_expr.h" #include "ast/ast_pp.h" -#include "ast/arith_decl_plugin.h" +#include "ast/recfun_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/solve_eqs.h" @@ -37,7 +37,7 @@ namespace euf { sz = std::max(sz, v->get_id()); m_var2id.resize(sz + 1, UINT_MAX); for (auto const& [v, t, d] : eqs) { - if (is_var(v)) + if (is_var(v) || !can_be_var(v)) continue; m_var2id[v->get_id()] = m_id2var.size(); m_id2var.push_back(v); @@ -103,7 +103,9 @@ namespace euf { } void solve_eqs::add_subst(dependent_eq const& eq) { + SASSERT(can_be_var(eq.var)); m_subst->insert(eq.var, eq.term, nullptr, eq.dep); + ++m_stats.m_num_elim_vars; } void solve_eqs::normalize() { @@ -118,10 +120,11 @@ namespace euf { proof_ref new_pr(m); for (unsigned id : m_subst_ids) { - // checkpoint(); + if (!m.inc()) + break; auto const& [v, def, dep] = m_next[id][0]; rp->operator()(def, new_def, new_pr, new_dep); - // m_num_steps += rp->get_num_steps() + 1; + m_stats.m_num_steps += rp->get_num_steps() + 1; new_dep = m.mk_join(dep, new_dep); m_subst->insert(v, new_def, new_pr, new_dep); // we updated the substitution, but we don't need to reset rp @@ -141,6 +144,8 @@ namespace euf { } void solve_eqs::apply_subst() { + if (!m.inc()) + return; scoped_ptr rp = mk_default_expr_replacer(m, true); rp->set_substitution(m_subst.get()); expr_ref new_f(m); @@ -170,6 +175,23 @@ namespace euf { advance_qhead(m_fmls.size()); } + void solve_eqs::filter_unsafe_vars() { + m_unsafe_vars.reset(); + recfun::util rec(m); + for (func_decl* f : rec.get_rec_funs()) + for (expr* term : subterms::all(expr_ref(rec.get_def(f).get_rhs(), m))) + m_unsafe_vars.mark(term); + } + +#if 0 + model_converter_ref solve_eqs::get_model_converter() { + model_converter_ref mc = alloc(gmc, m, "solve-eqs"); + for (unsigned id : m_subst_ids) + static_cast(mc.get())->add(id2var(id), m_subst->find(v)); + return mc; + } +#endif + solve_eqs::solve_eqs(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_rewriter(m) { register_extract_eqs(m, m_extract_plugins); @@ -186,4 +208,9 @@ namespace euf { #endif } + void solve_eqs::collect_statistics(statistics& st) const { + st.update("solve-eqs-steps", m_stats.m_num_steps); + st.update("solve-eqs-elim-vars", m_stats.m_num_elim_vars); + } + } diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 942498a52..62f24413a 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -26,6 +26,11 @@ Author: namespace euf { class solve_eqs : public dependent_expr_simplifier { + struct stats { + unsigned m_num_steps = 0; + unsigned m_num_elim_vars = 0; + }; + th_rewriter m_rewriter; scoped_ptr_vector m_extract_plugins; unsigned_vector m_var2id, m_id2level, m_subst_ids; @@ -33,6 +38,9 @@ namespace euf { vector m_next; scoped_ptr m_subst; + expr_mark m_unsafe_vars; // expressions that cannot be replaced + stats m_stats; + void add_subst(dependent_eq const& eq); bool is_var(expr* e) const { return e->get_id() < m_var2id.size() && m_var2id[e->get_id()] != UINT_MAX; } @@ -48,6 +56,8 @@ namespace euf { ex->get_eqs(f, eqs); } + void filter_unsafe_vars(); + bool can_be_var(expr* e) const { return is_uninterp_const(e) && !m_unsafe_vars.is_marked(e); } void extract_subst(); void extract_dep_graph(dep_eq_vector& eqs); void normalize(); @@ -62,5 +72,8 @@ namespace euf { void reduce() override; void updt_params(params_ref const& p) override; + void collect_statistics(statistics& st) const override; + + // model_converter_ref get_model_converter(); }; } diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 5a076aa0f..0a0525e70 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -977,14 +977,8 @@ class solve_eqs_tactic : public tactic { if (m_produce_models) { if (!mc.get()) mc = alloc(gmc, m(), "solve-eqs"); - for (app* v : m_ordered_vars) { - expr * def = nullptr; - proof * pr; - expr_dependency * dep = nullptr; - m_norm_subst->find(v, def, pr, dep); - SASSERT(def); - static_cast(mc.get())->add(v, def); - } + for (app* v : m_ordered_vars) + static_cast(mc.get())->add(v, m_norm_subst->find(v)); } } From 1dca6402fba7ddb1ed1df914f7f6252c9cd2900a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 05:23:01 -0700 Subject: [PATCH 218/477] move model and proof converters to self-contained module --- src/CMakeLists.txt | 1 + .../ackermannize_bv_model_converter.h | 2 +- src/ackermannization/ackr_model_converter.h | 2 +- .../lackr_model_converter_lazy.h | 2 +- src/ast/converters/CMakeLists.txt | 8 +++ src/{tactic => ast/converters}/converter.h | 0 .../converters}/generic_model_converter.cpp | 2 +- .../converters}/generic_model_converter.h | 2 +- .../converters}/model_converter.cpp | 2 +- .../converters}/model_converter.h | 2 +- .../converters}/proof_converter.cpp | 38 +---------- .../converters}/proof_converter.h | 9 +-- src/ast/simplifiers/dependent_expr_state.h | 2 + src/ast/simplifiers/solve_eqs.cpp | 11 ++-- src/ast/simplifiers/solve_eqs.h | 6 +- src/cmd_context/cmd_context.cpp | 2 +- src/cmd_context/cmd_context.h | 2 +- src/muz/base/dl_context.h | 2 +- src/muz/base/dl_rule.cpp | 2 +- src/muz/base/dl_rule.h | 4 +- src/muz/base/hnf.h | 2 +- src/muz/fp/horn_tactic.cpp | 6 +- src/muz/spacer/spacer_manager.cpp | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 2 +- src/muz/transforms/dl_mk_coi_filter.cpp | 2 +- .../transforms/dl_mk_subsumption_checker.cpp | 2 +- src/nlsat/tactic/goal2nlsat.h | 2 +- src/opt/opt_context.cpp | 2 +- src/opt/opt_context.h | 2 +- src/opt/opt_solver.h | 2 +- src/opt/sortmax.cpp | 2 +- src/qe/qsat.h | 2 +- src/sat/smt/euf_solver.h | 2 +- src/sat/tactic/goal2sat.cpp | 2 +- src/sat/tactic/sat2goal.cpp | 2 +- src/sat/tactic/sat2goal.h | 2 +- src/smt/tactic/smt_tactic_core.cpp | 2 +- src/smt/theory_arith_aux.h | 2 +- src/smt/theory_lra.cpp | 2 +- src/smt/theory_wmaxsat.h | 2 +- src/solver/check_sat_result.h | 2 +- src/solver/solver.cpp | 2 +- src/solver/solver2tactic.cpp | 2 +- src/solver/solver2tactic.h | 2 +- src/tactic/CMakeLists.txt | 4 +- src/tactic/arith/card2bv_tactic.cpp | 2 +- src/tactic/arith/degree_shift_tactic.cpp | 2 +- src/tactic/arith/fix_dl_var_tactic.cpp | 2 +- src/tactic/arith/lia2card_tactic.cpp | 2 +- src/tactic/arith/lia2pb_tactic.cpp | 2 +- src/tactic/arith/nla2bv_tactic.cpp | 2 +- src/tactic/arith/normalize_bounds_tactic.cpp | 2 +- src/tactic/arith/pb2bv_model_converter.h | 2 +- src/tactic/arith/pb2bv_tactic.cpp | 2 +- src/tactic/arith/purify_arith_tactic.cpp | 2 +- src/tactic/arith/recover_01_tactic.cpp | 2 +- src/tactic/bv/bit_blaster_model_converter.cpp | 2 +- src/tactic/bv/bit_blaster_model_converter.h | 2 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 2 +- src/tactic/bv/bvarray2uf_rewriter.h | 2 +- src/tactic/bv/bvarray2uf_tactic.cpp | 2 +- src/tactic/bv/dt2bv_tactic.cpp | 2 +- src/tactic/bv/elim_small_bv_tactic.cpp | 2 +- src/tactic/core/elim_term_ite_tactic.cpp | 2 +- src/tactic/core/elim_uncnstr_tactic.cpp | 2 +- src/tactic/core/nnf_tactic.cpp | 2 +- src/tactic/core/occf_tactic.cpp | 2 +- src/tactic/core/pb_preprocess_tactic.cpp | 2 +- src/tactic/core/reduce_args_tactic.cpp | 2 +- src/tactic/core/reduce_invertible_tactic.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 2 +- src/tactic/core/split_clause_tactic.cpp | 1 + src/tactic/core/tseitin_cnf_tactic.cpp | 2 +- src/tactic/dependency_converter.h | 2 +- src/tactic/dependent_expr_state_tactic.h | 2 + .../fd_solver/bounded_int2bv_solver.cpp | 2 +- src/tactic/fd_solver/enum2bv_solver.cpp | 2 +- src/tactic/fd_solver/pb2bv_solver.cpp | 2 +- src/tactic/fpa/fpa2bv_model_converter.h | 2 +- src/tactic/goal.h | 4 +- src/tactic/goal_proof_converter.h | 63 +++++++++++++++++++ src/tactic/horn_subsume_model_converter.h | 2 +- src/tactic/replace_proof_converter.h | 2 +- src/tactic/sls/sls_engine.h | 2 +- .../smtlogics/qfufbv_ackr_model_converter.h | 2 +- src/tactic/tactical.cpp | 1 + src/tactic/ufbv/macro_finder_tactic.cpp | 2 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 2 +- 88 files changed, 170 insertions(+), 134 deletions(-) create mode 100644 src/ast/converters/CMakeLists.txt rename src/{tactic => ast/converters}/converter.h (100%) rename src/{tactic => ast/converters}/generic_model_converter.cpp (99%) rename src/{tactic => ast/converters}/generic_model_converter.h (97%) rename src/{tactic => ast/converters}/model_converter.cpp (99%) rename src/{tactic => ast/converters}/model_converter.h (98%) rename src/{tactic => ast/converters}/proof_converter.cpp (68%) rename src/{tactic => ast/converters}/proof_converter.h (78%) create mode 100644 src/tactic/goal_proof_converter.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad6fbcdb2..fd4fa04b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,7 @@ add_subdirectory(ast/normal_forms) add_subdirectory(ast/macros) add_subdirectory(model) add_subdirectory(ast/euf) +add_subdirectory(ast/converters) add_subdirectory(ast/simplifiers) add_subdirectory(tactic) add_subdirectory(ast/substitution) diff --git a/src/ackermannization/ackermannize_bv_model_converter.h b/src/ackermannization/ackermannize_bv_model_converter.h index 59dff3ed2..759ec3c13 100644 --- a/src/ackermannization/ackermannize_bv_model_converter.h +++ b/src/ackermannization/ackermannize_bv_model_converter.h @@ -16,7 +16,7 @@ --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ackermannization/ackr_info.h" model_converter * mk_ackermannize_bv_model_converter(ast_manager & m, const ackr_info_ref& info); diff --git a/src/ackermannization/ackr_model_converter.h b/src/ackermannization/ackr_model_converter.h index 8fc8edecc..df134f227 100644 --- a/src/ackermannization/ackr_model_converter.h +++ b/src/ackermannization/ackr_model_converter.h @@ -15,7 +15,7 @@ Revision History: --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ackermannization/ackr_info.h" model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref & info, model_ref & abstr_model); diff --git a/src/ackermannization/lackr_model_converter_lazy.h b/src/ackermannization/lackr_model_converter_lazy.h index 9a713753b..a16722356 100644 --- a/src/ackermannization/lackr_model_converter_lazy.h +++ b/src/ackermannization/lackr_model_converter_lazy.h @@ -16,7 +16,7 @@ --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ackermannization/ackr_info.h" model_converter * mk_lackr_model_converter_lazy(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model); diff --git a/src/ast/converters/CMakeLists.txt b/src/ast/converters/CMakeLists.txt new file mode 100644 index 000000000..c11b0dbe1 --- /dev/null +++ b/src/ast/converters/CMakeLists.txt @@ -0,0 +1,8 @@ +z3_add_component(converters + SOURCES + model_converter.cpp + proof_converter.cpp + generic_model_converter.cpp + COMPONENT_DEPENDENCIES + model +) diff --git a/src/tactic/converter.h b/src/ast/converters/converter.h similarity index 100% rename from src/tactic/converter.h rename to src/ast/converters/converter.h diff --git a/src/tactic/generic_model_converter.cpp b/src/ast/converters/generic_model_converter.cpp similarity index 99% rename from src/tactic/generic_model_converter.cpp rename to src/ast/converters/generic_model_converter.cpp index 2886eb6ab..f805e169b 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/ast/converters/generic_model_converter.cpp @@ -24,7 +24,7 @@ Notes: #include "ast/occurs.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "model/model_v2_pp.h" #include "model/model_evaluator.h" diff --git a/src/tactic/generic_model_converter.h b/src/ast/converters/generic_model_converter.h similarity index 97% rename from src/tactic/generic_model_converter.h rename to src/ast/converters/generic_model_converter.h index e809fe734..c20bfebb3 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/ast/converters/generic_model_converter.h @@ -19,7 +19,7 @@ Notes: --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" class generic_model_converter : public model_converter { enum instruction { HIDE, ADD }; diff --git a/src/tactic/model_converter.cpp b/src/ast/converters/model_converter.cpp similarity index 99% rename from src/tactic/model_converter.cpp rename to src/ast/converters/model_converter.cpp index 5c08da76f..bba18ecd6 100644 --- a/src/tactic/model_converter.cpp +++ b/src/ast/converters/model_converter.cpp @@ -16,7 +16,7 @@ Author: Notes: --*/ -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "model/model_v2_pp.h" #include "ast/ast_smt2_pp.h" diff --git a/src/tactic/model_converter.h b/src/ast/converters/model_converter.h similarity index 98% rename from src/tactic/model_converter.h rename to src/ast/converters/model_converter.h index 377ecce67..335e0d276 100644 --- a/src/tactic/model_converter.h +++ b/src/ast/converters/model_converter.h @@ -57,7 +57,7 @@ Notes: #include "util/ref.h" #include "ast/ast_pp_util.h" #include "model/model.h" -#include "tactic/converter.h" +#include "ast/converters/converter.h" class labels_vec : public svector {}; class smt2_pp_environment; diff --git a/src/tactic/proof_converter.cpp b/src/ast/converters/proof_converter.cpp similarity index 68% rename from src/tactic/proof_converter.cpp rename to src/ast/converters/proof_converter.cpp index d1905b383..88358b7c3 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/ast/converters/proof_converter.cpp @@ -16,8 +16,7 @@ Author: Notes: --*/ -#include "tactic/proof_converter.h" -#include "tactic/goal.h" +#include "ast/converters/proof_converter.h" #include "ast/ast_smt2_pp.h" class concat_proof_converter : public concat_converter { @@ -46,41 +45,6 @@ proof_converter * concat(proof_converter * pc1, proof_converter * pc2) { return alloc(concat_proof_converter, pc1, pc2); } -class subgoal_proof_converter : public proof_converter { - proof_converter_ref m_pc; - goal_ref_buffer m_goals; -public: - subgoal_proof_converter(proof_converter* pc, unsigned n, goal * const* goals): - m_pc(pc) - { - for (unsigned i = 0; i < n; ++i) m_goals.push_back(goals[i]); - } - - proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { - // ignore the proofs from the arguments, instead obtain the proofs fromt he subgoals. - SASSERT(num_source == 0); - proof_converter_ref_buffer pc_buffer; - for (goal_ref g : m_goals) { - pc_buffer.push_back(g->pc()); - - } - return apply(m, m_pc, pc_buffer); - } - - proof_converter* translate(ast_translation& tr) override { - proof_converter_ref pc1 = m_pc->translate(tr); - goal_ref_buffer goals; - for (goal_ref g : m_goals) goals.push_back(g->translate(tr)); - return alloc(subgoal_proof_converter, pc1.get(), goals.size(), goals.data()); - } - - void display(std::ostream& out) override {} - -}; - -proof_converter * concat(proof_converter *pc, unsigned n, goal* const* goals) { - return alloc(subgoal_proof_converter, pc, n, goals); -} class proof2pc : public proof_converter { proof_ref m_pr; diff --git a/src/tactic/proof_converter.h b/src/ast/converters/proof_converter.h similarity index 78% rename from src/tactic/proof_converter.h rename to src/ast/converters/proof_converter.h index 88152ce5b..d977f2563 100644 --- a/src/tactic/proof_converter.h +++ b/src/ast/converters/proof_converter.h @@ -20,8 +20,7 @@ Notes: #include "ast/ast.h" #include "util/ref.h" -#include "tactic/converter.h" -class goal; +#include "ast/converters/converter.h" class proof_converter : public converter { public: @@ -36,12 +35,6 @@ typedef sref_buffer proof_converter_ref_buffer; proof_converter * concat(proof_converter * pc1, proof_converter * pc2); -/** - \brief create a proof converter that takes a set of subgoals and converts their proofs to a proof of - the goal they were derived from. - */ -proof_converter * concat(proof_converter *pc1, unsigned n, goal* const* goals); - proof_converter * proof2proof_converter(ast_manager & m, proof * pr); void apply(ast_manager & m, proof_converter * pc, proof_ref & pr); diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index e67aa56cc..34517525f 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -33,6 +33,7 @@ Author: #include "util/statistics.h" #include "util/params.h" #include "ast/simplifiers/dependent_expr.h" +#include "ast/converters/model_converter.h" /** abstract interface to state updated by simplifiers. @@ -66,6 +67,7 @@ public: virtual void collect_statistics(statistics& st) const {} virtual void reset_statistics() {} virtual void updt_params(params_ref const& p) {} + virtual model_converter_ref get_model_converter() { return model_converter_ref(); } }; /** diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 38100fcdc..cc3ad5b7b 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -23,6 +23,7 @@ Author: #include "ast/recfun_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/solve_eqs.h" +#include "ast/converters/generic_model_converter.h" namespace euf { @@ -183,14 +184,16 @@ namespace euf { m_unsafe_vars.mark(term); } -#if 0 + typedef generic_model_converter gmc; + model_converter_ref solve_eqs::get_model_converter() { model_converter_ref mc = alloc(gmc, m, "solve-eqs"); - for (unsigned id : m_subst_ids) - static_cast(mc.get())->add(id2var(id), m_subst->find(v)); + for (unsigned id : m_subst_ids) { + auto* v = m_id2var[id]; + static_cast(mc.get())->add(v, m_subst->find(v)); + } return mc; } -#endif solve_eqs::solve_eqs(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_rewriter(m) { diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 62f24413a..02d20a50e 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -18,9 +18,9 @@ Author: #pragma once -#include "ast/rewriter/th_rewriter.h" -#include "ast/expr_substitution.h" #include "util/scoped_ptr_vector.h" +#include "ast/expr_substitution.h" +#include "ast/rewriter/th_rewriter.h" #include "ast/simplifiers/extract_eqs.h" namespace euf { @@ -74,6 +74,6 @@ namespace euf { void updt_params(params_ref const& p) override; void collect_statistics(statistics& st) const override; - // model_converter_ref get_model_converter(); + model_converter_ref get_model_converter() override; }; } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index a5c66f78b..2d90b70c3 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -47,7 +47,7 @@ Notes: #include "model/model_v2_pp.h" #include "model/model_params.hpp" #include "tactic/tactic_exception.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "solver/smt_logics.h" #include "cmd_context/basic_cmds.h" #include "cmd_context/cmd_context.h" diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 15b5df0d1..93d2c0d3e 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -33,7 +33,7 @@ Notes: #include "ast/datatype_decl_plugin.h" #include "ast/recfun_decl_plugin.h" #include "ast/rewriter/seq_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "solver/solver.h" #include "solver/check_logic.h" #include "solver/progress_callback.h" diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index eae846835..3479fef0d 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -30,7 +30,7 @@ Revision History: #include "util/statistics.h" #include "util/params.h" #include "util/trail.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "model/model2expr.h" #include "smt/params/smt_params.h" #include "muz/base/dl_rule_transformer.h" diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index d0c872c3c..a1864d3b9 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -41,7 +41,7 @@ Revision History: #include "ast/rewriter/expr_replacer.h" #include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/expr_safe_replace.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/scoped_proof.h" #include "ast/datatype_decl_plugin.h" #include "ast/ast_util.h" diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index c9fa2f6b3..6a21a2621 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -23,8 +23,8 @@ Revision History: #include "muz/base/dl_costs.h" #include "muz/base/dl_util.h" #include "ast/used_vars.h" -#include "tactic/proof_converter.h" -#include "tactic/model_converter.h" +#include "ast/converters/proof_converter.h" +#include "ast/converters/model_converter.h" #include "ast/rewriter/ast_counter.h" #include "ast/rewriter/rewriter.h" #include "muz/base/hnf.h" diff --git a/src/muz/base/hnf.h b/src/muz/base/hnf.h index 45b651b56..0df0269d9 100644 --- a/src/muz/base/hnf.h +++ b/src/muz/base/hnf.h @@ -27,7 +27,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast.h" #include "util/params.h" #include "ast/normal_forms/defined_names.h" -#include "tactic/proof_converter.h" +#include "ast/converters/proof_converter.h" class hnf { class imp; diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 560202ab3..1a58bc92b 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -20,9 +20,9 @@ Revision History: #include "ast/rewriter/var_subst.h" #include "ast/rewriter/expr_replacer.h" #include "tactic/tactical.h" -#include "tactic/model_converter.h" -#include "tactic/proof_converter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/model_converter.h" +#include "ast/converters/proof_converter.h" +#include "ast/converters/generic_model_converter.h" #include "muz/fp/horn_tactic.h" #include "muz/base/dl_context.h" #include "muz/fp/dl_register_engine.h" diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index e8d769621..470901a96 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -28,7 +28,7 @@ Revision History: #include "ast/expr_abstract.h" #include "model/model2expr.h" #include "model/model_smt2_pp.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "smt/smt_solver.h" namespace spacer { diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 070432e52..439cb4540 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -22,7 +22,7 @@ Revision History: #include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" #include "ast/rewriter/expr_safe_replace.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "muz/transforms/dl_mk_interp_tail_simplifier.h" #include "muz/base/fp_params.hpp" #include "ast/scoped_proof.h" diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index ba85e569a..73541b0cd 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -21,7 +21,7 @@ Author: #include "muz/dataflow/dataflow.h" #include "muz/dataflow/reachability.h" #include "ast/ast_pp.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/ast_util.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index b91b9e5c8..e8b1f4001 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -25,7 +25,7 @@ Revision History: #include "ast/rewriter/rewriter_def.h" #include "muz/transforms/dl_mk_subsumption_checker.h" #include "muz/base/fp_params.hpp" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" namespace datalog { diff --git a/src/nlsat/tactic/goal2nlsat.h b/src/nlsat/tactic/goal2nlsat.h index 8dda03105..52b975cc2 100644 --- a/src/nlsat/tactic/goal2nlsat.h +++ b/src/nlsat/tactic/goal2nlsat.h @@ -24,7 +24,7 @@ Notes: #pragma once #include "nlsat/nlsat_types.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" class goal; class expr2var; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ba31d74cf..5895643bd 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -39,7 +39,7 @@ Notes: #include "tactic/arith/card2bv_tactic.h" #include "tactic/arith/eq2bv_tactic.h" #include "tactic/bv/dt2bv_tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ackermannization/ackermannize_bv_tactic.h" #include "sat/sat_solver/inc_sat_solver.h" #include "sat/sat_params.hpp" diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index a93400592..9e61ae92c 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -20,7 +20,7 @@ Notes: #include "ast/ast.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "tactic/tactic.h" #include "qe/qsat.h" #include "opt/opt_solver.h" diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index bd83f06c8..84d31ed0f 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -29,7 +29,7 @@ Notes: #include "smt/params/smt_params.h" #include "smt/smt_types.h" #include "smt/theory_opt.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" namespace opt { diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index da25e2285..28448fbe4 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -24,7 +24,7 @@ Notes: #include "smt/smt_context.h" #include "opt/opt_context.h" #include "util/sorting_network.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" namespace opt { diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 381d244e1..2f7502a67 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -21,7 +21,7 @@ Revision History: #pragma once #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "qe/qe_mbp.h" namespace qe { diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index beb0809fb..f935ad9ff 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -22,7 +22,7 @@ Author: #include "ast/ast_util.h" #include "ast/euf/euf_egraph.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "sat/sat_extension.h" #include "sat/smt/atom2bool_var.h" #include "sat/smt/sat_th.h" diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 403cee684..97a766df9 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -37,7 +37,7 @@ Notes: #include "model/model_evaluator.h" #include "model/model_v2_pp.h" #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "sat/sat_cut_simplifier.h" #include "sat/sat_drat.h" #include "sat/tactic/goal2sat.h" diff --git a/src/sat/tactic/sat2goal.cpp b/src/sat/tactic/sat2goal.cpp index 7614857cb..899345ad8 100644 --- a/src/sat/tactic/sat2goal.cpp +++ b/src/sat/tactic/sat2goal.cpp @@ -37,7 +37,7 @@ Notes: #include "model/model_evaluator.h" #include "model/model_v2_pp.h" #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "sat/sat_cut_simplifier.h" #include "sat/sat_drat.h" #include "sat/tactic/sat2goal.h" diff --git a/src/sat/tactic/sat2goal.h b/src/sat/tactic/sat2goal.h index 1e1dfcd5e..8c0b1bf83 100644 --- a/src/sat/tactic/sat2goal.h +++ b/src/sat/tactic/sat2goal.h @@ -31,7 +31,7 @@ Notes: #include "tactic/goal.h" #include "sat/sat_model_converter.h" #include "sat/sat_solver.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "sat/smt/atom2bool_var.h" class sat2goal { diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index 5527f12f5..5ef52a54c 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -26,7 +26,7 @@ Notes: #include "smt/smt_solver.h" #include "tactic/tactic.h" #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "solver/solver2tactic.h" #include "solver/solver.h" #include "solver/mus.h" diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 4b57f043e..593c32d83 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -22,7 +22,7 @@ Revision History: #include "smt/theory_arith.h" #include "smt/smt_farkas_util.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" namespace smt { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index c46331d07..4075f39dd 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -43,7 +43,7 @@ #include "smt/smt_model_generator.h" #include "smt/arith_eq_adapter.h" #include "util/nat_set.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" #include "util/cancel_eh.h" diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 03a205ca6..9cac6b96b 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -21,7 +21,7 @@ Notes: #include "smt/smt_theory.h" #include "smt/smt_clause.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" namespace smt { class theory_wmaxsat : public theory { diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index e00b53cc9..936f6d3df 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -23,7 +23,7 @@ Notes: #include "util/statistics.h" #include "util/event_handler.h" #include "util/timer.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" /** \brief Abstract interface for the result of a (check-sat) like command. diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index d582ec2db..bf05554af 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -22,7 +22,7 @@ Notes: #include "ast/ast_pp.h" #include "ast/ast_pp_util.h" #include "ast/display_dimacs.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "solver/solver.h" #include "params/solver_params.hpp" #include "model/model_evaluator.h" diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 81d21f959..b8e3dd37a 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -19,7 +19,7 @@ Notes: #include "solver/solver.h" #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "solver/solver2tactic.h" #include "ast/ast_util.h" diff --git a/src/solver/solver2tactic.h b/src/solver/solver2tactic.h index a5b529f69..4640ee276 100644 --- a/src/solver/solver2tactic.h +++ b/src/solver/solver2tactic.h @@ -19,7 +19,7 @@ Notes: #pragma once #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class solver; tactic * mk_solver2tactic(solver* s); diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index b9b4394d9..f0910fcc2 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -2,15 +2,12 @@ z3_add_component(tactic SOURCES dependency_converter.cpp equiv_proof_converter.cpp - generic_model_converter.cpp goal.cpp goal_num_occurs.cpp goal_shared_occs.cpp goal_util.cpp horn_subsume_model_converter.cpp - model_converter.cpp probe.cpp - proof_converter.cpp replace_proof_converter.cpp tactical.cpp tactic.cpp @@ -18,6 +15,7 @@ z3_add_component(tactic ast model simplifiers + converters TACTIC_HEADERS probe.h tactic.h diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 25c5620c2..4f79a887d 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -22,7 +22,7 @@ Notes: #include "ast/rewriter/pb2bv_rewriter.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class card2bv_tactic : public tactic { ast_manager & m; diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index e34910e78..26c3f9ef5 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -20,7 +20,7 @@ Revision History: --*/ #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "tactic/core/simplify_tactic.h" #include "ast/ast_smt2_pp.h" diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 87061b189..13479e1bf 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -23,7 +23,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 97c6f466f..cb6f6c228 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -25,7 +25,7 @@ Notes: #include "ast/ast_pp_util.h" #include "tactic/tactical.h" #include "tactic/arith/bound_manager.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class lia2card_tactic : public tactic { diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 46404ffb0..f78e85621 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -20,7 +20,7 @@ Revision History: #include "tactic/arith/bound_manager.h" #include "ast/rewriter/th_rewriter.h" #include "ast/for_each_expr.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 36df89da5..bdcf57953 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -27,7 +27,7 @@ Notes: #include "util/optional.h" #include "tactic/arith/bv2int_rewriter.h" #include "tactic/arith/bv2real_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "tactic/arith/bound_manager.h" #include "util/obj_pair_hashtable.h" #include "ast/ast_smt2_pp.h" diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index b7ef28f49..cba791ee1 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -21,7 +21,7 @@ Revision History: #include "tactic/tactical.h" #include "tactic/arith/bound_manager.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" diff --git a/src/tactic/arith/pb2bv_model_converter.h b/src/tactic/arith/pb2bv_model_converter.h index 5560ce7da..2de873ba2 100644 --- a/src/tactic/arith/pb2bv_model_converter.h +++ b/src/tactic/arith/pb2bv_model_converter.h @@ -18,7 +18,7 @@ Notes: --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "tactic/arith/bound_manager.h" class pb2bv_model_converter : public model_converter { diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index c418115a9..5ff7425ba 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -29,7 +29,7 @@ Notes: #include "ast/rewriter/pb2bv_rewriter.h" #include "tactic/tactical.h" #include "tactic/arith/bound_manager.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "tactic/arith/pb2bv_model_converter.h" #include "tactic/arith/pb2bv_tactic.h" diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index afcecd7d3..7c69ef12e 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -27,7 +27,7 @@ Revision History: #include "tactic/core/nnf_tactic.h" #include "tactic/core/simplify_tactic.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_pp.h" #include "ast/rewriter/expr_replacer.h" diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index 251d78e72..d97f9b80f 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -57,7 +57,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "util/dec_ref_util.h" diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 5c26fb2b5..88ff11683 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -18,7 +18,7 @@ Notes: --*/ #include "model/model.h" #include "model/model_pp.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ast/bv_decl_plugin.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_pp.h" diff --git a/src/tactic/bv/bit_blaster_model_converter.h b/src/tactic/bv/bit_blaster_model_converter.h index debfdd526..dae3cd40e 100644 --- a/src/tactic/bv/bit_blaster_model_converter.h +++ b/src/tactic/bv/bit_blaster_model_converter.h @@ -18,7 +18,7 @@ Notes: --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits, ptr_vector const& newbits); model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits, ptr_vector const& newbits); diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 788f562d3..286375b6a 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -24,7 +24,7 @@ Notes: #include "tactic/tactical.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/ast_smt2_pp.h" namespace { diff --git a/src/tactic/bv/bvarray2uf_rewriter.h b/src/tactic/bv/bvarray2uf_rewriter.h index df5c93a14..d6733d4a6 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.h +++ b/src/tactic/bv/bvarray2uf_rewriter.h @@ -20,7 +20,7 @@ Notes: #pragma once #include "ast/rewriter/rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { ast_manager & m_manager; diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index da86ed663..3a4971e04 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -20,7 +20,7 @@ Notes: #include "tactic/tactical.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/ast_smt2_pp.h" #include "tactic/bv/bvarray2uf_tactic.h" diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 650095207..190403349 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -21,7 +21,7 @@ Revision History: #include "tactic/bv/dt2bv_tactic.h" #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/datatype_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 02ec522c6..54f4dc915 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/bv_decl_plugin.h" #include "ast/used_vars.h" #include "ast/well_sorted.h" diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 2a0593ade..c67443862 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -20,7 +20,7 @@ Notes: #include "tactic/tactical.h" #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class elim_term_ite_tactic : public tactic { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index c97fa670e..cb60eb482 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -17,7 +17,7 @@ Notes: --*/ #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/rewriter/rewriter_def.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 959a1fc18..3a5ce8d0a 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "ast/normal_forms/nnf.h" #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class nnf_tactic : public tactic { params_ref m_params; diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index c3c027fef..1784a434d 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -23,7 +23,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "tactic/core/occf_tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" class occf_tactic : public tactic { struct imp { diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 2c4b80b93..9f0717135 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -33,7 +33,7 @@ Notes: --*/ #include "tactic/core/pb_preprocess_tactic.h" #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/for_each_expr.h" #include "ast/pb_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index 7f0d82f2e..b2a10fafa 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -22,7 +22,7 @@ Notes: #include "ast/has_free_vars.h" #include "util/map.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" /** \brief Reduce the number of arguments in function applications. diff --git a/src/tactic/core/reduce_invertible_tactic.cpp b/src/tactic/core/reduce_invertible_tactic.cpp index df3de8219..ba9b5d752 100644 --- a/src/tactic/core/reduce_invertible_tactic.cpp +++ b/src/tactic/core/reduce_invertible_tactic.cpp @@ -29,7 +29,7 @@ Notes: #include "tactic/tactic.h" #include "tactic/core/reduce_invertible_tactic.h" #include "tactic/core/collect_occs.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include namespace { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 0a0525e70..977a0d614 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -27,7 +27,7 @@ Revision History: #include "ast/rewriter/hoist_rewriter.h" #include "tactic/goal_shared_occs.h" #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "tactic/tactic_params.hpp" class solve_eqs_tactic : public tactic { diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 99a69395b..c29a2f3f2 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "tactic/tactical.h" +#include "tactic/goal_proof_converter.h" #include "tactic/core/split_clause_tactic.h" class split_clause_tactic : public tactic { diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index eec05b604..e4476548a 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -52,7 +52,7 @@ Notes: #include "ast/ast_pp.h" #include "tactic/tactical.h" #include "tactic/goal_shared_occs.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/rewriter/bool_rewriter.h" #include "tactic/core/simplify_tactic.h" diff --git a/src/tactic/dependency_converter.h b/src/tactic/dependency_converter.h index 474767a98..1d86f8c39 100644 --- a/src/tactic/dependency_converter.h +++ b/src/tactic/dependency_converter.h @@ -22,7 +22,7 @@ Notes: #include "util/ref.h" #include "ast/ast_pp_util.h" #include "model/model.h" -#include "tactic/converter.h" +#include "ast/converters/converter.h" class goal; diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index c62125459..116baedf7 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -82,6 +82,8 @@ public: m_goal = in.get(); m_simp->reduce(); m_goal->inc_depth(); + if (in->models_enabled()) + in->set(m_simp->get_model_converter()); result.push_back(in.get()); } diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index ed10f7efb..7b7ca630e 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -20,7 +20,7 @@ Notes: #include "solver/solver_na2as.h" #include "tactic/tactic.h" #include "ast/rewriter/pb2bv_rewriter.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" #include "tactic/arith/bound_manager.h" diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 5e05fdf31..7ec5243e7 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -26,7 +26,7 @@ Notes: #include "ast/rewriter/enum2bv_rewriter.h" #include "model/model_smt2_pp.h" #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "tactic/fd_solver/enum2bv_solver.h" #include "solver/solver_na2as.h" diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index 609ed173d..1a5f7d16a 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -22,7 +22,7 @@ Notes: #include "ast/rewriter/th_rewriter.h" #include "model/model_smt2_pp.h" #include "tactic/tactic.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "solver/solver_na2as.h" #include "tactic/fd_solver/pb2bv_solver.h" diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 452a629c4..4debe781a 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -19,7 +19,7 @@ Notes: #pragma once #include "ast/fpa/fpa2bv_converter.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ast/fpa/bv2fpa_converter.h" class fpa2bv_model_converter : public model_converter { diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 5e7e0b2fe..b0b8d95f1 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -34,8 +34,8 @@ Revision History: #include "util/ref.h" #include "util/ref_vector.h" #include "util/ref_buffer.h" -#include "tactic/model_converter.h" -#include "tactic/proof_converter.h" +#include "ast/converters/model_converter.h" +#include "ast/converters/proof_converter.h" #include "tactic/dependency_converter.h" class goal { diff --git a/src/tactic/goal_proof_converter.h b/src/tactic/goal_proof_converter.h new file mode 100644 index 000000000..a17ff0ea1 --- /dev/null +++ b/src/tactic/goal_proof_converter.h @@ -0,0 +1,63 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + goal_proof_converter.h + +Abstract: + + Proof converter for goals + +Author: + + Nikolaj Bjorner (nbjorner) 2012-11-23 + +--*/ + +#pragma once + +#include "ast/converters/proof_converter.h" +class goal; + +/** + \brief create a proof converter that takes a set of subgoals and converts their proofs to a proof of + the goal they were derived from. + */ +proof_converter * concat(proof_converter *pc1, unsigned n, goal* const* goals); + +class subgoal_proof_converter : public proof_converter { + proof_converter_ref m_pc; + goal_ref_buffer m_goals; +public: + subgoal_proof_converter(proof_converter* pc, unsigned n, goal * const* goals): + m_pc(pc) + { + for (unsigned i = 0; i < n; ++i) m_goals.push_back(goals[i]); + } + + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { + // ignore the proofs from the arguments, instead obtain the proofs fromt he subgoals. + SASSERT(num_source == 0); + proof_converter_ref_buffer pc_buffer; + for (goal_ref g : m_goals) { + pc_buffer.push_back(g->pc()); + + } + return apply(m, m_pc, pc_buffer); + } + + proof_converter* translate(ast_translation& tr) override { + proof_converter_ref pc1 = m_pc->translate(tr); + goal_ref_buffer goals; + for (goal_ref g : m_goals) goals.push_back(g->translate(tr)); + return alloc(subgoal_proof_converter, pc1.get(), goals.size(), goals.data()); + } + + void display(std::ostream& out) override {} + +}; + +inline proof_converter * concat(proof_converter *pc, unsigned n, goal* const* goals) { + return alloc(subgoal_proof_converter, pc, n, goals); +} diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index 41e59070e..2576ad1f9 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -34,7 +34,7 @@ Subsumption transformation (remove Horn clause): #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ast/rewriter/th_rewriter.h" class horn_subsume_model_converter : public model_converter { diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index 37bbf55b3..6a877bc58 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -22,7 +22,7 @@ Revision History: #pragma once -#include "tactic/proof_converter.h" +#include "ast/converters/proof_converter.h" class replace_proof_converter : public proof_converter { ast_manager& m; diff --git a/src/tactic/sls/sls_engine.h b/src/tactic/sls/sls_engine.h index bf726beb9..5f290c626 100644 --- a/src/tactic/sls/sls_engine.h +++ b/src/tactic/sls/sls_engine.h @@ -20,7 +20,7 @@ Notes: #include "util/stopwatch.h" #include "util/lbool.h" -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "tactic/goal.h" #include "tactic/sls/sls_tracker.h" diff --git a/src/tactic/smtlogics/qfufbv_ackr_model_converter.h b/src/tactic/smtlogics/qfufbv_ackr_model_converter.h index 092e41634..c60902228 100644 --- a/src/tactic/smtlogics/qfufbv_ackr_model_converter.h +++ b/src/tactic/smtlogics/qfufbv_ackr_model_converter.h @@ -16,7 +16,7 @@ --*/ #pragma once -#include "tactic/model_converter.h" +#include "ast/converters/model_converter.h" #include "ackermannization/ackr_info.h" model_converter * mk_qfufbv_ackr_model_converter(ast_manager & m, const ackr_info_ref& info, model_ref& abstr_model); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 0d1062d78..5b1ea9587 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -20,6 +20,7 @@ Notes: #include "util/cancel_eh.h" #include "util/scoped_ptr_vector.h" #include "tactic/tactical.h" +#include "tactic/goal_proof_converter.h" #ifndef SINGLE_THREAD #include #endif diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 2358abcd1..3f45feb37 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -20,7 +20,7 @@ Notes: #include "ast/recfun_decl_plugin.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "tactic/ufbv/macro_finder_tactic.h" class macro_finder_tactic : public tactic { diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index b0eb113b8..051ee4fed 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -17,7 +17,7 @@ Notes: --*/ #include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" +#include "ast/converters/generic_model_converter.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" #include "ast/macros/quasi_macros.h" From ba6b21d7d4d5b3faa46696b707a59afb4a8c5ed6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 05:23:38 -0700 Subject: [PATCH 219/477] Create solve_eqs2_tactic.h --- src/tactic/core/solve_eqs2_tactic.h | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/tactic/core/solve_eqs2_tactic.h diff --git a/src/tactic/core/solve_eqs2_tactic.h b/src/tactic/core/solve_eqs2_tactic.h new file mode 100644 index 000000000..91b3875ae --- /dev/null +++ b/src/tactic/core/solve_eqs2_tactic.h @@ -0,0 +1,41 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + solve_eqs2_tactic.h + +Abstract: + + Tactic for solving variables + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ +#pragma once + +#include "util/params.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/solve_eqs.h" + + +class solve_eqs2_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(euf::solve_eqs, m, s); + } +}; + +inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p) { + return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs2"); +} + + +/* + ADD_TACTIC("solve-eqs2", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") +*/ + + From 203652da740863a317d2024ecccd460ace86f8c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 05:26:06 -0700 Subject: [PATCH 220/477] add converters module to python build --- scripts/mk_project.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 9c4cda4a1..e9f54be05 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -31,10 +31,11 @@ def init_project_def(): add_lib('nlsat', ['polynomial', 'sat']) add_lib('lp', ['util', 'nlsat', 'grobner', 'interval', 'smt_params'], 'math/lp') add_lib('rewriter', ['ast', 'polynomial', 'automata', 'params'], 'ast/rewriter') - add_lib('simplifiers', ['euf', 'rewriter'], 'ast/simplifiers') add_lib('macros', ['rewriter'], 'ast/macros') - add_lib('normal_forms', ['rewriter'], 'ast/normal_forms') add_lib('model', ['rewriter', 'macros']) + add_lib('converters', ['model'], 'ast/converters') + add_lib('simplifiers', ['euf', 'rewriter', 'converters'], 'ast/simplifiers') + add_lib('normal_forms', ['rewriter'], 'ast/normal_forms') add_lib('tactic', ['ast', 'model', 'simplifiers']) add_lib('substitution', ['ast', 'rewriter'], 'ast/substitution') add_lib('parser_util', ['ast'], 'parsers/util') From 06eb460c752184e8a1415ef171945d5eb91d6b89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 05:50:46 -0700 Subject: [PATCH 221/477] move tactic_params to params --- src/ast/simplifiers/extract_eqs.cpp | 20 ++++++++++++++++- src/ast/simplifiers/extract_eqs.h | 1 + src/ast/simplifiers/solve_eqs.cpp | 22 ++++++++----------- src/ast/simplifiers/solve_eqs.h | 5 +++++ src/params/CMakeLists.txt | 1 + src/{tactic => params}/tactic_params.pyg | 0 src/tactic/CMakeLists.txt | 2 -- src/tactic/core/blast_term_ite_tactic.cpp | 2 +- src/tactic/core/propagate_values_tactic.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 2 +- src/tactic/dependent_expr_state_tactic.h | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 2 +- 12 files changed, 40 insertions(+), 21 deletions(-) rename src/{tactic => params}/tactic_params.pyg (100%) diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 99be4268c..1e9b576e1 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -21,12 +21,14 @@ Author: #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/simplifiers/extract_eqs.h" +#include "params/tactic_params.hpp" namespace euf { class basic_extract_eq : public extract_eq { ast_manager& m; + bool m_ite_solver = true; public: basic_extract_eq(ast_manager& m) : m(m) {} @@ -41,7 +43,7 @@ namespace euf { eqs.push_back(dependent_eq(to_app(y), expr_ref(x, m), d)); } expr* c, * th, * el, * x1, * y1, * x2, * y2; - if (m.is_ite(f, c, th, el)) { + if (m_ite_solver && m.is_ite(f, c, th, el)) { if (m.is_eq(th, x1, y1) && m.is_eq(el, x2, y2)) { if (x1 == y2 && is_uninterp_const(x1)) std::swap(x2, y2); @@ -58,6 +60,11 @@ namespace euf { if (m.is_not(f, x) && is_uninterp_const(x)) eqs.push_back(dependent_eq(to_app(x), expr_ref(m.mk_false(), m), d)); } + + void updt_params(params_ref const& p) { + tactic_params tp(p); + m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); + } }; class arith_extract_eq : public extract_eq { @@ -65,6 +72,7 @@ namespace euf { arith_util a; expr_ref_vector m_args; expr_sparse_mark m_nonzero; + bool m_enabled = true; // solve u mod r1 = y -> u = r1*mod!1 + y @@ -215,6 +223,8 @@ namespace euf { public: arith_extract_eq(ast_manager& m) : m(m), a(m), m_args(m) {} void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { + if (!m_enabled) + return; auto [f, d] = e(); expr* x, * y; if (m.is_eq(f, x, y) && a.is_int_real(x)) { @@ -224,12 +234,20 @@ namespace euf { } void pre_process(dependent_expr_state& fmls) override { + if (!m_enabled) + return; m_nonzero.reset(); for (unsigned i = 0; i < fmls.size(); ++i) { auto [f, d] = fmls[i](); add_pos(f); } } + + + void updt_params(params_ref const& p) { + tactic_params tp(p); + m_enabled = p.get_bool("theory_solver", tp.solve_eqs_ite_solver()); + } }; void register_extract_eqs(ast_manager& m, scoped_ptr_vector& ex) { diff --git a/src/ast/simplifiers/extract_eqs.h b/src/ast/simplifiers/extract_eqs.h index 29c136028..00f96f59b 100644 --- a/src/ast/simplifiers/extract_eqs.h +++ b/src/ast/simplifiers/extract_eqs.h @@ -40,6 +40,7 @@ namespace euf { virtual ~extract_eq() {} virtual void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) = 0; virtual void pre_process(dependent_expr_state& fmls) {} + virtual void updt_params(params_ref const& p) {} }; void register_extract_eqs(ast_manager& m, scoped_ptr_vector& ex); diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index cc3ad5b7b..6b2a27d2d 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -24,6 +24,7 @@ Author: #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/solve_eqs.h" #include "ast/converters/generic_model_converter.h" +#include "params/tactic_params.hpp" namespace euf { @@ -46,7 +47,8 @@ namespace euf { m_next.resize(m_id2var.size()); for (auto const& eq : eqs) - m_next[var2id(eq.var)].push_back(eq); + if (can_be_var(eq.var)) + m_next[var2id(eq.var)].push_back(eq); } /** @@ -136,10 +138,7 @@ namespace euf { tout << "after normalizing variables\n"; for (unsigned id : m_subst_ids) { auto const& eq = m_next[id][0]; - expr* def = nullptr; - proof* pr = nullptr; - expr_dependency* dep = nullptr; - m_subst->find(eq.var, def, pr, dep); + expr* def = m_subst->find(eq.var); tout << mk_pp(eq.var, m) << "\n----->\n" << mk_pp(def, m) << "\n\n"; }); } @@ -201,14 +200,11 @@ namespace euf { } void solve_eqs::updt_params(params_ref const& p) { - // TODO -#if 0 - tactic_params tp(m_params); - m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); - m_theory_solver = p.get_bool("theory_solver", tp.solve_eqs_theory_solver()); - m_max_occs = p.get_uint("solve_eqs_max_occs", tp.solve_eqs_max_occs()); - m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); -#endif + tactic_params tp(p); + m_config.m_max_occs = p.get_uint("solve_eqs_max_occs", tp.solve_eqs_max_occs()); + m_config.m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); + for (auto* ex : m_extract_plugins) + ex->updt_params(p); } void solve_eqs::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 02d20a50e..49cd90ca2 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -30,6 +30,10 @@ namespace euf { unsigned m_num_steps = 0; unsigned m_num_elim_vars = 0; }; + struct config { + bool m_context_solve = true; + unsigned m_max_occs = UINT_MAX; + }; th_rewriter m_rewriter; scoped_ptr_vector m_extract_plugins; @@ -40,6 +44,7 @@ namespace euf { expr_mark m_unsafe_vars; // expressions that cannot be replaced stats m_stats; + config m_config; void add_subst(dependent_eq const& eq); diff --git a/src/params/CMakeLists.txt b/src/params/CMakeLists.txt index f420ddd6d..cdc21da97 100644 --- a/src/params/CMakeLists.txt +++ b/src/params/CMakeLists.txt @@ -16,6 +16,7 @@ z3_add_component(params rewriter_params.pyg seq_rewriter_params.pyg solver_params.pyg + tactic_params.pyg EXTRA_REGISTER_MODULE_HEADERS context_params.h ) diff --git a/src/tactic/tactic_params.pyg b/src/params/tactic_params.pyg similarity index 100% rename from src/tactic/tactic_params.pyg rename to src/params/tactic_params.pyg diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index f0910fcc2..ab81ebfe2 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -19,6 +19,4 @@ z3_add_component(tactic TACTIC_HEADERS probe.h tactic.h - PYG_FILES - tactic_params.pyg ) diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 38b4e172e..49e43e633 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -20,7 +20,7 @@ Notes: #include "ast/rewriter/rewriter_def.h" #include "ast/scoped_proof.h" #include "tactic/tactical.h" -#include "tactic/tactic_params.hpp" +#include "params/tactic_params.hpp" diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 5b7fcbf10..041e4d1c2 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -24,7 +24,7 @@ Revision History: #include "ast/ast_pp.h" #include "ast/expr_substitution.h" #include "tactic/goal_shared_occs.h" -#include "tactic/tactic_params.hpp" +#include "params/tactic_params.hpp" namespace { class propagate_values_tactic : public tactic { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 977a0d614..3e338b57e 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -28,7 +28,7 @@ Revision History: #include "tactic/goal_shared_occs.h" #include "tactic/tactical.h" #include "ast/converters/generic_model_converter.h" -#include "tactic/tactic_params.hpp" +#include "params/tactic_params.hpp" class solve_eqs_tactic : public tactic { struct imp { diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 116baedf7..ae3635c77 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -83,7 +83,7 @@ public: m_simp->reduce(); m_goal->inc_depth(); if (in->models_enabled()) - in->set(m_simp->get_model_converter()); + in->set(m_simp->get_model_converter().get()); result.push_back(in.get()); } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 483be4cca..b521095be 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -44,7 +44,7 @@ Notes: #include "solver/solver2tactic.h" #include "solver/parallel_tactic.h" #include "solver/parallel_params.hpp" -#include "tactic/tactic_params.hpp" +#include "params/tactic_params.hpp" #include "parsers/smt2/smt2parser.h" From 25bb935793551d19791119f48181a2ccd1fb7316 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 20:18:21 -0700 Subject: [PATCH 222/477] move more converters --- src/ast/converters/CMakeLists.txt | 4 +++- src/{tactic => ast/converters}/equiv_proof_converter.cpp | 2 +- src/{tactic => ast/converters}/equiv_proof_converter.h | 2 +- src/{tactic => ast/converters}/replace_proof_converter.cpp | 2 +- src/{tactic => ast/converters}/replace_proof_converter.h | 0 src/muz/base/dl_util.h | 2 +- src/muz/transforms/dl_mk_array_blast.h | 2 +- src/muz/transforms/dl_mk_elim_term_ite.h | 2 +- src/tactic/CMakeLists.txt | 2 -- 9 files changed, 9 insertions(+), 9 deletions(-) rename src/{tactic => ast/converters}/equiv_proof_converter.cpp (93%) rename src/{tactic => ast/converters}/equiv_proof_converter.h (95%) rename src/{tactic => ast/converters}/replace_proof_converter.cpp (97%) rename src/{tactic => ast/converters}/replace_proof_converter.h (100%) diff --git a/src/ast/converters/CMakeLists.txt b/src/ast/converters/CMakeLists.txt index c11b0dbe1..5343c32a2 100644 --- a/src/ast/converters/CMakeLists.txt +++ b/src/ast/converters/CMakeLists.txt @@ -1,8 +1,10 @@ z3_add_component(converters SOURCES + equiv_proof_converter.cpp + generic_model_converter.cpp model_converter.cpp proof_converter.cpp - generic_model_converter.cpp + replace_proof_converter.cpp COMPONENT_DEPENDENCIES model ) diff --git a/src/tactic/equiv_proof_converter.cpp b/src/ast/converters/equiv_proof_converter.cpp similarity index 93% rename from src/tactic/equiv_proof_converter.cpp rename to src/ast/converters/equiv_proof_converter.cpp index 8bec082d3..d0ed94d8b 100644 --- a/src/tactic/equiv_proof_converter.cpp +++ b/src/ast/converters/equiv_proof_converter.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include "tactic/equiv_proof_converter.h" +#include "ast/converters/equiv_proof_converter.h" #include "ast/ast_pp.h" #include "ast/scoped_proof.h" diff --git a/src/tactic/equiv_proof_converter.h b/src/ast/converters/equiv_proof_converter.h similarity index 95% rename from src/tactic/equiv_proof_converter.h rename to src/ast/converters/equiv_proof_converter.h index 87a8f7131..7f98d1e0c 100644 --- a/src/tactic/equiv_proof_converter.h +++ b/src/ast/converters/equiv_proof_converter.h @@ -23,7 +23,7 @@ Revision History: #pragma once -#include "tactic/replace_proof_converter.h" +#include "ast/converters/replace_proof_converter.h" class equiv_proof_converter : public proof_converter { ast_manager& m; diff --git a/src/tactic/replace_proof_converter.cpp b/src/ast/converters/replace_proof_converter.cpp similarity index 97% rename from src/tactic/replace_proof_converter.cpp rename to src/ast/converters/replace_proof_converter.cpp index 4a98110eb..81fe251a3 100644 --- a/src/tactic/replace_proof_converter.cpp +++ b/src/ast/converters/replace_proof_converter.cpp @@ -17,7 +17,7 @@ Revision History: --*/ -#include "tactic/replace_proof_converter.h" +#include "ast/converters/replace_proof_converter.h" #include "ast/expr_functors.h" #include "ast/ast_pp.h" #include "ast/for_each_expr.h" diff --git a/src/tactic/replace_proof_converter.h b/src/ast/converters/replace_proof_converter.h similarity index 100% rename from src/tactic/replace_proof_converter.h rename to src/ast/converters/replace_proof_converter.h diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 46e0b42bf..3d5501b37 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -24,7 +24,7 @@ Revision History: #include "util/obj_hashtable.h" #include "util/uint_set.h" #include "tactic/horn_subsume_model_converter.h" -#include "tactic/replace_proof_converter.h" +#include "ast/converters/replace_proof_converter.h" #include "ast/substitution/substitution.h" #include "ast/rewriter/ast_counter.h" #include "util/statistics.h" diff --git a/src/muz/transforms/dl_mk_array_blast.h b/src/muz/transforms/dl_mk_array_blast.h index 6d1a69825..352c8a248 100644 --- a/src/muz/transforms/dl_mk_array_blast.h +++ b/src/muz/transforms/dl_mk_array_blast.h @@ -22,9 +22,9 @@ Revision History: #include "muz/base/dl_rule_set.h" #include "muz/base/dl_rule_transformer.h" #include "muz/transforms/dl_mk_interp_tail_simplifier.h" -#include "tactic/equiv_proof_converter.h" #include "ast/array_decl_plugin.h" #include "ast/rewriter/expr_safe_replace.h" +#include "ast/converters/equiv_proof_converter.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_elim_term_ite.h b/src/muz/transforms/dl_mk_elim_term_ite.h index 11bfb8f23..98acd12f1 100644 --- a/src/muz/transforms/dl_mk_elim_term_ite.h +++ b/src/muz/transforms/dl_mk_elim_term_ite.h @@ -21,7 +21,7 @@ Revision History: #include "muz/base/dl_context.h" #include "muz/base/dl_rule_set.h" #include "muz/base/dl_rule_transformer.h" -#include "tactic/equiv_proof_converter.h" +#include "ast/converters/equiv_proof_converter.h" namespace datalog { class mk_elim_term_ite : public rule_transformer::plugin { diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index ab81ebfe2..17f31cacf 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -1,14 +1,12 @@ z3_add_component(tactic SOURCES dependency_converter.cpp - equiv_proof_converter.cpp goal.cpp goal_num_occurs.cpp goal_shared_occs.cpp goal_util.cpp horn_subsume_model_converter.cpp probe.cpp - replace_proof_converter.cpp tactical.cpp tactic.cpp COMPONENT_DEPENDENCIES From 9007bdf780fa575a4787c121c6daf3b8ec3fea84 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 20:26:02 -0700 Subject: [PATCH 223/477] move horn_subsume_model_converter to ast/converters --- src/ast/converters/CMakeLists.txt | 1 + .../converters}/horn_subsume_model_converter.cpp | 10 +++++----- .../converters}/horn_subsume_model_converter.h | 0 src/muz/base/dl_util.h | 3 ++- src/tactic/CMakeLists.txt | 1 - 5 files changed, 8 insertions(+), 7 deletions(-) rename src/{tactic => ast/converters}/horn_subsume_model_converter.cpp (99%) rename src/{tactic => ast/converters}/horn_subsume_model_converter.h (100%) diff --git a/src/ast/converters/CMakeLists.txt b/src/ast/converters/CMakeLists.txt index 5343c32a2..52895f064 100644 --- a/src/ast/converters/CMakeLists.txt +++ b/src/ast/converters/CMakeLists.txt @@ -2,6 +2,7 @@ z3_add_component(converters SOURCES equiv_proof_converter.cpp generic_model_converter.cpp + horn_subsume_model_converter.cpp model_converter.cpp proof_converter.cpp replace_proof_converter.cpp diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/ast/converters/horn_subsume_model_converter.cpp similarity index 99% rename from src/tactic/horn_subsume_model_converter.cpp rename to src/ast/converters/horn_subsume_model_converter.cpp index 979359a46..a0c8b341e 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/ast/converters/horn_subsume_model_converter.cpp @@ -18,14 +18,14 @@ Revision History: --*/ -#include "tactic/horn_subsume_model_converter.h" -#include "ast/rewriter/var_subst.h" #include "ast/ast_pp.h" -#include "model/model_smt2_pp.h" -#include "ast/rewriter/bool_rewriter.h" -#include "ast/rewriter/th_rewriter.h" #include "ast/for_each_expr.h" #include "ast/well_sorted.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" +#include "model/model_smt2_pp.h" +#include "ast/converters/horn_subsume_model_converter.h" void horn_subsume_model_converter::insert(app* head, expr* body) { m_delay_head.push_back(head); diff --git a/src/tactic/horn_subsume_model_converter.h b/src/ast/converters/horn_subsume_model_converter.h similarity index 100% rename from src/tactic/horn_subsume_model_converter.h rename to src/ast/converters/horn_subsume_model_converter.h diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 3d5501b37..4688a67fd 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -18,12 +18,13 @@ Revision History: --*/ #pragma once + #include #include "ast/ast.h" #include "util/hashtable.h" #include "util/obj_hashtable.h" #include "util/uint_set.h" -#include "tactic/horn_subsume_model_converter.h" +#include "ast/converters/horn_subsume_model_converter.h" #include "ast/converters/replace_proof_converter.h" #include "ast/substitution/substitution.h" #include "ast/rewriter/ast_counter.h" diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index 17f31cacf..72bbbc303 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -5,7 +5,6 @@ z3_add_component(tactic goal_num_occurs.cpp goal_shared_occs.cpp goal_util.cpp - horn_subsume_model_converter.cpp probe.cpp tactical.cpp tactic.cpp From e8112a6564fa5891b8459ae477971282e5e7d5f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 21:35:07 -0700 Subject: [PATCH 224/477] add initial stubs for model reconstruction trail --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/dependent_expr_state.h | 3 +- .../model_reconstruction_trail.cpp | 43 ++++++++++ .../simplifiers/model_reconstruction_trail.h | 80 +++++++++++++++++++ 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/ast/simplifiers/model_reconstruction_trail.cpp create mode 100644 src/ast/simplifiers/model_reconstruction_trail.h diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index a260dd3b7..dc7aa6fb6 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(simplifiers bv_slice.cpp euf_completion.cpp extract_eqs.cpp + model_reconstruction_trail.cpp solve_eqs.cpp COMPONENT_DEPENDENCIES euf diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 34517525f..32ad59681 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -32,8 +32,9 @@ Author: #include "util/trail.h" #include "util/statistics.h" #include "util/params.h" -#include "ast/simplifiers/dependent_expr.h" #include "ast/converters/model_converter.h" +#include "ast/simplifiers/dependent_expr.h" + /** abstract interface to state updated by simplifiers. diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp new file mode 100644 index 000000000..f99685854 --- /dev/null +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + model_reconstruction_trail.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-3. + +--*/ + + +#include "ast/simplifiers/model_reconstruction_trail.h" +#include "ast/converters/generic_model_converter.h" + + +void model_reconstruction_trail::replay(dependent_expr const& d, vector& added) { + // accumulate a set of dependent exprs, updating m_trail to exclude loose + // substitutions that use variables from the dependent expressions. + ast_mark free_vars; + auto [f, dep] = d; + for (expr* t : subterms::all(expr_ref(f, m))) + free_vars.mark(t); + + NOT_IMPLEMENTED_YET(); +} + +/** + * retrieve the current model converter corresponding to chaining substitutions from the trail. + */ +model_converter_ref model_reconstruction_trail::get_model_converter() { + model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); + // walk the trail from the back. + // add substitutions from the back to the generic model converter + // after they have been normalized using a global replace that replaces + // substituted variables by their terms. + NOT_IMPLEMENTED_YET(); + return mc; + +} + diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h new file mode 100644 index 000000000..eeaf786d9 --- /dev/null +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -0,0 +1,80 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + model_reconstruction_trail.h + +Abstract: + + Model reconstruction trail + A model reconstruction trail comprises of a sequence of assignments + together with assertions that were removed in favor of the assignments. + The assignments satisfy the removed assertions but are not (necessarily) + equivalent to the removed assertions. For the case where assignments + are equivalent to removed assertions, we squash the removed assertions + and don't track them. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-3. + +--*/ + +#pragma once + +#include "util/scoped_ptr_vector.h" +#include "ast/rewriter/expr_replacer.h" +#include "ast/simplifiers/dependent_expr.h" +#include "ast/converters/model_converter.h" + +class model_reconstruction_trail { + + ast_manager& m; + + struct model_reconstruction_trail_entry { + scoped_ptr m_replace; + vector m_removed; + model_reconstruction_trail_entry(expr_replacer* r, vector const& rem) : + m_replace(r), m_removed(rem) {} + }; + + scoped_ptr_vector m_trail; + unsigned_vector m_limit; + +public: + + model_reconstruction_trail(ast_manager& m) : m(m) {} + + /** + * add a new substitution to the stack + */ + void push(expr_replacer* r, vector const& removed) { + m_trail.push_back(alloc(model_reconstruction_trail_entry, r, removed)); + } + + /** + * register a new depedent expression, update the trail + * by removing substitutions that are not equivalence preserving. + */ + void replay(dependent_expr const& d, vector& added); + + /** + * retrieve the current model converter corresponding to chaining substitutions from the trail. + */ + model_converter_ref get_model_converter(); + + /** + * push a context. Portions of the trail added within a context are removed after a context pop. + */ + void push() { + m_limit.push_back(m_trail.size()); + } + + void pop(unsigned n) { + unsigned old_sz = m_limit[m_limit.size() - n]; + m_trail.resize(old_sz); + m_limit.shrink(m_limit.size() - n); + } +}; + From 626380b3c7573da941bed303e4548cac49b17953 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 Nov 2022 22:08:21 -0700 Subject: [PATCH 225/477] fixing build Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/model_reconstruction_trail.cpp | 7 ++++--- src/test/horn_subsume_model_converter.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index f99685854..2e8eab0e6 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -12,6 +12,7 @@ Author: --*/ +#include "ast/for_each_expr.h" #include "ast/simplifiers/model_reconstruction_trail.h" #include "ast/converters/generic_model_converter.h" @@ -20,9 +21,9 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vector Date: Fri, 4 Nov 2022 09:35:58 -0700 Subject: [PATCH 226/477] fixes #6439 #6436 --- src/api/api_ast.cpp | 8 +++++++- src/ast/ast.h | 1 + src/ast/recfun_decl_plugin.h | 3 ++- src/muz/base/dl_context.cpp | 6 ++++++ src/smt/smt_context_pp.cpp | 2 +- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index df3059d4b..a8f4d74b7 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -137,7 +137,7 @@ extern "C" { ast_manager& m = mk_c(c)->m(); recfun::decl::plugin& p = mk_c(c)->recfun().get_plugin(); if (!p.has_def(d)) { - std::string msg = "function " + mk_pp(d, m) + " needs to be defined using rec_func_decl"; + std::string msg = "function " + mk_pp(d, m) + " needs to be declared using rec_func_decl"; SET_ERROR_CODE(Z3_INVALID_ARG, msg.c_str()); return; } @@ -158,6 +158,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } + if (!pd.get_def()->get_cases().empty()) { + std::string msg = "function " + mk_pp(d, m) + " has already been given a definition"; + SET_ERROR_CODE(Z3_INVALID_ARG, msg.c_str()); + return; + } + if (abs_body->get_sort() != d->get_range()) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; diff --git a/src/ast/ast.h b/src/ast/ast.h index ce9de96d4..7514055c5 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1387,6 +1387,7 @@ inline bool is_app_of(expr const * n, family_id fid, decl_kind k) { return n->ge inline bool is_sort_of(sort const * s, family_id fid, decl_kind k) { return s->is_sort_of(fid, k); } inline bool is_uninterp_const(expr const * n) { return n->get_kind() == AST_APP && to_app(n)->get_num_args() == 0 && to_app(n)->get_family_id() == null_family_id; } inline bool is_uninterp(expr const * n) { return n->get_kind() == AST_APP && to_app(n)->get_family_id() == null_family_id; } +inline bool is_uninterp(func_decl const * n) { return n->get_family_id() == null_family_id; } inline bool is_decl_of(func_decl const * d, family_id fid, decl_kind k) { return d->get_family_id() == fid && d->get_decl_kind() == k; } inline bool is_ground(expr const * n) { return is_app(n) && to_app(n)->is_ground(); } inline bool is_non_ground(expr const * n) { return ( ! is_ground(n)); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index dcff35e82..8e1279c0a 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -203,8 +203,9 @@ namespace recfun { def const& get_def(func_decl* f) const { return *(m_defs[f]); } promise_def get_promise_def(func_decl* f) const { return promise_def(&u(), m_defs[f]); } def& get_def(func_decl* f) { return *(m_defs[f]); } - bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); } + bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); } case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); } + bool is_defined(func_decl* f) {return has_case_def(f) && !get_def(f).get_cases().empty(); } func_decl_ref_vector get_rec_funs() { func_decl_ref_vector result(m()); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 4efe79dd3..c9d2c7797 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -644,6 +644,12 @@ namespace datalog { } void context::add_table_fact(func_decl * pred, const table_fact & fact) { + if (!is_uninterp(pred)) { + std::stringstream strm; + strm << "Predicate " << pred->get_name() << " when used for facts should be uninterpreted"; + throw default_exception(strm.str()); + } + if (get_engine() == DATALOG_ENGINE) { ensure_engine(); m_rel->add_fact(pred, fact); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 24bfb3355..40e789204 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -166,7 +166,7 @@ namespace smt { unsigned num = get_num_bool_vars(); for (unsigned v = 0; v < num; v++) { expr * n = m_bool_var2expr[v]; - ast_def_ll_pp(out, m, n, get_pp_visited(), true, false); + ast_def_ll_pp(out << v << " ", m, n, get_pp_visited(), true, false); } } From 28668c6efc5c6d6fa5cdfe630b56d7c370b13f53 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2022 11:25:05 -0700 Subject: [PATCH 227/477] set up model reconstruction trail --- src/ast/expr_substitution.h | 4 +- src/ast/rewriter/expr_replacer.cpp | 5 ++ src/ast/rewriter/expr_replacer.h | 7 +- src/ast/simplifiers/dependent_expr.h | 4 + .../model_reconstruction_trail.cpp | 76 +++++++++++++++++-- .../simplifiers/model_reconstruction_trail.h | 62 +++++++++------ src/ast/simplifiers/solve_eqs.cpp | 10 +-- src/muz/spacer/spacer_iuc_solver.cpp | 6 +- 8 files changed, 130 insertions(+), 44 deletions(-) diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index 6d4b1b618..0e285ff7d 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -44,8 +44,10 @@ public: bool empty() const { return m_subst.empty(); } unsigned size() const { return m_subst.size(); } void insert(expr * s, expr * def, proof * def_pr = nullptr, expr_dependency * def_dep = nullptr); + void insert(expr* s, expr* def, expr_dependency* def_dep) { insert(s, def, nullptr, def_dep); } void erase(expr * s); - expr* find(expr* s) { proof* pr; expr* def; VERIFY(find(s, def, pr)); SASSERT(def); return def; } + expr* find(expr* s) { return m_subst[s]; } + expr_dependency* dep(expr* s) { return (*m_subst_dep)[s]; } bool find(expr * s, expr * & def, proof * & def_pr); bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep); bool contains(expr * s); diff --git a/src/ast/rewriter/expr_replacer.cpp b/src/ast/rewriter/expr_replacer.cpp index 4fa83bed0..1007261ae 100644 --- a/src/ast/rewriter/expr_replacer.cpp +++ b/src/ast/rewriter/expr_replacer.cpp @@ -25,6 +25,11 @@ void expr_replacer::operator()(expr * t, expr_ref & result, proof_ref & result_p operator()(t, result, result_pr, result_dep); } +void expr_replacer::operator()(expr* t, expr_ref& result, expr_dependency_ref& result_dep) { + proof_ref result_pr(m()); + operator()(t, result, result_pr, result_dep); +} + void expr_replacer::operator()(expr * t, expr_ref & result) { proof_ref pr(m()); operator()(t, result, pr); diff --git a/src/ast/rewriter/expr_replacer.h b/src/ast/rewriter/expr_replacer.h index 82982adff..50831073b 100644 --- a/src/ast/rewriter/expr_replacer.h +++ b/src/ast/rewriter/expr_replacer.h @@ -34,9 +34,10 @@ public: virtual void set_substitution(expr_substitution * s) = 0; virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & deps) = 0; - virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr); - virtual void operator()(expr * t, expr_ref & result); - virtual void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); } + void operator()(expr* t, expr_ref& result, expr_dependency_ref& deps); + void operator()(expr * t, expr_ref & result, proof_ref & result_pr); + void operator()(expr * t, expr_ref & result); + void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); } virtual unsigned get_num_steps() const { return 0; } virtual void reset() = 0; diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index 9d6d8625e..53f9cb9d8 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -68,6 +68,10 @@ public: m_fml = nullptr; m_dep = nullptr; } + + ast_manager& get_manager() const { return m; } + + expr* fml() const { return m_fml; } std::tuple operator()() const { return { m_fml, m_dep }; diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 2e8eab0e6..077443e7e 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -21,24 +21,86 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorm_active) + continue; + + // updates that have no intersections with current variables are skipped + if (!t->intersects(free_vars)) + continue; + + // loose entries that intersect with free vars are deleted from the trail + // and their removed formulas are added to the resulting constraints. + if (t->is_loose()) { + added.append(t->m_removed); + for (auto r : t->m_removed) + add_vars(r, free_vars); + m_trail_stack.push(value_trail(t->m_active)); + t->m_active = false; + continue; + } + + // rigid entries: + // apply substitution to added in case of rigid model convertions + for (auto& d : added) { + auto [f, dep1] = d(); + expr_ref g(m); + expr_dependency_ref dep2(m); + (*t->m_replace)(f, g, dep2); + d = dependent_expr(m, g, m.mk_join(dep1, dep2)); + } + } } /** * retrieve the current model converter corresponding to chaining substitutions from the trail. */ model_converter_ref model_reconstruction_trail::get_model_converter() { - model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); + + // // walk the trail from the back // add substitutions from the back to the generic model converter // after they have been normalized using a global replace that replaces // substituted variables by their terms. - NOT_IMPLEMENTED_YET(); - return mc; + // + + scoped_ptr rp = mk_default_expr_replacer(m, true); + scoped_ptr subst = alloc(expr_substitution, m, true, false); + rp->set_substitution(subst.get()); + generic_model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); + bool first = true; + for (unsigned i = m_trail.size(); i-- > 0; ) { + auto* t = m_trail[i]; + if (!t->m_active) + continue; + + if (first) { + first = false; + for (auto const& [v, def] : t->m_subst->sub()) { + expr_dependency* dep = t->m_subst->dep(v); + subst->insert(v, def, dep); + mc->add(v, def); + } + continue; + } + expr_dependency_ref new_dep(m); + expr_ref new_def(m); + + for (auto const& [v, def] : t->m_subst->sub()) { + rp->operator()(def, new_def, new_dep); + expr_dependency* dep = t->m_subst->dep(v); + new_dep = m.mk_join(dep, new_dep); + subst->insert(v, new_def, new_dep); + mc->add(v, new_def); + } + + } + return model_converter_ref(mc.get()); } diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index eeaf786d9..8f1ba4381 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -24,33 +24,62 @@ Author: #pragma once #include "util/scoped_ptr_vector.h" +#include "util/trail.h" +#include "ast/for_each_expr.h" #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/dependent_expr.h" #include "ast/converters/model_converter.h" class model_reconstruction_trail { - ast_manager& m; + struct entry { + scoped_ptr m_replace; + scoped_ptr m_subst; + vector m_removed; + bool m_active = true; + + entry(expr_replacer* r, expr_substitution* s, vector const& rem) : + m_replace(r), m_subst(s), m_removed(rem) {} + + bool is_loose() const { return !m_removed.empty(); } + + bool intersects(ast_mark const& free_vars) const { + return std::any_of(m_subst->sub().begin(), m_subst->sub().end(), [&](auto const& kv) { return free_vars.is_marked(kv.m_key); }); + } + - struct model_reconstruction_trail_entry { - scoped_ptr m_replace; - vector m_removed; - model_reconstruction_trail_entry(expr_replacer* r, vector const& rem) : - m_replace(r), m_removed(rem) {} }; - scoped_ptr_vector m_trail; - unsigned_vector m_limit; + ast_manager& m; + trail_stack& m_trail_stack; + scoped_ptr_vector m_trail; + + void add_vars(dependent_expr const& d, ast_mark& free_vars) { + for (expr* t : subterms::all(expr_ref(d.fml(), d.get_manager()))) + free_vars.mark(t, true); + } + + bool intersects(ast_mark const& free_vars, dependent_expr const& d) { + expr_ref term(d.fml(), d.get_manager()); + auto iter = subterms::all(term); + return std::any_of(iter.begin(), iter.end(), [&](expr* t) { return free_vars.is_marked(t); }); + } + + bool intersects(ast_mark const& free_vars, vector const& added) { + return std::any_of(added.begin(), added.end(), [&](dependent_expr const& d) { return intersects(free_vars, d); }); + } public: - model_reconstruction_trail(ast_manager& m) : m(m) {} + model_reconstruction_trail(ast_manager& m, trail_stack& tr): + m(m), m_trail_stack(tr) {} /** * add a new substitution to the stack */ void push(expr_replacer* r, vector const& removed) { - m_trail.push_back(alloc(model_reconstruction_trail_entry, r, removed)); + m_trail.push_back(alloc(entry, r, nullptr, removed)); + m_trail_stack.push(push_back_vector(m_trail)); } /** @@ -63,18 +92,5 @@ public: * retrieve the current model converter corresponding to chaining substitutions from the trail. */ model_converter_ref get_model_converter(); - - /** - * push a context. Portions of the trail added within a context are removed after a context pop. - */ - void push() { - m_limit.push_back(m_trail.size()); - } - - void pop(unsigned n) { - unsigned old_sz = m_limit[m_limit.size() - n]; - m_trail.resize(old_sz); - m_limit.shrink(m_limit.size() - n); - } }; diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 6b2a27d2d..e4361ad97 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -60,7 +60,7 @@ namespace euf { m_id2level.reset(); m_id2level.resize(m_id2var.size(), UINT_MAX); m_subst_ids.reset(); - m_subst = alloc(expr_substitution, m, false, false); + m_subst = alloc(expr_substitution, m, true, false); auto is_explored = [&](unsigned id) { return m_id2level[id] != UINT_MAX; @@ -120,16 +120,15 @@ namespace euf { expr_dependency_ref new_dep(m); expr_ref new_def(m); - proof_ref new_pr(m); for (unsigned id : m_subst_ids) { if (!m.inc()) break; auto const& [v, def, dep] = m_next[id][0]; - rp->operator()(def, new_def, new_pr, new_dep); + rp->operator()(def, new_def, new_dep); m_stats.m_num_steps += rp->get_num_steps() + 1; new_dep = m.mk_join(dep, new_dep); - m_subst->insert(v, new_def, new_pr, new_dep); + m_subst->insert(v, new_def, nullptr, new_dep); // we updated the substitution, but we don't need to reset rp // because all cached values there do not depend on v. } @@ -149,11 +148,10 @@ namespace euf { scoped_ptr rp = mk_default_expr_replacer(m, true); rp->set_substitution(m_subst.get()); expr_ref new_f(m); - proof_ref new_pr(m); expr_dependency_ref new_dep(m); for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { auto [f, d] = m_fmls[i](); - rp->operator()(f, new_f, new_pr, new_dep); + rp->operator()(f, new_f, new_dep); if (new_f == f) continue; new_dep = m.mk_join(d, new_dep); diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 4f7342590..b8b51c0c6 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -244,12 +244,10 @@ namespace spacer { } void iuc_solver::elim_proxies (expr_ref_vector &v) { - expr_ref f = mk_and (v); scoped_ptr rep = mk_expr_simp_replacer (m); rep->set_substitution (&m_elim_proxies_sub); - (*rep)(f); - v.reset(); - flatten_and(f, v); + (*rep)(v); + flatten_and(v); } void iuc_solver::get_iuc(expr_ref_vector &core) { From de9368bab05cc29b7f151bcc1987985d1f0456fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2022 11:25:34 -0700 Subject: [PATCH 228/477] Update expr_replacer.h --- src/ast/rewriter/expr_replacer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/rewriter/expr_replacer.h b/src/ast/rewriter/expr_replacer.h index 50831073b..c1bfabd12 100644 --- a/src/ast/rewriter/expr_replacer.h +++ b/src/ast/rewriter/expr_replacer.h @@ -38,6 +38,7 @@ public: void operator()(expr * t, expr_ref & result, proof_ref & result_pr); void operator()(expr * t, expr_ref & result); void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); } + void operator()(expr_ref_vector& v) { expr_ref t(m()); for (unsigned i = 0; i < v.size(); ++i) (*this)(v.get(i), t), v[i] = t; } virtual unsigned get_num_steps() const { return 0; } virtual void reset() = 0; From 49d149045461c5078b4cd86ec65081959a9c1d48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2022 12:48:30 -0700 Subject: [PATCH 229/477] add ad-hoc any-of for cross compatibility and simplifying interface Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/model_reconstruction_trail.h | 8 +++++--- src/util/util.h | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 8f1ba4381..96d27e4c4 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -44,7 +44,10 @@ class model_reconstruction_trail { bool is_loose() const { return !m_removed.empty(); } bool intersects(ast_mark const& free_vars) const { - return std::any_of(m_subst->sub().begin(), m_subst->sub().end(), [&](auto const& kv) { return free_vars.is_marked(kv.m_key); }); + for (auto const& [k, v] : m_subst->sub()) + if (free_vars.is_marked(k)) + return true; + return false; } @@ -61,8 +64,7 @@ class model_reconstruction_trail { bool intersects(ast_mark const& free_vars, dependent_expr const& d) { expr_ref term(d.fml(), d.get_manager()); - auto iter = subterms::all(term); - return std::any_of(iter.begin(), iter.end(), [&](expr* t) { return free_vars.is_marked(t); }); + return any_of(subterms::all(term), [&](expr* t) { return free_vars.is_marked(t); }); } bool intersects(ast_mark const& free_vars, vector const& added) { diff --git a/src/util/util.h b/src/util/util.h index 9d129f9a7..c3f06d8d3 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -25,6 +25,7 @@ Revision History: #include #include #include +#include #ifndef SIZE_MAX #define SIZE_MAX std::numeric_limits::max() @@ -179,9 +180,8 @@ void display(std::ostream & out, const IT & begin, const IT & end, const char * template struct delete_proc { void operator()(T * ptr) { - if (ptr) { - dealloc(ptr); - } + if (ptr) + dealloc(ptr); } }; @@ -360,6 +360,15 @@ void fatal_error(int error_code); void set_fatal_error_handler(void (*pfn)(int error_code)); +template +bool any_of(S& set, T& p) { + for (auto const& s : set) + if (p(s)) + return true; + return false; +} +// #define any_of(S, p) { for (auto const& s : S) if (p(s)) return true; return false; } + /** \brief Iterator for the [0..sz[0]) X [0..sz[1]) X ... X [0..sz[n-1]). it contains the current value. From 7bb962d9340ca96c088bc8878f813dc4490823b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2022 12:49:55 -0700 Subject: [PATCH 230/477] add ad-hoc any-of for cross compatibility and simplifying interface Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/model_reconstruction_trail.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 96d27e4c4..4aa8a54fd 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -68,7 +68,7 @@ class model_reconstruction_trail { } bool intersects(ast_mark const& free_vars, vector const& added) { - return std::any_of(added.begin(), added.end(), [&](dependent_expr const& d) { return intersects(free_vars, d); }); + return any_of(added, [&](dependent_expr const& d) { return intersects(free_vars, d); }); } public: From 154b09309b5ea5200b71a25966d1f733d5e10e6f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2022 14:04:44 -0700 Subject: [PATCH 231/477] fixing build, wip on model reconstruction integration into dependent-expr-state --- src/ast/rewriter/expr_replacer.h | 1 + src/ast/simplifiers/bv_slice.cpp | 4 +- src/ast/simplifiers/dependent_expr_state.h | 24 +++++--- src/ast/simplifiers/euf_completion.cpp | 2 +- .../model_reconstruction_trail.cpp | 22 ++++--- .../simplifiers/model_reconstruction_trail.h | 14 ++--- src/ast/simplifiers/solve_eqs.cpp | 58 +++++++++---------- src/ast/simplifiers/solve_eqs.h | 3 +- src/tactic/dependent_expr_state_tactic.h | 10 +++- src/util/util.h | 1 - 10 files changed, 74 insertions(+), 65 deletions(-) diff --git a/src/ast/rewriter/expr_replacer.h b/src/ast/rewriter/expr_replacer.h index c1bfabd12..96418f00b 100644 --- a/src/ast/rewriter/expr_replacer.h +++ b/src/ast/rewriter/expr_replacer.h @@ -39,6 +39,7 @@ public: void operator()(expr * t, expr_ref & result); void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); } void operator()(expr_ref_vector& v) { expr_ref t(m()); for (unsigned i = 0; i < v.size(); ++i) (*this)(v.get(i), t), v[i] = t; } + std::pair replace_with_dep(expr* t) { expr_ref r(m()); expr_dependency_ref d(m()); (*this)(t, r, d); return { r, d }; } virtual unsigned get_num_steps() const { return 0; } virtual void reset() = 0; diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp index f39fa932e..75e0a890c 100644 --- a/src/ast/simplifiers/bv_slice.cpp +++ b/src/ast/simplifiers/bv_slice.cpp @@ -109,12 +109,12 @@ namespace bv { }; if (lo > 0 && !b.contains(lo)) { b.insert(lo); - if (m_num_scopes > 0) + if (num_scopes() > 0) m_trail.push(remove_set(b, lo)); } if (hi + 1 < sz && !b.contains(hi + 1)) { b.insert(hi + 1); - if (m_num_scopes > 0) + if (num_scopes() > 0) m_trail.push(remove_set(b, hi+ 1)); } } diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 32ad59681..803c58510 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -34,6 +34,7 @@ Author: #include "util/params.h" #include "ast/converters/model_converter.h" #include "ast/simplifiers/dependent_expr.h" +#include "ast/simplifiers/model_reconstruction_trail.h" /** @@ -46,6 +47,12 @@ public: virtual dependent_expr const& operator[](unsigned i) = 0; virtual void update(unsigned i, dependent_expr const& j) = 0; virtual bool inconsistent() = 0; + + trail_stack m_trail; + void push() { m_trail.push_scope(); } + void pop(unsigned n) { m_trail.pop_scope(n); } + + virtual model_reconstruction_trail* model_trail() { return nullptr; } }; /** @@ -55,20 +62,21 @@ class dependent_expr_simplifier { protected: ast_manager& m; dependent_expr_state& m_fmls; - unsigned m_qhead = 0; // pointer into last processed formula in m_fmls - unsigned m_num_scopes = 0; - trail_stack m_trail; - void advance_qhead(unsigned sz) { if (m_num_scopes > 0) m_trail.push(value_trail(m_qhead)); m_qhead = sz; } + trail_stack& m_trail; + unsigned m_qhead = 0; // pointer into last processed formula in m_fmls + + unsigned num_scopes() const { return m_trail.get_num_scopes(); } + + void advance_qhead(unsigned sz) { if (num_scopes() > 0) m_trail.push(value_trail(m_qhead)); m_qhead = sz; } public: - dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s) {} + dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {} virtual ~dependent_expr_simplifier() {} - virtual void push() { m_num_scopes++; m_trail.push_scope(); } - virtual void pop(unsigned n) { m_num_scopes -= n; m_trail.pop_scope(n); } + virtual void push() { } + virtual void pop(unsigned n) { } virtual void reduce() = 0; virtual void collect_statistics(statistics& st) const {} virtual void reset_statistics() {} virtual void updt_params(params_ref const& p) {} - virtual model_converter_ref get_model_converter() { return model_converter_ref(); } }; /** diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index e5b328d7f..e1360fa0b 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -213,7 +213,7 @@ namespace euf { old_value = nullptr; } }; - if (m_num_scopes > 0) + if (num_scopes() > 0) m_trail.push(vtrail(m_canonical, n->get_id())); m_canonical.setx(n->get_id(), e); m_epochs.setx(n->get_id(), m_epoch, 0); diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 077443e7e..a8e75bfa3 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -21,11 +21,12 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vector rp = mk_default_expr_replacer(m, false); add_vars(d, free_vars); added.push_back(d); + for (auto& t : m_trail) { if (!t->m_active) continue; @@ -45,13 +46,12 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorset_substitution(t->m_subst.get()); // rigid entries: // apply substitution to added in case of rigid model convertions for (auto& d : added) { auto [f, dep1] = d(); - expr_ref g(m); - expr_dependency_ref dep2(m); - (*t->m_replace)(f, g, dep2); + auto [g, dep2] = rp->replace_with_dep(f); d = dependent_expr(m, g, m.mk_join(dep1, dep2)); } } @@ -69,9 +69,9 @@ model_converter_ref model_reconstruction_trail::get_model_converter() { // substituted variables by their terms. // - scoped_ptr rp = mk_default_expr_replacer(m, true); - scoped_ptr subst = alloc(expr_substitution, m, true, false); - rp->set_substitution(subst.get()); + scoped_ptr rp = mk_default_expr_replacer(m, false); + expr_substitution subst(m, true, false); + rp->set_substitution(&subst); generic_model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); bool first = true; for (unsigned i = m_trail.size(); i-- > 0; ) { @@ -83,19 +83,17 @@ model_converter_ref model_reconstruction_trail::get_model_converter() { first = false; for (auto const& [v, def] : t->m_subst->sub()) { expr_dependency* dep = t->m_subst->dep(v); - subst->insert(v, def, dep); + subst.insert(v, def, dep); mc->add(v, def); } continue; } - expr_dependency_ref new_dep(m); - expr_ref new_def(m); for (auto const& [v, def] : t->m_subst->sub()) { - rp->operator()(def, new_def, new_dep); + auto [new_def, new_dep] = rp->replace_with_dep(def); expr_dependency* dep = t->m_subst->dep(v); new_dep = m.mk_join(dep, new_dep); - subst->insert(v, new_def, new_dep); + subst.insert(v, new_def, new_dep); mc->add(v, new_def); } diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 4aa8a54fd..c9b42bc92 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -33,13 +33,12 @@ Author: class model_reconstruction_trail { struct entry { - scoped_ptr m_replace; scoped_ptr m_subst; vector m_removed; bool m_active = true; - entry(expr_replacer* r, expr_substitution* s, vector const& rem) : - m_replace(r), m_subst(s), m_removed(rem) {} + entry(expr_substitution* s, vector const& rem) : + m_subst(s), m_removed(rem) {} bool is_loose() const { return !m_removed.empty(); } @@ -64,7 +63,8 @@ class model_reconstruction_trail { bool intersects(ast_mark const& free_vars, dependent_expr const& d) { expr_ref term(d.fml(), d.get_manager()); - return any_of(subterms::all(term), [&](expr* t) { return free_vars.is_marked(t); }); + auto iter = subterms::all(term); + return any_of(iter, [&](expr* t) { return free_vars.is_marked(t); }); } bool intersects(ast_mark const& free_vars, vector const& added) { @@ -77,10 +77,10 @@ public: m(m), m_trail_stack(tr) {} /** - * add a new substitution to the stack + * add a new substitution to the trail */ - void push(expr_replacer* r, vector const& removed) { - m_trail.push_back(alloc(entry, r, nullptr, removed)); + void push(expr_substitution* s, vector const& removed) { + m_trail.push_back(alloc(entry, s, removed)); m_trail_stack.push(push_back_vector(m_trail)); } diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index e4361ad97..b5b500a96 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -60,7 +60,7 @@ namespace euf { m_id2level.reset(); m_id2level.resize(m_id2var.size(), UINT_MAX); m_subst_ids.reset(); - m_subst = alloc(expr_substitution, m, true, false); + m_subst = alloc(expr_substitution, m, true, false); auto is_explored = [&](unsigned id) { return m_id2level[id] != UINT_MAX; @@ -105,30 +105,22 @@ namespace euf { } } - void solve_eqs::add_subst(dependent_eq const& eq) { - SASSERT(can_be_var(eq.var)); - m_subst->insert(eq.var, eq.term, nullptr, eq.dep); - ++m_stats.m_num_elim_vars; - } - void solve_eqs::normalize() { scoped_ptr rp = mk_default_expr_replacer(m, true); - m_subst->reset(); rp->set_substitution(m_subst.get()); std::sort(m_subst_ids.begin(), m_subst_ids.end(), [&](unsigned u, unsigned v) { return m_id2level[u] > m_id2level[v]; }); - expr_dependency_ref new_dep(m); - expr_ref new_def(m); - for (unsigned id : m_subst_ids) { if (!m.inc()) break; auto const& [v, def, dep] = m_next[id][0]; - rp->operator()(def, new_def, new_dep); + auto [new_def, new_dep] = rp->replace_with_dep(def); m_stats.m_num_steps += rp->get_num_steps() + 1; + ++m_stats.m_num_elim_vars; new_dep = m.mk_join(dep, new_dep); - m_subst->insert(v, new_def, nullptr, new_dep); + m_subst->insert(v, new_def, new_dep); + SASSERT(can_be_var(v)); // we updated the substitution, but we don't need to reset rp // because all cached values there do not depend on v. } @@ -147,11 +139,10 @@ namespace euf { return; scoped_ptr rp = mk_default_expr_replacer(m, true); rp->set_substitution(m_subst.get()); - expr_ref new_f(m); - expr_dependency_ref new_dep(m); + for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { auto [f, d] = m_fmls[i](); - rp->operator()(f, new_f, new_dep); + auto [new_f, new_dep] = rp->replace_with_dep(f); if (new_f == f) continue; new_dep = m.mk_join(d, new_dep); @@ -164,13 +155,27 @@ namespace euf { for (extract_eq* ex : m_extract_plugins) ex->pre_process(m_fmls); - // TODO add a loop. - dep_eq_vector eqs; - get_eqs(eqs); - extract_dep_graph(eqs); - extract_subst(); - apply_subst(); + unsigned count = 0; + do { + m_subst_ids.reset(); + if (!m.inc()) + return; + dep_eq_vector eqs; + get_eqs(eqs); + extract_dep_graph(eqs); + extract_subst(); + apply_subst(); + ++count; + } + while (!m_subst_ids.empty() && count < 20); + advance_qhead(m_fmls.size()); + save_subst(); + } + + void solve_eqs::save_subst() { + if (!m_subst->empty()) + m_fmls.model_trail()->push(m_subst.detach(), {}); } void solve_eqs::filter_unsafe_vars() { @@ -181,16 +186,7 @@ namespace euf { m_unsafe_vars.mark(term); } - typedef generic_model_converter gmc; - model_converter_ref solve_eqs::get_model_converter() { - model_converter_ref mc = alloc(gmc, m, "solve-eqs"); - for (unsigned id : m_subst_ids) { - auto* v = m_id2var[id]; - static_cast(mc.get())->add(v, m_subst->find(v)); - } - return mc; - } solve_eqs::solve_eqs(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_rewriter(m) { diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 49cd90ca2..db7a1323b 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -67,6 +67,7 @@ namespace euf { void extract_dep_graph(dep_eq_vector& eqs); void normalize(); void apply_subst(); + void save_subst(); public: @@ -78,7 +79,5 @@ namespace euf { void updt_params(params_ref const& p) override; void collect_statistics(statistics& st) const override; - - model_converter_ref get_model_converter() override; }; } diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index ae3635c77..719a29eea 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -24,12 +24,16 @@ class dependent_expr_state_tactic : public tactic, public dependent_expr_state { std::string m_name; ref m_factory; scoped_ptr m_simp; + trail_stack m_trail; + scoped_ptr m_model_trail; goal_ref m_goal; dependent_expr m_dep; void init() { if (!m_simp) m_simp = m_factory->mk(m, m_params, *this); + if (!m_model_trail) + m_model_trail = alloc(model_reconstruction_trail, m, m_trail); } public: @@ -60,6 +64,10 @@ public: bool inconsistent() override { return m_goal->inconsistent(); } + + model_reconstruction_trail* model_trail() override { + return m_model_trail.get(); + } char const* name() const override { return m_name.c_str(); } @@ -83,7 +91,7 @@ public: m_simp->reduce(); m_goal->inc_depth(); if (in->models_enabled()) - in->set(m_simp->get_model_converter().get()); + in->set(m_model_trail->get_model_converter().get()); result.push_back(in.get()); } diff --git a/src/util/util.h b/src/util/util.h index c3f06d8d3..925e20186 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -367,7 +367,6 @@ bool any_of(S& set, T& p) { return true; return false; } -// #define any_of(S, p) { for (auto const& s : S) if (p(s)) return true; return false; } /** \brief Iterator for the [0..sz[0]) X [0..sz[1]) X ... X [0..sz[n-1]). From ae2672f132b6d35fea65e178db06bf2133d45513 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2022 14:11:24 -0700 Subject: [PATCH 232/477] fix build Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/util.h b/src/util/util.h index 925e20186..2a037770d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -361,7 +361,7 @@ void set_fatal_error_handler(void (*pfn)(int error_code)); template -bool any_of(S& set, T& p) { +bool any_of(S& set, T const& p) { for (auto const& s : set) if (p(s)) return true; From 4d8860c0bc4f4a587e9e66b3494df446a52c3112 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 5 Nov 2022 10:34:57 -0700 Subject: [PATCH 233/477] wip - adding context equation solver the solve_eqs_tactic is to be replaced by a re-implementation that uses solve_eqs in the simplifiers directory. The re-implementation should address efficiency issues with the previous code. At this point it punts on low level proofs. The plan is to use coarser dependency tracking instead of low level proofs for pre-processing. Dependencies can be converted into a proof hint representation that can be checked using a stronger checker. --- src/ast/occurs.cpp | 43 +++++ src/ast/occurs.h | 9 +- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/dependent_expr.h | 2 + src/ast/simplifiers/dependent_expr_state.h | 3 +- src/ast/simplifiers/extract_eqs.cpp | 52 +++--- src/ast/simplifiers/extract_eqs.h | 7 +- src/ast/simplifiers/solve_context_eqs.cpp | 203 +++++++++++++++++++++ src/ast/simplifiers/solve_context_eqs.h | 58 ++++++ src/ast/simplifiers/solve_eqs.cpp | 39 +++- src/ast/simplifiers/solve_eqs.h | 45 ++--- src/tactic/core/solve_eqs_tactic.cpp | 51 +----- src/tactic/dependent_expr_state_tactic.h | 4 +- src/util/mpn.cpp | 8 +- src/util/util.h | 8 + 15 files changed, 416 insertions(+), 117 deletions(-) create mode 100644 src/ast/simplifiers/solve_context_eqs.cpp create mode 100644 src/ast/simplifiers/solve_context_eqs.h diff --git a/src/ast/occurs.cpp b/src/ast/occurs.cpp index 21e7f5906..2bcd98396 100644 --- a/src/ast/occurs.cpp +++ b/src/ast/occurs.cpp @@ -74,3 +74,46 @@ bool occurs(func_decl * d, expr * n) { return false; } +void mark_occurs(ptr_vector& to_check, expr* v, expr_mark& occ) { + expr_fast_mark2 visited; + occ.mark(v, true); + visited.mark(v, true); + while (!to_check.empty()) { + expr* e = to_check.back(); + if (visited.is_marked(e)) { + to_check.pop_back(); + continue; + } + if (is_app(e)) { + bool does_occur = false; + bool all_visited = true; + for (expr* arg : *to_app(e)) { + if (!visited.is_marked(arg)) { + to_check.push_back(arg); + all_visited = false; + } + else + does_occur |= occ.is_marked(arg); + } + if (all_visited) { + occ.mark(e, does_occur); + visited.mark(e, true); + to_check.pop_back(); + } + } + else if (is_quantifier(e)) { + expr* body = to_quantifier(e)->get_expr(); + if (visited.is_marked(body)) { + visited.mark(e, true); + occ.mark(e, occ.is_marked(body)); + to_check.pop_back(); + } + else + to_check.push_back(body); + } + else { + visited.mark(e, true); + to_check.pop_back(); + } + } +} \ No newline at end of file diff --git a/src/ast/occurs.h b/src/ast/occurs.h index 15a33ddf5..7475a292c 100644 --- a/src/ast/occurs.h +++ b/src/ast/occurs.h @@ -18,8 +18,8 @@ Revision History: --*/ #pragma once -class expr; -class func_decl; +#include "util/vector.h" +#include "ast/ast.h" /** \brief Return true if n1 occurs in n2 @@ -31,4 +31,9 @@ bool occurs(expr * n1, expr * n2); */ bool occurs(func_decl * d, expr * n); +/** +* \brief Mark sub-expressions of to_check by whether v occurs in these. +*/ +void mark_occurs(ptr_vector& to_check, expr* v, expr_mark& occurs); + diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index dc7aa6fb6..ef04cc433 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -4,6 +4,7 @@ z3_add_component(simplifiers euf_completion.cpp extract_eqs.cpp model_reconstruction_trail.cpp + solve_context_eqs.cpp solve_eqs.cpp COMPONENT_DEPENDENCIES euf diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index 53f9cb9d8..f789bf332 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -72,6 +72,8 @@ public: ast_manager& get_manager() const { return m; } expr* fml() const { return m_fml; } + + expr_dependency* dep() const { return m_dep; } std::tuple operator()() const { return { m_fml, m_dep }; diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 803c58510..6bdd34626 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -47,12 +47,13 @@ public: virtual dependent_expr const& operator[](unsigned i) = 0; virtual void update(unsigned i, dependent_expr const& j) = 0; virtual bool inconsistent() = 0; + virtual model_reconstruction_trail& model_trail() = 0; trail_stack m_trail; void push() { m_trail.push_scope(); } void pop(unsigned n) { m_trail.pop_scope(n); } - virtual model_reconstruction_trail* model_trail() { return nullptr; } + }; /** diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 1e9b576e1..e77ce9e06 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -38,9 +38,9 @@ namespace euf { expr* x, * y; if (m.is_eq(f, x, y)) { if (is_uninterp_const(x)) - eqs.push_back(dependent_eq(to_app(x), expr_ref(y, m), d)); + eqs.push_back(dependent_eq(e.fml(), to_app(x), expr_ref(y, m), d)); if (is_uninterp_const(y)) - eqs.push_back(dependent_eq(to_app(y), expr_ref(x, m), d)); + eqs.push_back(dependent_eq(e.fml(), to_app(y), expr_ref(x, m), d)); } expr* c, * th, * el, * x1, * y1, * x2, * y2; if (m_ite_solver && m.is_ite(f, c, th, el)) { @@ -52,13 +52,13 @@ namespace euf { if (x2 == y1 && is_uninterp_const(x2)) std::swap(x1, y1); if (x1 == x2 && is_uninterp_const(x1)) - eqs.push_back(dependent_eq(to_app(x1), expr_ref(m.mk_ite(c, y1, y2), m), d)); + eqs.push_back(dependent_eq(e.fml(), to_app(x1), expr_ref(m.mk_ite(c, y1, y2), m), d)); } } if (is_uninterp_const(f)) - eqs.push_back(dependent_eq(to_app(f), expr_ref(m.mk_true(), m), d)); + eqs.push_back(dependent_eq(e.fml(), to_app(f), expr_ref(m.mk_true(), m), d)); if (m.is_not(f, x) && is_uninterp_const(x)) - eqs.push_back(dependent_eq(to_app(x), expr_ref(m.mk_false(), m), d)); + eqs.push_back(dependent_eq(e.fml(), to_app(x), expr_ref(m.mk_false(), m), d)); } void updt_params(params_ref const& p) { @@ -76,7 +76,7 @@ namespace euf { // solve u mod r1 = y -> u = r1*mod!1 + y - void solve_mod(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + void solve_mod(expr* orig, expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { expr* u, * z; rational r1, r2; if (!a.is_mod(x, u, z)) @@ -87,7 +87,11 @@ namespace euf { return; expr_ref term(m); term = a.mk_add(a.mk_mul(z, m.mk_fresh_const("mod", a.mk_int())), y); - solve_eq(u, term, d, eqs); + + if (is_uninterp_const(u)) + eqs.push_back(dependent_eq(orig, to_app(u), term, d)); + else + solve_eq(orig, u, term, d, eqs); } /*** @@ -96,7 +100,7 @@ namespace euf { * -1*x + Y = Z -> x = Y - Z * a*x + Y = Z -> x = (Z - Y)/a for is-real(x) */ - void solve_add(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + void solve_add(expr* orig, expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { if (!a.is_add(x)) return; expr* u, * z; @@ -115,18 +119,18 @@ namespace euf { for (expr* arg : *to_app(x)) { if (is_uninterp_const(arg)) { mk_term(i); - eqs.push_back(dependent_eq(to_app(arg), term, d)); + eqs.push_back(dependent_eq(orig, to_app(arg), term, d)); } else if (a.is_mul(arg, u, z) && a.is_numeral(u, r) && is_uninterp_const(z)) { if (r == -1) { mk_term(i); term = a.mk_uminus(term); - eqs.push_back(dependent_eq(to_app(z), term, d)); + eqs.push_back(dependent_eq(orig, to_app(z), term, d)); } else if (a.is_real(arg) && r != 0) { mk_term(i); term = a.mk_div(term, u); - eqs.push_back(dependent_eq(to_app(z), term, d)); + eqs.push_back(dependent_eq(orig, to_app(z), term, d)); } } else if (a.is_real(arg) && a.is_mul(arg)) { @@ -155,7 +159,7 @@ namespace euf { } mk_term(i); term = a.mk_div(term, a.mk_mul(args.size(), args.data())); - eqs.push_back(dependent_eq(to_app(xarg), term, d)); + eqs.push_back(dependent_eq(orig, to_app(xarg), term, d)); } } ++i; @@ -165,7 +169,7 @@ namespace euf { /*** * Solve for x * Y = Z, where Y != 0 -> x = Z / Y */ - void solve_mul(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + void solve_mul(expr* orig, expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { if (!a.is_mul(x)) return; rational r; @@ -193,7 +197,7 @@ namespace euf { args.push_back(arg2); } term = a.mk_div(y, a.mk_mul(args)); - eqs.push_back(dependent_eq(to_app(arg), term, d)); + eqs.push_back(dependent_eq(orig, to_app(arg), term, d)); } } @@ -214,22 +218,24 @@ namespace euf { } } - void solve_eq(expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { - solve_add(x, y, d, eqs); - solve_mod(x, y, d, eqs); - solve_mul(x, y, d, eqs); + void solve_eq(expr* orig, expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + solve_add(orig, x, y, d, eqs); + solve_mod(orig, x, y, d, eqs); + solve_mul(orig, x, y, d, eqs); } public: + arith_extract_eq(ast_manager& m) : m(m), a(m), m_args(m) {} + void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { if (!m_enabled) return; auto [f, d] = e(); expr* x, * y; if (m.is_eq(f, x, y) && a.is_int_real(x)) { - solve_eq(x, y, d, eqs); - solve_eq(y, x, d, eqs); + solve_eq(f, x, y, d, eqs); + solve_eq(f, y, x, d, eqs); } } @@ -237,10 +243,8 @@ namespace euf { if (!m_enabled) return; m_nonzero.reset(); - for (unsigned i = 0; i < fmls.size(); ++i) { - auto [f, d] = fmls[i](); - add_pos(f); - } + for (unsigned i = 0; i < fmls.size(); ++i) + add_pos(fmls[i].fml()); } diff --git a/src/ast/simplifiers/extract_eqs.h b/src/ast/simplifiers/extract_eqs.h index 00f96f59b..f38829dfc 100644 --- a/src/ast/simplifiers/extract_eqs.h +++ b/src/ast/simplifiers/extract_eqs.h @@ -27,10 +27,11 @@ Author: namespace euf { struct dependent_eq { - app* var; - expr_ref term; + expr* orig; // original expression that encoded equation + app* var; // isolated variable + expr_ref term; // defined term expr_dependency* dep; - dependent_eq(app* var, expr_ref const& term, expr_dependency* d) : var(var), term(term), dep(d) {} + dependent_eq(expr* orig, app* var, expr_ref const& term, expr_dependency* d) : orig(orig), var(var), term(term), dep(d) {} }; typedef vector dep_eq_vector; diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp new file mode 100644 index 000000000..766c18535 --- /dev/null +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -0,0 +1,203 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + solve_context_eqs.cpp + +Abstract: + + simplifier for solving equations within a context + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +Notes: + +The variable v is solved based on expression e. +Check that every occurrence of v uses e in conjunctive context. + +Walk formulas containing v in as and-or. +Equalities that occur within at least one alternation of or are +considered as candidates. + +To constrain how formulas are traversed, first +label sub-expressions that contain v. An equality eq is safe for v +if every occurrence of v occurs in the same conjunctive context as eq. + +--*/ + +#include "ast/ast.h" +#include "ast/ast_pp.h" +#include "ast/occurs.h" +#include "ast/simplifiers/solve_context_eqs.h" +#include "ast/simplifiers/solve_eqs.h" + +namespace euf { + + + solve_context_eqs::solve_context_eqs(solve_eqs& s): m(s.m), m_fmls(s.m_fmls), m_solve_eqs(s) {} + + bool solve_context_eqs::is_safe_eq(expr* e) { + m_and_pos.reset(); m_and_neg.reset(); m_or_pos.reset(); m_or_neg.reset(); + for (unsigned i = 0; i < m_fmls.size(); ++i) + if (!is_safe_eq(m_fmls[i].fml(), e)) + return false; + return true; + } + + /** + * Check if some conjunction of f contains equality 'e'. + * If this is not the case, then check that every conjunct that contains v + * recursively contains a disjunction that contains 'e'. + */ + bool solve_context_eqs::is_safe_eq(unsigned recursion_depth, expr* f, bool sign, expr* e) { + if (!contains_v(f)) + return true; + signed_expressions conjuncts; + if (contains_conjunctively(f, sign, e, conjuncts)) + return true; + if (recursion_depth > 3) + return false; + return all_of(conjuncts, [&](std::pair const& p) { return is_disjunctively_safe(recursion_depth, p.second, p.first, e); }); + } + + /* + * Every disjunction in f that contains v also contains the equation e. + */ + bool solve_context_eqs::is_disjunctively_safe(unsigned recursion_depth, expr* f, bool sign, expr* e) { + signed_expressions todo; + todo.push_back({sign, f}); + while (!todo.empty()) { + auto [s, f] = todo.back(); + todo.pop_back(); + if (s && m_or_neg.is_marked(f)) + continue; + if (!s && m_or_pos.is_marked(f)) + continue; + if (s) + m_or_neg.mark(f, true); + else + m_or_pos.mark(f, true); + if (!s && f == e) + continue; + else if (!contains_v(f)) + continue; + else if (s && m.is_and(f)) + for (auto* arg : *to_app(f)) + todo.push_back({s, arg}); + else if (!s && m.is_or(f)) + for (auto* arg : *to_app(f)) + todo.push_back({s, arg}); + else if (m.is_not(f, f)) + todo.push_back({!s, f}); + else if (!is_safe_eq(recursion_depth + 1, f, s, e)) + return false; + } + return true; + } + + /** + * Determine whether some conjunction in f contains e. + * If no conjunction contains e, then return the set of conjunctions that contain v. + */ + bool solve_context_eqs::contains_conjunctively(expr* f, bool sign, expr* e, signed_expressions& conjuncts) { + signed_expressions todo; + todo.push_back({sign, f}); + while (!todo.empty()) { + auto [s, f] = todo.back(); + todo.pop_back(); + if (!s && f == e) + return true; + if (!s && m_and_pos.is_marked(f)) + continue; + if (s && m_and_neg.is_marked(f)) + continue; + if (s) + m_and_neg.mark(f, true); + else + m_and_pos.mark(f, true); + if (!contains_v(f)) + continue; + if (!s && m.is_and(f)) + for (auto* arg : *to_app(f)) + todo.push_back({false, arg}); + else if (s && m.is_or(f)) + for (auto* arg : *to_app(f)) + todo.push_back({true, arg}); + else if (m.is_not(f, f)) + todo.push_back({!s, f}); + else + conjuncts.push_back({s, f}); + } + return false; + } + + void solve_context_eqs::init_contains(expr* v) { + m_contains_v.reset(); + for (unsigned i = 0; i < m_fmls.size(); ++i) + m_todo.push_back(m_fmls[i].fml()); + mark_occurs(m_todo, v, m_contains_v); + SASSERT(m_todo.empty()); + } + + void solve_context_eqs::collect_nested_equalities(dep_eq_vector& eqs) { + expr_mark visited; + for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) + collect_nested_equalities(m_fmls[i], visited, eqs); + + unsigned j = 0; + for (auto const& eq : eqs) { + init_contains(eq.var); + if (is_safe_eq(eq.orig)) + eqs[j++] = eq; + } + eqs.shrink(j); + } + + void solve_context_eqs::collect_nested_equalities(dependent_expr const& df, expr_mark& visited, dep_eq_vector& eqs) { + + svector> todo; + todo.push_back({ false, 0, df.fml()}); + + // even depth is conjunctive context, odd is disjunctive + // when alternating between conjunctive and disjunctive context, increment depth. + auto inc_or = [](unsigned depth) { + return (0 == depth % 2) ? depth + 1 : depth; + }; + auto inc_and = [](unsigned depth) { + return (0 == depth % 2) ? depth : depth + 1; + }; + + while (!todo.empty()) { + auto [s, depth, f] = todo.back(); + todo.pop_back(); + if (visited.is_marked(f)) + continue; + visited.mark(f, true); + if (s && m.is_and(f)) { + for (auto* arg : *to_app(f)) + todo.push_back({ s, inc_or(depth), arg }); + } + else if (!s && m.is_or(f)) { + for (auto* arg : *to_app(f)) + todo.push_back({ s, inc_or(depth), arg }); + } + if (!s && m.is_and(f)) { + for (auto* arg : *to_app(f)) + todo.push_back({ s, inc_and(depth), arg }); + } + else if (s && m.is_or(f)) { + for (auto* arg : *to_app(f)) + todo.push_back({ s, inc_and(depth), arg }); + } + else if (m.is_not(f, f)) + todo.push_back({ !s, depth, f }); + else if (!s && 1 == depth % 2) { + for (extract_eq* ex : m_solve_eqs.m_extract_plugins) + ex->get_eqs(dependent_expr(m, f, df.dep()), eqs); + } + } + } +} diff --git a/src/ast/simplifiers/solve_context_eqs.h b/src/ast/simplifiers/solve_context_eqs.h new file mode 100644 index 000000000..b3db74127 --- /dev/null +++ b/src/ast/simplifiers/solve_context_eqs.h @@ -0,0 +1,58 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + solve_context_eqs.h + +Abstract: + + simplifier for solving equations within a context + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/simplifiers/extract_eqs.h" + +namespace euf { + + class solve_eqs; + + + class solve_context_eqs { + + ast_manager& m; + dependent_expr_state& m_fmls; + solve_eqs& m_solve_eqs; + expr_mark m_and_pos, m_and_neg, m_or_pos, m_or_neg; + expr_mark m_contains_v; + ptr_vector m_todo; + + typedef svector> signed_expressions; + + bool contains_v(expr* f) const { return m_contains_v.is_marked(f); } + bool is_safe_eq(expr* e); + bool is_safe_eq(unsigned recursion_depth, expr* f, bool sign, expr* e); + bool is_safe_eq(expr* f, expr* e) { return is_safe_eq(0, f, false, e); } + bool is_disjunctively_safe(unsigned recursion_depth, expr* f, bool sign, expr* e); + bool contains_conjunctively(expr* f, bool sign, expr* e, signed_expressions& conjuncts); + + void collect_nested_equalities(dependent_expr const& f, expr_mark& visited, dep_eq_vector& eqs); + void init_contains(expr* v); + + + public: + + solve_context_eqs(solve_eqs& s); + + void collect_nested_equalities(dep_eq_vector& eqs); + + }; +} diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index b5b500a96..31e063119 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -23,22 +23,29 @@ Author: #include "ast/recfun_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/solve_eqs.h" +#include "ast/simplifiers/solve_context_eqs.h" #include "ast/converters/generic_model_converter.h" #include "params/tactic_params.hpp" namespace euf { + void solve_eqs::get_eqs(dep_eq_vector& eqs) { + for (extract_eq* ex : m_extract_plugins) + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) + ex->get_eqs(m_fmls[i], eqs); + } + // initialize graph that maps variable ids to next ids void solve_eqs::extract_dep_graph(dep_eq_vector& eqs) { m_var2id.reset(); m_id2var.reset(); m_next.reset(); unsigned sz = 0; - for (auto const& [v, t, d] : eqs) + for (auto const& [orig, v, t, d] : eqs) sz = std::max(sz, v->get_id()); m_var2id.resize(sz + 1, UINT_MAX); - for (auto const& [v, t, d] : eqs) { + for (auto const& [orig, v, t, d] : eqs) { if (is_var(v) || !can_be_var(v)) continue; m_var2id[v->get_id()] = m_id2var.size(); @@ -91,7 +98,7 @@ namespace euf { continue; m_id2level[id] = curr_level++; for (auto const& eq : m_next[j]) { - auto const& [v, t, d] = eq; + auto const& [orig, v, t, d] = eq; if (!is_safe(curr_level, t)) continue; m_next[j][0] = eq; @@ -114,7 +121,7 @@ namespace euf { for (unsigned id : m_subst_ids) { if (!m.inc()) break; - auto const& [v, def, dep] = m_next[id][0]; + auto const& [orig, v, def, dep] = m_next[id][0]; auto [new_def, new_dep] = rp->replace_with_dep(def); m_stats.m_num_steps += rp->get_num_steps() + 1; ++m_stats.m_num_elim_vars; @@ -134,7 +141,7 @@ namespace euf { }); } - void solve_eqs::apply_subst() { + void solve_eqs::apply_subst(vector& old_fmls) { if (!m.inc()) return; scoped_ptr rp = mk_default_expr_replacer(m, true); @@ -146,6 +153,7 @@ namespace euf { if (new_f == f) continue; new_dep = m.mk_join(d, new_dep); + old_fmls.push_back(m_fmls[i]); m_fmls.update(i, dependent_expr(m, new_f, new_dep)); } } @@ -157,6 +165,7 @@ namespace euf { unsigned count = 0; do { + vector old_fmls; m_subst_ids.reset(); if (!m.inc()) return; @@ -164,18 +173,30 @@ namespace euf { get_eqs(eqs); extract_dep_graph(eqs); extract_subst(); - apply_subst(); + apply_subst(old_fmls); ++count; } while (!m_subst_ids.empty() && count < 20); + save_subst({}); + + if (m_config.m_context_solve) { + vector old_fmls; + dep_eq_vector eqs; + m_subst_ids.reset(); + solve_context_eqs context_solve(*this); + context_solve.collect_nested_equalities(eqs); + extract_dep_graph(eqs); + extract_subst(); + apply_subst(old_fmls); + save_subst(old_fmls); + } advance_qhead(m_fmls.size()); - save_subst(); } - void solve_eqs::save_subst() { + void solve_eqs::save_subst(vector const& old_fmls) { if (!m_subst->empty()) - m_fmls.model_trail()->push(m_subst.detach(), {}); + m_fmls.model_trail().push(m_subst.detach(), old_fmls); } void solve_eqs::filter_unsafe_vars() { diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index db7a1323b..35044b373 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -26,58 +26,51 @@ Author: namespace euf { class solve_eqs : public dependent_expr_simplifier { + + friend class solve_context_eqs; + struct stats { unsigned m_num_steps = 0; unsigned m_num_elim_vars = 0; }; + struct config { bool m_context_solve = true; unsigned m_max_occs = UINT_MAX; }; - th_rewriter m_rewriter; - scoped_ptr_vector m_extract_plugins; - unsigned_vector m_var2id, m_id2level, m_subst_ids; - ptr_vector m_id2var; - vector m_next; - scoped_ptr m_subst; - - expr_mark m_unsafe_vars; // expressions that cannot be replaced stats m_stats; config m_config; - - void add_subst(dependent_eq const& eq); + th_rewriter m_rewriter; + scoped_ptr_vector m_extract_plugins; + unsigned_vector m_var2id; // app->get_id() |-> small numeral + ptr_vector m_id2var; // small numeral |-> app + unsigned_vector m_id2level; // small numeral |-> level in substitution ordering + unsigned_vector m_subst_ids; // sorted list of small numeral by level + vector m_next; // adjacency list for solved equations + scoped_ptr m_subst; // current substitution + expr_mark m_unsafe_vars; // expressions that cannot be replaced bool is_var(expr* e) const { return e->get_id() < m_var2id.size() && m_var2id[e->get_id()] != UINT_MAX; } unsigned var2id(expr* v) const { return m_var2id[v->get_id()]; } - - void get_eqs(dep_eq_vector& eqs) { - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) - get_eqs(m_fmls[i], eqs); - } - - void get_eqs(dependent_expr const& f, dep_eq_vector& eqs) { - for (extract_eq* ex : m_extract_plugins) - ex->get_eqs(f, eqs); - } - - void filter_unsafe_vars(); bool can_be_var(expr* e) const { return is_uninterp_const(e) && !m_unsafe_vars.is_marked(e); } + void get_eqs(dep_eq_vector& eqs); + void filter_unsafe_vars(); void extract_subst(); void extract_dep_graph(dep_eq_vector& eqs); void normalize(); - void apply_subst(); - void save_subst(); + void apply_subst(vector& old_fmls); + void save_subst(vector const& old_fmls); public: solve_eqs(ast_manager& m, dependent_expr_state& fmls); - void push() override { dependent_expr_simplifier::push(); } - void pop(unsigned n) override { dependent_expr_simplifier::pop(n); } void reduce() override; void updt_params(params_ref const& p) override; + void collect_statistics(statistics& st) const override; + }; } diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 3e338b57e..cfc4d8eeb 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -479,52 +479,11 @@ class solve_eqs_tactic : public tactic { ptr_vector m_todo; void mark_occurs(expr_mark& occ, goal const& g, expr* v) { - expr_fast_mark2 visited; - occ.mark(v, true); - visited.mark(v, true); - for (unsigned j = 0; j < g.size(); ++j) { - m_todo.push_back(g.form(j)); - } - while (!m_todo.empty()) { - expr* e = m_todo.back(); - if (visited.is_marked(e)) { - m_todo.pop_back(); - continue; - } - if (is_app(e)) { - bool does_occur = false; - bool all_visited = true; - for (expr* arg : *to_app(e)) { - if (!visited.is_marked(arg)) { - m_todo.push_back(arg); - all_visited = false; - } - else { - does_occur |= occ.is_marked(arg); - } - } - if (all_visited) { - occ.mark(e, does_occur); - visited.mark(e, true); - m_todo.pop_back(); - } - } - else if (is_quantifier(e)) { - expr* body = to_quantifier(e)->get_expr(); - if (visited.is_marked(body)) { - visited.mark(e, true); - occ.mark(e, occ.is_marked(body)); - m_todo.pop_back(); - } - else { - m_todo.push_back(body); - } - } - else { - visited.mark(e, true); - m_todo.pop_back(); - } - } + SASSERT(m_todo.empty()); + for (unsigned j = 0; j < g.size(); ++j) + m_todo.push_back(g.form(j)); + ::mark_occurs(m_todo, v, occ); + SASSERT(m_todo.empty()); } expr_mark m_compatible_tried; diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 719a29eea..41b32baac 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -65,8 +65,8 @@ public: return m_goal->inconsistent(); } - model_reconstruction_trail* model_trail() override { - return m_model_trail.get(); + model_reconstruction_trail& model_trail() override { + return *m_model_trail; } char const* name() const override { return m_name.c_str(); } diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index 0cbe9e9f8..bc9017726 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -34,8 +34,8 @@ int mpn_manager::compare(mpn_digit const * a, unsigned lnga, trace(a, lnga); - unsigned j = max(lnga, lngb) - 1; - for (; j != -1u && res == 0; j--) { + unsigned j = max(lnga, lngb); + for (; j-- > 0 && res == 0;) { mpn_digit const & u_j = (j < lnga) ? a[j] : zero; mpn_digit const & v_j = (j < lngb) ? b[j] : zero; if (u_j > v_j) @@ -310,7 +310,7 @@ bool mpn_manager::div_n(mpn_sbuffer & numer, mpn_sbuffer const & denom, mpn_double_digit q_hat, temp, r_hat; mpn_digit borrow; - for (unsigned j = m-1; j != -1u; j--) { + for (unsigned j = m; j-- > 0; ) { temp = (((mpn_double_digit)numer[j+n]) << DIGIT_BITS) | ((mpn_double_digit)numer[j+n-1]); q_hat = temp / (mpn_double_digit) denom[n-1]; r_hat = temp % (mpn_double_digit) denom[n-1]; @@ -388,7 +388,7 @@ char * mpn_manager::to_string(mpn_digit const * a, unsigned lng, char * buf, uns void mpn_manager::display_raw(std::ostream & out, mpn_digit const * a, unsigned lng) const { out << "["; - for (unsigned i = lng-1; i != -1u; i-- ) { out << a[i]; if (i != 0) out << "|"; } + for (unsigned i = lng; i-- > 0; ) { out << a[i]; if (i != 0) out << "|"; } out << "]"; } diff --git a/src/util/util.h b/src/util/util.h index 2a037770d..121031492 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -368,6 +368,14 @@ bool any_of(S& set, T const& p) { return false; } +template +bool all_of(S& set, T const& p) { + for (auto const& s : set) + if (!p(s)) + return false; + return true; +} + /** \brief Iterator for the [0..sz[0]) X [0..sz[1]) X ... X [0..sz[n-1]). it contains the current value. From 6c12aaad747d11b35113c3166029b6a33baaa916 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 5 Nov 2022 22:42:59 -0700 Subject: [PATCH 234/477] wip - testing solve-eqs2, added as tactic --- src/ast/expr_substitution.h | 4 ++ src/ast/for_each_expr.cpp | 41 +++++++++++-------- src/ast/for_each_expr.h | 26 ++++++------ src/ast/rewriter/bool_rewriter.cpp | 23 +++++++++-- src/ast/simplifiers/extract_eqs.cpp | 2 + src/ast/simplifiers/solve_context_eqs.cpp | 27 ++++++++----- src/ast/simplifiers/solve_context_eqs.h | 4 +- src/ast/simplifiers/solve_eqs.cpp | 48 +++++++++++++++-------- src/ast/simplifiers/solve_eqs.h | 2 + src/tactic/core/CMakeLists.txt | 1 + src/tactic/core/solve_eqs_tactic.cpp | 13 +++++- src/tactic/dependent_expr_state_tactic.h | 4 ++ 12 files changed, 135 insertions(+), 60 deletions(-) diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index 0e285ff7d..8f756e061 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -59,6 +59,10 @@ public: std::ostream& display(std::ostream& out); }; +inline std::ostream& operator<<(std::ostream& out, expr_substitution& s) { + return s.display(out); +} + class scoped_expr_substitution { expr_substitution& m_subst; expr_ref_vector m_trail; diff --git a/src/ast/for_each_expr.cpp b/src/ast/for_each_expr.cpp index 54e176fc5..0790b418d 100644 --- a/src/ast/for_each_expr.cpp +++ b/src/ast/for_each_expr.cpp @@ -64,15 +64,22 @@ bool has_skolem_functions(expr * n) { return false; } -subterms::subterms(expr_ref_vector const& es, bool include_bound): m_include_bound(include_bound), m_es(es) {} -subterms::subterms(expr_ref const& e, bool include_bound) : m_include_bound(include_bound), m_es(e.m()) {if (e) m_es.push_back(e); } -subterms::iterator subterms::begin() { return iterator(*this, true); } -subterms::iterator subterms::end() { return iterator(*this, false); } -subterms::iterator::iterator(subterms& f, bool start): m_include_bound(f.m_include_bound), m_es(f.m_es) { - if (!start) m_es.reset(); +subterms::subterms(expr_ref_vector const& es, bool include_bound, ptr_vector* esp, expr_mark* vp): m_include_bound(include_bound), m_es(es), m_esp(esp), m_vp(vp) {} +subterms::subterms(expr_ref const& e, bool include_bound, ptr_vector* esp, expr_mark* vp) : m_include_bound(include_bound), m_es(e.m()), m_esp(esp), m_vp(vp) { if (e) m_es.push_back(e); } +subterms::iterator subterms::begin() { return iterator(* this, m_esp, m_vp, true); } +subterms::iterator subterms::end() { return iterator(*this, nullptr, nullptr, false); } +subterms::iterator::iterator(subterms& f, ptr_vector* esp, expr_mark* vp, bool start): m_include_bound(f.m_include_bound), m_esp(esp), m_visitedp(vp) { + if (!esp) + m_esp = &m_es; + else + m_esp->reset(); + if (!m_visitedp) + m_visitedp = &m_visited; + if (start) + m_esp->append(f.m_es.size(), f.m_es.data()); } expr* subterms::iterator::operator*() { - return m_es.back(); + return m_esp->back(); } subterms::iterator subterms::iterator::operator++(int) { iterator tmp = *this; @@ -80,27 +87,29 @@ subterms::iterator subterms::iterator::operator++(int) { return tmp; } subterms::iterator& subterms::iterator::operator++() { - expr* e = m_es.back(); - m_visited.mark(e, true); + expr* e = m_esp->back(); + // IF_VERBOSE(0, verbose_stream() << e->get_ref_count() << "\n"); + SASSERT(e->get_ref_count() > 0); + m_visitedp->mark(e, true); if (is_app(e)) for (expr* arg : *to_app(e)) - m_es.push_back(arg); + m_esp->push_back(arg); else if (is_quantifier(e) && m_include_bound) - m_es.push_back(to_quantifier(e)->get_expr()); + m_esp->push_back(to_quantifier(e)->get_expr()); - while (!m_es.empty() && m_visited.is_marked(m_es.back())) - m_es.pop_back(); + while (!m_esp->empty() && m_visitedp->is_marked(m_esp->back())) + m_esp->pop_back(); return *this; } bool subterms::iterator::operator==(iterator const& other) const { // ignore state of visited - if (other.m_es.size() != m_es.size()) { + if (other.m_esp->size() != m_esp->size()) { return false; } - for (unsigned i = m_es.size(); i-- > 0; ) { - if (m_es.get(i) != other.m_es.get(i)) + for (unsigned i = m_esp->size(); i-- > 0; ) { + if (m_esp->get(i) != other.m_esp->get(i)) return false; } return true; diff --git a/src/ast/for_each_expr.h b/src/ast/for_each_expr.h index b724bed86..99a0f6b9d 100644 --- a/src/ast/for_each_expr.h +++ b/src/ast/for_each_expr.h @@ -170,15 +170,20 @@ bool has_skolem_functions(expr * n); class subterms { bool m_include_bound = false; expr_ref_vector m_es; - subterms(expr_ref const& e, bool include_bound); - subterms(expr_ref_vector const& es, bool include_bound); + ptr_vector* m_esp = nullptr; + expr_mark* m_vp = nullptr; + subterms(expr_ref const& e, bool include_bound, ptr_vector* esp, expr_mark* vp); + subterms(expr_ref_vector const& es, bool include_bound, ptr_vector* esp, expr_mark* vp); public: + ~subterms() { if (m_vp) m_vp->reset(); } class iterator { - bool m_include_bound = false; - expr_ref_vector m_es; - expr_mark m_visited; + bool m_include_bound = false; + ptr_vector m_es; + ptr_vector* m_esp = nullptr; + expr_mark m_visited; + expr_mark* m_visitedp = nullptr; public: - iterator(subterms& f, bool start); + iterator(subterms& f, ptr_vector* esp, expr_mark* vp, bool start); expr* operator*(); iterator operator++(int); iterator& operator++(); @@ -186,11 +191,10 @@ public: bool operator!=(iterator const& other) const; }; - - static subterms all(expr_ref const& e) { return subterms(e, true); } - static subterms ground(expr_ref const& e) { return subterms(e, false); } - static subterms all(expr_ref_vector const& e) { return subterms(e, true); } - static subterms ground(expr_ref_vector const& e) { return subterms(e, false); } + static subterms all(expr_ref const& e, ptr_vector* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, true, esp, vp); } + static subterms ground(expr_ref const& e, ptr_vector* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, false, esp, vp); } + static subterms all(expr_ref_vector const& e, ptr_vector* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, true, esp, vp); } + static subterms ground(expr_ref_vector const& e, ptr_vector* esp = nullptr, expr_mark* vp = nullptr) { return subterms(e, false, esp, vp); } iterator begin(); iterator end(); }; diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 1964e6528..442bef855 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -244,10 +244,29 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args result = buffer.back(); return BR_DONE; default: +#if 0 + // stupid or removal. A very special case of circuit optimization. + expr* x, * y, * z, * u; + auto is_complement = [&](expr* a, expr* b) { + expr* c; + if (m().is_not(a, c) && c == b) + return true; + if (m().is_not(b, c) && c == a) + return true; + return false; + }; + + if (sz == 2 && m().is_and(buffer[0], x, y) && m().is_and(buffer[1], z, u) && x == z && is_complement(y, u)) { + result = x; + return BR_DONE; + } +#endif + if (m_local_ctx && m_local_ctx_cost <= m_local_ctx_limit) { if (local_ctx_simp(sz, buffer.data(), result)) return BR_DONE; } + if (s) { ast_lt lt; std::sort(buffer.begin(), buffer.end(), lt); @@ -556,9 +575,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ return true; \ } \ if (m_flat_and_or && m().is_or(arg)) { \ - unsigned sz = to_app(arg)->get_num_args(); \ - for (unsigned j = 0; j < sz; j++) { \ - expr * arg_arg = to_app(arg)->get_arg(j); \ + for (expr * arg_arg : *to_app(arg)) { \ push_new_arg(arg_arg, new_args, neg_lits, pos_lits); \ } \ } \ diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index e77ce9e06..543030e91 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -37,6 +37,8 @@ namespace euf { auto [f, d] = e(); expr* x, * y; if (m.is_eq(f, x, y)) { + if (x == y) + return; if (is_uninterp_const(x)) eqs.push_back(dependent_eq(e.fml(), to_app(x), expr_ref(y, m), d)); if (is_uninterp_const(y)) diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index 766c18535..c11505726 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -30,6 +30,7 @@ if every occurrence of v occurs in the same conjunctive context as eq. #include "ast/ast.h" #include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include "ast/occurs.h" #include "ast/simplifiers/solve_context_eqs.h" #include "ast/simplifiers/solve_eqs.h" @@ -134,14 +135,6 @@ namespace euf { return false; } - void solve_context_eqs::init_contains(expr* v) { - m_contains_v.reset(); - for (unsigned i = 0; i < m_fmls.size(); ++i) - m_todo.push_back(m_fmls[i].fml()); - mark_occurs(m_todo, v, m_contains_v); - SASSERT(m_todo.empty()); - } - void solve_context_eqs::collect_nested_equalities(dep_eq_vector& eqs) { expr_mark visited; for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) @@ -149,7 +142,23 @@ namespace euf { unsigned j = 0; for (auto const& eq : eqs) { - init_contains(eq.var); + + m_contains_v.reset(); + + // first check if v is in term. If it is, then the substitution candidate is unsafe + m_todo.push_back(eq.term); + mark_occurs(m_todo, eq.var, m_contains_v); + SASSERT(m_todo.empty()); + if (m_contains_v.is_marked(eq.term)) + continue; + + // then mark occurrences + for (unsigned i = 0; i < m_fmls.size(); ++i) + m_todo.push_back(m_fmls[i].fml()); + mark_occurs(m_todo, eq.var, m_contains_v); + SASSERT(m_todo.empty()); + + // subject to occurrences, check if equality is safe if (is_safe_eq(eq.orig)) eqs[j++] = eq; } diff --git a/src/ast/simplifiers/solve_context_eqs.h b/src/ast/simplifiers/solve_context_eqs.h index b3db74127..fb330b57b 100644 --- a/src/ast/simplifiers/solve_context_eqs.h +++ b/src/ast/simplifiers/solve_context_eqs.h @@ -44,9 +44,7 @@ namespace euf { bool is_disjunctively_safe(unsigned recursion_depth, expr* f, bool sign, expr* e); bool contains_conjunctively(expr* f, bool sign, expr* e, signed_expressions& conjuncts); - void collect_nested_equalities(dependent_expr const& f, expr_mark& visited, dep_eq_vector& eqs); - void init_contains(expr* v); - + void collect_nested_equalities(dependent_expr const& f, expr_mark& visited, dep_eq_vector& eqs); public: diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 31e063119..b611e0144 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -20,6 +20,8 @@ Author: #include "ast/ast_util.h" #include "ast/for_each_expr.h" #include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/occurs.h" #include "ast/recfun_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/solve_eqs.h" @@ -75,13 +77,15 @@ namespace euf { auto is_safe = [&](unsigned lvl, expr* t) { for (auto* e : subterms::all(expr_ref(t, m))) + for (auto* e : subterms::all(expr_ref(t, m), &m_todo, &m_visited)) if (is_var(e) && m_id2level[var2id(e)] < lvl) - return false; + return false; return true; }; unsigned init_level = UINT_MAX; unsigned_vector todo; + for (unsigned id = 0; id < m_id2var.size(); ++id) { if (is_explored(id)) continue; @@ -96,14 +100,16 @@ namespace euf { todo.pop_back(); if (is_explored(j)) continue; - m_id2level[id] = curr_level++; + m_id2level[j] = curr_level++; for (auto const& eq : m_next[j]) { auto const& [orig, v, t, d] = eq; + SASSERT(j == var2id(v)); if (!is_safe(curr_level, t)) continue; + SASSERT(!occurs(v, t)); m_next[j][0] = eq; - m_subst_ids.push_back(id); - for (expr* e : subterms::all(expr_ref(t, m))) + m_subst_ids.push_back(j); + for (expr* e : subterms::all(expr_ref(t, m), &m_todo, &m_visited)) if (is_var(e) && !is_explored(var2id(e))) todo.push_back(var2id(e)); break; @@ -113,19 +119,20 @@ namespace euf { } void solve_eqs::normalize() { - scoped_ptr rp = mk_default_expr_replacer(m, true); + scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); std::sort(m_subst_ids.begin(), m_subst_ids.end(), [&](unsigned u, unsigned v) { return m_id2level[u] > m_id2level[v]; }); for (unsigned id : m_subst_ids) { if (!m.inc()) - break; + return; auto const& [orig, v, def, dep] = m_next[id][0]; auto [new_def, new_dep] = rp->replace_with_dep(def); m_stats.m_num_steps += rp->get_num_steps() + 1; ++m_stats.m_num_elim_vars; new_dep = m.mk_join(dep, new_dep); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(v, m) << " -> " << mk_bounded_pp(new_def, m) << "\n"); m_subst->insert(v, new_def, new_dep); SASSERT(can_be_var(v)); // we updated the substitution, but we don't need to reset rp @@ -139,12 +146,14 @@ namespace euf { expr* def = m_subst->find(eq.var); tout << mk_pp(eq.var, m) << "\n----->\n" << mk_pp(def, m) << "\n\n"; }); + + } void solve_eqs::apply_subst(vector& old_fmls) { if (!m.inc()) return; - scoped_ptr rp = mk_default_expr_replacer(m, true); + scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { @@ -152,6 +161,7 @@ namespace euf { auto [new_f, new_dep] = rp->replace_with_dep(f); if (new_f == f) continue; + m_rewriter(new_f); new_dep = m.mk_join(d, new_dep); old_fmls.push_back(m_fmls[i]); m_fmls.update(i, dependent_expr(m, new_f, new_dep)); @@ -164,29 +174,35 @@ namespace euf { ex->pre_process(m_fmls); unsigned count = 0; + vector old_fmls; + dep_eq_vector eqs; do { - vector old_fmls; + old_fmls.reset(); m_subst_ids.reset(); - if (!m.inc()) - return; - dep_eq_vector eqs; + eqs.reset(); get_eqs(eqs); extract_dep_graph(eqs); extract_subst(); + normalize(); apply_subst(old_fmls); ++count; } - while (!m_subst_ids.empty() && count < 20); + while (!m_subst_ids.empty() && count < 20 && m.inc()); + + if (!m.inc()) + return; + save_subst({}); - if (m_config.m_context_solve) { - vector old_fmls; - dep_eq_vector eqs; + if (m_config.m_context_solve) { + old_fmls.reset(); m_subst_ids.reset(); + eqs.reset(); solve_context_eqs context_solve(*this); context_solve.collect_nested_equalities(eqs); extract_dep_graph(eqs); extract_subst(); + normalize(); apply_subst(old_fmls); save_subst(old_fmls); } @@ -203,7 +219,7 @@ namespace euf { m_unsafe_vars.reset(); recfun::util rec(m); for (func_decl* f : rec.get_rec_funs()) - for (expr* term : subterms::all(expr_ref(rec.get_def(f).get_rhs(), m))) + for (expr* term : subterms::all(expr_ref(rec.get_def(f).get_rhs(), m), &m_todo, &m_visited)) m_unsafe_vars.mark(term); } diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 35044b373..8f5988a38 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -50,6 +50,8 @@ namespace euf { vector m_next; // adjacency list for solved equations scoped_ptr m_subst; // current substitution expr_mark m_unsafe_vars; // expressions that cannot be replaced + ptr_vector m_todo; + expr_mark m_visited; bool is_var(expr* e) const { return e->get_id() < m_var2id.size() && m_var2id[e->get_id()] != UINT_MAX; } unsigned var2id(expr* v) const { return m_var2id[v->get_id()]; } diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index e57510d4f..38d2699f0 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -49,6 +49,7 @@ z3_add_component(core_tactics reduce_invertible_tactic.h simplify_tactic.h solve_eqs_tactic.h + solve_eqs2_tactic.h special_relations_tactic.h split_clause_tactic.h symmetry_reduce_tactic.h diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index cfc4d8eeb..fdba65b3f 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -425,6 +425,7 @@ class solve_eqs_tactic : public tactic { else pr = m().mk_modus_ponens(g.pr(idx), pr); } + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(var, m()) << " -> " << mk_bounded_pp(def, m()) << "\n"); m_subst->insert(var, def, pr, g.dep(idx)); } @@ -620,9 +621,11 @@ class solve_eqs_tactic : public tactic { expr* arg = args.get(i), *lhs = nullptr, *rhs = nullptr; if (m().is_eq(arg, lhs, rhs) && !m().is_bool(lhs)) { if (trivial_solve1(lhs, rhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { + IF_VERBOSE(11, verbose_stream() << "nested " << mk_bounded_pp(var.get(), m()) << " -> " << mk_bounded_pp(def, m()) << "\n"); insert_solution(g, idx, arg, var, def, pr); } else if (trivial_solve1(rhs, lhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { + IF_VERBOSE(11, verbose_stream() << "nested " << mk_bounded_pp(var.get(), m()) << " -> " << mk_bounded_pp(def, m()) << "\n"); insert_solution(g, idx, arg, var, def, pr); } else { @@ -981,6 +984,10 @@ class solve_eqs_tactic : public tactic { unsigned get_num_eliminated_vars() const { return m_num_eliminated_vars; } + + void collect_statistics(statistics& st) { + st.update("solve eqs elim vars", get_num_eliminated_vars()); + } // // TBD: rewrite the tactic to first apply a topological sorting that @@ -1033,6 +1040,9 @@ class solve_eqs_tactic : public tactic { g->inc_depth(); g->add(mc.get()); result.push_back(g.get()); + + + IF_VERBOSE(10, statistics st; collect_statistics(st); st.display_smt2(verbose_stream())); } }; @@ -1066,7 +1076,6 @@ public: void operator()(goal_ref const & in, goal_ref_buffer & result) override { (*m_imp)(in, result); - report_tactic_progress(":num-elim-vars", m_imp->get_num_eliminated_vars()); } void cleanup() override { @@ -1085,7 +1094,7 @@ public: } void collect_statistics(statistics & st) const override { - st.update("eliminated vars", m_imp->get_num_eliminated_vars()); + m_imp->collect_statistics(st); } void reset_statistics() override { diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 41b32baac..01e135e8a 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -93,6 +93,10 @@ public: if (in->models_enabled()) in->set(m_model_trail->get_model_converter().get()); result.push_back(in.get()); + + statistics st; + collect_statistics(st); + IF_VERBOSE(10, st.display_smt2(verbose_stream())); } void cleanup() override { From d8133a47c209ff0140de0c823027da84507af862 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 5 Nov 2022 22:47:46 -0700 Subject: [PATCH 235/477] Update solve_eqs.cpp --- src/ast/simplifiers/solve_eqs.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index b611e0144..f364c31e1 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -76,7 +76,6 @@ namespace euf { }; auto is_safe = [&](unsigned lvl, expr* t) { - for (auto* e : subterms::all(expr_ref(t, m))) for (auto* e : subterms::all(expr_ref(t, m), &m_todo, &m_visited)) if (is_var(e) && m_id2level[var2id(e)] < lvl) return false; From 4c1a3fab647ca405198ef6cbb2ce06dc782f7f45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 5 Nov 2022 23:15:03 -0700 Subject: [PATCH 236/477] fix #6442 --- src/api/api_seq.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index d64589cde..6a9d0f81c 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -212,6 +212,8 @@ extern "C" { buffer.push_back('\\'); buffer.push_back('u'); buffer.push_back('{'); + if (ch == 0) + buff.push_back('0'); while (ch > 0) { unsigned d = ch & 0xF; if (d < 10) From 78f9e6b31a9f2defc7be77ed263469649208dfe7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Nov 2022 11:57:21 -0800 Subject: [PATCH 237/477] extend error type message with more information - display the arguments that are passed --- src/ast/ast.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 50b9e5a4d..7bb732a5d 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2250,7 +2250,9 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar if (type_error) { std::ostringstream buffer; buffer << "Wrong number of arguments (" << num_args - << ") passed to function " << mk_pp(decl, *this); + << ") passed to function " << mk_pp(decl, *this) << " "; + for (unsigned i = 0; i < num_args; ++i) + buffer << "\narg: " << mk_pp(args[i], *this) << "\n"; throw ast_exception(std::move(buffer).str()); } app * r = nullptr; From a4c2a2b22c105e1b9045ddc18cbf8ad652cee49d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Nov 2022 11:57:46 -0800 Subject: [PATCH 238/477] use ast_util::mk_not to avoid redundant double negations during nff --- src/ast/normal_forms/nnf.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index d0398543b..a35956454 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -22,6 +22,7 @@ Notes: #include "ast/normal_forms/nnf.h" #include "ast/normal_forms/nnf_params.hpp" #include "ast/used_vars.h" +#include "ast/ast_util.h" #include "ast/well_sorted.h" #include "ast/act_cache.h" #include "ast/rewriter/var_subst.h" @@ -137,7 +138,7 @@ class skolemizer { if (is_sk_hack(p)) { expr * sk_hack = to_app(p)->get_arg(0); if (q->get_kind() == forall_k) // check whether is in negative/positive context. - tmp = m.mk_or(body, m.mk_not(sk_hack)); // negative context + tmp = m.mk_or(body, mk_not(m, sk_hack)); // negative context else tmp = m.mk_and(body, sk_hack); // positive context body = tmp; @@ -148,7 +149,7 @@ class skolemizer { p = nullptr; if (m_proofs_enabled) { if (q->get_kind() == forall_k) - p = m.mk_skolemization(m.mk_not(q), m.mk_not(r)); + p = m.mk_skolemization(mk_not(m, q), mk_not(m, r)); else p = m.mk_skolemization(q, r); } @@ -388,7 +389,7 @@ struct nnf::imp { } void skip(expr * t, bool pol) { - expr * r = pol ? t : m.mk_not(t); + expr * r = pol ? t : mk_not(m, t); m_result_stack.push_back(r); if (proofs_enabled()) { m_result_pr_stack.push_back(m.mk_oeq_reflexivity(r)); @@ -639,7 +640,7 @@ struct nnf::imp { m_name_quant->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2); if (!fr.m_pol) - n2 = m.mk_not(n2); + n2 = mk_not(m, n2); m_result_stack.push_back(n2); if (proofs_enabled()) { if (!fr.m_pol) { From 8ff1e44a9593d729a028bc93996a2b9032e5faeb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Nov 2022 11:58:21 -0800 Subject: [PATCH 239/477] add discriminator to whether context contains recursive functions to avoid enabling recursive function solver when there are just macros --- src/ast/recfun_decl_plugin.cpp | 1 + src/ast/recfun_decl_plugin.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index bf865b393..755a3eccd 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -473,6 +473,7 @@ namespace recfun { } void plugin::set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { + m_has_rec_defs |= !is_macro; 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); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 8e1279c0a..c369e2827 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -165,6 +165,7 @@ namespace recfun { mutable scoped_ptr m_util; def_map m_defs; // function->def case_def_map m_case_defs; // case_pred->def + bool m_has_rec_defs = false; ast_manager & m() { return *m_manager; } @@ -200,6 +201,7 @@ namespace recfun { bool has_def(func_decl* f) const { return m_defs.contains(f); } bool has_defs() const; + bool has_rec_defs() const { return m_has_rec_defs; } def const& get_def(func_decl* f) const { return *(m_defs[f]); } promise_def get_promise_def(func_decl* f) const { return promise_def(&u(), m_defs[f]); } def& get_def(func_decl* f) { return *(m_defs[f]); } @@ -249,6 +251,8 @@ namespace recfun { //has_defs(); } + bool has_rec_defs() const { return m_plugin->has_rec_defs(); } + // Date: Sun, 6 Nov 2022 11:59:56 -0800 Subject: [PATCH 240/477] bypass built-in proof objects for clause trail the build-in proof constructors are not flexible when it comes to allowing alternation of justified lemmas and lemmas without justifications. --- src/smt/smt_clause_proof.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index a2bc381e4..ad3d3818c 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -147,18 +147,22 @@ namespace smt { for (auto& info : m_trail) { expr_ref fact = mk_or(info.m_clause); proof* pr = info.m_proof; + expr* args[2] = { pr, fact }; + unsigned num_args = 2, offset = 0; + if (!pr) + offset = 1; switch (info.m_status) { case status::assumption: - ps.push_back(m.mk_assumption_add(pr, fact)); + ps.push_back(m.mk_app(symbol("assumption"), num_args - offset, args + offset, m.mk_proof_sort())); break; case status::lemma: - ps.push_back(m.mk_lemma_add(pr, fact)); + ps.push_back(m.mk_app(symbol("lemma"), num_args - offset, args + offset, m.mk_proof_sort())); break; case status::th_assumption: - ps.push_back(m.mk_th_assumption_add(pr, fact)); + ps.push_back(m.mk_app(symbol("th-assumption"), num_args - offset, args + offset, m.mk_proof_sort())); break; case status::th_lemma: - ps.push_back(m.mk_th_lemma_add(pr, fact)); + ps.push_back(m.mk_app(symbol("th-lemma"), num_args - offset, args + offset, m.mk_proof_sort())); break; case status::deleted: ps.push_back(m.mk_redundant_del(fact)); From f004478565fe29eaf28cf48d328841e803e57a29 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Nov 2022 12:00:25 -0800 Subject: [PATCH 241/477] produce tseitin justification for clause proofs when a clause is a "gate". --- src/smt/smt_internalizer.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 2483b2ca4..63848418f 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1593,6 +1593,18 @@ namespace smt { TRACE("gate_clause", tout << mk_ll_pp(pr, m);); mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); } + else if (m_clause_proof.on_clause_active()) { + ptr_buffer new_lits; + for (unsigned i = 0; i < num_lits; i++) { + literal l = lits[i]; + bool_var v = l.var(); + expr * atom = m_bool_var2expr[v]; + new_lits.push_back(l.sign() ? m.mk_not(atom) : atom); + } + // expr* fact = m.mk_or(new_lits); + proof* pr = m.mk_app(symbol("tseitin"), new_lits.size(), new_lits.data(), m.mk_proof_sort()); + mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); + } else { mk_clause(num_lits, lits, nullptr); } From cbc5b1f4f600cf5964b82a7aaedeb6cdfc9316c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Nov 2022 12:09:45 -0800 Subject: [PATCH 242/477] have theory_recfun use recursive function discriminator to control when it is enabled --- src/ast/recfun_decl_plugin.cpp | 9 +++++---- src/smt/theory_recfun.cpp | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 755a3eccd..558488592 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -442,17 +442,18 @@ namespace recfun { return promise_def(&u(), d); } - void plugin::inherit(decl_plugin* other, ast_translation& tr) { - for (auto [k, v] : static_cast(other)->m_defs) { + void plugin::inherit(decl_plugin* _other, ast_translation& tr) { + plugin* other = static_cast(_other); + for (auto [k, v] : other->m_defs) { func_decl_ref f(tr(k), tr.to()); if (m_defs.contains(f)) continue; def* d = v->copy(u(), tr); m_defs.insert(f, d); for (case_def & c : d->get_cases()) - m_case_defs.insert(c.get_decl(), &c); - + m_case_defs.insert(c.get_decl(), &c); } + m_has_rec_defs = other->m_has_rec_defs; } promise_def plugin::ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated) { diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 416275275..515a51a17 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -102,9 +102,8 @@ namespace smt { void theory_recfun::relevant_eh(app * n) { SASSERT(ctx.relevancy()); // TRACEFN("relevant_eh: (defined) " << u().is_defined(n) << " " << mk_pp(n, m)); - if (u().is_defined(n) && u().has_defs()) { + if (u().is_defined(n) && u().has_defs()) push_case_expand(n); - } } void theory_recfun::push_scope_eh() { @@ -418,7 +417,7 @@ namespace smt { } void theory_recfun::add_theory_assumptions(expr_ref_vector & assumptions) { - if (u().has_defs() || !m_disabled_guards.empty()) { + if (u().has_rec_defs() || !m_disabled_guards.empty()) { app_ref dlimit = m_util.mk_num_rounds_pred(m_num_rounds); TRACEFN("add_theory_assumption " << dlimit); assumptions.push_back(dlimit); From 10fb71cf93c6a1e92996c8eb220412c2b0fba0c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:18:45 -0800 Subject: [PATCH 243/477] better error description for configuring restart --- src/sat/sat_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 32d764658..4ca223be6 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -46,7 +46,7 @@ namespace sat { else if (s == symbol("static")) m_restart = RS_STATIC; else - throw sat_param_exception("invalid restart strategy"); + throw sat_param_exception("invalid restart strategy. Use ema (default), luby, geometric, static"); m_fast_glue_avg = p.restart_emafastglue(); m_slow_glue_avg = p.restart_emaslowglue(); From 8afec86fe8850dab73dc6ac1d0fdfcf20f9cecdc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:19:27 -0800 Subject: [PATCH 244/477] add option for flat_and_or --- src/params/bool_rewriter_params.pyg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/params/bool_rewriter_params.pyg b/src/params/bool_rewriter_params.pyg index 85583cbca..c8d7ddbb7 100644 --- a/src/params/bool_rewriter_params.pyg +++ b/src/params/bool_rewriter_params.pyg @@ -1,8 +1,9 @@ def_module_params(module_name='rewriter', class_name='bool_rewriter_params', export=True, - params=(("ite_extra_rules", BOOL, False, "extra ite simplifications, these additional simplifications may reduce size locally but increase globally"), - ("flat", BOOL, True, "create nary applications for and,or,+,*,bvadd,bvmul,bvand,bvor,bvxor"), + params=(("ite_extra_rules", BOOL, True, "extra ite simplifications, these additional simplifications may reduce size locally but increase globally"), + ("flat", BOOL, True, "create nary applications for +,*,bvadd,bvmul,bvand,bvor,bvxor"), + ("flat_and_or", BOOL, True, "create nary applications for and,or"), ("elim_and", BOOL, False, "conjunctions are rewritten using negation and disjunctions"), ('elim_ite', BOOL, True, "eliminate ite in favor of and/or"), ("local_ctx", BOOL, False, "perform local (i.e., cheap) context simplifications"), From ab36f86843aead141e1865907538432d1426cc6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:19:48 -0800 Subject: [PATCH 245/477] add handler for reporting statistics --- src/tactic/tactic.cpp | 12 ++++++++++++ src/tactic/tactic.h | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index b1609ed85..8bf6efac5 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -75,6 +75,18 @@ void report_tactic_progress(char const * id, unsigned val) { } } +statistics_report::~statistics_report() { + statistics st; + if (m_tactic) + m_tactic->collect_statistics(st); + else if (m_collector) + m_collector(st); + if (st.size() == 0) + return; + IF_VERBOSE(TACTIC_VERBOSITY_LVL, st.display_smt2(verbose_stream())); +} + + void skip_tactic::operator()(goal_ref const & in, goal_ref_buffer& result) { result.push_back(in.get()); } diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 0f55ea0fe..c43120943 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -115,6 +115,15 @@ public: void report_tactic_progress(char const * id, unsigned val); +class statistics_report { + tactic* m_tactic = nullptr; + std::function m_collector; +public: + statistics_report(tactic& t):m_tactic(&t) {} + statistics_report(std::function& coll): m_collector(coll) {} + ~statistics_report(); +}; + class skip_tactic : public tactic { public: void operator()(goal_ref const & in, goal_ref_buffer& result) override; From a34701471fc6d8b1c37eb2b63697e63a358c6f1b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:20:25 -0800 Subject: [PATCH 246/477] clean up hoist rewriter --- src/ast/rewriter/hoist_rewriter.cpp | 80 ++++++++++++----------------- src/ast/rewriter/hoist_rewriter.h | 16 +++--- 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/ast/rewriter/hoist_rewriter.cpp b/src/ast/rewriter/hoist_rewriter.cpp index 4116945f0..40ad4604a 100644 --- a/src/ast/rewriter/hoist_rewriter.cpp +++ b/src/ast/rewriter/hoist_rewriter.cpp @@ -13,8 +13,6 @@ Author: Nikolaj Bjorner (nbjorner) 2019-2-4 -Notes: - --*/ @@ -25,19 +23,17 @@ Notes: hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p): - m_manager(m), m_args1(m), m_args2(m), m_subst(m) { + m(m), m_args1(m), m_args2(m), m_subst(m) { updt_params(p); } br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) { - if (num_args < 2) { + if (num_args < 2) return BR_FAILED; - } - for (unsigned i = 0; i < num_args; ++i) { - if (!is_and(es[i], nullptr)) { + + for (unsigned i = 0; i < num_args; ++i) + if (!is_and(es[i], nullptr)) return BR_FAILED; - } - } bool turn = false; m_preds1.reset(); @@ -52,12 +48,10 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & VERIFY(is_and(es[0], args[turn])); expr* e1, *e2; for (expr* e : *(args[turn])) { - if (m().is_eq(e, e1, e2)) { + if (m.is_eq(e, e1, e2)) (*uf)[turn].merge(mk_var(e1), mk_var(e2)); - } - else { + else (*preds)[turn].insert(e); - } } unsigned round = 0; for (unsigned j = 1; j < num_args; ++j) { @@ -72,44 +66,39 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & VERIFY(is_and(es[j], args[turn])); for (expr* e : *args[turn]) { - if (m().is_eq(e, e1, e2)) { + if (m.is_eq(e, e1, e2)) { m_es.push_back(e1); m_uf0.merge(mk_var(e1), mk_var(e2)); } - else if ((*preds)[last].contains(e)) { + else if ((*preds)[last].contains(e)) (*preds)[turn].insert(e); - } } - if ((*preds)[turn].empty() && m_es.empty()) { + if ((*preds)[turn].empty() && m_es.empty()) return BR_FAILED; - } m_eqs.reset(); for (expr* e : m_es) { - if (m_mark.is_marked(e)) { + if (m_mark.is_marked(e)) continue; - } unsigned u = mk_var(e); unsigned v = u; m_roots.reset(); do { m_mark.mark(e); unsigned r = (*uf)[last].find(v); - if (m_roots.find(r, e2)) { - m_eqs.push_back(std::make_pair(e, e2)); - } - else { + if (m_roots.find(r, e2)) + m_eqs.push_back({e, e2}); + else m_roots.insert(r, e); - } v = m_uf0.next(v); e = mk_expr(v); } while (u != v); } reset((*uf)[turn]); - for (auto const& p : m_eqs) - (*uf)[turn].merge(mk_var(p.first), mk_var(p.second)); + for (auto const& [e1, e2] : m_eqs) + (*uf)[turn].merge(mk_var(e1), mk_var(e2)); if ((*preds)[turn].empty() && m_eqs.empty()) return BR_FAILED; } @@ -118,25 +107,23 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & return BR_DONE; } // p & eqs & (or fmls) - expr_ref_vector fmls(m()); + expr_ref_vector fmls(m); m_subst.reset(); for (expr * p : (*preds)[turn]) { expr* q = nullptr; - if (m().is_not(p, q)) { - m_subst.insert(q, m().mk_false()); - } - else { - m_subst.insert(p, m().mk_true()); - } + if (m.is_not(p, q)) + m_subst.insert(q, m.mk_false()); + else + m_subst.insert(p, m.mk_true()); fmls.push_back(p); } for (auto& p : m_eqs) { - if (m().is_value(p.first)) + if (m.is_value(p.first)) std::swap(p.first, p.second); m_subst.insert(p.first, p.second); - fmls.push_back(m().mk_eq(p.first, p.second)); + fmls.push_back(m.mk_eq(p.first, p.second)); } - expr_ref ors(::mk_or(m(), num_args, es), m()); + expr_ref ors(::mk_or(m, num_args, es), m); m_subst(ors); fmls.push_back(ors); result = mk_and(fmls); @@ -146,9 +133,8 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & unsigned hoist_rewriter::mk_var(expr* e) { unsigned v = 0; - if (m_expr2var.find(e, v)) { + if (m_expr2var.find(e, v)) return v; - } m_uf1.mk_var(); v = m_uf2.mk_var(); SASSERT(v == m_var2expr.size()); @@ -158,15 +144,14 @@ unsigned hoist_rewriter::mk_var(expr* e) { } expr_ref hoist_rewriter::hoist_predicates(obj_hashtable const& preds, unsigned num_args, expr* const* es) { - expr_ref result(m()); - expr_ref_vector args(m()), fmls(m()); + expr_ref result(m); + expr_ref_vector args(m), fmls(m); for (unsigned i = 0; i < num_args; ++i) { VERIFY(is_and(es[i], &m_args1)); fmls.reset(); - for (expr* e : m_args1) { + for (expr* e : m_args1) if (!preds.contains(e)) fmls.push_back(e); - } args.push_back(::mk_and(fmls)); } fmls.reset(); @@ -188,19 +173,18 @@ br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c } bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) { - if (m().is_and(e)) { + if (m.is_and(e)) { if (args) { args->reset(); args->append(to_app(e)->get_num_args(), to_app(e)->get_args()); } return true; } - if (m().is_not(e, e) && m().is_or(e)) { + if (m.is_not(e, e) && m.is_or(e)) { if (args) { args->reset(); - for (expr* arg : *to_app(e)) { - args->push_back(::mk_not(m(), arg)); - } + for (expr* arg : *to_app(e)) + args->push_back(::mk_not(m, arg)); } return true; } diff --git a/src/ast/rewriter/hoist_rewriter.h b/src/ast/rewriter/hoist_rewriter.h index 2c627ad59..cc83bfa56 100644 --- a/src/ast/rewriter/hoist_rewriter.h +++ b/src/ast/rewriter/hoist_rewriter.h @@ -26,7 +26,7 @@ Notes: #include "util/obj_hashtable.h" class hoist_rewriter { - ast_manager & m_manager; + ast_manager & m; expr_ref_vector m_args1, m_args2; obj_hashtable m_preds1, m_preds2; basic_union_find m_uf1, m_uf2, m_uf0; @@ -34,11 +34,9 @@ class hoist_rewriter { svector> m_eqs; u_map m_roots; expr_safe_replace m_subst; - obj_map m_expr2var; - ptr_vector m_var2expr; - expr_mark m_mark; - - br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result); + obj_map m_expr2var; + ptr_vector m_var2expr; + expr_mark m_mark; bool is_and(expr* e, expr_ref_vector* args); @@ -52,12 +50,12 @@ class hoist_rewriter { public: hoist_rewriter(ast_manager & m, params_ref const & p = params_ref()); - ast_manager& m() const { return m_manager; } - family_id get_fid() const { return m().get_basic_family_id(); } - bool is_eq(expr * t) const { return m().is_eq(t); } + family_id get_fid() const { return m.get_basic_family_id(); } + bool is_eq(expr * t) const { return m.is_eq(t); } void updt_params(params_ref const & p) {} static void get_param_descrs(param_descrs & r) {} br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); + br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result); }; struct hoist_rewriter_cfg : public default_rewriter_cfg { From 3a4b8e2334001362aae12e94fbd6c9c989538d6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:20:51 -0800 Subject: [PATCH 247/477] add rewrite rules to bv-rewriter --- src/ast/rewriter/bv_rewriter.cpp | 44 +++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index a04436e63..209f7a13b 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -1513,11 +1513,14 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re bool fused_numeral = false; bool expanded = false; bool fused_extract = false; + bool eq_args = true; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; expr * prev = nullptr; - if (i > 0) + if (i > 0) { prev = new_args.back(); + eq_args &= prev == arg; + } if (is_numeral(arg, v1, sz1) && prev != nullptr && is_numeral(prev, v2, sz2)) { v2 *= rational::power_of_two(sz1); v2 += v1; @@ -1526,10 +1529,8 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re fused_numeral = true; } else if (m_flat && m_util.is_concat(arg)) { - unsigned num2 = to_app(arg)->get_num_args(); - for (unsigned j = 0; j < num2; j++) { - new_args.push_back(to_app(arg)->get_arg(j)); - } + for (expr* arg2 : *to_app(arg)) + new_args.push_back(arg2); expanded = true; } else if (m_util.is_extract(arg) && @@ -1539,8 +1540,8 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re m_util.get_extract_low(prev) == m_util.get_extract_high(arg) + 1) { // (concat (extract[h1,l1] a) (extract[h2,l2] a)) --> (extract[h1,l2] a) if l1 == h2+1 expr * new_arg = m_mk_extract(m_util.get_extract_high(prev), - m_util.get_extract_low(arg), - to_app(arg)->get_arg(0)); + m_util.get_extract_low(arg), + to_app(arg)->get_arg(0)); new_args.pop_back(); new_args.push_back(new_arg); fused_extract = true; @@ -1549,14 +1550,26 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re new_args.push_back(arg); } } - if (!fused_numeral && !expanded && !fused_extract) + if (!fused_numeral && !expanded && !fused_extract) { + expr* x, *y, *z; + if (eq_args) { + if (m().is_ite(new_args.back(), x, y, z)) { + ptr_buffer args1, args2; + for (expr* arg : new_args) + args1.push_back(y), args2.push_back(z); + result = m().mk_ite(x, m_util.mk_concat(args1), m_util.mk_concat(args2)); + return BR_REWRITE2; + } + } return BR_FAILED; + + } SASSERT(!new_args.empty()); if (new_args.size() == 1) { result = new_args.back(); return fused_extract ? BR_REWRITE1 : BR_DONE; } - result = m_util.mk_concat(new_args.size(), new_args.data()); + result = m_util.mk_concat(new_args); if (fused_extract) return BR_REWRITE2; else if (expanded) @@ -2013,6 +2026,19 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) { return BR_REWRITE2; } + expr* x, *y, *z; + if (m().is_ite(arg, x, y, z) && m_util.is_numeral(y, val, bv_size)) { + val = bitwise_not(bv_size, val); + result = m().mk_ite(x, m_util.mk_numeral(val, bv_size), m_util.mk_bv_not(z)); + return BR_REWRITE2; + } + + if (m().is_ite(arg, x, y, z) && m_util.is_numeral(z, val, bv_size)) { + val = bitwise_not(bv_size, val); + result = m().mk_ite(x, m_util.mk_bv_not(y), m_util.mk_numeral(val, bv_size)); + return BR_REWRITE2; + } + if (m_bvnot_simpl) { expr *s(nullptr), *t(nullptr); if (m_util.is_bv_mul(arg, s, t)) { From 238ea0a26433d3149361cd3fa8148266b426ef78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:21:25 -0800 Subject: [PATCH 248/477] add shorthands for concatentation --- src/ast/bv_decl_plugin.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 1cb17900f..37531d936 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -430,6 +430,9 @@ public: } app * mk_concat(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_CONCAT, num, args); } app * mk_concat(expr_ref_vector const& es) { return m_manager.mk_app(get_fid(), OP_CONCAT, es.size(), es.data()); } + app * mk_concat(expr_ref_buffer const& es) { return m_manager.mk_app(get_fid(), OP_CONCAT, es.size(), es.data()); } + app * mk_concat(ptr_buffer const& es) { return m_manager.mk_app(get_fid(), OP_CONCAT, es.size(), es.data()); } + app * mk_concat(ptr_vector const& es) { return m_manager.mk_app(get_fid(), OP_CONCAT, es.size(), es.data()); } app * mk_bv_or(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_BOR, num, args); } app * mk_bv_and(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_BAND, num, args); } app * mk_bv_xor(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_BXOR, num, args); } From f769e2f1f66cc87266ab373bacdd12257df0c3d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:21:50 -0800 Subject: [PATCH 249/477] have bool rewriter use flat_and_or, and integrate hoist rewriter --- src/ast/rewriter/bool_rewriter.cpp | 11 ++++++++++- src/ast/rewriter/bool_rewriter.h | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 442bef855..632b6c0f6 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -24,7 +24,7 @@ Notes: void bool_rewriter::updt_params(params_ref const & _p) { bool_rewriter_params p(_p); - m_flat_and_or = p.flat(); + m_flat_and_or = p.flat_and_or(); m_elim_and = p.elim_and(); m_elim_ite = p.elim_ite(); m_local_ctx = p.local_ctx(); @@ -267,6 +267,15 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args return BR_DONE; } +#if 1 + br_status st; + st = m_hoist.mk_or(buffer.size(), buffer.data(), result); + if (st == BR_DONE) + return BR_REWRITE1; + if (st != BR_FAILED) + return st; +#endif + if (s) { ast_lt lt; std::sort(buffer.begin(), buffer.end(), lt); diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index a25a0f8a3..2cec0b2ce 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -20,6 +20,7 @@ Notes: #include "ast/ast.h" #include "ast/rewriter/rewriter.h" +#include "ast/rewriter/hoist_rewriter.h" #include "util/params.h" /** @@ -50,6 +51,7 @@ Notes: */ class bool_rewriter { ast_manager & m_manager; + hoist_rewriter m_hoist; bool m_flat_and_or; bool m_local_ctx; bool m_elim_and; @@ -78,7 +80,7 @@ class bool_rewriter { void push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits); public: - bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) { updt_params(p); } + bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_hoist(m), m_local_ctx_cost(0) { updt_params(p); } ast_manager & m() const { return m_manager; } family_id get_fid() const { return m().get_basic_family_id(); } bool is_eq(expr * t) const { return m().is_eq(t); } From 3a37cfca307bce55e3dd31859c5664572d9b83bc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 12:23:36 -0800 Subject: [PATCH 250/477] switch to solve_eqs2 tactic --- src/ast/rewriter/th_rewriter.cpp | 5 ++ src/ast/rewriter/th_rewriter.h | 3 + src/ast/simplifiers/extract_eqs.cpp | 11 ++++ src/ast/simplifiers/extract_eqs.h | 6 ++ .../model_reconstruction_trail.cpp | 2 +- src/ast/simplifiers/solve_context_eqs.cpp | 63 +++++++++++++------ src/ast/simplifiers/solve_context_eqs.h | 1 + src/ast/simplifiers/solve_eqs.cpp | 15 +++-- src/nlsat/tactic/qfnra_nlsat_tactic.cpp | 1 + src/opt/opt_context.cpp | 1 + src/tactic/core/solve_eqs2_tactic.h | 12 +++- src/tactic/core/solve_eqs_tactic.cpp | 5 +- src/tactic/core/solve_eqs_tactic.h | 10 ++- src/tactic/dependent_expr_state_tactic.h | 31 +++++---- src/tactic/sls/sls_tactic.cpp | 1 + src/tactic/smtlogics/qfaufbv_tactic.cpp | 1 + src/tactic/smtlogics/qfauflia_tactic.cpp | 1 + src/tactic/smtlogics/qfbv_tactic.cpp | 11 +++- src/tactic/smtlogics/qfidl_tactic.cpp | 1 + src/tactic/smtlogics/qflia_tactic.cpp | 1 + src/tactic/smtlogics/qfuf_tactic.cpp | 1 + src/tactic/smtlogics/qfufbv_tactic.cpp | 16 +++-- src/tactic/smtlogics/quant_tactics.cpp | 1 + src/tactic/ufbv/ufbv_tactic.cpp | 1 + 24 files changed, 149 insertions(+), 52 deletions(-) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 96b69dbc3..9604f6d16 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -924,6 +924,11 @@ void th_rewriter::get_param_descrs(param_descrs & r) { rewriter_params::collect_param_descrs(r); } +void th_rewriter::set_flat_and_or(bool f) { + m_imp->cfg().m_b_rw.set_flat_and_or(f); +} + + th_rewriter::~th_rewriter() { dealloc(m_imp); } diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index e432678a4..b84164abc 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -38,6 +38,9 @@ public: void updt_params(params_ref const & p); static void get_param_descrs(param_descrs & r); + + void set_flat_and_or(bool f); + unsigned get_cache_size() const; unsigned get_num_steps() const; diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 543030e91..775eb4d22 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -29,16 +29,23 @@ namespace euf { class basic_extract_eq : public extract_eq { ast_manager& m; bool m_ite_solver = true; + bool m_allow_bool = true; public: basic_extract_eq(ast_manager& m) : m(m) {} + virtual void set_allow_booleans(bool f) { + m_allow_bool = f; + } + void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { auto [f, d] = e(); expr* x, * y; if (m.is_eq(f, x, y)) { if (x == y) return; + if (!m_allow_bool && m.is_bool(x)) + return; if (is_uninterp_const(x)) eqs.push_back(dependent_eq(e.fml(), to_app(x), expr_ref(y, m), d)); if (is_uninterp_const(y)) @@ -47,6 +54,8 @@ namespace euf { expr* c, * th, * el, * x1, * y1, * x2, * y2; if (m_ite_solver && m.is_ite(f, c, th, el)) { if (m.is_eq(th, x1, y1) && m.is_eq(el, x2, y2)) { + if (!m_allow_bool && m.is_bool(x1)) + return; if (x1 == y2 && is_uninterp_const(x1)) std::swap(x2, y2); if (x2 == y2 && is_uninterp_const(x2)) @@ -57,6 +66,8 @@ namespace euf { eqs.push_back(dependent_eq(e.fml(), to_app(x1), expr_ref(m.mk_ite(c, y1, y2), m), d)); } } + if (!m_allow_bool) + return; if (is_uninterp_const(f)) eqs.push_back(dependent_eq(e.fml(), to_app(f), expr_ref(m.mk_true(), m), d)); if (m.is_not(f, x) && is_uninterp_const(x)) diff --git a/src/ast/simplifiers/extract_eqs.h b/src/ast/simplifiers/extract_eqs.h index f38829dfc..724425d6a 100644 --- a/src/ast/simplifiers/extract_eqs.h +++ b/src/ast/simplifiers/extract_eqs.h @@ -18,6 +18,7 @@ Author: #pragma once +#include "ast/ast_pp.h" #include "ast/simplifiers/dependent_expr_state.h" #include "ast/rewriter/th_rewriter.h" #include "ast/expr_substitution.h" @@ -42,8 +43,13 @@ namespace euf { virtual void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) = 0; virtual void pre_process(dependent_expr_state& fmls) {} virtual void updt_params(params_ref const& p) {} + virtual void set_allow_booleans(bool f) {} }; void register_extract_eqs(ast_manager& m, scoped_ptr_vector& ex); } + +inline std::ostream& operator<<(std::ostream& out, euf::dependent_eq const& eq) { + return out << mk_pp(eq.var, eq.term.m()) << " = " << eq.term << "\n"; +} diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index a8e75bfa3..373a500bf 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -26,7 +26,6 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorm_active) continue; @@ -69,6 +68,7 @@ model_converter_ref model_reconstruction_trail::get_model_converter() { // substituted variables by their terms. // + scoped_ptr rp = mk_default_expr_replacer(m, false); expr_substitution subst(m, true, false); rp->set_substitution(&subst); diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index c11505726..37836db27 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -57,7 +57,7 @@ namespace euf { if (!contains_v(f)) return true; signed_expressions conjuncts; - if (contains_conjunctively(f, sign, e, conjuncts)) + if (contains_conjunctively(f, sign, e, conjuncts)) return true; if (recursion_depth > 3) return false; @@ -67,9 +67,9 @@ namespace euf { /* * Every disjunction in f that contains v also contains the equation e. */ - bool solve_context_eqs::is_disjunctively_safe(unsigned recursion_depth, expr* f, bool sign, expr* e) { + bool solve_context_eqs::is_disjunctively_safe(unsigned recursion_depth, expr* f0, bool sign, expr* e) { signed_expressions todo; - todo.push_back({sign, f}); + todo.push_back({sign, f0}); while (!todo.empty()) { auto [s, f] = todo.back(); todo.pop_back(); @@ -93,11 +93,21 @@ namespace euf { todo.push_back({s, arg}); else if (m.is_not(f, f)) todo.push_back({!s, f}); + else if (!is_conjunction(s, f)) + return false; else if (!is_safe_eq(recursion_depth + 1, f, s, e)) return false; } return true; } + + bool solve_context_eqs::is_conjunction(bool sign, expr* f) const { + if (!sign && m.is_and(f)) + return true; + if (sign && m.is_or(f)) + return true; + return false; + } /** * Determine whether some conjunction in f contains e. @@ -140,29 +150,43 @@ namespace euf { for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) collect_nested_equalities(m_fmls[i], visited, eqs); + std::stable_sort(eqs.begin(), eqs.end(), [&](dependent_eq const& e1, dependent_eq const& e2) { + return e1.var->get_id() < e2.var->get_id(); }); unsigned j = 0; + expr* last_var = nullptr; for (auto const& eq : eqs) { - - m_contains_v.reset(); - // first check if v is in term. If it is, then the substitution candidate is unsafe - m_todo.push_back(eq.term); - mark_occurs(m_todo, eq.var, m_contains_v); - SASSERT(m_todo.empty()); - if (m_contains_v.is_marked(eq.term)) + SASSERT(!m.is_bool(eq.var)); + + if (eq.var != last_var) { + + m_contains_v.reset(); + + // first check if v is in term. If it is, then the substitution candidate is unsafe + m_todo.push_back(eq.term); + mark_occurs(m_todo, eq.var, m_contains_v); + SASSERT(m_todo.empty()); + last_var = eq.var; + if (m_contains_v.is_marked(eq.term)) + continue; + + // then mark occurrences + for (unsigned i = 0; i < m_fmls.size(); ++i) + m_todo.push_back(m_fmls[i].fml()); + mark_occurs(m_todo, eq.var, m_contains_v); + SASSERT(m_todo.empty()); + } + else if (m_contains_v.is_marked(eq.term)) continue; - // then mark occurrences - for (unsigned i = 0; i < m_fmls.size(); ++i) - m_todo.push_back(m_fmls[i].fml()); - mark_occurs(m_todo, eq.var, m_contains_v); - SASSERT(m_todo.empty()); - // subject to occurrences, check if equality is safe - if (is_safe_eq(eq.orig)) + if (is_safe_eq(eq.orig)) eqs[j++] = eq; } eqs.shrink(j); + TRACE("solve_eqs", + for (auto const& eq : eqs) + tout << eq << "\n"); } void solve_context_eqs::collect_nested_equalities(dependent_expr const& df, expr_mark& visited, dep_eq_vector& eqs) { @@ -204,8 +228,11 @@ namespace euf { else if (m.is_not(f, f)) todo.push_back({ !s, depth, f }); else if (!s && 1 == depth % 2) { - for (extract_eq* ex : m_solve_eqs.m_extract_plugins) + for (extract_eq* ex : m_solve_eqs.m_extract_plugins) { + ex->set_allow_booleans(false); ex->get_eqs(dependent_expr(m, f, df.dep()), eqs); + ex->set_allow_booleans(true); + } } } } diff --git a/src/ast/simplifiers/solve_context_eqs.h b/src/ast/simplifiers/solve_context_eqs.h index fb330b57b..8332d3a73 100644 --- a/src/ast/simplifiers/solve_context_eqs.h +++ b/src/ast/simplifiers/solve_context_eqs.h @@ -43,6 +43,7 @@ namespace euf { bool is_safe_eq(expr* f, expr* e) { return is_safe_eq(0, f, false, e); } bool is_disjunctively_safe(unsigned recursion_depth, expr* f, bool sign, expr* e); bool contains_conjunctively(expr* f, bool sign, expr* e, signed_expressions& conjuncts); + bool is_conjunction(bool sign, expr* f) const; void collect_nested_equalities(dependent_expr const& f, expr_mark& visited, dep_eq_vector& eqs); diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index f364c31e1..96b0427f6 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -118,6 +118,8 @@ namespace euf { } void solve_eqs::normalize() { + if (m_subst_ids.empty()) + return; scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); @@ -152,15 +154,18 @@ namespace euf { void solve_eqs::apply_subst(vector& old_fmls) { if (!m.inc()) return; + if (m_subst_ids.empty()) + return; + scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { auto [f, d] = m_fmls[i](); auto [new_f, new_dep] = rp->replace_with_dep(f); + m_rewriter(new_f); if (new_f == f) continue; - m_rewriter(new_f); new_dep = m.mk_join(d, new_dep); old_fmls.push_back(m_fmls[i]); m_fmls.update(i, dependent_expr(m, new_f, new_dep)); @@ -185,14 +190,13 @@ namespace euf { normalize(); apply_subst(old_fmls); ++count; + save_subst({}); } while (!m_subst_ids.empty() && count < 20 && m.inc()); if (!m.inc()) return; - save_subst({}); - if (m_config.m_context_solve) { old_fmls.reset(); m_subst_ids.reset(); @@ -211,7 +215,7 @@ namespace euf { void solve_eqs::save_subst(vector const& old_fmls) { if (!m_subst->empty()) - m_fmls.model_trail().push(m_subst.detach(), old_fmls); + m_fmls.model_trail().push(m_subst.detach(), old_fmls); } void solve_eqs::filter_unsafe_vars() { @@ -222,11 +226,10 @@ namespace euf { m_unsafe_vars.mark(term); } - - solve_eqs::solve_eqs(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_rewriter(m) { register_extract_eqs(m, m_extract_plugins); + m_rewriter.set_flat_and_or(false); } void solve_eqs::updt_params(params_ref const& p) { diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index fc812c4f5..e41347c2b 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -27,6 +27,7 @@ Notes: #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_term_ite_tactic.h" tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5895643bd..66a391cb8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -31,6 +31,7 @@ Notes: #include "tactic/tactic.h" #include "tactic/arith/lia2card_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" diff --git a/src/tactic/core/solve_eqs2_tactic.h b/src/tactic/core/solve_eqs2_tactic.h index 91b3875ae..fa095aad0 100644 --- a/src/tactic/core/solve_eqs2_tactic.h +++ b/src/tactic/core/solve_eqs2_tactic.h @@ -29,13 +29,19 @@ public: } }; -inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p) { - return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs2"); +inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs"); } +#if 1 +inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { + return mk_solve_eqs2_tactic(m, p); +} +#endif + /* - ADD_TACTIC("solve-eqs2", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") + ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") */ diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index fdba65b3f..d445b68ac 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -997,6 +997,8 @@ class solve_eqs_tactic : public tactic { // void operator()(goal_ref const & g, goal_ref_buffer & result) { model_converter_ref mc; + std::function coll = [&](statistics& st) { collect_statistics(st); }; + statistics_report sreport(coll); tactic_report report("solve_eqs", *g); TRACE("goal", g->display(tout);); m_produce_models = g->models_enabled(); @@ -1042,7 +1044,6 @@ class solve_eqs_tactic : public tactic { result.push_back(g.get()); - IF_VERBOSE(10, statistics st; collect_statistics(st); st.display_smt2(verbose_stream())); } }; @@ -1103,6 +1104,6 @@ public: }; -tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p) { +tactic * mk_solve_eqs1_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true)); } diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index d65a33046..4b26254a0 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -22,10 +22,16 @@ Revision History: class ast_manager; class tactic; -tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic * mk_solve_eqs1_tactic(ast_manager & m, params_ref const & p = params_ref()); + +#if 0 +inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { + return mk_solve_eqs1_tactic(m, p); +} +#endif /* - ADD_TACTIC("solve-eqs", "eliminate variables by solving equations.", "mk_solve_eqs_tactic(m, p)") + ADD_TACTIC("solve-eqs1", "eliminate variables by solving equations.", "mk_solve_eqs1_tactic(m, p)") */ diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 01e135e8a..24f12aeae 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -22,16 +22,19 @@ class dependent_expr_state_tactic : public tactic, public dependent_expr_state { ast_manager& m; params_ref m_params; std::string m_name; - ref m_factory; - scoped_ptr m_simp; - trail_stack m_trail; - scoped_ptr m_model_trail; + trail_stack m_trail; goal_ref m_goal; dependent_expr m_dep; + statistics m_st; + ref m_factory; + scoped_ptr m_simp; + scoped_ptr m_model_trail; void init() { - if (!m_simp) + if (!m_simp) { m_simp = m_factory->mk(m, m_params, *this); + m_st.reset(); + } if (!m_model_trail) m_model_trail = alloc(model_reconstruction_trail, m, m_trail); } @@ -43,7 +46,7 @@ public: m_params(p), m_name(name), m_factory(f), - m_simp(f->mk(m, p, *this)), + m_simp(nullptr), m_dep(m, m.mk_true(), nullptr) {} @@ -86,30 +89,34 @@ public: if (in->proofs_enabled()) throw tactic_exception("tactic does not support low level proofs"); init(); + statistics_report sreport(*this); tactic_report report(name(), *in); m_goal = in.get(); m_simp->reduce(); m_goal->inc_depth(); if (in->models_enabled()) - in->set(m_model_trail->get_model_converter().get()); + in->add(m_model_trail->get_model_converter().get()); result.push_back(in.get()); - - statistics st; - collect_statistics(st); - IF_VERBOSE(10, st.display_smt2(verbose_stream())); } void cleanup() override { + if (m_simp) + m_simp->collect_statistics(m_st); + m_simp = nullptr; + m_model_trail = nullptr; } void collect_statistics(statistics & st) const override { - if (m_simp) + if (m_simp) m_simp->collect_statistics(st); + else + st.copy(m_st); } void reset_statistics() override { if (m_simp) m_simp->reset_statistics(); + m_st.reset(); } }; diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index e631c23e9..a09da60a9 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "ast/normal_forms/nnf.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/bv/bv_size_reduction_tactic.h" #include "tactic/bv/max_bv_sharing_tactic.h" #include "tactic/core/simplify_tactic.h" diff --git a/src/tactic/smtlogics/qfaufbv_tactic.cpp b/src/tactic/smtlogics/qfaufbv_tactic.cpp index acad15fd6..6d44addf0 100644 --- a/src/tactic/smtlogics/qfaufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfaufbv_tactic.cpp @@ -17,6 +17,7 @@ Notes: --*/ #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/bv/bit_blaster_tactic.h" diff --git a/src/tactic/smtlogics/qfauflia_tactic.cpp b/src/tactic/smtlogics/qfauflia_tactic.cpp index 2f1879d58..9ca6b70ef 100644 --- a/src/tactic/smtlogics/qfauflia_tactic.cpp +++ b/src/tactic/smtlogics/qfauflia_tactic.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/core/propagate_values_tactic.h" #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/smtlogics/smt_tactic.h" diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 1366b701e..90df4fe42 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -20,6 +20,7 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/bv/bit_blaster_tactic.h" #include "tactic/bv/bv1_blaster_tactic.h" @@ -39,6 +40,9 @@ static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { // conservative gaussian elimination. solve_eq_p.set_uint("solve_eqs_max_occs", 2); + params_ref flat_and_or_p = p; + flat_and_or_p.set_bool("flat_and_or", false); + params_ref simp2_p = p; simp2_p.set_bool("som", true); simp2_p.set_bool("pull_cheap_ite", true); @@ -47,15 +51,17 @@ static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { simp2_p.set_uint("local_ctx_limit", 10000000); simp2_p.set_bool("flat", true); // required by som simp2_p.set_bool("hoist_mul", false); // required by som + simp2_p.set_bool("flat_and_or", false); params_ref hoist_p; hoist_p.set_bool("hoist_mul", true); hoist_p.set_bool("som", false); + hoist_p.set_bool("flat_and_or", false); return and_then( - mk_simplify_tactic(m), - mk_propagate_values_tactic(m), + using_params(mk_simplify_tactic(m), flat_and_or_p), + using_params(mk_propagate_values_tactic(m), flat_and_or_p), using_params(mk_solve_eqs_tactic(m), solve_eq_p), mk_elim_uncnstr_tactic(m), if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), @@ -87,6 +93,7 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat params_ref local_ctx_p = p; local_ctx_p.set_bool("local_ctx", true); local_ctx_p.set_bool("flat", false); + local_ctx_p.set_bool("flat_and_or", false); params_ref solver_p; solver_p.set_bool("preprocess", false); // preprocessor of smt::context is not needed. diff --git a/src/tactic/smtlogics/qfidl_tactic.cpp b/src/tactic/smtlogics/qfidl_tactic.cpp index c86789ed0..5c1ba5f44 100644 --- a/src/tactic/smtlogics/qfidl_tactic.cpp +++ b/src/tactic/smtlogics/qfidl_tactic.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/core/propagate_values_tactic.h" #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/arith/normalize_bounds_tactic.h" #include "tactic/arith/fix_dl_var_tactic.h" diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index b8ebbd8a9..d116414ea 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -22,6 +22,7 @@ Notes: #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/arith/normalize_bounds_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" diff --git a/src/tactic/smtlogics/qfuf_tactic.cpp b/src/tactic/smtlogics/qfuf_tactic.cpp index 609107a48..d9f723d67 100644 --- a/src/tactic/smtlogics/qfuf_tactic.cpp +++ b/src/tactic/smtlogics/qfuf_tactic.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/symmetry_reduce_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/smtlogics/smt_tactic.h" diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index d93a17ce1..98e09b56a 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/bv/max_bv_sharing_tactic.h" #include "tactic/bv/bv_size_reduction_tactic.h" @@ -136,22 +137,23 @@ private: }; static tactic * mk_qfufbv_preamble1(ast_manager & m, params_ref const & p) { - params_ref simp2_p = p; + params_ref simp2_p = p, flat_and_or_p = p; + flat_and_or_p.set_bool("flat_and_or", false); simp2_p.set_bool("pull_cheap_ite", true); simp2_p.set_bool("push_ite_bv", false); simp2_p.set_bool("local_ctx", true); simp2_p.set_uint("local_ctx_limit", 10000000); - simp2_p.set_bool("ite_extra_rules", true); simp2_p.set_bool("mul2concat", true); + simp2_p.set_bool("flat_and_or", false); params_ref ctx_simp_p; ctx_simp_p.set_uint("max_depth", 32); ctx_simp_p.set_uint("max_steps", 5000000); return and_then( - mk_simplify_tactic(m), - mk_propagate_values_tactic(m), + using_params(mk_simplify_tactic(m), flat_and_or_p), + using_params(mk_propagate_values_tactic(m), flat_and_or_p), if_no_proofs(if_no_unsat_cores(mk_bv_bound_chk_tactic(m))), //using_params(mk_ctx_simplify_tactic(m_m), ctx_simp_p), mk_solve_eqs_tactic(m), @@ -163,8 +165,10 @@ static tactic * mk_qfufbv_preamble1(ast_manager & m, params_ref const & p) { } static tactic * mk_qfufbv_preamble(ast_manager & m, params_ref const & p) { - return and_then(mk_simplify_tactic(m), - mk_propagate_values_tactic(m), + params_ref simp2_p = p, flat_and_or_p = p; + flat_and_or_p.set_bool("flat_and_or", false); + return and_then(using_params(mk_simplify_tactic(m), flat_and_or_p), + using_params(mk_propagate_values_tactic(m), flat_and_or_p), mk_solve_eqs_tactic(m), mk_elim_uncnstr_tactic(m), if_no_proofs(if_no_unsat_cores(mk_reduce_args_tactic(m))), diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index daf020a14..3bf6b658d 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -20,6 +20,7 @@ Revision History: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "qe/lite/qe_lite.h" #include "qe/qsat.h" diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index e8495c013..728e6397d 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -20,6 +20,7 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" +#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/distribute_forall_tactic.h" #include "tactic/core/der_tactic.h" #include "tactic/core/reduce_args_tactic.h" From 9ef78fcfa7b6163b18827a208dd2b0a1cc3210b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 13:57:58 -0800 Subject: [PATCH 251/477] revert new solve-eqs Signed-off-by: Nikolaj Bjorner --- src/tactic/core/solve_eqs2_tactic.h | 2 +- src/tactic/core/solve_eqs_tactic.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/core/solve_eqs2_tactic.h b/src/tactic/core/solve_eqs2_tactic.h index fa095aad0..34c0befa4 100644 --- a/src/tactic/core/solve_eqs2_tactic.h +++ b/src/tactic/core/solve_eqs2_tactic.h @@ -33,7 +33,7 @@ inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p = param return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs"); } -#if 1 +#if 0 inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { return mk_solve_eqs2_tactic(m, p); } diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 4b26254a0..29c11a9c3 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -24,7 +24,7 @@ class tactic; tactic * mk_solve_eqs1_tactic(ast_manager & m, params_ref const & p = params_ref()); -#if 0 +#if 1 inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { return mk_solve_eqs1_tactic(m, p); } From 3faca52c400f090062b69f8d6218a2cc5129d3ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 14:17:17 -0800 Subject: [PATCH 252/477] re-enable new solve_eqs with bug fixes --- src/ast/simplifiers/extract_eqs.cpp | 2 ++ src/tactic/core/solve_eqs2_tactic.h | 4 ++-- src/tactic/core/solve_eqs_tactic.h | 4 ++-- src/tactic/dependent_expr_state_tactic.h | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 775eb4d22..d65f9b167 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -192,6 +192,8 @@ namespace euf { ++i; if (!is_uninterp_const(arg)) continue; + if (!a.is_real(arg)) + continue; unsigned j = 0; bool nonzero = true; for (expr* arg2 : *to_app(x)) { diff --git a/src/tactic/core/solve_eqs2_tactic.h b/src/tactic/core/solve_eqs2_tactic.h index 34c0befa4..7d13b571e 100644 --- a/src/tactic/core/solve_eqs2_tactic.h +++ b/src/tactic/core/solve_eqs2_tactic.h @@ -33,7 +33,7 @@ inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p = param return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs"); } -#if 0 +#if 1 inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { return mk_solve_eqs2_tactic(m, p); } @@ -41,7 +41,7 @@ inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = para /* - ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") + ADD_TACTIC("solve-eqs2", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") */ diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 29c11a9c3..7b97172a3 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -24,14 +24,14 @@ class tactic; tactic * mk_solve_eqs1_tactic(ast_manager & m, params_ref const & p = params_ref()); -#if 1 +#if 0 inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { return mk_solve_eqs1_tactic(m, p); } #endif /* - ADD_TACTIC("solve-eqs1", "eliminate variables by solving equations.", "mk_solve_eqs1_tactic(m, p)") + ADD_TACTIC("solve-eqs", "eliminate variables by solving equations.", "mk_solve_eqs1_tactic(m, p)") */ diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 24f12aeae..4b89028f3 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -86,13 +86,13 @@ public: void operator()(goal_ref const & in, goal_ref_buffer & result) override { - if (in->proofs_enabled()) - throw tactic_exception("tactic does not support low level proofs"); init(); statistics_report sreport(*this); tactic_report report(name(), *in); m_goal = in.get(); - m_simp->reduce(); + if (!in->proofs_enabled()) + m_simp->reduce(); + m_goal->elim_true(); m_goal->inc_depth(); if (in->models_enabled()) in->add(m_model_trail->get_model_converter().get()); From 823cd23ecc7f8b86079486a4c11c82badc7b5e73 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 15:37:56 -0800 Subject: [PATCH 253/477] building x64 windows tests during ci is too slow, skipping tests Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f338a5d98..0f2fee6a2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -195,14 +195,14 @@ jobs: setupCmd2: '' setupCmd3: '' bindings: '$(cmakePy)' - runTests: 'False' + runTests: 'True' x64: arch: 'x64' setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' setupCmd2: 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' setupCmd3: 'set /P JlCxxDir= Date: Tue, 8 Nov 2022 15:56:10 -0800 Subject: [PATCH 254/477] cleanup state to clear model trail during calls. --- src/tactic/dependent_expr_state_tactic.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 4b89028f3..56e27ee9a 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -96,7 +96,8 @@ public: m_goal->inc_depth(); if (in->models_enabled()) in->add(m_model_trail->get_model_converter().get()); - result.push_back(in.get()); + result.push_back(in.get()); + cleanup(); } void cleanup() override { From ff68df34510dc2e09030784e9e179f8ad8955131 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 16:10:50 -0800 Subject: [PATCH 255/477] update output of z3 doc --- src/api/python/z3/z3.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index bbe212453..05df8186e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10079,7 +10079,7 @@ def FPs(names, fpsort, ctx=None): >>> x.ebits() 8 >>> fpMul(RNE(), fpAdd(RNE(), x, y), z) - fpMul(RNE(), fpAdd(RNE(), x, y), z) + x + y * z """ ctx = _get_ctx(ctx) if isinstance(names, str): @@ -10186,9 +10186,9 @@ def fpAdd(rm, a, b, ctx=None): >>> x = FP('x', s) >>> y = FP('y', s) >>> fpAdd(rm, x, y) - fpAdd(RNE(), x, y) - >>> fpAdd(RTZ(), x, y) # default rounding mode is RTZ x + y + >>> fpAdd(RTZ(), x, y) # default rounding mode is RTZ + fpAdd(RTZ(), x, y) >>> fpAdd(rm, x, y).sort() FPSort(8, 24) """ @@ -10203,7 +10203,7 @@ def fpSub(rm, a, b, ctx=None): >>> x = FP('x', s) >>> y = FP('y', s) >>> fpSub(rm, x, y) - fpSub(RNE(), x, y) + x - y >>> fpSub(rm, x, y).sort() FPSort(8, 24) """ @@ -10218,7 +10218,7 @@ def fpMul(rm, a, b, ctx=None): >>> x = FP('x', s) >>> y = FP('y', s) >>> fpMul(rm, x, y) - fpMul(RNE(), x, y) + x * y >>> fpMul(rm, x, y).sort() FPSort(8, 24) """ @@ -10233,7 +10233,7 @@ def fpDiv(rm, a, b, ctx=None): >>> x = FP('x', s) >>> y = FP('y', s) >>> fpDiv(rm, x, y) - fpDiv(RNE(), x, y) + x / y >>> fpDiv(rm, x, y).sort() FPSort(8, 24) """ From 4d86d739429e11faf4b8ec93f53c4c4ab7bd6b16 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 17:15:59 -0800 Subject: [PATCH 256/477] disable also tests for Windows x86, does not work with CI pipeline --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0f2fee6a2..382c2efc9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -195,7 +195,7 @@ jobs: setupCmd2: '' setupCmd3: '' bindings: '$(cmakePy)' - runTests: 'True' + runTests: 'False' x64: arch: 'x64' setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' From 9a656772b437e02ede9bc1e9850c112a325cb4cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 18:37:16 -0800 Subject: [PATCH 257/477] fix #6446 --- src/muz/fp/datalog_parser.cpp | 51 ++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 030d88d71..d748dca63 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -286,9 +286,8 @@ public: dtoken read_num() { - while(isdigit(m_curr_char)) { + while (isdigit(m_curr_char)) save_and_next(); - } return TK_NUM; } @@ -781,15 +780,29 @@ protected: symbol td1(td); expr_ref v1(m), v2(m); sort* s = nullptr; - dtoken tok2 = m_lexer->next_token(); - if (tok2 != TK_NEQ && tok2 != TK_GT && tok2 != TK_LT && tok2 != TK_EQ) { - return unexpected(tok2, "built-in infix operator"); + uint64_t num1(0), num3(0); + if (tok1 == TK_NUM) { + char const* data = m_lexer->get_token_data(); + rational num(data); + if (!num.is_uint64()) + return unexpected(tok1, "integer expected"); + num1 = num.get_uint64(); } + dtoken tok2 = m_lexer->next_token(); + if (tok2 != TK_NEQ && tok2 != TK_GT && tok2 != TK_LT && tok2 != TK_EQ) + return unexpected(tok2, "built-in infix operator"); dtoken tok3 = m_lexer->next_token(); td = m_lexer->get_token_data(); - if (tok3 != TK_STRING && tok3 != TK_NUM && !(tok3 == TK_ID && m_vars.contains(td))) { + if (tok3 != TK_STRING && tok3 != TK_NUM && !(tok3 == TK_ID && m_vars.contains(td))) return unexpected(tok3, "identifier"); + if (tok3 == TK_NUM) { + char const* data = m_lexer->get_token_data(); + rational num(data); + if (!num.is_uint64()) + return unexpected(tok1, "integer expected"); + num3 = num.get_uint64(); } + symbol td2(td); if (tok1 == TK_ID) { @@ -805,18 +818,21 @@ protected: if (!v1 && !v2) { return unexpected(tok3, "at least one argument should be a variable"); } - if (v1) { + if (v1) s = v1->get_sort(); - } - else { + else s = v2->get_sort(); - } - if (!v1) { + + if (tok1 == TK_NUM) + v1 = mk_symbol_const(num1, s); + + if (tok3 == TK_NUM) + v2 = mk_symbol_const(num3, s); + + if (!v1) v1 = mk_const(td1, s); - } - if (!v2) { + if (!v2) v2 = mk_const(td2, s); - } switch(tok2) { case TK_EQ: @@ -1126,8 +1142,11 @@ protected: if (m_arith.is_int(s)) return m_arith.mk_numeral(rational(el, rational::ui64()), s); else if (m_decl_util.try_get_size(s, sz)) { - if (el >= sz) - throw default_exception("numeric value out of bounds of domain"); + if (el >= sz) { + std::ostringstream ous; + ous << "numeric value " << el << " is out of bounds of domain size " << sz; + throw default_exception(ous.str()); + } return m_decl_util.mk_numeral(el, s); } else { From 8da13ae24a2b8ab9948fb413f2d8510691ee7354 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 Nov 2022 18:37:30 -0800 Subject: [PATCH 258/477] add statistics to verbose output of asserted formulas --- src/solver/assertions/asserted_formulas.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 90c84e7ee..2b20ebd80 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -306,7 +306,7 @@ void asserted_formulas::reduce() { if (!invoke(m_flatten_clauses)) return; // if (!invoke(m_propagate_values)) return; - IF_VERBOSE(10, verbose_stream() << "(smt.simplifier-done)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.simplifier-done :num-exprs " << get_total_size() << ")\n";); TRACE("after_reduce", display(tout);); TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); TRACE("macros", m_macro_manager.display(tout);); @@ -327,8 +327,8 @@ unsigned asserted_formulas::get_formulas_last_level() const { bool asserted_formulas::invoke(simplify_fmls& s) { if (!s.should_apply()) return true; - IF_VERBOSE(10, verbose_stream() << "(smt." << s.id() << ")\n";); s(); + IF_VERBOSE(10, verbose_stream() << "(smt." << s.id() << " :num-exprs " << get_total_size() << ")\n";); IF_VERBOSE(10000, verbose_stream() << "total size: " << get_total_size() << "\n";); TRACE("reduce_step_ll", ast_mark visited; display_ll(tout, visited);); CASSERT("well_sorted",check_well_sorted()); @@ -514,9 +514,9 @@ void asserted_formulas::simplify_fmls::operator()() { void asserted_formulas::reduce_and_solve() { - IF_VERBOSE(10, verbose_stream() << "(smt.reducing)\n";); flush_cache(); // collect garbage m_reduce_asserted_formulas(); + IF_VERBOSE(10, verbose_stream() << "(smt.reduced " << get_total_size() << ")\n";); } From 15be80c9548f335527a39c011bdd19b03a0fe62d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 Nov 2022 09:06:34 -0800 Subject: [PATCH 259/477] remove dependency on hash_compare --- src/test/hashtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/hashtable.cpp b/src/test/hashtable.cpp index befd0b8e9..fb8042dc7 100644 --- a/src/test/hashtable.cpp +++ b/src/test/hashtable.cpp @@ -26,8 +26,8 @@ Revision History: struct int_hash_proc { unsigned operator()(int x) const { return x * 3; } }; typedef int_hashtable > int_set; -typedef std::unordered_set > > safe_int_set; // typedef safe_int_set int_set; +typedef std::unordered_set safe_int_set; inline bool contains(int_set & h, int i) { // return h.find(i) != h.end(); From 689af3b4df2abcc0f45be9521066311e3654c980 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 Nov 2022 16:42:09 -0800 Subject: [PATCH 260/477] add comments to elim_unconstr_tactic Signed-off-by: Nikolaj Bjorner --- src/tactic/core/elim_uncnstr_tactic.cpp | 93 +++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index cb60eb482..34aa748d9 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -270,7 +270,36 @@ class elim_uncnstr_tactic : public tactic { } return nullptr; } - + + /** + * if (c, x, x') -> fresh + * x := fresh + * x' := fresh + * + * if (x, x', e) -> fresh + * x := true + * x' := fresh + * + * if (x, t, x') -> fresh + * x := false + * x' := fresh + * + * not x -> fresh + * x := not fresh + * + * x & x' -> fresh + * x := fresh + * x' := true + * + * x or x' -> fresh + * x := fresh + * x' := false + * + * x = t -> fresh + * x := if(fresh, t, diff(t)) + * where diff is a diagnonalization function available in domains of size > 1. + * + */ app * process_basic_app(func_decl * f, unsigned num, expr * const * args) { SASSERT(f->get_family_id() == m().get_basic_family_id()); switch (f->get_decl_kind()) { @@ -434,6 +463,10 @@ class elim_uncnstr_tactic : public tactic { } return nullptr; } + + /** + * similar as for bit-vectors + */ app * process_arith_app(func_decl * f, unsigned num, expr * const * args) { @@ -466,7 +499,7 @@ class elim_uncnstr_tactic : public tactic { add_defs(num, args, r, m_bv_util.mk_numeral(rational(1), s)); return r; } - // c * v (c is even) case + // c * v (c is odd) case unsigned bv_size; rational val; rational inv; @@ -595,7 +628,46 @@ class elim_uncnstr_tactic : public tactic { } return nullptr; } - + + /** + * x + t -> fresh + * x := fresh - t + * + * x * x' * x'' -> fresh + * x := fresh + * x', x'' := 1 + * + * c * x -> fresh, c is odd + * x := fresh*c^-1 + * + * x[sz-1:0] -> fresh + * x := fresh + * + * x[hi:lo] -> fresh + * x := fresh1 ++ fresh ++ fresh2 + * + * x udiv x', x sdiv x' -> fresh + * x' := 1 + * x := fresh + * + * x ++ x' ++ x'' -> fresh + * x := fresh[hi1:lo1] + * x' := fresh[hi2:lo2] + * x'' := fresh[hi3:lo3] + * + * x <= t -> fresh or t == MAX + * x := if(fresh, t, t + 1) + * t <= x -> fresh or t == MIN + * x := if(fresh, t, t - 1) + * + * ~x -> fresh + * x := ~fresh + * + * x | y -> fresh + * x := fresh + * y := 0 + * + */ app * process_bv_app(func_decl * f, unsigned num, expr * const * args) { SASSERT(f->get_family_id() == m_bv_util.get_family_id()); switch (f->get_decl_kind()) { @@ -646,6 +718,15 @@ class elim_uncnstr_tactic : public tactic { return nullptr; } } + + /** + * F[select(x, i)] -> F[fresh] + * x := const(fresh) + + * F[store(x, ..., x')] -> F[fresh] + * x' := select(x, ...) + * x := fresh + */ app * process_array_app(func_decl * f, unsigned num, expr * const * args) { SASSERT(f->get_family_id() == m_ar_util.get_family_id()); @@ -676,7 +757,11 @@ class elim_uncnstr_tactic : public tactic { return nullptr; } } - + + /** + * head(x) -> fresh + * x := cons(fresh, arb) + */ app * process_datatype_app(func_decl * f, unsigned num, expr * const * args) { if (m_dt_util.is_accessor(f)) { SASSERT(num == 1); From efbe0a655414ba8e64c5a0b3c62e02730f622691 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2022 17:56:45 -0800 Subject: [PATCH 261/477] wip - updated version of elim_uncstr_tactic - remove reduce_invertible. It is subsumed by reduce_uncstr(2) - introduce a simplifier for reduce_unconstrained. It uses reference counting to deal with inefficiency bug of legacy reduce_uncstr. It decomposes theory plugins into expr_inverter. reduce_invertible is a tactic used in most built-in scenarios. It is useful for removing subterms that can be eliminated using "cheap" quantifier elimination. Specifically variables that occur only once can be removed in many cases by computing an expression that represents the effect computing a value for the eliminated occurrence. The theory plugins for variable elimination are very partial and should be augmented by extensions, esp. for the case of bit-vectors where the invertibility conditions are thoroughly documented by Niemetz and Preiner. --- src/ast/arith_decl_plugin.h | 2 + src/ast/array_decl_plugin.h | 4 + src/ast/bv_decl_plugin.h | 8 + src/ast/converters/CMakeLists.txt | 1 + src/ast/converters/expr_inverter.cpp | 791 ++++++++++++++++++ src/ast/converters/expr_inverter.h | 57 ++ src/ast/converters/generic_model_converter.h | 4 + src/ast/for_each_expr.cpp | 13 +- src/ast/for_each_expr.h | 12 +- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/elim_unconstrained.cpp | 297 +++++++ src/ast/simplifiers/elim_unconstrained.h | 84 ++ .../model_reconstruction_trail.cpp | 8 + .../simplifiers/model_reconstruction_trail.h | 13 +- src/tactic/core/CMakeLists.txt | 3 +- src/tactic/core/elim_uncnstr2_tactic.h | 41 + src/tactic/core/elim_uncnstr_tactic.cpp | 7 +- src/tactic/core/reduce_invertible_tactic.cpp | 576 ------------- src/tactic/core/reduce_invertible_tactic.h | 32 - src/tactic/dependent_expr_state_tactic.h | 1 + 20 files changed, 1334 insertions(+), 621 deletions(-) create mode 100644 src/ast/converters/expr_inverter.cpp create mode 100644 src/ast/converters/expr_inverter.h create mode 100644 src/ast/simplifiers/elim_unconstrained.cpp create mode 100644 src/ast/simplifiers/elim_unconstrained.h create mode 100644 src/tactic/core/elim_uncnstr2_tactic.h delete mode 100644 src/tactic/core/reduce_invertible_tactic.cpp delete mode 100644 src/tactic/core/reduce_invertible_tactic.h diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 0c77867d4..93d0edf2f 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -447,6 +447,8 @@ public: app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(arith_family_id, OP_ADD, arg1, arg2, arg3); } app * mk_add(expr_ref_vector const& args) const { return mk_add(args.size(), args.data()); } app * mk_add(expr_ref_buffer const& args) const { return mk_add(args.size(), args.data()); } + app * mk_add(ptr_buffer const& args) const { return mk_add(args.size(), args.data()); } + app * mk_add(ptr_vector const& args) const { return mk_add(args.size(), args.data()); } app * mk_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(arith_family_id, OP_SUB, arg1, arg2); } app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(arith_family_id, OP_SUB, num_args, args); } diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 83d541097..79c6e682e 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -207,6 +207,10 @@ public: return mk_store(args.size(), args.data()); } + app* mk_store(ptr_buffer const& args) const { + return mk_store(args.size(), args.data()); + } + app * mk_select(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_fid, OP_SELECT, 0, nullptr, num_args, args); } diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 37531d936..ee618b42c 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -448,9 +448,17 @@ public: app * mk_bv_srem(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BSREM, arg1, arg2); } app * mk_bv_smod(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BSMOD, arg1, arg2); } app * mk_bv_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BADD, arg1, arg2); } + app * mk_bv_add(ptr_buffer const & args) const { return m_manager.mk_app(get_fid(), OP_BADD, args.size(), args.data()); } + app * mk_bv_add(ptr_vector const & args) const { return m_manager.mk_app(get_fid(), OP_BADD, args.size(), args.data()); } + app * mk_bv_add(expr_ref_vector const & args) const { return m_manager.mk_app(get_fid(), OP_BADD, args.size(), args.data()); } + app * mk_bv_add(expr_ref_buffer const & args) const { return m_manager.mk_app(get_fid(), OP_BADD, args.size(), args.data()); } app * mk_bv_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BSUB, arg1, arg2); } app * mk_bv_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BMUL, arg1, arg2); } app * mk_bv_mul(unsigned n, expr* const* args) const { return m_manager.mk_app(get_fid(), OP_BMUL, n, args); } + app* mk_bv_mul(ptr_buffer const& args) const { return m_manager.mk_app(get_fid(), OP_BMUL, args.size(), args.data()); } + app* mk_bv_mul(ptr_vector const& args) const { return m_manager.mk_app(get_fid(), OP_BMUL, args.size(), args.data()); } + app* mk_bv_mul(expr_ref_vector const& args) const { return m_manager.mk_app(get_fid(), OP_BMUL, args.size(), args.data()); } + app* mk_bv_mul(expr_ref_buffer const& args) const { return m_manager.mk_app(get_fid(), OP_BMUL, args.size(), args.data()); } app * mk_bv_udiv(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BUDIV, arg1, arg2); } app * mk_bv_udiv_i(expr * arg1, expr * arg2) const { return m_manager.mk_app(get_fid(), OP_BUDIV_I, arg1, arg2); } app * mk_bv_udiv0(expr * arg) const { return m_manager.mk_app(get_fid(), OP_BUDIV0, arg); } diff --git a/src/ast/converters/CMakeLists.txt b/src/ast/converters/CMakeLists.txt index 52895f064..64f5060e7 100644 --- a/src/ast/converters/CMakeLists.txt +++ b/src/ast/converters/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(converters SOURCES + expr_inverter.cpp equiv_proof_converter.cpp generic_model_converter.cpp horn_subsume_model_converter.cpp diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp new file mode 100644 index 000000000..504c04ab0 --- /dev/null +++ b/src/ast/converters/expr_inverter.cpp @@ -0,0 +1,791 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + expr_inverter.cpp + +Abstract: + + inverter interface and instance + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-11 + +--*/ + +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_util.h" +#include "ast/arith_decl_plugin.h" +#include "ast/converters/expr_inverter.h" + +class basic_expr_inverter : public iexpr_inverter { +public: + + basic_expr_inverter(ast_manager& m) : iexpr_inverter(m) {} + + /** + * if (c, x, x') -> fresh + * x := fresh + * x' := fresh + * + * if (x, x', e) -> fresh + * x := true + * x' := fresh + * + * if (x, t, x') -> fresh + * x := false + * x' := fresh + * + * not x -> fresh + * x := not fresh + * + * x & x' -> fresh + * x := fresh + * x' := true + * + * x or x' -> fresh + * x := fresh + * x' := false + * + * x = t -> fresh + * x := if(fresh, t, diff(t)) + * where diff is a diagnonalization function available in domains of size > 1. + * + */ + + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) { + SASSERT(f->get_family_id() == m.get_basic_family_id()); + switch (f->get_decl_kind()) { + case OP_ITE: + SASSERT(num == 3); + if (uncnstr(args[1]) && uncnstr(args[2])) { + mk_fresh_uncnstr_var_for(f, r); + add_def(args[1], r); + add_def(args[2], r); + return true; + } + if (uncnstr(args[0]) && uncnstr(args[1])) { + mk_fresh_uncnstr_var_for(f, r); + add_def(args[0], m.mk_true()); + add_def(args[1], r); + return true; + } + if (uncnstr(args[0]) && uncnstr(args[2])) { + mk_fresh_uncnstr_var_for(f, r); + add_def(args[0], m.mk_false()); + add_def(args[2], r); + return true; + } + return false; + case OP_NOT: + SASSERT(num == 1); + if (uncnstr(args[0])) { + mk_fresh_uncnstr_var_for(f, r); + add_def(args[0], m.mk_not(r)); + return true; + } + return false; + case OP_AND: + if (num > 0 && uncnstr(num, args)) { + mk_fresh_uncnstr_var_for(f, r); + add_defs(num, args, r, m.mk_true()); + return true; + } + return false; + case OP_OR: + if (num > 0 && uncnstr(num, args)) { + mk_fresh_uncnstr_var_for(f, r); + add_defs(num, args, r, m.mk_false()); + return true; + } + return false; + case OP_EQ: + SASSERT(num == 2); + // return process_eq(f, args[0], args[1]); + default: + return false; + } + return false; + } + + bool mk_diff(expr* t, expr_ref& r) override { + SASSERT(m.is_bool(t)); + r = mk_not(m, t); + return true; + } +}; + +class arith_expr_inverter : public iexpr_inverter { + arith_util a; +public: + + arith_expr_inverter(ast_manager& m) : iexpr_inverter(m), a(m) {} + + family_id get_fid() const { return a.get_family_id(); } + + bool process_le_ge(func_decl* f, expr* arg1, expr* arg2, bool le, expr_ref& r) { + expr* v; + expr* t; + if (uncnstr(arg1)) { + v = arg1; + t = arg2; + } + else if (uncnstr(arg2)) { + v = arg2; + t = arg1; + le = !le; + } + else + return false; + + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) { + // v = ite(u, t, t + 1) if le + // v = ite(u, t, t - 1) if !le + add_def(v, m.mk_ite(r, t, a.mk_add(t, a.mk_numeral(rational(le ? 1 : -1), arg1->get_sort())))); + } + return true; + } + + bool process_add(unsigned num, expr* const* args, expr_ref& u) { + if (num == 0) + return false; + unsigned i; + expr* v = nullptr; + for (i = 0; i < num; i++) { + expr* arg = args[i]; + if (uncnstr(arg)) { + v = arg; + break; + } + } + if (v == nullptr) + return false; + mk_fresh_uncnstr_var_for(v->get_sort(), u); + if (!m_mc) + return true; + ptr_buffer new_args; + for (unsigned j = 0; j < num; j++) + if (j != i) + new_args.push_back(args[j]); + + if (new_args.empty()) + add_def(v, u); + else { + expr* rest = a.mk_add(new_args); + add_def(v, a.mk_sub(u, rest)); + } + return true; + } + + bool process_arith_mul(unsigned num, expr* const* args, expr_ref & u) { + if (num == 0) + return false; + sort* s = args[0]->get_sort(); + if (uncnstr(num, args)) { + mk_fresh_uncnstr_var_for(s, u); + if (m_mc) + add_defs(num, args, u, a.mk_numeral(rational(1), s)); + return true; + } + // c * v case for reals + bool is_int; + rational val; + if (num == 2 && uncnstr(args[1]) && a.is_numeral(args[0], val, is_int) && !is_int) { + if (val.is_zero()) + return false; + mk_fresh_uncnstr_var_for(s, u); + if (m_mc) { + val = rational(1) / val; + add_def(args[1], a.mk_mul(a.mk_numeral(val, false), u)); + } + return true; + } + return false; + } + + + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + SASSERT(f->get_family_id() == a.get_family_id()); + switch (f->get_decl_kind()) { + case OP_ADD: + return process_add(num, args, r); + case OP_MUL: + return process_arith_mul(num, args, r); + case OP_LE: + SASSERT(num == 2); + return process_le_ge(f, args[0], args[1], true, r); + case OP_GE: + SASSERT(num == 2); + return process_le_ge(f, args[0], args[1], false, r); + default: + return false; + } + } + + + bool mk_diff(expr* t, expr_ref& r) override { + SASSERT(a.is_int_real(t)); + r = a.mk_add(t, a.mk_numeral(rational(1), a.is_int(t))); + return true; + } +}; + +class bv_expr_inverter : public iexpr_inverter { + bv_util bv; + + bool process_add(unsigned num, expr* const* args, expr_ref& u) { + if (num == 0) + return false; + unsigned i; + expr* v = nullptr; + for (i = 0; i < num; i++) { + expr* arg = args[i]; + if (uncnstr(arg)) { + v = arg; + break; + } + } + if (!v) + return false; + mk_fresh_uncnstr_var_for(v->get_sort(), u); + if (!m_mc) + return true; + ptr_buffer new_args; + for (unsigned j = 0; j < num; j++) + if (j != i) + new_args.push_back(args[j]); + + if (new_args.empty()) + add_def(v, u); + else { + expr* rest = bv.mk_bv_add(new_args); + add_def(v, bv.mk_bv_sub(u, rest)); + } + return true; + } + + bool process_bv_mul(func_decl* f, unsigned num, expr* const* args, expr_ref& r) { + if (num == 0) + return nullptr; + if (uncnstr(num, args)) { + sort* s = args[0]->get_sort(); + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) + add_defs(num, args, r, bv.mk_numeral(rational(1), s)); + return true; + } + // c * v (c is odd) case + unsigned sz; + rational val; + rational inv; + if (num == 2 && + uncnstr(args[1]) && + bv.is_numeral(args[0], val, sz) && + val.mult_inverse(sz, inv)) { + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) + add_def(args[1], bv.mk_bv_mul(bv.mk_numeral(inv, sz), r)); + return true; + } + + // + // x * K -> fresh[hi-sh-1:0] ++ 0...0 + // where sh = parity of K + // then x -> J^-1*fresh + // where J = K >> sh + // Because x * K = fresh * K * J^-1 = fresh * 2^sh = fresh[hi-sh-1:0] ++ 0...0 + // + if (num == 2 && + uncnstr(args[1]) && + bv.is_numeral(args[0], val, sz) && + val.is_pos()) { + unsigned sh = 0; + while (val.is_even()) { + val /= rational(2); + ++sh; + } + mk_fresh_uncnstr_var_for(f, r); + if (sh > 0) + r = bv.mk_concat(bv.mk_extract(sz - sh - 1, 0, r), bv.mk_numeral(0, sh)); + + if (m_mc) { + rational inv_r; + VERIFY(val.mult_inverse(sz, inv_r)); + add_def(args[1], bv.mk_bv_mul(bv.mk_numeral(inv_r, sz), r)); + } + return true; + } + + // + // assume x is unconstrained, we can handle general multiplication as follows: + // x * y -> if y = 0 then y else fresh << parity(y) + // and x -> if y = 0 then y else (y >> parity(y))^-1 + // parity can be defined using a "giant" ite expression. + // + + return false; + } + + + bool process_extract(func_decl* f, expr* arg, expr_ref& r) { + if (!uncnstr(arg)) + return false; + mk_fresh_uncnstr_var_for(f, r); + if (!m_mc) + return true; + unsigned high = bv.get_extract_high(f); + unsigned low = bv.get_extract_low(f); + unsigned bv_size = bv.get_bv_size(arg->get_sort()); + if (bv_size == high - low + 1) + add_def(arg, r); + else { + ptr_buffer args; + if (high < bv_size - 1) + args.push_back(bv.mk_numeral(rational(0), bv_size - high - 1)); + args.push_back(r); + if (low > 0) + args.push_back(bv.mk_numeral(rational(0), low)); + add_def(arg, bv.mk_concat(args.size(), args.data())); + } + return true; + } + + bool process_bv_div(func_decl* f, expr* arg1, expr* arg2, expr_ref& r) { + if (uncnstr(arg1) && uncnstr(arg2)) { + sort* s = arg1->get_sort(); + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) { + add_def(arg1, r); + add_def(arg2, bv.mk_numeral(rational(1), s)); + } + return true; + } + return false; + } + + bool process_concat(func_decl* f, unsigned num, expr* const* args, expr_ref& r) { + if (num == 0) + return false; + if (!uncnstr(num, args)) + return false; + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) { + unsigned i = num; + unsigned low = 0; + while (i > 0) { + --i; + expr* arg = args[i]; + unsigned sz = bv.get_bv_size(arg); + add_def(arg, bv.mk_extract(low + sz - 1, low, r)); + low += sz; + } + } + return true; + } + + bool process_bv_le(func_decl* f, expr* arg1, expr* arg2, bool is_signed, expr_ref& r) { + if (uncnstr(arg1)) { + // v <= t + expr* v = arg1; + expr* t = arg2; + // v <= t ---> (u or t == MAX) u is fresh + // add definition v = ite(u or t == MAX, t, t+1) + unsigned bv_sz = bv.get_bv_size(arg1); + rational MAX; + if (is_signed) + MAX = rational::power_of_two(bv_sz - 1) - rational(1); + else + MAX = rational::power_of_two(bv_sz) - rational(1); + mk_fresh_uncnstr_var_for(f, r); + r = m.mk_or(r, m.mk_eq(t, bv.mk_numeral(MAX, bv_sz))); + if (m_mc) + add_def(v, m.mk_ite(r, t, bv.mk_bv_add(t, bv.mk_numeral(rational(1), bv_sz)))); + return true; + } + if (uncnstr(arg2)) { + // v >= t + expr* v = arg2; + expr* t = arg1; + // v >= t ---> (u ot t == MIN) u is fresh + // add definition v = ite(u or t == MIN, t, t-1) + unsigned bv_sz = bv.get_bv_size(arg1); + rational MIN; + if (is_signed) + MIN = -rational::power_of_two(bv_sz - 1); + else + MIN = rational(0); + mk_fresh_uncnstr_var_for(f, r); + r = m.mk_or(r, m.mk_eq(t, bv.mk_numeral(MIN, bv_sz))); + if (m_mc) + add_def(v, m.mk_ite(r, t, bv.mk_bv_sub(t, bv.mk_numeral(rational(1), bv_sz)))); + return true; + } + return false; + } + + bool process_bvnot(expr* e, expr_ref& r) { + if (!uncnstr(e)) + return false; + mk_fresh_uncnstr_var_for(e->get_sort(), r); + if (m_mc) + add_def(e, bv.mk_bv_not(r)); + return true; + } + + public: + bv_expr_inverter(ast_manager& m) : iexpr_inverter(m), bv(m) {} + + family_id get_fid() const { return bv.get_family_id(); } + + /** + * x + t -> fresh + * x := fresh - t + * + * x * x' * x'' -> fresh + * x := fresh + * x', x'' := 1 + * + * c * x -> fresh, c is odd + * x := fresh*c^-1 + * + * x[sz-1:0] -> fresh + * x := fresh + * + * x[hi:lo] -> fresh + * x := fresh1 ++ fresh ++ fresh2 + * + * x udiv x', x sdiv x' -> fresh + * x' := 1 + * x := fresh + * + * x ++ x' ++ x'' -> fresh + * x := fresh[hi1:lo1] + * x' := fresh[hi2:lo2] + * x'' := fresh[hi3:lo3] + * + * x <= t -> fresh or t == MAX + * x := if(fresh, t, t + 1) + * t <= x -> fresh or t == MIN + * x := if(fresh, t, t - 1) + * + * ~x -> fresh + * x := ~fresh + * + * x | y -> fresh + * x := fresh + * y := 0 + * + */ + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + SASSERT(f->get_family_id() == bv.get_family_id()); + switch (f->get_decl_kind()) { + case OP_BADD: + return process_add(num, args, r); + case OP_BMUL: + return process_bv_mul(f, num, args, r); + case OP_BSDIV: + case OP_BUDIV: + case OP_BSDIV_I: + case OP_BUDIV_I: + SASSERT(num == 2); + return process_bv_div(f, args[0], args[1], r); + case OP_SLEQ: + SASSERT(num == 2); + return process_bv_le(f, args[0], args[1], true, r); + case OP_ULEQ: + SASSERT(num == 2); + return process_bv_le(f, args[0], args[1], false, r); + case OP_CONCAT: + return process_concat(f, num, args, r); + case OP_EXTRACT: + SASSERT(num == 1); + return process_extract(f, args[0], r); + case OP_BNOT: + SASSERT(num == 1); + return process_bvnot(args[0], r); + case OP_BOR: + if (num > 0 && uncnstr(num, args)) { + sort* s = args[0]->get_sort(); + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) + add_defs(num, args, r, bv.mk_numeral(rational(0), s)); + return true; + } + return false; + default: + return false; + } + } + + bool mk_diff(expr* t, expr_ref& r) override { + r = bv.mk_bv_not(t); + return true; + } +}; + + + +/** + * F[select(x, i)] -> F[fresh] + * x := const(fresh) + + * F[store(x, ..., x')] -> F[fresh] + * x' := select(x, ...) + * x := fresh + */ + +class array_expr_inverter : public iexpr_inverter { + array_util a; + iexpr_inverter& inv; +public: + array_expr_inverter(ast_manager& m, iexpr_inverter& s) : iexpr_inverter(m), a(m), inv(s) {} + + family_id get_fid() const { return a.get_family_id(); } + + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + SASSERT(f->get_family_id() == a.get_family_id()); + switch (f->get_decl_kind()) { + case OP_SELECT: + if (uncnstr(args[0])) { + mk_fresh_uncnstr_var_for(f, r); + sort* s = args[0]->get_sort(); + if (m_mc) + add_def(args[0], a.mk_const_array(s, r)); + return true; + } + return false; + case OP_STORE: + if (uncnstr(args[0]) && uncnstr(args[num - 1])) { + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) { + add_def(args[num - 1], m.mk_app(a.get_family_id(), OP_SELECT, num - 1, args)); + add_def(args[0], r); + } + return true; + } + default: + return false; + } + } + + bool mk_diff(expr* t, expr_ref& r) override { + sort* s = t->get_sort(); + SASSERT(a.is_array(s)); + if (m.is_uninterp(get_array_range(s))) + return false; + unsigned arity = get_array_arity(s); + for (unsigned i = 0; i < arity; i++) + if (m.is_uninterp(get_array_domain(s, i))) + return false; + // building + // r = (store t i1 ... in d) + // where i1 ... in are arbitrary values + // and d is a term different from (select t i1 ... in) + expr_ref_vector new_args(m); + new_args.push_back(t); + for (unsigned i = 0; i < arity; i++) + new_args.push_back(m.get_some_value(get_array_domain(s, i))); + expr_ref sel(m); + sel = a.mk_select(new_args); + expr_ref diff_sel(m); + if (!inv.mk_diff(sel, diff_sel)) + return false; + new_args.push_back(diff_sel); + r = a.mk_store(new_args); + return true; + } +}; + + + +class dt_expr_inverter : public iexpr_inverter { + datatype_util dt; +public: + + dt_expr_inverter(ast_manager& m) : iexpr_inverter(m), dt(m) {} + + family_id get_fid() const { return dt.get_family_id(); } + /** + * head(x) -> fresh + * x := cons(fresh, arb) + */ + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + if (dt.is_accessor(f)) { + SASSERT(num == 1); + if (uncnstr(args[0])) { + if (!m_mc) { + mk_fresh_uncnstr_var_for(f, r); + return true; + } + func_decl* c = dt.get_accessor_constructor(f); + for (unsigned i = 0; i < c->get_arity(); i++) + if (!m.is_fully_interp(c->get_domain(i))) + return false; + mk_fresh_uncnstr_var_for(f, r); + ptr_vector const& accs = *dt.get_constructor_accessors(c); + ptr_buffer new_args; + for (unsigned i = 0; i < accs.size(); i++) { + if (accs[i] == f) + new_args.push_back(r); + else + new_args.push_back(m.get_some_value(c->get_domain(i))); + } + add_def(args[0], m.mk_app(c, new_args)); + return true; + } + } + return false; + } + + bool mk_diff(expr* t, expr_ref& r) override { + // In the current implementation, I only handle the case where + // the datatype has a recursive constructor. + sort* s = t->get_sort(); + ptr_vector const& constructors = *dt.get_datatype_constructors(s); + for (func_decl* constructor : constructors) { + unsigned num = constructor->get_arity(); + unsigned target = UINT_MAX; + for (unsigned i = 0; i < num; i++) { + sort* s_arg = constructor->get_domain(i); + if (s == s_arg) { + target = i; + continue; + } + if (m.is_uninterp(s_arg)) + break; + } + if (target == UINT_MAX) + continue; + // use the constructor the distinct term constructor(...,t,...) + ptr_buffer new_args; + for (unsigned i = 0; i < num; i++) { + if (i == target) + new_args.push_back(t); + else + new_args.push_back(m.get_some_value(constructor->get_domain(i))); + } + r = m.mk_app(constructor, new_args); + return true; + } + return false; + } +}; + + + +expr_inverter::~expr_inverter() { + for (auto* v : m_inverters) + dealloc(v); +} + + +bool iexpr_inverter::uncnstr(unsigned num, expr * const * args) const { + for (unsigned i = 0; i < num; i++) + if (!m_is_var(args[i])) + return false; + return true; +} + +/** + \brief Create a fresh variable for abstracting (f args[0] ... args[num-1]) + Return true if it a new variable was created, and false if the variable already existed for this + application. Store the variable in v +*/ +void iexpr_inverter::mk_fresh_uncnstr_var_for(sort * s, expr_ref & v) { + v = m.mk_fresh_const(nullptr, s); + if (m_mc) + m_mc->hide(v); +} + +void iexpr_inverter::add_def(expr * v, expr * def) { + expr_ref _v(v, m); + expr_ref _d(def, m); + if (!m_mc) + return; + SASSERT(uncnstr(v)); + SASSERT(to_app(v)->get_num_args() == 0); + m_mc->add(to_app(v)->get_decl(), def); +} + +void iexpr_inverter::add_defs(unsigned num, expr* const* args, expr* u, expr* identity) { + expr_ref _id(identity, m); + if (!m_mc) + return; + add_def(args[0], u); + for (unsigned i = 1; i < num; i++) + add_def(args[i], identity); +} + + +expr_inverter::expr_inverter(ast_manager& m): iexpr_inverter(m) { + auto* a = alloc(arith_expr_inverter, m); + auto* b = alloc(bv_expr_inverter, m); + auto* ar = alloc(array_expr_inverter, m, *this); + auto* dt = alloc(dt_expr_inverter, m); + m_inverters.setx(m.get_basic_family_id(), alloc(basic_expr_inverter, m), nullptr); + m_inverters.setx(a->get_fid(), a, nullptr); + m_inverters.setx(b->get_fid(), b, nullptr); + m_inverters.setx(ar->get_fid(), ar, nullptr); + m_inverters.setx(dt->get_fid(), dt, nullptr); +} + +bool expr_inverter::is_converted(func_decl* f, unsigned num, expr* const* args) { + return false; +} + +bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) { + if (num == 0) + return false; + + for (unsigned i = 0; i < num; i++) + if (!is_ground(args[i])) + return false; + + family_id fid = f->get_family_id(); + if (fid == null_family_id) + return false; + + if (is_converted(f, num, args)) + return false; + + auto* p = m_inverters.get(fid, nullptr); + return p && (*p)(f, num, args, new_expr, side_cond); +} + +bool expr_inverter::mk_diff(expr* t, expr_ref& r) { + sort * s = t->get_sort(); + if (!m.is_fully_interp(s)) + return false; + + // If the interpreted sort has only one element, + // then it is unsound to eliminate the unconstrained variable in the equality + sort_size sz = s->get_num_elements(); + if (sz.is_finite() && sz.size() <= 1) + return false; + + if (!m_mc) { + // easy case, model generation is disabled. + mk_fresh_uncnstr_var_for(s, r); + return true; + } + + family_id fid = s->get_family_id(); + auto* p = m_inverters.get(fid, nullptr); + return p && p->mk_diff(t, r); +} + +void expr_inverter::set_is_var(std::function& is_var) { + for (auto* p : m_inverters) + if (p) + p->set_is_var(is_var); +} + +void expr_inverter::set_model_converter(generic_model_converter* mc) { + for (auto* p : m_inverters) + if (p) + p->set_model_converter(mc); +} \ No newline at end of file diff --git a/src/ast/converters/expr_inverter.h b/src/ast/converters/expr_inverter.h new file mode 100644 index 000000000..1ca77dbab --- /dev/null +++ b/src/ast/converters/expr_inverter.h @@ -0,0 +1,57 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + expr_inverter.h + +Abstract: + + inverter interface and instance + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-11 + + +--*/ +#pragma once + +#include "ast/converters/generic_model_converter.h" + +class iexpr_inverter { +protected: + ast_manager& m; + std::function m_is_var; + generic_model_converter_ref m_mc; + + bool uncnstr(expr* e) const { return m_is_var(e); } + bool uncnstr(unsigned num, expr * const * args) const; + void mk_fresh_uncnstr_var_for(sort* s, expr_ref& v); + void mk_fresh_uncnstr_var_for(func_decl* f, expr_ref& v) { mk_fresh_uncnstr_var_for(f->get_range(), v); } + void add_def(expr * v, expr * def); + void add_defs(unsigned num, expr * const * args, expr * u, expr * identity); + +public: + iexpr_inverter(ast_manager& m): m(m) {} + virtual ~iexpr_inverter() {} + virtual void set_is_var(std::function& is_var) { m_is_var = is_var; } + virtual void set_model_converter(generic_model_converter* mc) { m_mc = mc; } + + virtual bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) = 0; + virtual bool mk_diff(expr* t, expr_ref& r) = 0; +}; + +class expr_inverter : public iexpr_inverter { + ptr_vector m_inverters; + + bool is_converted(func_decl* f, unsigned num, expr* const* args); + +public: + expr_inverter(ast_manager& m); + ~expr_inverter() override; + bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) override; + bool mk_diff(expr* t, expr_ref& r) override; + void set_is_var(std::function& is_var) override; + void set_model_converter(generic_model_converter* mc) override; +}; diff --git a/src/ast/converters/generic_model_converter.h b/src/ast/converters/generic_model_converter.h index c20bfebb3..85e8d0390 100644 --- a/src/ast/converters/generic_model_converter.h +++ b/src/ast/converters/generic_model_converter.h @@ -22,6 +22,7 @@ Notes: #include "ast/converters/model_converter.h" class generic_model_converter : public model_converter { +public: enum instruction { HIDE, ADD }; struct entry { func_decl_ref m_f; @@ -30,6 +31,7 @@ class generic_model_converter : public model_converter { entry(func_decl* f, expr* d, ast_manager& m, instruction i): m_f(f, m), m_def(d, m), m_instruction(i) {} }; +private: ast_manager& m; std::string m_orig; vector m_entries; @@ -67,6 +69,8 @@ public: void set_env(ast_pp_util* visitor) override; void get_units(obj_map& units) override; + + vector const& entries() const { return m_entries; } }; typedef ref generic_model_converter_ref; diff --git a/src/ast/for_each_expr.cpp b/src/ast/for_each_expr.cpp index 0790b418d..1e7b6da3b 100644 --- a/src/ast/for_each_expr.cpp +++ b/src/ast/for_each_expr.cpp @@ -120,11 +120,11 @@ bool subterms::iterator::operator!=(iterator const& other) const { } -subterms_postorder::subterms_postorder(expr_ref_vector const& es): m_es(es) {} -subterms_postorder::subterms_postorder(expr_ref const& e) : m_es(e.m()) { if (e) m_es.push_back(e); } +subterms_postorder::subterms_postorder(expr_ref_vector const& es, bool include_bound): m_include_bound(include_bound), m_es(es) {} +subterms_postorder::subterms_postorder(expr_ref const& e, bool include_bound) : m_include_bound(include_bound), m_es(e.m()) { if (e) m_es.push_back(e); } subterms_postorder::iterator subterms_postorder::begin() { return iterator(*this, true); } subterms_postorder::iterator subterms_postorder::end() { return iterator(*this, false); } -subterms_postorder::iterator::iterator(subterms_postorder& f, bool start): m_es(f.m_es) { +subterms_postorder::iterator::iterator(subterms_postorder& f, bool start): m_include_bound(f.m_include_bound), m_es(f.m_es) { if (!start) m_es.reset(); next(); } @@ -153,6 +153,13 @@ void subterms_postorder::iterator::next() { } } } + else if (is_quantifier(e) && m_include_bound) { + expr* body = to_quantifier(e)->get_expr(); + if (!m_visited.is_marked(body)) { + m_es.push_back(body); + all_visited = false; + } + } if (all_visited) { m_visited.mark(e, true); break; diff --git a/src/ast/for_each_expr.h b/src/ast/for_each_expr.h index 99a0f6b9d..2d5ed05ae 100644 --- a/src/ast/for_each_expr.h +++ b/src/ast/for_each_expr.h @@ -200,9 +200,15 @@ public: }; class subterms_postorder { + bool m_include_bound; expr_ref_vector m_es; + subterms_postorder(expr_ref_vector const& es, bool include_bound); + subterms_postorder(expr_ref const& e, bool include_bound); + + public: class iterator { + bool m_include_bound = false; expr_ref_vector m_es; expr_mark m_visited, m_seen; void next(); @@ -214,8 +220,10 @@ public: bool operator==(iterator const& other) const; bool operator!=(iterator const& other) const; }; - subterms_postorder(expr_ref_vector const& es); - subterms_postorder(expr_ref const& e); + static subterms_postorder all(expr_ref_vector const& es) { return subterms_postorder(es, true); } + static subterms_postorder ground(expr_ref_vector const& es) { return subterms_postorder(es, false); } + static subterms_postorder all(expr_ref const& e) { return subterms_postorder(e, true); } + static subterms_postorder ground(expr_ref const& e) { return subterms_postorder(e, false); } iterator begin(); iterator end(); }; diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index ef04cc433..75aa1ec7a 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(simplifiers SOURCES bv_slice.cpp + elim_unconstrained.cpp euf_completion.cpp extract_eqs.cpp model_reconstruction_trail.cpp diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp new file mode 100644 index 000000000..cbd575b6a --- /dev/null +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -0,0 +1,297 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + elim_unconstrained.cpp + +Abstract: + + Incremental, modular and more efficient version of elim_unconstr_tactic and + reduce_invertible_tactic. + + reduce_invertible_tactic should be subsumed by elim_unconstr_tactic + elim_unconstr_tactic has some built-in limitations that are not easy to fix with small changes: + - it is inefficient for examples like x <= y, y <= z, z <= u, ... + All variables x, y, z, .. can eventually be eliminated, but the tactic requires a global + analysis between each elimination. We address this by using reference counts and maintaining + a heap of reference counts. + - it does not accomodate side constraints. The more general invertibility reduction methods, such + as those introduced for bit-vectors use side constraints. + - it is not modular: we detach the expression invertion routines to self-contained code. + + Maintain a representation of terms as a set of nodes. + Each node has: + + - reference count = number of parents that are live + - orig - original term, the orig->get_id() is the index to the node + - term - current term representing the node after rewriting + - parents - list of parents where orig occurs. + + Subterms have reference counts + Elegible variables are inserted into a heap ordered by reference counts. + Variables that have reference count 1 are examined for invertibility. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-11. + +--*/ + + + +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/recfun_decl_plugin.h" +#include "ast/simplifiers/elim_unconstrained.h" + +elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fmls) : + dependent_expr_simplifier(m, fmls), m_inverter(m), m_lt(*this), m_heap(1024, m_lt), m_trail(m) { + + std::function is_var = [&](expr* e) { + return is_uninterp_const(e) && !m_frozen.is_marked(e) && get_node(e).m_refcount == 1; + }; + + m_inverter.set_is_var(is_var); +} + + +void elim_unconstrained::eliminate() { + + while (!m_heap.empty()) { + expr_ref r(m), side_cond(m); + int v = m_heap.erase_min(); + node& n = get_node(v); + IF_VERBOSE(11, verbose_stream() << mk_pp(n.m_orig, m) << " @ " << n.m_refcount << "\n"); + if (n.m_refcount == 0) + continue; + if (n.m_refcount > 1) + return; + + if (n.m_parents.empty()) + continue; + expr* e = get_parent(v); + for (expr* p : n.m_parents) + IF_VERBOSE(11, verbose_stream() << "parent " << mk_pp(p, m) << "\n"); + if (!is_app(e)) + continue; + if (!is_ground(e)) + continue; + app* t = to_app(e); + m_args.reset(); + for (expr* arg : *to_app(t)) + m_args.push_back(get_node(arg).m_term); + if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) + continue; + + m_stats.m_num_eliminated++; + n.m_refcount = 0; + SASSERT(r); + m_trail.push_back(r); + gc(e); + + get_node(e).m_term = r; + get_node(e).m_refcount++; + IF_VERBOSE(11, verbose_stream() << mk_pp(e, m) << "\n"); + SASSERT(!m_heap.contains(e->get_id())); + if (is_uninterp_const(r)) + m_heap.insert(e->get_id()); + + IF_VERBOSE(11, verbose_stream() << mk_pp(n.m_orig, m) << " " << mk_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n"); + + SASSERT(!side_cond && "not implemented to add side conditions\n"); + } +} + +void elim_unconstrained::add_term(expr* t) { + expr_ref_vector terms(m); + terms.push_back(t); + init_terms(terms); +} + +expr* elim_unconstrained::get_parent(unsigned n) const { + for (expr* p : get_node(n).m_parents) + if (get_node(p).m_refcount > 0 && get_node(p).m_term == get_node(p).m_orig) + return p; + IF_VERBOSE(0, verbose_stream() << "term " << mk_pp(get_node(n).m_term, m) << "\n"); + for (expr* p : get_node(n).m_parents) + IF_VERBOSE(0, verbose_stream() << "parent " << mk_pp(p, m) << "\n"); + UNREACHABLE(); + return nullptr; +} +/** + * initialize node structure + */ +void elim_unconstrained::init_nodes() { + expr_ref_vector terms(m); + for (unsigned i = 0; i < m_fmls.size(); ++i) + terms.push_back(m_fmls[i].fml()); + m_trail.append(terms); + m_heap.reset(); + + init_terms(terms); + + for (expr* e : terms) + inc_ref(e); + + // freeze subterms before the head. + terms.reset(); + for (unsigned i = 0; i < m_qhead; ++i) + terms.push_back(m_fmls[i].fml()); + for (expr* e : subterms::all(terms)) + m_frozen.mark(e, true); + + + recfun::util rec(m); + if (rec.has_rec_defs()) { + for (func_decl* f : rec.get_rec_funs()) { + expr* rhs = rec.get_def(f).get_rhs(); + for (expr* t : subterms::all(expr_ref(rhs, m))) + m_frozen.mark(t); + } + } +} + +void elim_unconstrained::init_terms(expr_ref_vector const& terms) { + unsigned max_id = 0; + for (expr* e : subterms::all(terms)) + max_id = std::max(max_id, e->get_id()); + + m_nodes.reserve(max_id + 1); + m_heap.reserve(max_id + 1); + + for (expr* e : subterms_postorder::all(terms)) { + node& n = get_node(e); + if (n.m_term) + continue; + n.m_orig = e; + n.m_term = e; + n.m_refcount = 0; + if (is_uninterp_const(e)) + m_heap.insert(e->get_id()); + if (is_quantifier(e)) { + expr* body = to_quantifier(e)->get_expr(); + get_node(body).m_parents.push_back(e); + inc_ref(body); + } + else if (is_app(e)) { + for (expr* arg : *to_app(e)) { + get_node(arg).m_parents.push_back(e); + inc_ref(arg); + } + } + } +} + +void elim_unconstrained::gc(expr* t) { + ptr_vector todo; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + node& n = get_node(t); + if (n.m_refcount == 0) + continue; + dec_ref(t); + if (n.m_refcount != 0) + continue; + if (is_app(t)) { + for (expr* arg : *to_app(t)) + todo.push_back(arg); + } + else if (is_quantifier(t)) + todo.push_back(to_quantifier(t)->get_expr()); + } +} + +/** + * walk nodes starting from lowest depth and reconstruct their normalized forms. + */ +void elim_unconstrained::reconstruct_terms() { + expr_ref_vector terms(m); + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) + terms.push_back(m_fmls[i].fml()); + + for (expr* e : subterms_postorder::all(terms)) { + node& n = get_node(e); + expr* t = n.m_term; + if (t != n.m_orig) + continue; + if (is_app(t)) { + bool change = false; + m_args.reset(); + for (expr* arg : *to_app(t)) { + node& n2 = get_node(arg); + m_args.push_back(n2.m_term); + change |= n2.m_term != n2.m_orig; + } + if (change) { + n.m_term = m.mk_app(to_app(t)->get_decl(), m_args); + m_trail.push_back(n.m_term); + } + } + else if (is_quantifier(t)) { + node& n2 = get_node(to_quantifier(t)->get_expr()); + if (n2.m_term != n2.m_orig) { + n.m_term = m.update_quantifier(to_quantifier(t), n2.m_term); + m_trail.push_back(n.m_term); + } + } + } +} + +void elim_unconstrained::assert_normalized(vector& old_fmls) { + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + auto [f, d] = m_fmls[i](); + node& n = get_node(f); + expr* g = n.m_term; + if (f == g) + continue; + old_fmls.push_back(m_fmls[i]); + m_fmls.update(i, dependent_expr(m, g, d)); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); + TRACE("elim_unconstrained", tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); + } +} + +void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector const& old_fmls) { + auto& trail = m_fmls.model_trail(); + scoped_ptr rp = mk_default_expr_replacer(m, false); + scoped_ptr sub = alloc(expr_substitution, m, true, false); + rp->set_substitution(sub.get()); + expr_ref new_def(m); + for (auto const& entry : mc.entries()) { + switch (entry.m_instruction) { + case generic_model_converter::instruction::HIDE: + break; + case generic_model_converter::instruction::ADD: + new_def = entry.m_def; + (*rp)(new_def); + sub->insert(m.mk_const(entry.m_f), new_def, nullptr, nullptr); + break; + } + } + trail.push(sub.detach(), old_fmls); + + for (auto const& entry : mc.entries()) { + switch (entry.m_instruction) { + case generic_model_converter::instruction::HIDE: + trail.push(entry.m_f); + break; + case generic_model_converter::instruction::ADD: + break; + } + } +} + +void elim_unconstrained::reduce() { + generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); + m_inverter.set_model_converter(mc.get()); + init_nodes(); + eliminate(); + reconstruct_terms(); + vector old_fmls; + assert_normalized(old_fmls); + update_model_trail(*mc, old_fmls); + advance_qhead(m_fmls.size()); +} diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h new file mode 100644 index 000000000..327ceeff0 --- /dev/null +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -0,0 +1,84 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + elim_unconstrained.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + + +#pragma once + +#include "util/heap.h" +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/converters/expr_inverter.h" + + +class elim_unconstrained : public dependent_expr_simplifier { + + struct node { + unsigned m_refcount; + expr* m_term; + expr* m_orig; + ptr_vector m_parents; + }; + struct var_lt { + elim_unconstrained& s; + var_lt(elim_unconstrained& s) : s(s) {} + bool operator()(int v1, int v2) const { + return s.get_node(v1).m_refcount < s.get_node(v2).m_refcount; + } + }; + struct stats { + unsigned m_num_eliminated = 0; + void reset() { m_num_eliminated = 0; } + }; + expr_inverter m_inverter; + vector m_nodes; + var_lt m_lt; + heap m_heap; + expr_ref_vector m_trail; + ptr_vector m_args; + expr_mark m_frozen; + stats m_stats; + + bool operator()(int v1, int v2) const { return get_node(v1).m_refcount < get_node(v2).m_refcount; } + + node& get_node(unsigned n) { return m_nodes[n]; } + node const& get_node(unsigned n) const { return m_nodes[n]; } + node& get_node(expr* t) { return m_nodes[t->get_id()]; } + node const& get_node(expr* t) const { return m_nodes[t->get_id()]; } + unsigned get_refcount(expr* t) const { return get_node(t).m_refcount; } + void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(t->get_id()); } + void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(t->get_id()); } + void gc(expr* t); + + expr* get_parent(unsigned n) const; + void init_refcounts(); + void dec_refcounts(expr* t); + + void add_term(expr* t); + void init_terms(expr_ref_vector const& terms); + + void init_nodes(); + void eliminate(); + void reconstruct_terms(); + void assert_normalized(vector& old_fmls); + void update_model_trail(generic_model_converter& mc, vector const& old_fmls); + +public: + + elim_unconstrained(ast_manager& m, dependent_expr_state& fmls); + + void reduce() override; + + void collect_statistics(statistics& st) const override { st.update("elim-unconstr", m_stats.m_num_eliminated); } + + void reset_statistics() override { m_stats.reset(); } +}; diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 373a500bf..a5f1cf8b0 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -30,6 +30,9 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorm_active) continue; + if (t->m_hide) + continue; + // updates that have no intersections with current variables are skipped if (!t->intersects(free_vars)) continue; @@ -79,6 +82,11 @@ model_converter_ref model_reconstruction_trail::get_model_converter() { if (!t->m_active) continue; + if (t->m_hide) { + mc->hide(t->m_hide); + continue; + } + if (first) { first = false; for (auto const& [v, def] : t->m_subst->sub()) { diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index c9b42bc92..eeef136ee 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -35,11 +35,14 @@ class model_reconstruction_trail { struct entry { scoped_ptr m_subst; vector m_removed; + func_decl* m_hide = nullptr; bool m_active = true; entry(expr_substitution* s, vector const& rem) : m_subst(s), m_removed(rem) {} + entry(func_decl* h) : m_hide(h) {} + bool is_loose() const { return !m_removed.empty(); } bool intersects(ast_mark const& free_vars) const { @@ -48,8 +51,6 @@ class model_reconstruction_trail { return true; return false; } - - }; ast_manager& m; @@ -81,6 +82,14 @@ public: */ void push(expr_substitution* s, vector const& removed) { m_trail.push_back(alloc(entry, s, removed)); + m_trail_stack.push(push_back_vector(m_trail)); + } + + /** + * add declaration to hide + */ + void push(func_decl* f) { + m_trail.push_back(alloc(entry, f)); m_trail_stack.push(push_back_vector(m_trail)); } diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 38d2699f0..bab61afce 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -17,7 +17,6 @@ z3_add_component(core_tactics pb_preprocess_tactic.cpp propagate_values_tactic.cpp reduce_args_tactic.cpp - reduce_invertible_tactic.cpp simplify_tactic.cpp solve_eqs_tactic.cpp special_relations_tactic.cpp @@ -39,6 +38,7 @@ z3_add_component(core_tactics dom_simplify_tactic.h elim_term_ite_tactic.h elim_uncnstr_tactic.h + elim_uncnstr2_tactic.h euf_completion_tactic.h injectivity_tactic.h nnf_tactic.h @@ -46,7 +46,6 @@ z3_add_component(core_tactics pb_preprocess_tactic.h propagate_values_tactic.h reduce_args_tactic.h - reduce_invertible_tactic.h simplify_tactic.h solve_eqs_tactic.h solve_eqs2_tactic.h diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h new file mode 100644 index 000000000..2c5f81d5e --- /dev/null +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -0,0 +1,41 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + elim_unconstr2_tactic.h + +Abstract: + + Tactic for eliminating unconstrained terms. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ +#pragma once + +#include "util/params.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/elim_unconstrained.h" +#include "ast/simplifiers/elim_unconstrained.h" + +class elim_uncnstr2_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(elim_unconstrained, m, s); + } +}; + +inline tactic * mk_elim_uncnstr2_tactic(ast_manager & m, params_ref const & p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(elim_uncnstr2_tactic_factory), "elim-unconstr2"); +} + + +/* + ADD_TACTIC("elim-uncnstr2", "eliminate unconstrained variables.", "mk_elim_uncnstr2_tactic(m, p)") +*/ + + diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 34aa748d9..5f0963bfd 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -856,9 +856,8 @@ class elim_uncnstr_tactic : public tactic { void init_mc(bool produce_models) { m_mc = nullptr; - if (produce_models) { - m_mc = alloc(mc, m(), "elim_uncstr"); - } + if (produce_models) + m_mc = alloc(mc, m(), "elim_uncstr"); } void init_rw(bool produce_proofs) { @@ -872,7 +871,7 @@ class elim_uncnstr_tactic : public tactic { m_vars.reset(); collect_occs p; p(*g, m_vars); - if (m_vars.empty() || recfun::util(m()).has_defs()) { + if (m_vars.empty() || recfun::util(m()).has_rec_defs()) { result.push_back(g.get()); // did not increase depth since it didn't do anything. return; diff --git a/src/tactic/core/reduce_invertible_tactic.cpp b/src/tactic/core/reduce_invertible_tactic.cpp deleted file mode 100644 index ba9b5d752..000000000 --- a/src/tactic/core/reduce_invertible_tactic.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/*++ -Copyright (c) 2018 Microsoft Corporation - -Module Name: - - reduce_invertible_tactic.cpp - -Abstract: - - Reduce invertible variables. - -Author: - - Nuno Lopes (nlopes) 2018-6-30 - Nikolaj Bjorner (nbjorner) - -Notes: - - 1. Walk through top-level uninterpreted constants. - ---*/ - -#include "ast/bv_decl_plugin.h" -#include "ast/arith_decl_plugin.h" -#include "ast/ast_pp.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/rewriter/th_rewriter.h" -#include "tactic/tactic.h" -#include "tactic/core/reduce_invertible_tactic.h" -#include "tactic/core/collect_occs.h" -#include "ast/converters/generic_model_converter.h" -#include - -namespace { -class reduce_invertible_tactic : public tactic { - ast_manager& m; - bv_util m_bv; - arith_util m_arith; - -public: - reduce_invertible_tactic(ast_manager & m): - m(m), - m_bv(m), - m_arith(m) - {} - - char const* name() const override { return "reduce_invertible"; } - - tactic * translate(ast_manager & m) override { - return alloc(reduce_invertible_tactic, m); - } - - void operator()(goal_ref const & g, goal_ref_buffer & result) override { - tactic_report report("reduce-invertible", *g); - bool change = true; - while (change) { - change = false; - m_inverted.reset(); - m_parents.reset(); - collect_parents(g); - collect_occs occs; - obj_hashtable vars; - generic_model_converter_ref mc; - occs(*g, vars); - expr_safe_replace sub(m); - expr_ref new_v(m); - expr * p; - for (expr* v : vars) { - if (is_invertible(v, p, new_v, &mc)) { - mark_inverted(p); - sub.insert(p, new_v); - TRACE("invertible_tactic", tout << mk_pp(p, m) << " " << new_v << "\n";); - change = true; - break; - } - } - reduce_q_rw rw(*this); - unsigned sz = g->size(); - for (unsigned idx = 0; !g->inconsistent() && idx < sz; idx++) { - checkpoint(); - expr* f = g->form(idx); - expr_ref f_new(m); - sub(f, f_new); - rw(f_new, f_new); - if (f == f_new) continue; - proof_ref new_pr(m); - if (g->proofs_enabled()) { - proof * pr = g->pr(idx); - new_pr = m.mk_rewrite(f, f_new); - new_pr = m.mk_modus_ponens(pr, new_pr); - } - g->update(idx, f_new, new_pr, g->dep(idx)); - } - if (mc) g->add(mc.get()); - TRACE("invertible_tactic", g->display(tout);); - g->inc_depth(); - } - result.push_back(g.get()); - CTRACE("invertible_tactic", g->mc(), g->mc()->display(tout);); - } - - void cleanup() override {} - -private: - void checkpoint() { - tactic::checkpoint(m); - } - - bool is_bv_neg(expr * e) { - if (m_bv.is_bv_neg(e)) - return true; - - expr *a, *b; - if (m_bv.is_bv_mul(e, a, b)) { - return m_bv.is_allone(a) || m_bv.is_allone(b); - } - return false; - } - - expr_mark m_inverted; - void mark_inverted(expr *p) { - ptr_buffer todo; - todo.push_back(p); - while (!todo.empty()) { - p = todo.back(); - todo.pop_back(); - if (!m_inverted.is_marked(p)) { - m_inverted.mark(p, true); - if (is_app(p)) { - for (expr* arg : *to_app(p)) { - todo.push_back(arg); - } - } - else if (is_quantifier(p)) { - todo.push_back(to_quantifier(p)->get_expr()); - } - } - } - } - - // store one parent of expression, or null if multiple - struct parents { - parents(): m_p(0) {} - uintptr_t m_p; - - void set(expr * e) { - SASSERT((uintptr_t)e != 1); - if (!m_p) m_p = (uintptr_t)e; - else m_p = 1; - } - - expr * get() const { - return m_p == 1 ? nullptr : (expr*)m_p; - } - }; - svector m_parents; - struct parent_collector { - reduce_invertible_tactic& c; - parent_collector(reduce_invertible_tactic& c):c(c) {} - void operator()(app* n) { - for (expr* arg : *n) { - c.m_parents.reserve(arg->get_id() + 1); - c.m_parents[arg->get_id()].set(n); - } - } - - void operator()(var* v) { - c.m_parents.reserve(v->get_id() + 1); - } - - void operator()(quantifier* q) {} - }; - - void collect_parents(goal_ref const& g) { - parent_collector proc(*this); - expr_fast_mark1 visited; - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - checkpoint(); - quick_for_each_expr(proc, visited, g->form(i)); - } - } - - void ensure_mc(generic_model_converter_ref* mc) { - if (mc && !(*mc)) *mc = alloc(generic_model_converter, m, "reduce-invertible"); - } - - bool is_full_domain_var(expr* v, rational& model) { - auto f = is_app(v) ? to_app(v)->get_decl() : nullptr; - if (!f || f->get_family_id() != m_bv.get_family_id() || f->get_arity() == 0) - return false; - - switch (f->get_decl_kind()) { - case OP_BADD: - case OP_BSUB: - model = rational::zero(); - return true; - - case OP_BAND: - model = rational::power_of_two(m_bv.get_bv_size(v)) - rational::one(); - return true; - - case OP_BMUL: - model = rational::one(); - return true; - - case OP_BSDIV: - case OP_BSDIV0: - case OP_BSDIV_I: - case OP_BUDIV: - case OP_BUDIV0: - case OP_BUDIV_I: - default: - return false; - } - } - - bool rewrite_unconstr(expr* v, expr_ref& new_v, generic_model_converter_ref* mc, unsigned max_var) { - rational mdl; - if (!is_full_domain_var(v, mdl)) - return false; - - rational r; - app* a = to_app(v); - expr* fst_arg = a->get_arg(0); - - for (expr* arg : *a) - if (!m_parents[arg->get_id()].get()) - return false; - - if (is_var(fst_arg)) { - for (expr* arg : *a) { - if (!is_var(arg)) - return false; - if (to_var(arg)->get_idx() >= max_var) - return false; - } - } - else { - if (!is_uninterp_const(fst_arg)) - return false; - bool first = true; - for (expr* arg : *a) { - if (!is_app(arg)) - return false; - if (is_uninterp_const(arg)) - continue; - if (m_bv.is_numeral(arg, r) && r == mdl) { - if (first || mdl.is_zero()) { - first = false; - continue; - } - else - return false; - } - return false; - } - } - - if (mc) { - ensure_mc(mc); - expr_ref num(m_bv.mk_numeral(mdl, fst_arg->get_sort()), m); - for (unsigned i = 1, n = a->get_num_args(); i != n; ++i) { - expr* arg = a->get_arg(i); - if (m_bv.is_numeral(arg)) - continue; - (*mc)->add(arg, num); - } - } - new_v = fst_arg; - return true; - } - - // TBD: could be made to be recursive, by walking multiple layers of parents. - - bool is_invertible(expr* v, expr*& p, expr_ref& new_v, generic_model_converter_ref* mc, unsigned max_var = 0) { - rational r; - if (m_parents.size() <= v->get_id()) { - return false; - } - p = m_parents[v->get_id()].get(); - if (!p || m_inverted.is_marked(p) || (mc && !is_ground(p))) { - return false; - } - - if (m_bv.is_bv_xor(p) || - m_bv.is_bv_not(p) || - is_bv_neg(p)) { - if (mc) { - ensure_mc(mc); - (*mc)->add(v, p); - } - new_v = v; - return true; - } - - if (rewrite_unconstr(p, new_v, mc, max_var)) - return true; - - if (m_bv.is_bv_add(p)) { - if (mc) { - ensure_mc(mc); - // if we solve for v' := v + t - // then the value for v is v' - t - expr_ref def(v, m); - for (expr* arg : *to_app(p)) { - if (arg != v) def = m_bv.mk_bv_sub(def, arg); - } - (*mc)->add(v, def); - } - new_v = v; - return true; - } - - if (m_bv.is_bv_mul(p)) { - expr_ref rest(m); - for (expr* arg : *to_app(p)) { - if (arg != v) { - if (rest) - rest = m_bv.mk_bv_mul(rest, arg); - else - rest = arg; - } - } - if (!rest) return false; - - // so far just support numeral - if (!m_bv.is_numeral(rest, r)) - return false; - - // create case split on - // divisbility of 2 - // v * t -> - // if t = 0, set v' := 0 and the solution for v is 0. - // otherwise, - // let i be the position of the least bit of t set to 1 - // then extract[sz-1:i](v) ++ zero[i-1:0] is the invertible of v * t - // thus - // extract[i+1:0](t) = 1 ++ zero[i-1:0] -> extract[sz-1:i](v) ++ zero[i-1:0] - // to reproduce the original v from t - // solve for v*t = extract[sz-1:i](v') ++ zero[i-1:0] - // using values for t and v' - // thus let t' = t / 2^i - // and t'' = the multiplicative inverse of t' - // then t'' * v' * t = t'' * v' * t' * 2^i = v' * 2^i = extract[sz-1:i](v') ++ zero[i-1:0] - // so t'' *v' works - // - unsigned sz = m_bv.get_bv_size(p); - expr_ref bit1(m_bv.mk_numeral(1, 1), m); - - - unsigned sh = 0; - while (r.is_pos() && r.is_even()) { - r /= rational(2); - ++sh; - } - if (r.is_pos() && sh > 0) - new_v = m_bv.mk_concat(m_bv.mk_extract(sz-sh-1, 0, v), m_bv.mk_numeral(0, sh)); - else - new_v = v; - if (mc && !r.is_zero()) { - ensure_mc(mc); - expr_ref def(m); - rational inv_r; - VERIFY(r.mult_inverse(sz, inv_r)); - def = m_bv.mk_bv_mul(m_bv.mk_numeral(inv_r, sz), v); - (*mc)->add(v, def); - TRACE("invertible_tactic", tout << def << "\n";); - } - return true; - } - if (m_bv.is_bv_sub(p)) { - // TBD - } - if (m_bv.is_bv_udivi(p)) { - // TBD - } - // sdivi, sremi, uremi, smodi - // TBD - - if (m_arith.is_mul(p) && m_arith.is_real(p)) { - expr_ref rest(m); - for (expr* arg : *to_app(p)) { - if (arg != v) { - if (rest) - rest = m_arith.mk_mul(rest, arg); - else - rest = arg; - } - } - if (!rest) return false; - if (!m_arith.is_numeral(rest, r) || r.is_zero()) - return false; - expr_ref zero(m_arith.mk_real(0), m); - new_v = m.mk_ite(m.mk_eq(zero, rest), zero, v); - if (mc) { - ensure_mc(mc); - expr_ref def(m_arith.mk_div(v, rest), m); - (*mc)->add(v, def); - } - return true; - } - - - expr* e1 = nullptr, *e2 = nullptr; - - // v / t unless t != 0 - if (m_arith.is_div(p, e1, e2) && e1 == v && m_arith.is_numeral(e2, r) && !r.is_zero()) { - new_v = v; - if (mc) { - ensure_mc(mc); - (*mc)->add(v, m_arith.mk_mul(e1, e2)); - } - return true; - } - - if (m.is_eq(p, e1, e2)) { - TRACE("invertible_tactic", tout << mk_pp(v, m) << "\n";); - if (mc && has_diagonal(e1)) { - ensure_mc(mc); - new_v = m.mk_fresh_const("eq", m.mk_bool_sort()); - SASSERT(v == e1 || v == e2); - expr* other = (v == e1) ? e2 : e1; - (*mc)->hide(new_v); - (*mc)->add(v, m.mk_ite(new_v, other, mk_diagonal(other))); - return true; - } - else if (mc) { - // diagonal functions for other types depend on theory. - return false; - } - else if (is_var(v) && is_non_singleton_sort(v->get_sort())) { - new_v = m.mk_var(to_var(v)->get_idx(), m.mk_bool_sort()); - return true; - } - } - - // - // v <= u - // => u + 1 == 0 or delta - // v := delta ? u : u + 1 - // - if (m_bv.is_bv_ule(p, e1, e2) && e1 == v && mc) { - ensure_mc(mc); - unsigned sz = m_bv.get_bv_size(e2); - expr_ref delta(m.mk_fresh_const("ule", m.mk_bool_sort()), m); - expr_ref succ_e2(m_bv.mk_bv_add(e2, m_bv.mk_numeral(1, sz)), m); - new_v = m.mk_or(delta, m.mk_eq(succ_e2, m_bv.mk_numeral(0, sz))); - (*mc)->hide(delta); - (*mc)->add(v, m.mk_ite(delta, e2, succ_e2)); - return true; - } - - // - // u <= v - // => u == 0 or delta - // v := delta ? u : u - 1 - // - if (m_bv.is_bv_ule(p, e1, e2) && e2 == v && mc) { - ensure_mc(mc); - unsigned sz = m_bv.get_bv_size(e1); - expr_ref delta(m.mk_fresh_const("ule", m.mk_bool_sort()), m); - expr_ref pred_e1(m_bv.mk_bv_sub(e1, m_bv.mk_numeral(1, sz)), m); - new_v = m.mk_or(delta, m.mk_eq(e1, m_bv.mk_numeral(0, sz))); - (*mc)->hide(delta); - (*mc)->add(v, m.mk_ite(delta, e1, pred_e1)); - return true; - } - return false; - } - - bool has_diagonal(expr* e) { - return - m_bv.is_bv(e) || - m.is_bool(e) || - m_arith.is_int_real(e); - } - - expr * mk_diagonal(expr* e) { - if (m_bv.is_bv(e)) return m_bv.mk_bv_not(e); - if (m.is_bool(e)) return m.mk_not(e); - if (m_arith.is_int(e)) return m_arith.mk_add(m_arith.mk_int(1), e); - if (m_arith.is_real(e)) return m_arith.mk_add(m_arith.mk_real(1), e); - UNREACHABLE(); - return e; - } - - bool is_non_singleton_sort(sort* s) { - if (m.is_uninterp(s)) return false; - sort_size sz = s->get_num_elements(); - if (sz.is_finite() && sz.size() == 1) return false; - return true; - } - - struct reduce_q_rw_cfg : public default_rewriter_cfg { - ast_manager& m; - reduce_invertible_tactic& t; - - reduce_q_rw_cfg(reduce_invertible_tactic& t): m(t.m), t(t) {} - - bool reduce_quantifier(quantifier * old_q, - expr * new_body, - expr * const * new_patterns, - expr * const * new_no_patterns, - expr_ref & result, - proof_ref & result_pr) { - if (is_lambda(old_q)) return false; - if (has_quantifiers(new_body)) return false; - ref_buffer vars(m); - ptr_buffer new_sorts; - unsigned n = old_q->get_num_decls(); - for (unsigned i = 0; i < n; ++i) { - sort* srt = old_q->get_decl_sort(i); - vars.push_back(m.mk_var(n - i - 1, srt)); - new_sorts.push_back(srt); - } - // for each variable, collect parents, - // ensure they are in unique location and not under other quantifiers. - // if they are invertible, then produce inverting expression. - // - expr_safe_replace sub(m); - t.m_parents.reset(); - t.m_inverted.reset(); - expr_ref new_v(m); - expr * p; - - { - parent_collector proc(t); - expr_fast_mark1 visited; - quick_for_each_expr(proc, visited, new_body); - } - bool has_new_var = false; - for (unsigned i = 0; i < vars.size(); ++i) { - var* v = vars[i]; - if (!occurs_under_nested_q(v, new_body) && t.is_invertible(v, p, new_v, nullptr, vars.size())) { - TRACE("invertible_tactic", tout << mk_pp(v, m) << " " << mk_pp(p, m) << "\n";); - t.mark_inverted(p); - sub.insert(p, new_v); - new_sorts[i] = new_v->get_sort(); - has_new_var |= new_v != v; - } - } - if (has_new_var) { - sub(new_body, result); - result = m.mk_quantifier(old_q->get_kind(), new_sorts.size(), new_sorts.data(), old_q->get_decl_names(), result, old_q->get_weight()); - result_pr = nullptr; - return true; - } - if (!sub.empty()) { - sub(new_body, result); - result = m.update_quantifier(old_q, old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns, result); - result_pr = nullptr; - return true; - } - return false; - } - - bool occurs_under_nested_q(var* v, expr* body) { - return has_quantifiers(body); - } - }; - - struct reduce_q_rw : rewriter_tpl { - reduce_q_rw_cfg m_cfg; - public: - reduce_q_rw(reduce_invertible_tactic& t): - rewriter_tpl(t.m, false, m_cfg), - m_cfg(t) {} - }; -}; -} - -tactic * mk_reduce_invertible_tactic(ast_manager & m, params_ref const &) { - return alloc(reduce_invertible_tactic, m); -} diff --git a/src/tactic/core/reduce_invertible_tactic.h b/src/tactic/core/reduce_invertible_tactic.h deleted file mode 100644 index d40bf8a59..000000000 --- a/src/tactic/core/reduce_invertible_tactic.h +++ /dev/null @@ -1,32 +0,0 @@ -/*++ -Copyright (c) 2018 Microsoft Corporation - -Module Name: - - reduce_invertible_tactic.h - -Abstract: - - Reduce invertible variables. - -Author: - - Nuno Lopes (nlopes) 2018-6-30 - Nikolaj Bjorner (nbjorner) - -Notes: - ---*/ - -#pragma once -#include "util/params.h" - -class tactic; -class ast_manager; - -tactic * mk_reduce_invertible_tactic(ast_manager & m, params_ref const & p = params_ref()); - -/* - ADD_TACTIC("reduce-invertible", "reduce invertible variable occurrences.", "mk_reduce_invertible_tactic(m, p)") -*/ - diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 56e27ee9a..419037839 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -15,6 +15,7 @@ Author: Nikolaj Bjorner (nbjorner) 2022-11-2. --*/ +#pragma once #include "tactic/tactic.h" #include "ast/simplifiers/dependent_expr_state.h" From 9d09064ad08211bfb436b02bf08ee7cc0ee56ce1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2022 18:01:38 -0800 Subject: [PATCH 262/477] add comments to elim_unconstrained and remove unused function --- src/ast/simplifiers/elim_unconstrained.cpp | 16 ++++++++-------- src/ast/simplifiers/elim_unconstrained.h | 4 ---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index cbd575b6a..2cdca3074 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -103,12 +103,6 @@ void elim_unconstrained::eliminate() { } } -void elim_unconstrained::add_term(expr* t) { - expr_ref_vector terms(m); - terms.push_back(t); - init_terms(terms); -} - expr* elim_unconstrained::get_parent(unsigned n) const { for (expr* p : get_node(n).m_parents) if (get_node(p).m_refcount > 0 && get_node(p).m_term == get_node(p).m_orig) @@ -128,20 +122,23 @@ void elim_unconstrained::init_nodes() { terms.push_back(m_fmls[i].fml()); m_trail.append(terms); m_heap.reset(); + m_frozen.reset(); + // initialize nodes for terms in the original goal init_terms(terms); + // top-level terms have reference count > 0 for (expr* e : terms) inc_ref(e); - // freeze subterms before the head. + // freeze subterms before the already processed head terms.reset(); for (unsigned i = 0; i < m_qhead; ++i) terms.push_back(m_fmls[i].fml()); for (expr* e : subterms::all(terms)) m_frozen.mark(e, true); - + // freeze subterms that occur with recursive function definitions recfun::util rec(m); if (rec.has_rec_defs()) { for (func_decl* f : rec.get_rec_funs()) { @@ -152,6 +149,9 @@ void elim_unconstrained::init_nodes() { } } +/** +* Create nodes for all terms in the goal +*/ void elim_unconstrained::init_terms(expr_ref_vector const& terms) { unsigned max_id = 0; for (expr* e : subterms::all(terms)) diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 327ceeff0..67d64027b 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -58,14 +58,10 @@ class elim_unconstrained : public dependent_expr_simplifier { void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(t->get_id()); } void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(t->get_id()); } void gc(expr* t); - expr* get_parent(unsigned n) const; void init_refcounts(); void dec_refcounts(expr* t); - - void add_term(expr* t); void init_terms(expr_ref_vector const& terms); - void init_nodes(); void eliminate(); void reconstruct_terms(); From f4e17ecc653a11ccd4efe3117f030c05949414b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 Nov 2022 19:50:22 -0800 Subject: [PATCH 263/477] add logging and diagnostics --- src/sat/sat_solver.cpp | 4 +++- src/solver/assertions/asserted_formulas.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 14e7e9775..0e5d7aa73 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -282,6 +282,7 @@ namespace sat { m_model_is_current = false; m_stats.m_mk_var++; bool_var v = m_justification.size(); + if (!m_free_vars.empty()) { v = m_free_vars.back(); m_free_vars.pop_back(); @@ -301,7 +302,7 @@ namespace sat { m_external.push_back(ext); m_var_scope.push_back(scope_lvl()); m_touched.push_back(0); - m_activity.push_back(0); + m_activity.push_back(0); m_mark.push_back(false); m_lit_mark.push_back(false); m_lit_mark.push_back(false); @@ -1262,6 +1263,7 @@ namespace sat { if (check_inconsistent()) return l_false; if (m_config.m_force_cleanup) do_cleanup(true); TRACE("sat", display(tout);); + TRACE("before_search", display(tout);); if (m_config.m_gc_burst) { // force gc diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 2b20ebd80..4e64ee39f 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -279,6 +279,8 @@ void asserted_formulas::reduce() { TRACE("before_reduce", display(tout);); CASSERT("well_sorted", check_well_sorted()); + IF_VERBOSE(10, verbose_stream() << "(smt.simplify-begin :num-exprs " << get_total_size() << ")\n";); + set_eliminate_and(false); // do not eliminate and before nnf. if (!invoke(m_propagate_values)) return; if (!invoke(m_find_macros)) return; From e33e66212c1a860c9bf5c48aa6f9926e3c0f2630 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2022 18:03:38 -0800 Subject: [PATCH 264/477] propagate values should not flatten and/or also, elim_uncstr should only be disabled on recursive functions --- src/sat/sat_params.pyg | 2 +- src/tactic/core/propagate_values_tactic.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c35e97b92..7466a1126 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -47,7 +47,7 @@ def_module_params('sat', ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.disable', BOOL, False, 'override anything that enables DRAT'), - ('smt.proof', SYMBOL, '', 'add SMT proof to file'), + ('smt.proof', SYMBOL, '', 'add SMT proof log to file'), ('smt.proof.check', BOOL, False, 'check SMT proof while it is created'), ('smt.proof.check_rup', BOOL, True, 'apply forward RUP proof checking'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 041e4d1c2..6b8395fd8 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -213,6 +213,7 @@ public: m_occs(m, true /* track atoms */), m_params(p) { updt_params_core(p); + m_r.set_flat_and_or(false); } tactic * translate(ast_manager & m) override { From 343603f64341676d059411af62c4145c48f8268f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2022 18:34:04 -0800 Subject: [PATCH 265/477] fix build Signed-off-by: Nikolaj Bjorner --- src/ast/converters/expr_inverter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 504c04ab0..0c433b10d 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -270,7 +270,7 @@ class bv_expr_inverter : public iexpr_inverter { bool process_bv_mul(func_decl* f, unsigned num, expr* const* args, expr_ref& r) { if (num == 0) - return nullptr; + return false; if (uncnstr(num, args)) { sort* s = args[0]->get_sort(); mk_fresh_uncnstr_var_for(f, r); From 0b83732b82a549b93e54ecf513c4992ba95df85f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2022 18:35:41 -0800 Subject: [PATCH 266/477] missing override specifier --- src/ast/converters/expr_inverter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 0c433b10d..553e3c591 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -56,7 +56,7 @@ public: * */ - bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) { + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { SASSERT(f->get_family_id() == m.get_basic_family_id()); switch (f->get_decl_kind()) { case OP_ITE: From 3d570aaa0af2f81fc19cf08af64d76d1c8ea9f22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2022 18:43:57 -0800 Subject: [PATCH 267/477] add missing process_eq Signed-off-by: Nikolaj Bjorner --- src/ast/converters/expr_inverter.cpp | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 553e3c591..0ef910a97 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -22,9 +22,32 @@ Author: #include "ast/converters/expr_inverter.h" class basic_expr_inverter : public iexpr_inverter { + iexpr_inverter& inv; + + bool process_eq(func_decl* f, expr* arg1, expr* arg2, expr_ref& r) { + expr* v; + expr* t; + if (uncnstr(arg1)) + v = arg1, t = arg2; + else if (uncnstr(arg2)) + v = arg2, t = arg1; + else + return false; + + expr_ref d(m); + if (!inv.mk_diff(t, d)) + return false; + + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) + add_def(v, m.mk_ite(t, t, d)); + + return true; + } + public: - basic_expr_inverter(ast_manager& m) : iexpr_inverter(m) {} + basic_expr_inverter(ast_manager& m, iexpr_inverter& inv) : iexpr_inverter(m), inv(inv) {} /** * if (c, x, x') -> fresh @@ -104,7 +127,7 @@ public: return false; case OP_EQ: SASSERT(num == 2); - // return process_eq(f, args[0], args[1]); + return process_eq(f, args[0], args[1], r); default: return false; } @@ -726,7 +749,7 @@ expr_inverter::expr_inverter(ast_manager& m): iexpr_inverter(m) { auto* b = alloc(bv_expr_inverter, m); auto* ar = alloc(array_expr_inverter, m, *this); auto* dt = alloc(dt_expr_inverter, m); - m_inverters.setx(m.get_basic_family_id(), alloc(basic_expr_inverter, m), nullptr); + m_inverters.setx(m.get_basic_family_id(), alloc(basic_expr_inverter, m, *this), nullptr); m_inverters.setx(a->get_fid(), a, nullptr); m_inverters.setx(b->get_fid(), b, nullptr); m_inverters.setx(ar->get_fid(), ar, nullptr); From ce76e3138d9625601c738e7eab29cd0408116360 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Nov 2022 11:48:32 -0800 Subject: [PATCH 268/477] streamlining expr-inverter code --- src/ast/converters/expr_inverter.cpp | 36 +++++++++++++--------------- src/ast/converters/expr_inverter.h | 4 ++-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 0ef910a97..95bfca98a 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -49,6 +49,8 @@ public: basic_expr_inverter(ast_manager& m, iexpr_inverter& inv) : iexpr_inverter(m), inv(inv) {} + family_id get_fid() const override { return m.get_basic_family_id(); } + /** * if (c, x, x') -> fresh * x := fresh @@ -147,7 +149,7 @@ public: arith_expr_inverter(ast_manager& m) : iexpr_inverter(m), a(m) {} - family_id get_fid() const { return a.get_family_id(); } + family_id get_fid() const override { return a.get_family_id(); } bool process_le_ge(func_decl* f, expr* arg1, expr* arg2, bool le, expr_ref& r) { expr* v; @@ -350,6 +352,9 @@ class bv_expr_inverter : public iexpr_inverter { // parity can be defined using a "giant" ite expression. // + if (uncnstr(args[i])) + IF_VERBOSE(11, verbose_stream() << "MISSED mult-unconstrained " << mk_bounded_pp(args[i], m) << "\n"); + return false; } @@ -462,7 +467,7 @@ class bv_expr_inverter : public iexpr_inverter { public: bv_expr_inverter(ast_manager& m) : iexpr_inverter(m), bv(m) {} - family_id get_fid() const { return bv.get_family_id(); } + family_id get_fid() const override { return bv.get_family_id(); } /** * x + t -> fresh @@ -567,7 +572,7 @@ class array_expr_inverter : public iexpr_inverter { public: array_expr_inverter(ast_manager& m, iexpr_inverter& s) : iexpr_inverter(m), a(m), inv(s) {} - family_id get_fid() const { return a.get_family_id(); } + family_id get_fid() const override { return a.get_family_id(); } bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { SASSERT(f->get_family_id() == a.get_family_id()); @@ -631,7 +636,7 @@ public: dt_expr_inverter(ast_manager& m) : iexpr_inverter(m), dt(m) {} - family_id get_fid() const { return dt.get_family_id(); } + family_id get_fid() const override { return dt.get_family_id(); } /** * head(x) -> fresh * x := cons(fresh, arb) @@ -745,20 +750,16 @@ void iexpr_inverter::add_defs(unsigned num, expr* const* args, expr* u, expr* id expr_inverter::expr_inverter(ast_manager& m): iexpr_inverter(m) { - auto* a = alloc(arith_expr_inverter, m); - auto* b = alloc(bv_expr_inverter, m); - auto* ar = alloc(array_expr_inverter, m, *this); - auto* dt = alloc(dt_expr_inverter, m); - m_inverters.setx(m.get_basic_family_id(), alloc(basic_expr_inverter, m, *this), nullptr); - m_inverters.setx(a->get_fid(), a, nullptr); - m_inverters.setx(b->get_fid(), b, nullptr); - m_inverters.setx(ar->get_fid(), ar, nullptr); - m_inverters.setx(dt->get_fid(), dt, nullptr); + auto add = [&](iexpr_inverter* i) { + m_inverters.setx(i->get_fid(), i, nullptr); + }; + add(alloc(arith_expr_inverter, m)); + add(alloc(bv_expr_inverter, m)); + add(alloc(array_expr_inverter, m, *this)); + add(alloc(dt_expr_inverter, m)); + add(alloc(basic_expr_inverter, m, *this)); } -bool expr_inverter::is_converted(func_decl* f, unsigned num, expr* const* args) { - return false; -} bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) { if (num == 0) @@ -771,9 +772,6 @@ bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, ex family_id fid = f->get_family_id(); if (fid == null_family_id) return false; - - if (is_converted(f, num, args)) - return false; auto* p = m_inverters.get(fid, nullptr); return p && (*p)(f, num, args, new_expr, side_cond); diff --git a/src/ast/converters/expr_inverter.h b/src/ast/converters/expr_inverter.h index 1ca77dbab..5b7965478 100644 --- a/src/ast/converters/expr_inverter.h +++ b/src/ast/converters/expr_inverter.h @@ -40,13 +40,12 @@ public: virtual bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) = 0; virtual bool mk_diff(expr* t, expr_ref& r) = 0; + virtual family_id get_fid() const = 0; }; class expr_inverter : public iexpr_inverter { ptr_vector m_inverters; - bool is_converted(func_decl* f, unsigned num, expr* const* args); - public: expr_inverter(ast_manager& m); ~expr_inverter() override; @@ -54,4 +53,5 @@ public: bool mk_diff(expr* t, expr_ref& r) override; void set_is_var(std::function& is_var) override; void set_model_converter(generic_model_converter* mc) override; + family_id get_fid() const override { return null_family_id; } }; From 196788a0915d69b8599bd7a89dd4d644f324a537 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Nov 2022 12:09:56 -0800 Subject: [PATCH 269/477] bug fix for equality solving --- src/ast/simplifiers/elim_unconstrained.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 2cdca3074..94201dde7 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -81,9 +81,9 @@ void elim_unconstrained::eliminate() { m_args.reset(); for (expr* arg : *to_app(t)) m_args.push_back(get_node(arg).m_term); - if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) + if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) continue; - + SASSERT(r->get_sort() == t->get_sort()); m_stats.m_num_eliminated++; n.m_refcount = 0; SASSERT(r); From 38cde14e087e0470cce4d6134860007e3f8798fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Nov 2022 12:10:43 -0800 Subject: [PATCH 270/477] wip missing updates --- src/ast/converters/expr_inverter.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 95bfca98a..2c4c960a7 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -40,7 +40,7 @@ class basic_expr_inverter : public iexpr_inverter { mk_fresh_uncnstr_var_for(f, r); if (m_mc) - add_def(v, m.mk_ite(t, t, d)); + add_def(v, m.mk_ite(r, t, d)); return true; } @@ -352,8 +352,11 @@ class bv_expr_inverter : public iexpr_inverter { // parity can be defined using a "giant" ite expression. // +#if 0 + for (unsigned i = 0; i < num; ++i) if (uncnstr(args[i])) IF_VERBOSE(11, verbose_stream() << "MISSED mult-unconstrained " << mk_bounded_pp(args[i], m) << "\n"); +#endif return false; } @@ -550,6 +553,7 @@ class bv_expr_inverter : public iexpr_inverter { } bool mk_diff(expr* t, expr_ref& r) override { + SASSERT(bv.is_bv(t)); r = bv.mk_bv_not(t); return true; } @@ -806,7 +810,8 @@ void expr_inverter::set_is_var(std::function& is_var) { } void expr_inverter::set_model_converter(generic_model_converter* mc) { + m_mc = mc; for (auto* p : m_inverters) if (p) p->set_model_converter(mc); -} \ No newline at end of file +} From 3fa81d65270731290a4e03293d92eeaaa1a38469 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Nov 2022 13:25:19 -0800 Subject: [PATCH 271/477] bug fixes to elim-uncnstr2 tactic Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/elim_unconstrained.cpp | 36 ++++++++++++++-------- src/ast/simplifiers/elim_unconstrained.h | 12 +++----- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 94201dde7..caeaf2958 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -55,6 +55,12 @@ elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fml m_inverter.set_is_var(is_var); } +bool elim_unconstrained::is_var_lt(int v1, int v2) const { + node const& n1 = get_node(v1); + node const& n2 = get_node(v2); + return n1.m_refcount < n2.m_refcount; +} + void elim_unconstrained::eliminate() { @@ -62,34 +68,39 @@ void elim_unconstrained::eliminate() { expr_ref r(m), side_cond(m); int v = m_heap.erase_min(); node& n = get_node(v); - IF_VERBOSE(11, verbose_stream() << mk_pp(n.m_orig, m) << " @ " << n.m_refcount << "\n"); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(n.m_orig, m) << " @ " << n.m_refcount << "\n"); if (n.m_refcount == 0) continue; if (n.m_refcount > 1) return; - if (n.m_parents.empty()) + if (n.m_parents.empty()) { + --n.m_refcount; continue; + } expr* e = get_parent(v); for (expr* p : n.m_parents) - IF_VERBOSE(11, verbose_stream() << "parent " << mk_pp(p, m) << "\n"); - if (!is_app(e)) - continue; - if (!is_ground(e)) + IF_VERBOSE(11, verbose_stream() << "parent " << mk_bounded_pp(p, m) << "\n"); + if (!e || !is_app(e) || !is_ground(e)) { + --n.m_refcount; continue; + } app* t = to_app(e); m_args.reset(); for (expr* arg : *to_app(t)) m_args.push_back(get_node(arg).m_term); - if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) + if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) { + --n.m_refcount; continue; + } + --n.m_refcount; SASSERT(r->get_sort() == t->get_sort()); m_stats.m_num_eliminated++; n.m_refcount = 0; SASSERT(r); - m_trail.push_back(r); gc(e); + m_root.setx(r->get_id(), e->get_id(), UINT_MAX); get_node(e).m_term = r; get_node(e).m_refcount++; IF_VERBOSE(11, verbose_stream() << mk_pp(e, m) << "\n"); @@ -107,10 +118,6 @@ expr* elim_unconstrained::get_parent(unsigned n) const { for (expr* p : get_node(n).m_parents) if (get_node(p).m_refcount > 0 && get_node(p).m_term == get_node(p).m_orig) return p; - IF_VERBOSE(0, verbose_stream() << "term " << mk_pp(get_node(n).m_term, m) << "\n"); - for (expr* p : get_node(n).m_parents) - IF_VERBOSE(0, verbose_stream() << "parent " << mk_pp(p, m) << "\n"); - UNREACHABLE(); return nullptr; } /** @@ -123,6 +130,7 @@ void elim_unconstrained::init_nodes() { m_trail.append(terms); m_heap.reset(); m_frozen.reset(); + m_root.reset(); // initialize nodes for terms in the original goal init_terms(terms); @@ -159,11 +167,13 @@ void elim_unconstrained::init_terms(expr_ref_vector const& terms) { m_nodes.reserve(max_id + 1); m_heap.reserve(max_id + 1); + m_root.reserve(max_id + 1, UINT_MAX); for (expr* e : subterms_postorder::all(terms)) { + m_root.setx(e->get_id(), e->get_id(), UINT_MAX); node& n = get_node(e); if (n.m_term) - continue; + continue; n.m_orig = e; n.m_term = e; n.m_refcount = 0; diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 67d64027b..964c56244 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -32,7 +32,7 @@ class elim_unconstrained : public dependent_expr_simplifier { elim_unconstrained& s; var_lt(elim_unconstrained& s) : s(s) {} bool operator()(int v1, int v2) const { - return s.get_node(v1).m_refcount < s.get_node(v2).m_refcount; + return s.is_var_lt(v1, v2); } }; struct stats { @@ -47,20 +47,18 @@ class elim_unconstrained : public dependent_expr_simplifier { ptr_vector m_args; expr_mark m_frozen; stats m_stats; + unsigned_vector m_root; - bool operator()(int v1, int v2) const { return get_node(v1).m_refcount < get_node(v2).m_refcount; } - + bool is_var_lt(int v1, int v2) const; node& get_node(unsigned n) { return m_nodes[n]; } node const& get_node(unsigned n) const { return m_nodes[n]; } - node& get_node(expr* t) { return m_nodes[t->get_id()]; } - node const& get_node(expr* t) const { return m_nodes[t->get_id()]; } + node& get_node(expr* t) { return m_nodes[m_root[t->get_id()]]; } + node const& get_node(expr* t) const { return m_nodes[m_root[t->get_id()]]; } unsigned get_refcount(expr* t) const { return get_node(t).m_refcount; } void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(t->get_id()); } void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(t->get_id()); } void gc(expr* t); expr* get_parent(unsigned n) const; - void init_refcounts(); - void dec_refcounts(expr* t); void init_terms(expr_ref_vector const& terms); void init_nodes(); void eliminate(); From ce6cfeaa6873e7facf0fb00ce87c1d24381fd6b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Nov 2022 18:01:17 -0800 Subject: [PATCH 272/477] fix bug in euf-completion relating to missed normalization --- src/ast/simplifiers/elim_unconstrained.cpp | 7 +++---- src/ast/simplifiers/euf_completion.cpp | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index caeaf2958..3d94cb0ef 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -75,14 +75,14 @@ void elim_unconstrained::eliminate() { return; if (n.m_parents.empty()) { - --n.m_refcount; + n.m_refcount = 0; continue; } expr* e = get_parent(v); for (expr* p : n.m_parents) IF_VERBOSE(11, verbose_stream() << "parent " << mk_bounded_pp(p, m) << "\n"); if (!e || !is_app(e) || !is_ground(e)) { - --n.m_refcount; + n.m_refcount = 0; continue; } app* t = to_app(e); @@ -90,10 +90,9 @@ void elim_unconstrained::eliminate() { for (expr* arg : *to_app(t)) m_args.push_back(get_node(arg).m_term); if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) { - --n.m_refcount; + n.m_refcount = 0; continue; } - --n.m_refcount; SASSERT(r->get_sort() == t->get_sort()); m_stats.m_num_eliminated++; n.m_refcount = 0; diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index e1360fa0b..0f03d7fe1 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -98,7 +98,7 @@ namespace euf { if (g != f) { m_fmls.update(i, dependent_expr(m, g, dep)); m_stats.m_num_rewrites++; - IF_VERBOSE(10, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); } CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } @@ -174,7 +174,7 @@ namespace euf { bool change = false; for (expr* arg : *to_app(f)) { m_eargs.push_back(get_canonical(arg, d)); - change = arg != m_eargs.back(); + change |= arg != m_eargs.back(); } if (!change) From 3d2bf13577547588cf22a197dbd020324596daa2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 Nov 2022 20:30:00 -0800 Subject: [PATCH 273/477] streamline statistics, fix bug in updating goals --- src/ast/simplifiers/elim_unconstrained.cpp | 5 ++++- src/ast/simplifiers/elim_unconstrained.h | 2 +- src/tactic/core/elim_uncnstr_tactic.cpp | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 3d94cb0ef..d0eb2a53f 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -96,6 +96,7 @@ void elim_unconstrained::eliminate() { SASSERT(r->get_sort() == t->get_sort()); m_stats.m_num_eliminated++; n.m_refcount = 0; + m_trail.push_back(r); SASSERT(r); gc(e); @@ -250,7 +251,9 @@ void elim_unconstrained::reconstruct_terms() { } void elim_unconstrained::assert_normalized(vector& old_fmls) { - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + + unsigned sz = m_fmls.size(); + for (unsigned i = m_qhead; i < sz; ++i) { auto [f, d] = m_fmls[i](); node& n = get_node(f); expr* g = n.m_term; diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 964c56244..b32ab367b 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -72,7 +72,7 @@ public: void reduce() override; - void collect_statistics(statistics& st) const override { st.update("elim-unconstr", m_stats.m_num_eliminated); } + void collect_statistics(statistics& st) const override { st.update("elim-unconstrained", m_stats.m_num_eliminated); } void reset_statistics() override { m_stats.reset(); } }; diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 5f0963bfd..60bdd2710 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -867,6 +867,8 @@ class elim_uncnstr_tactic : public tactic { void run(goal_ref const & g, goal_ref_buffer & result) { bool produce_proofs = g->proofs_enabled(); TRACE("goal", g->display(tout);); + std::function coll = [&](statistics& st) { collect_statistics(st); }; + statistics_report sreport(coll); tactic_report report("elim-uncnstr", *g); m_vars.reset(); collect_occs p; @@ -959,7 +961,6 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result) override { run(g, result); - report_tactic_progress(":num-elim-apps", m_num_elim_apps); } void cleanup() override { @@ -969,7 +970,7 @@ public: } void collect_statistics(statistics & st) const override { - st.update("eliminated applications", m_num_elim_apps); + st.update("elim-unconstrained", m_num_elim_apps); } void reset_statistics() override { From 3f2bbe558948f5c3cbaa5ca77e65c6d8687e8c46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Nov 2022 08:54:08 -0800 Subject: [PATCH 274/477] harness del_object #6452 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index cef63621d..2b7a4ce43 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -51,6 +51,8 @@ namespace api { } void context::del_object(api::object* o) { + if (!o) + return; #ifndef SINGLE_THREAD if (m_concurrent_dec_ref) { lock_guard lock(m_mux); From 6297c001eed19b11f4871d764c2f93ed1d94d086 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Nov 2022 18:57:16 -0800 Subject: [PATCH 275/477] remove legacy solve_eqs_tactic entirely also, bug fixes to elim_unconstrained (elim_uncnstr2) which is to replace legacy tactic for eliminating unconstrained constants. --- src/ast/simplifiers/dependent_expr_state.h | 5 +- src/ast/simplifiers/elim_unconstrained.cpp | 19 +- src/ast/simplifiers/elim_unconstrained.h | 15 +- src/ast/simplifiers/solve_eqs.cpp | 7 + src/ast/simplifiers/solve_eqs.h | 2 + src/nlsat/tactic/qfnra_nlsat_tactic.cpp | 1 - src/opt/opt_context.cpp | 1 - src/tactic/core/CMakeLists.txt | 2 - src/tactic/core/elim_uncnstr2_tactic.h | 2 +- src/tactic/core/solve_eqs2_tactic.h | 47 - src/tactic/core/solve_eqs_tactic.cpp | 1109 -------------------- src/tactic/core/solve_eqs_tactic.h | 34 +- src/tactic/dependent_expr_state_tactic.h | 5 + src/tactic/sls/sls_tactic.cpp | 1 - src/tactic/smtlogics/qfaufbv_tactic.cpp | 1 - src/tactic/smtlogics/qfauflia_tactic.cpp | 1 - src/tactic/smtlogics/qfbv_tactic.cpp | 1 - src/tactic/smtlogics/qfidl_tactic.cpp | 1 - src/tactic/smtlogics/qflia_tactic.cpp | 1 - src/tactic/smtlogics/qfuf_tactic.cpp | 1 - src/tactic/smtlogics/qfufbv_tactic.cpp | 1 - src/tactic/smtlogics/quant_tactics.cpp | 1 - src/tactic/ufbv/ufbv_tactic.cpp | 1 - 23 files changed, 56 insertions(+), 1203 deletions(-) delete mode 100644 src/tactic/core/solve_eqs2_tactic.h delete mode 100644 src/tactic/core/solve_eqs_tactic.cpp diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 6bdd34626..fa4bbdd49 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -61,9 +61,9 @@ public: */ class dependent_expr_simplifier { protected: - ast_manager& m; + ast_manager& m; dependent_expr_state& m_fmls; - trail_stack& m_trail; + trail_stack& m_trail; unsigned m_qhead = 0; // pointer into last processed formula in m_fmls unsigned num_scopes() const { return m_trail.get_num_scopes(); } @@ -78,6 +78,7 @@ public: virtual void collect_statistics(statistics& st) const {} virtual void reset_statistics() {} virtual void updt_params(params_ref const& p) {} + virtual void collect_param_descrs(param_descrs& r) {} }; /** diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index d0eb2a53f..d590f3e59 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -47,11 +47,9 @@ Author: elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_inverter(m), m_lt(*this), m_heap(1024, m_lt), m_trail(m) { - std::function is_var = [&](expr* e) { - return is_uninterp_const(e) && !m_frozen.is_marked(e) && get_node(e).m_refcount == 1; + return is_uninterp_const(e) && !m_frozen.is_marked(e) && get_node(e).m_refcount <= 1; }; - m_inverter.set_is_var(is_var); } @@ -61,7 +59,6 @@ bool elim_unconstrained::is_var_lt(int v1, int v2) const { return n1.m_refcount < n2.m_refcount; } - void elim_unconstrained::eliminate() { while (!m_heap.empty()) { @@ -79,8 +76,7 @@ void elim_unconstrained::eliminate() { continue; } expr* e = get_parent(v); - for (expr* p : n.m_parents) - IF_VERBOSE(11, verbose_stream() << "parent " << mk_bounded_pp(p, m) << "\n"); + IF_VERBOSE(11, for (expr* p : n.m_parents) verbose_stream() << "parent " << mk_bounded_pp(p, m) << " @ " << get_node(p).m_refcount << "\n";); if (!e || !is_app(e) || !is_ground(e)) { n.m_refcount = 0; continue; @@ -90,6 +86,7 @@ void elim_unconstrained::eliminate() { for (expr* arg : *to_app(t)) m_args.push_back(get_node(arg).m_term); if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) { + IF_VERBOSE(11, verbose_stream() << "not inverted " << mk_bounded_pp(e, m) << "\n"); n.m_refcount = 0; continue; } @@ -103,12 +100,12 @@ void elim_unconstrained::eliminate() { m_root.setx(r->get_id(), e->get_id(), UINT_MAX); get_node(e).m_term = r; get_node(e).m_refcount++; - IF_VERBOSE(11, verbose_stream() << mk_pp(e, m) << "\n"); - SASSERT(!m_heap.contains(e->get_id())); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(e, m) << "\n"); + SASSERT(!m_heap.contains(root(e))); if (is_uninterp_const(r)) - m_heap.insert(e->get_id()); + m_heap.insert(root(e)); - IF_VERBOSE(11, verbose_stream() << mk_pp(n.m_orig, m) << " " << mk_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n"); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(n.m_orig, m) << " " << mk_bounded_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n";); SASSERT(!side_cond && "not implemented to add side conditions\n"); } @@ -178,7 +175,7 @@ void elim_unconstrained::init_terms(expr_ref_vector const& terms) { n.m_term = e; n.m_refcount = 0; if (is_uninterp_const(e)) - m_heap.insert(e->get_id()); + m_heap.insert(root(e)); if (is_quantifier(e)) { expr* body = to_quantifier(e)->get_expr(); get_node(body).m_parents.push_back(e); diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index b32ab367b..89f28fe33 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -23,9 +23,9 @@ Author: class elim_unconstrained : public dependent_expr_simplifier { struct node { - unsigned m_refcount; - expr* m_term; - expr* m_orig; + unsigned m_refcount = 0; + expr* m_term = nullptr; + expr* m_orig = nullptr; ptr_vector m_parents; }; struct var_lt { @@ -52,11 +52,12 @@ class elim_unconstrained : public dependent_expr_simplifier { bool is_var_lt(int v1, int v2) const; node& get_node(unsigned n) { return m_nodes[n]; } node const& get_node(unsigned n) const { return m_nodes[n]; } - node& get_node(expr* t) { return m_nodes[m_root[t->get_id()]]; } - node const& get_node(expr* t) const { return m_nodes[m_root[t->get_id()]]; } + node& get_node(expr* t) { return m_nodes[root(t)]; } + unsigned root(expr* t) const { return m_root[t->get_id()]; } + node const& get_node(expr* t) const { return m_nodes[root(t)]; } unsigned get_refcount(expr* t) const { return get_node(t).m_refcount; } - void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(t->get_id()); } - void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(t->get_id()); } + void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(root(t)); } + void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(root(t)); } void gc(expr* t); expr* get_parent(unsigned n) const; void init_terms(expr_ref_vector const& terms); diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 96b0427f6..0b6f12160 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -240,6 +240,13 @@ namespace euf { ex->updt_params(p); } + void solve_eqs::collect_param_descrs(param_descrs& r) { + r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations."); + r.insert("theory_solver", CPK_BOOL, "(default: true) use theory solvers."); + r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); + r.insert("context_solve", CPK_BOOL, "(default: false) solve equalities under disjunctions."); + } + void solve_eqs::collect_statistics(statistics& st) const { st.update("solve-eqs-steps", m_stats.m_num_steps); st.update("solve-eqs-elim-vars", m_stats.m_num_elim_vars); diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 8f5988a38..a2afd6e58 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -72,6 +72,8 @@ namespace euf { void updt_params(params_ref const& p) override; + void collect_param_descrs(param_descrs& r) override; + void collect_statistics(statistics& st) const override; }; diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index e41347c2b..fc812c4f5 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -27,7 +27,6 @@ Notes: #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_term_ite_tactic.h" tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 66a391cb8..5895643bd 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -31,7 +31,6 @@ Notes: #include "tactic/tactic.h" #include "tactic/arith/lia2card_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index bab61afce..6bb6793fd 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -18,7 +18,6 @@ z3_add_component(core_tactics propagate_values_tactic.cpp reduce_args_tactic.cpp simplify_tactic.cpp - solve_eqs_tactic.cpp special_relations_tactic.cpp split_clause_tactic.cpp symmetry_reduce_tactic.cpp @@ -48,7 +47,6 @@ z3_add_component(core_tactics reduce_args_tactic.h simplify_tactic.h solve_eqs_tactic.h - solve_eqs2_tactic.h special_relations_tactic.h split_clause_tactic.h symmetry_reduce_tactic.h diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h index 2c5f81d5e..65b5d3426 100644 --- a/src/tactic/core/elim_uncnstr2_tactic.h +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -30,7 +30,7 @@ public: }; inline tactic * mk_elim_uncnstr2_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(elim_uncnstr2_tactic_factory), "elim-unconstr2"); + return alloc(dependent_expr_state_tactic, m, p, alloc(elim_uncnstr2_tactic_factory), "elim-uncnstr2"); } diff --git a/src/tactic/core/solve_eqs2_tactic.h b/src/tactic/core/solve_eqs2_tactic.h deleted file mode 100644 index 7d13b571e..000000000 --- a/src/tactic/core/solve_eqs2_tactic.h +++ /dev/null @@ -1,47 +0,0 @@ -/*++ -Copyright (c) 2022 Microsoft Corporation - -Module Name: - - solve_eqs2_tactic.h - -Abstract: - - Tactic for solving variables - -Author: - - Nikolaj Bjorner (nbjorner) 2022-10-30 - ---*/ -#pragma once - -#include "util/params.h" -#include "tactic/tactic.h" -#include "tactic/dependent_expr_state_tactic.h" -#include "ast/simplifiers/solve_eqs.h" - - -class solve_eqs2_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(euf::solve_eqs, m, s); - } -}; - -inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs"); -} - -#if 1 -inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return mk_solve_eqs2_tactic(m, p); -} -#endif - - -/* - ADD_TACTIC("solve-eqs2", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") -*/ - - diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp deleted file mode 100644 index d445b68ac..000000000 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ /dev/null @@ -1,1109 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - solve_eqs_tactic.cpp - -Abstract: - - Tactic for solving equations and performing gaussian elimination. - -Author: - - Leonardo de Moura (leonardo) 2011-12-29. - -Revision History: - ---*/ -#include "ast/rewriter/expr_replacer.h" -#include "ast/occurs.h" -#include "ast/ast_util.h" -#include "ast/ast_pp.h" -#include "ast/pb_decl_plugin.h" -#include "ast/recfun_decl_plugin.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/rewriter/hoist_rewriter.h" -#include "tactic/goal_shared_occs.h" -#include "tactic/tactical.h" -#include "ast/converters/generic_model_converter.h" -#include "params/tactic_params.hpp" - -class solve_eqs_tactic : public tactic { - struct imp { - typedef generic_model_converter gmc; - - ast_manager & m_manager; - expr_replacer * m_r; - params_ref m_params; - bool m_r_owner; - arith_util m_a_util; - obj_map m_num_occs; - unsigned m_num_steps; - unsigned m_num_eliminated_vars; - bool m_theory_solver; - bool m_ite_solver; - unsigned m_max_occs; - bool m_context_solve; - scoped_ptr m_subst; - scoped_ptr m_norm_subst; - expr_sparse_mark m_candidate_vars; - expr_sparse_mark m_candidate_set; - ptr_vector m_candidates; - expr_ref_vector m_marked_candidates; - ptr_vector m_vars; - expr_sparse_mark m_nonzero; - ptr_vector m_ordered_vars; - bool m_produce_proofs; - bool m_produce_unsat_cores; - bool m_produce_models; - - imp(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner): - m_manager(m), - m_r(r), - m_r_owner(r == nullptr || owner), - m_a_util(m), - m_num_steps(0), - m_num_eliminated_vars(0), - m_marked_candidates(m), - m_var_trail(m) { - updt_params(p); - if (m_r == nullptr) - m_r = mk_default_expr_replacer(m, true); - } - - ~imp() { - if (m_r_owner) - dealloc(m_r); - } - - ast_manager & m() const { return m_manager; } - - void updt_params(params_ref const & p) { - m_params.append(p); - tactic_params tp(m_params); - m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); - m_theory_solver = p.get_bool("theory_solver", tp.solve_eqs_theory_solver()); - m_max_occs = p.get_uint("solve_eqs_max_occs", tp.solve_eqs_max_occs()); - m_context_solve = p.get_bool("context_solve", tp.solve_eqs_context_solve()); - } - - void checkpoint() { - tactic::checkpoint(m()); - } - - // Check if the number of occurrences of t is below the specified threshold :solve-eqs-max-occs - bool check_occs(expr * t) const { - if (m_max_occs == UINT_MAX) - return true; - unsigned num = 0; - m_num_occs.find(t, num); - TRACE("solve_eqs_check_occs", tout << mk_ismt2_pp(t, m_manager) << " num_occs: " << num << " max: " << m_max_occs << "\n";); - return num <= m_max_occs; - } - - // Use: (= x def) and (= def x) - - bool trivial_solve1(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { - - if (is_uninterp_const(lhs) && !m_candidate_vars.is_marked(lhs) && !occurs(lhs, rhs) && check_occs(lhs)) { - var = to_app(lhs); - def = rhs; - pr = nullptr; - return true; - } - else { - return false; - } - } - bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { - if (trivial_solve1(lhs, rhs, var, def, pr)) - return true; - if (trivial_solve1(rhs, lhs, var, def, pr)) { - if (m_produce_proofs) { - pr = m().mk_commutativity(m().mk_eq(lhs, rhs)); - } - return true; - } - return false; - } - - // (ite c (= x t1) (= x t2)) --> (= x (ite c t1 t2)) - bool solve_ite_core(app * ite, expr * lhs1, expr * rhs1, expr * lhs2, expr * rhs2, app_ref & var, expr_ref & def, proof_ref & pr) { - if (lhs1 != lhs2) - return false; - if (!is_uninterp_const(lhs1) || m_candidate_vars.is_marked(lhs1)) - return false; - if (occurs(lhs1, ite->get_arg(0)) || occurs(lhs1, rhs1) || occurs(lhs1, rhs2)) - return false; - if (!check_occs(lhs1)) - return false; - var = to_app(lhs1); - def = m().mk_ite(ite->get_arg(0), rhs1, rhs2); - - if (m_produce_proofs) - pr = m().mk_rewrite(ite, m().mk_eq(var, def)); - return true; - } - - // (ite c (= x t1) (= x t2)) --> (= x (ite c t1 t2)) - bool solve_ite(app * ite, app_ref & var, expr_ref & def, proof_ref & pr) { - expr * t = ite->get_arg(1); - expr * e = ite->get_arg(2); - - if (!m().is_eq(t) || !m().is_eq(e)) - return false; - - expr * lhs1 = to_app(t)->get_arg(0); - expr * rhs1 = to_app(t)->get_arg(1); - expr * lhs2 = to_app(e)->get_arg(0); - expr * rhs2 = to_app(e)->get_arg(1); - - return - solve_ite_core(ite, lhs1, rhs1, lhs2, rhs2, var, def, pr) || - solve_ite_core(ite, rhs1, lhs1, lhs2, rhs2, var, def, pr) || - solve_ite_core(ite, lhs1, rhs1, rhs2, lhs2, var, def, pr) || - solve_ite_core(ite, rhs1, lhs1, rhs2, lhs2, var, def, pr); - } - - bool is_pos_literal(expr * n) { - return is_app(n) && to_app(n)->get_num_args() == 0 && to_app(n)->get_family_id() == null_family_id; - } - - bool is_neg_literal(expr * n) { - if (m_manager.is_not(n)) - return is_pos_literal(to_app(n)->get_arg(0)); - return false; - } - - - /** - \brief Given t of the form (f s_0 ... s_n), - return true if x occurs in some s_j for j != i - */ - bool occurs_except(expr * x, app * t, unsigned i) { - unsigned num = t->get_num_args(); - for (unsigned j = 0; j < num; j++) { - if (i != j && occurs(x, t->get_arg(j))) - return true; - } - return false; - } - - void add_pos(expr* f) { - expr* lhs = nullptr, *rhs = nullptr; - rational val; - if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_neg()) { - m_nonzero.mark(lhs); - } - else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_pos()) { - m_nonzero.mark(lhs); - } - else if (m().is_not(f, f)) { - if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_neg()) { - m_nonzero.mark(lhs); - } - else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_pos()) { - m_nonzero.mark(lhs); - } - else if (m().is_eq(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_zero()) { - m_nonzero.mark(lhs); - } - } - } - - bool is_nonzero(expr* e) { - return m_nonzero.is_marked(e); - } - - bool isolate_var(app* arg, app_ref& var, expr_ref& div, unsigned i, app* lhs, expr* rhs) { - if (!m_a_util.is_mul(arg)) return false; - unsigned n = arg->get_num_args(); - for (unsigned j = 0; j < n; ++j) { - expr* e = arg->get_arg(j); - bool ok = is_uninterp_const(e) && check_occs(e) && !occurs(e, rhs) && !occurs_except(e, lhs, i); - if (!ok) continue; - var = to_app(e); - for (unsigned k = 0; ok && k < n; ++k) { - expr* arg_k = arg->get_arg(k); - ok = k == j || (!occurs(var, arg_k) && is_nonzero(arg_k)); - } - if (!ok) continue; - ptr_vector args; - for (unsigned k = 0; k < n; ++k) { - if (k != j) args.push_back(arg->get_arg(k)); - } - div = m_a_util.mk_mul(args.size(), args.data()); - return true; - } - return false; - } - - bool solve_nl(app * lhs, expr * rhs, expr* eq, app_ref& var, expr_ref & def, proof_ref & pr) { - SASSERT(m_a_util.is_add(lhs)); - if (m_a_util.is_int(lhs)) return false; - unsigned num = lhs->get_num_args(); - expr_ref div(m()); - for (unsigned i = 0; i < num; i++) { - expr * arg = lhs->get_arg(i); - if (is_app(arg) && isolate_var(to_app(arg), var, div, i, lhs, rhs)) { - ptr_vector args; - for (unsigned k = 0; k < num; ++k) { - if (k != i) args.push_back(lhs->get_arg(k)); - } - def = m_a_util.mk_sub(rhs, m_a_util.mk_add(args.size(), args.data())); - def = m_a_util.mk_div(def, div); - if (m_produce_proofs) - pr = m().mk_rewrite(eq, m().mk_eq(var, def)); - return true; - } - } - return false; - } - - bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { - SASSERT(m_a_util.is_add(lhs)); - bool is_int = m_a_util.is_int(lhs); - expr * a = nullptr; - expr * v = nullptr; - rational a_val; - unsigned num = lhs->get_num_args(); - unsigned i; - for (i = 0; i < num; i++) { - expr * arg = lhs->get_arg(i); - if (is_uninterp_const(arg) && !m_candidate_vars.is_marked(arg) && check_occs(arg) && !occurs(arg, rhs) && !occurs_except(arg, lhs, i)) { - a_val = rational(1); - v = arg; - break; - } - else if (m_a_util.is_mul(arg, a, v) && - is_uninterp_const(v) && - !m_candidate_vars.is_marked(v) && - m_a_util.is_numeral(a, a_val) && - !a_val.is_zero() && - (!is_int || a_val.is_minus_one()) && - check_occs(v) && - !occurs(v, rhs) && - !occurs_except(v, lhs, i)) { - break; - } - } - if (i == num) - return false; - var = to_app(v); - expr_ref inv_a(m()); - if (!a_val.is_one()) { - inv_a = m_a_util.mk_numeral(rational(1)/a_val, is_int); - rhs = m_a_util.mk_mul(inv_a, rhs); - } - - ptr_buffer other_args; - for (unsigned j = 0; j < num; j++) { - if (i != j) { - if (inv_a) - other_args.push_back(m_a_util.mk_mul(inv_a, lhs->get_arg(j))); - else - other_args.push_back(lhs->get_arg(j)); - } - } - switch (other_args.size()) { - case 0: - def = rhs; - break; - case 1: - def = m_a_util.mk_sub(rhs, other_args[0]); - break; - default: - def = m_a_util.mk_sub(rhs, m_a_util.mk_add(other_args.size(), other_args.data())); - break; - } - if (m_produce_proofs) - pr = m().mk_rewrite(eq, m().mk_eq(var, def)); - return true; - } - - bool solve_mod(expr * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { - rational r1, r2; - expr* arg1; - if (m_produce_proofs) - return false; - - auto fresh = [&]() { return m().mk_fresh_const("mod", m_a_util.mk_int()); }; - auto mk_int = [&](rational const& r) { return m_a_util.mk_int(r); }; - auto add = [&](expr* a, expr* b) { return m_a_util.mk_add(a, b); }; - auto mul = [&](expr* a, expr* b) { return m_a_util.mk_mul(a, b); }; - - VERIFY(m_a_util.is_mod(lhs, lhs, arg1)); - if (!m_a_util.is_numeral(arg1, r1) || !r1.is_pos()) { - return false; - } - // - // solve lhs mod r1 = r2 - // as lhs = r1*mod!1 + r2 - // - if (m_a_util.is_numeral(rhs, r2) && !r2.is_neg() && r2 < r1) { - expr_ref def0(m()); - def0 = add(mk_int(r2), mul(fresh(), mk_int(r1))); - return solve_eq(lhs, def0, eq, var, def, pr); - } - return false; - } - - bool solve_arith(expr * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { - return - (m_a_util.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, def, pr)) || - (m_a_util.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, def, pr)) || - (m_a_util.is_mod(lhs) && solve_mod(lhs, rhs, eq, var, def, pr)) || - (m_a_util.is_mod(rhs) && solve_mod(rhs, lhs, eq, var, def, pr)); - } - - - bool solve_eq(expr* arg1, expr* arg2, expr* eq, app_ref& var, expr_ref & def, proof_ref& pr) { - if (trivial_solve(arg1, arg2, var, def, pr)) - return true; - if (m_theory_solver) { - if (solve_arith(arg1, arg2, eq, var, def, pr)) - return true; - } - return false; - } - - bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) { - expr* arg1 = nullptr, *arg2 = nullptr; - if (m().is_eq(f, arg1, arg2)) { - return solve_eq(arg1, arg2, f, var, def, pr); - } - - if (m_ite_solver && m().is_ite(f)) - return solve_ite(to_app(f), var, def, pr); - - if (is_pos_literal(f)) { - if (m_candidate_vars.is_marked(f)) - return false; - var = to_app(f); - def = m().mk_true(); - if (m_produce_proofs) { - // [rewrite]: (iff (iff l true) l) - // [symmetry T1]: (iff l (iff l true)) - pr = m().mk_rewrite(m().mk_eq(var, def), var); - pr = m().mk_symmetry(pr); - } - TRACE("solve_eqs_bug2", tout << "eliminating: " << mk_ismt2_pp(f, m()) << "\n";); - return true; - } - - if (is_neg_literal(f)) { - var = to_app(to_app(f)->get_arg(0)); - if (m_candidate_vars.is_marked(var)) - return false; - def = m().mk_false(); - if (m_produce_proofs) { - // [rewrite]: (iff (iff l false) ~l) - // [symmetry T1]: (iff ~l (iff l false)) - pr = m().mk_rewrite(m().mk_eq(var, def), f); - pr = m().mk_symmetry(pr); - } - return true; - } - - return false; - } - - void insert_solution(goal const& g, unsigned idx, expr* f, app* var, expr* def, proof* pr) { - - if (!is_safe(var)) - return; - m_vars.push_back(var); - m_candidates.push_back(f); - m_candidate_set.mark(f); - m_candidate_vars.mark(var); - m_marked_candidates.push_back(f); - if (m_produce_proofs) { - if (!pr) - pr = g.pr(idx); - else - pr = m().mk_modus_ponens(g.pr(idx), pr); - } - IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(var, m()) << " -> " << mk_bounded_pp(def, m()) << "\n"); - m_subst->insert(var, def, pr, g.dep(idx)); - } - - /** - \brief Start collecting candidates - */ - void collect(goal const & g) { - m_subst->reset(); - m_norm_subst->reset(); - m_r->set_substitution(nullptr); - m_candidate_vars.reset(); - m_candidate_set.reset(); - m_candidates.reset(); - m_marked_candidates.reset(); - m_vars.reset(); - m_nonzero.reset(); - app_ref var(m()); - expr_ref def(m()); - proof_ref pr(m()); - unsigned size = g.size(); - for (unsigned idx = 0; idx < size; idx++) { - add_pos(g.form(idx)); - } - for (unsigned idx = 0; idx < size; idx++) { - checkpoint(); - expr * f = g.form(idx); - pr = nullptr; - if (solve(f, var, def, pr)) { - insert_solution(g, idx, f, var, def, pr); - } - m_num_steps++; - } - - TRACE("solve_eqs", - tout << "candidate vars:\n"; - for (app* v : m_vars) { - tout << mk_ismt2_pp(v, m()) << " "; - } - tout << "\n";); - } - - struct nnf_context { - bool m_is_and; - expr_ref_vector m_args; - unsigned m_index; - nnf_context(bool is_and, expr_ref_vector const& args, unsigned idx): - m_is_and(is_and), - m_args(args), - m_index(idx) - {} - }; - - ptr_vector m_todo; - void mark_occurs(expr_mark& occ, goal const& g, expr* v) { - SASSERT(m_todo.empty()); - for (unsigned j = 0; j < g.size(); ++j) - m_todo.push_back(g.form(j)); - ::mark_occurs(m_todo, v, occ); - SASSERT(m_todo.empty()); - } - - expr_mark m_compatible_tried; - expr_ref_vector m_var_trail; - - bool is_compatible(goal const& g, unsigned idx, vector const & path, expr* v, expr* eq) { - if (m_compatible_tried.is_marked(v)) - return false; - m_compatible_tried.mark(v); - m_var_trail.push_back(v); - expr_mark occ; - svector cache; - mark_occurs(occ, g, v); - return is_goal_compatible(g, occ, cache, idx, v, eq) && is_path_compatible(occ, cache, path, v, eq); - } - - bool is_goal_compatible(goal const& g, expr_mark& occ, svector& cache, unsigned idx, expr* v, expr* eq) { - bool all_e = false; - for (unsigned j = 0; j < g.size(); ++j) { - if (j != idx && !check_eq_compat_rec(occ, cache, g.form(j), v, eq, all_e)) { - TRACE("solve_eqs", tout << "occurs goal " << mk_pp(eq, m()) << "\n";); - return false; - } - } - return true; - } - - // - // all_e := all disjunctions contain eq - // - // or, all_e -> skip if all disjunctions contain eq - // or, all_e -> fail if some disjunction contains v but not eq - // or, all_e -> all_e := false if some disjunction does not contain v - // and, all_e -> all_e - // - - bool is_path_compatible(expr_mark& occ, svector& cache, vector const & path, expr* v, expr* eq) { - bool all_e = true; - auto is_marked = [&](expr* e) { - if (occ.is_marked(e)) - return true; - if (m().is_not(e, e) && occ.is_marked(e)) - return true; - return false; - }; - for (unsigned i = path.size(); i-- > 0; ) { - auto const& p = path[i]; - auto const& args = p.m_args; - if (p.m_is_and && !all_e) { - for (unsigned j = 0; j < args.size(); ++j) { - if (j != p.m_index && is_marked(args[j])) { - TRACE("solve_eqs", tout << "occurs and " << mk_pp(eq, m()) << " " << mk_pp(args[j], m()) << "\n";); - return false; - } - } - } - else if (!p.m_is_and) { - for (unsigned j = 0; j < args.size(); ++j) { - if (j != p.m_index) { - if (occurs(v, args[j])) { - if (!check_eq_compat_rec(occ, cache, args[j], v, eq, all_e)) { - TRACE("solve_eqs", tout << "occurs or " << mk_pp(eq, m()) << " " << mk_pp(args[j], m()) << "\n";); - return false; - } - } - else { - all_e = false; - } - } - } - } - } - return true; - } - - bool check_eq_compat_rec(expr_mark& occ, svector& cache, expr* f, expr* v, expr* eq, bool& all) { - expr_ref_vector args(m()); - expr* f1 = nullptr; - // flattening may introduce fresh negations, - // occ is not defined on these negations - if (!m().is_not(f) && !occ.is_marked(f)) { - all = false; - return true; - } - unsigned idx = f->get_id(); - if (cache.size() > idx && cache[idx] != l_undef) { - return cache[idx] == l_true; - } - if (m().is_not(f, f1) && m().is_or(f1)) { - flatten_and(f, args); - for (expr* arg : args) { - if (arg == eq) { - cache.reserve(idx+1, l_undef); - cache[idx] = l_true; - return true; - } - } - } - else if (m().is_or(f)) { - flatten_or(f, args); - } - else { - return false; - } - - for (expr* arg : args) { - if (!check_eq_compat_rec(occ, cache, arg, v, eq, all)) { - cache.reserve(idx+1, l_undef); - cache[idx] = l_false; - return false; - } - } - cache.reserve(idx+1, l_undef); - cache[idx] = l_true; - return true; - } - - void hoist_nnf(goal const& g, expr* f, vector & path, unsigned idx, unsigned depth, ast_mark& mark) { - if (depth > 3 || mark.is_marked(f)) { - return; - } - mark.mark(f, true); - checkpoint(); - app_ref var(m()); - expr_ref def(m()); - proof_ref pr(m()); - expr_ref_vector args(m()); - expr* f1 = nullptr; - - if (m().is_not(f, f1) && m().is_or(f1)) { - flatten_and(f, args); - for (unsigned i = 0; i < args.size(); ++i) { - pr = nullptr; - expr* arg = args.get(i), *lhs = nullptr, *rhs = nullptr; - if (m().is_eq(arg, lhs, rhs) && !m().is_bool(lhs)) { - if (trivial_solve1(lhs, rhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { - IF_VERBOSE(11, verbose_stream() << "nested " << mk_bounded_pp(var.get(), m()) << " -> " << mk_bounded_pp(def, m()) << "\n"); - insert_solution(g, idx, arg, var, def, pr); - } - else if (trivial_solve1(rhs, lhs, var, def, pr) && is_compatible(g, idx, path, var, arg)) { - IF_VERBOSE(11, verbose_stream() << "nested " << mk_bounded_pp(var.get(), m()) << " -> " << mk_bounded_pp(def, m()) << "\n"); - insert_solution(g, idx, arg, var, def, pr); - } - else { - IF_VERBOSE(10000, - verbose_stream() << "eq not solved " << mk_pp(arg, m()) << "\n"; - verbose_stream() << is_uninterp_const(lhs) << " " << !m_candidate_vars.is_marked(lhs) << " " - << !occurs(lhs, rhs) << " " << check_occs(lhs) << "\n";); - } - } - else { - path.push_back(nnf_context(true, args, i)); - hoist_nnf(g, arg, path, idx, depth + 1, mark); - path.pop_back(); - } - } - } - else if (m().is_or(f)) { - flatten_or(f, args); - for (unsigned i = 0; i < args.size(); ++i) { - path.push_back(nnf_context(false, args, i)); - hoist_nnf(g, args.get(i), path, idx, depth + 1, mark); - path.pop_back(); - } - } - } - - void collect_hoist(goal const& g) { - unsigned size = g.size(); - ast_mark mark; - vector path; - for (unsigned idx = 0; idx < size; idx++) { - checkpoint(); - hoist_nnf(g, g.form(idx), path, idx, 0, mark); - } - } - - void distribute_and_or(goal & g) { - if (m_produce_proofs) - return; - unsigned size = g.size(); - hoist_rewriter_star rw(m(), m_params); - th_rewriter thrw(m(), m_params); - expr_ref tmp(m()), tmp2(m()); - - TRACE("solve_eqs", g.display(tout);); - for (unsigned idx = 0; !g.inconsistent() && idx < size; idx++) { - checkpoint(); - if (g.is_decided_unsat()) break; - expr* f = g.form(idx); - proof_ref pr1(m()), pr2(m()); - thrw(f, tmp, pr1); - rw(tmp, tmp2, pr2); - TRACE("solve_eqs", tout << mk_pp(f, m()) << "\n->\n" << tmp << "\n->\n" << tmp2 - << "\n" << pr1 << "\n" << pr2 << "\n" << mk_pp(g.pr(idx), m()) << "\n";); - pr1 = m().mk_transitivity(pr1, pr2); - if (!pr1) pr1 = g.pr(idx); else pr1 = m().mk_modus_ponens(g.pr(idx), pr1); - g.update(idx, tmp2, pr1, g.dep(idx)); - } - } - - expr_mark m_unsafe_vars; - - void filter_unsafe_vars() { - m_unsafe_vars.reset(); - recfun::util rec(m()); - for (func_decl* f : rec.get_rec_funs()) - for (expr* term : subterms::all(expr_ref(rec.get_def(f).get_rhs(), m()))) - m_unsafe_vars.mark(term); - } - - bool is_safe(expr* f) { - return !m_unsafe_vars.is_marked(f); - } - - void sort_vars() { - SASSERT(m_candidates.size() == m_vars.size()); - TRACE("solve_eqs_bug", tout << "sorting vars...\n";); - m_ordered_vars.reset(); - - - // The variables (and its definitions) in m_subst must remain alive until the end of this procedure. - // Reason: they are scheduled for unmarking in visiting/done. - // They should remain alive while they are on the stack. - // To make sure this is the case, whenever a variable (and its definition) is removed from m_subst, - // I add them to the saved vector. - - expr_ref_vector saved(m()); - - expr_fast_mark1 visiting; - expr_fast_mark2 done; - - typedef std::pair frame; - svector todo; - unsigned num = 0; - for (app* v : m_vars) { - checkpoint(); - if (!m_candidate_vars.is_marked(v)) - continue; - todo.push_back(frame(v, 0)); - while (!todo.empty()) { - start: - frame & fr = todo.back(); - expr * t = fr.first; - m_num_steps++; - TRACE("solve_eqs_bug", tout << "processing:\n" << mk_ismt2_pp(t, m()) << "\n";); - if (t->get_ref_count() > 1 && done.is_marked(t)) { - todo.pop_back(); - continue; - } - switch (t->get_kind()) { - case AST_VAR: - todo.pop_back(); - break; - case AST_QUANTIFIER: - num = to_quantifier(t)->get_num_children(); - while (fr.second < num) { - expr * c = to_quantifier(t)->get_child(fr.second); - fr.second++; - if (c->get_ref_count() > 1 && done.is_marked(c)) - continue; - todo.push_back(frame(c, 0)); - goto start; - } - if (t->get_ref_count() > 1) - done.mark(t); - todo.pop_back(); - break; - case AST_APP: - num = to_app(t)->get_num_args(); - if (num == 0) { - if (fr.second == 0) { - if (m_candidate_vars.is_marked(t)) { - if (visiting.is_marked(t)) { - // cycle detected: remove t - visiting.reset_mark(t); - m_candidate_vars.mark(t, false); - SASSERT(!m_candidate_vars.is_marked(t)); - - // Must save t and its definition. - // See comment in the beginning of the function - expr * def = nullptr; - proof * pr; - expr_dependency * dep; - m_subst->find(to_app(t), def, pr, dep); - SASSERT(def != 0); - saved.push_back(t); - saved.push_back(def); - // - - m_subst->erase(t); - } - else { - visiting.mark(t); - fr.second = 1; - expr * def = nullptr; - proof * pr; - expr_dependency * dep; - m_subst->find(to_app(t), def, pr, dep); - SASSERT(def != 0); - todo.push_back(frame(def, 0)); - goto start; - } - } - } - else { - SASSERT(fr.second == 1); - if (m_candidate_vars.is_marked(t)) { - visiting.reset_mark(t); - m_ordered_vars.push_back(to_app(t)); - } - else { - // var was removed from the list of candidate vars to elim cycle - // do nothing - } - } - } - else { - while (fr.second < num) { - expr * arg = to_app(t)->get_arg(fr.second); - fr.second++; - if (arg->get_ref_count() > 1 && done.is_marked(arg)) - continue; - todo.push_back(frame(arg, 0)); - goto start; - } - } - if (t->get_ref_count() > 1) - done.mark(t); - todo.pop_back(); - break; - default: - UNREACHABLE(); - todo.pop_back(); - break; - } - } - } - - // cleanup - unsigned idx = 0; - for (expr* v : m_vars) { - if (!m_candidate_vars.is_marked(v)) { - m_candidate_set.mark(m_candidates[idx], false); - m_marked_candidates.push_back(m_candidates[idx]); - m_marked_candidates.push_back(v); - } - ++idx; - } - - IF_VERBOSE(10000, - verbose_stream() << "ordered vars: "; - for (app* v : m_ordered_vars) verbose_stream() << mk_pp(v, m()) << " "; - verbose_stream() << "\n";); - TRACE("solve_eqs", - tout << "ordered vars:\n"; - for (app* v : m_ordered_vars) { - SASSERT(m_candidate_vars.is_marked(v)); - tout << mk_ismt2_pp(v, m()) << " "; - } - tout << "\n";); - m_candidate_vars.reset(); - } - - void normalize() { - m_norm_subst->reset(); - m_r->set_substitution(m_norm_subst.get()); - - - expr_dependency_ref new_dep(m()); - for (app * v : m_ordered_vars) { - checkpoint(); - expr_ref new_def(m()); - proof_ref new_pr(m()); - expr * def = nullptr; - proof * pr = nullptr; - expr_dependency * dep = nullptr; - m_subst->find(v, def, pr, dep); - SASSERT(def); - m_r->operator()(def, new_def, new_pr, new_dep); - m_num_steps += m_r->get_num_steps() + 1; - if (m_produce_proofs) - new_pr = m().mk_transitivity(pr, new_pr); - new_dep = m().mk_join(dep, new_dep); - m_norm_subst->insert(v, new_def, new_pr, new_dep); - // we updated the substituting, but we don't need to reset m_r - // because all cached values there do not depend on v. - } - m_subst->reset(); - TRACE("solve_eqs", - tout << "after normalizing variables\n"; - for (expr * v : m_ordered_vars) { - expr * def = 0; - proof * pr = 0; - expr_dependency * dep = 0; - m_norm_subst->find(v, def, pr, dep); - tout << mk_ismt2_pp(v, m()) << "\n----->\n" << mk_ismt2_pp(def, m()) << "\n\n"; - }); - } - - void substitute(goal & g) { - // force the cache of m_r to be reset. - m_r->set_substitution(m_norm_subst.get()); - - expr_ref new_f(m()); - proof_ref new_pr(m()); - expr_dependency_ref new_dep(m()); - unsigned size = g.size(); - for (unsigned idx = 0; idx < size; idx++) { - checkpoint(); - expr * f = g.form(idx); - TRACE("gaussian_leak", tout << "processing:\n" << mk_ismt2_pp(f, m()) << "\n";); - if (m_candidate_set.is_marked(f)) { - m_marked_candidates.push_back(f); - // f may be deleted after the following update. - // so, we must remove the mark before doing the update - m_candidate_set.mark(f, false); - SASSERT(!m_candidate_set.is_marked(f)); - g.update(idx, m().mk_true(), m().mk_true_proof(), nullptr); - m_num_steps ++; - continue; - } - - m_r->operator()(f, new_f, new_pr, new_dep); - - TRACE("solve_eqs_subst", tout << mk_ismt2_pp(f, m()) << "\n--->\n" << mk_ismt2_pp(new_f, m()) << "\n";); - m_num_steps += m_r->get_num_steps() + 1; - if (m_produce_proofs) - new_pr = m().mk_modus_ponens(g.pr(idx), new_pr); - if (m_produce_unsat_cores) - new_dep = m().mk_join(g.dep(idx), new_dep); - - g.update(idx, new_f, new_pr, new_dep); - if (g.inconsistent()) - return; - } - g.elim_true(); - TRACE("solve_eqs", g.display(tout << "after applying substitution\n");); -#if 0 - DEBUG_CODE({ - for (expr* v : m_ordered_vars) { - for (unsigned j = 0; j < g.size(); j++) { - CASSERT("solve_eqs_bug", !occurs(v, g.form(j))); - } - }}); -#endif - } - - void save_elim_vars(model_converter_ref & mc) { - IF_VERBOSE(100, if (!m_ordered_vars.empty()) verbose_stream() << "num. eliminated vars: " << m_ordered_vars.size() << "\n";); - m_num_eliminated_vars += m_ordered_vars.size(); - if (m_produce_models) { - if (!mc.get()) - mc = alloc(gmc, m(), "solve-eqs"); - for (app* v : m_ordered_vars) - static_cast(mc.get())->add(v, m_norm_subst->find(v)); - } - } - - void collect_num_occs(expr * t, expr_fast_mark1 & visited) { - ptr_buffer stack; - - auto visit = [&](expr* arg) { - if (is_uninterp_const(arg)) { - m_num_occs.insert_if_not_there(arg, 0)++; - } - if (!visited.is_marked(arg) && is_app(arg)) { - visited.mark(arg, true); - stack.push_back(to_app(arg)); - } - }; - - visit(t); - - while (!stack.empty()) { - app * t = stack.back(); - stack.pop_back(); - for (expr* arg : *t) - visit(arg); - } - } - - void collect_num_occs(goal const & g) { - if (m_max_occs == UINT_MAX) - return; // no need to compute num occs - m_num_occs.reset(); - expr_fast_mark1 visited; - unsigned sz = g.size(); - for (unsigned i = 0; i < sz; i++) - collect_num_occs(g.form(i), visited); - } - - unsigned get_num_steps() const { - return m_num_steps; - } - - unsigned get_num_eliminated_vars() const { - return m_num_eliminated_vars; - } - - void collect_statistics(statistics& st) { - st.update("solve eqs elim vars", get_num_eliminated_vars()); - } - - // - // TBD: rewrite the tactic to first apply a topological sorting that - // approximates the dependencies between variables. Then apply - // simplification on top of this sorting, so that it can apply sub-quadratic - // equality and unit propagation. - // - void operator()(goal_ref const & g, goal_ref_buffer & result) { - model_converter_ref mc; - std::function coll = [&](statistics& st) { collect_statistics(st); }; - statistics_report sreport(coll); - tactic_report report("solve_eqs", *g); - TRACE("goal", g->display(tout);); - m_produce_models = g->models_enabled(); - m_produce_proofs = g->proofs_enabled(); - m_produce_unsat_cores = g->unsat_core_enabled(); - - if (!g->inconsistent()) { - m_subst = alloc(expr_substitution, m(), m_produce_unsat_cores, m_produce_proofs); - m_norm_subst = alloc(expr_substitution, m(), m_produce_unsat_cores, m_produce_proofs); - unsigned rounds = 0; - - filter_unsafe_vars(); - while (rounds < 20) { - ++rounds; - if (!m_produce_proofs && m_context_solve && rounds < 3) { - distribute_and_or(*(g.get())); - } - collect_num_occs(*g); - collect(*g); - if (!m_produce_proofs && m_context_solve && rounds < 3) { - collect_hoist(*g); - } - if (m_subst->empty()) { - break; - } - sort_vars(); - if (m_ordered_vars.empty()) { - break; - } - normalize(); - substitute(*(g.get())); - if (g->inconsistent()) { - break; - } - save_elim_vars(mc); - TRACE("solve_eqs_round", g->display(tout); if (mc) mc->display(tout);); - if (rounds > 10 && m_ordered_vars.size() == 1) - break; - } - } - g->inc_depth(); - g->add(mc.get()); - result.push_back(g.get()); - - - } - }; - - imp * m_imp; -public: - solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner) { - m_imp = alloc(imp, m, p, r, owner); - } - - tactic * translate(ast_manager & m) override { - return alloc(solve_eqs_tactic, m, m_imp->m_params, mk_expr_simp_replacer(m, m_imp->m_params), true); - } - - ~solve_eqs_tactic() override { - dealloc(m_imp); - } - - char const* name() const override { return "solve_eqs"; } - - void updt_params(params_ref const & p) override { - m_imp->updt_params(p); - } - - void collect_param_descrs(param_descrs & r) override { - r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations."); - r.insert("theory_solver", CPK_BOOL, "(default: true) use theory solvers."); - r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); - r.insert("context_solve", CPK_BOOL, "(default: false) solve equalities under disjunctions."); - } - - void operator()(goal_ref const & in, - goal_ref_buffer & result) override { - (*m_imp)(in, result); - } - - void cleanup() override { - unsigned num_elim_vars = m_imp->m_num_eliminated_vars; - ast_manager & m = m_imp->m(); - expr_replacer * r = m_imp->m_r; - if (r) - r->set_substitution(nullptr); - bool owner = m_imp->m_r_owner; - m_imp->m_r_owner = false; // stole replacer - - imp * d = alloc(imp, m, m_imp->m_params, r, owner); - d->m_num_eliminated_vars = num_elim_vars; - std::swap(d, m_imp); - dealloc(d); - } - - void collect_statistics(statistics & st) const override { - m_imp->collect_statistics(st); - } - - void reset_statistics() override { - m_imp->m_num_eliminated_vars = 0; - } - -}; - -tactic * mk_solve_eqs1_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true)); -} diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 7b97172a3..fa095aad0 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -1,37 +1,47 @@ /*++ -Copyright (c) 2011 Microsoft Corporation +Copyright (c) 2022 Microsoft Corporation Module Name: - solve_eqs_tactic.h + solve_eqs2_tactic.h Abstract: - Tactic for solving equations and performing gaussian elimination. + Tactic for solving variables Author: - Leonardo de Moura (leonardo) 2011-12-29. - -Revision History: + Nikolaj Bjorner (nbjorner) 2022-10-30 --*/ #pragma once #include "util/params.h" -class ast_manager; -class tactic; +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/solve_eqs.h" -tactic * mk_solve_eqs1_tactic(ast_manager & m, params_ref const & p = params_ref()); -#if 0 +class solve_eqs2_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(euf::solve_eqs, m, s); + } +}; + +inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs"); +} + +#if 1 inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return mk_solve_eqs1_tactic(m, p); + return mk_solve_eqs2_tactic(m, p); } #endif + /* - ADD_TACTIC("solve-eqs", "eliminate variables by solving equations.", "mk_solve_eqs1_tactic(m, p)") + ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") */ diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 419037839..aaf744d5f 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -81,6 +81,11 @@ public: m_simp->updt_params(m_params); } + void collect_param_descrs(param_descrs& r) override { + init(); + m_simp->collect_param_descrs(r); + } + tactic * translate(ast_manager & m) override { return alloc(dependent_expr_state_tactic, m, m_params, m_factory.get(), name()); } diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index a09da60a9..e631c23e9 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -18,7 +18,6 @@ Notes: --*/ #include "ast/normal_forms/nnf.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/bv/bv_size_reduction_tactic.h" #include "tactic/bv/max_bv_sharing_tactic.h" #include "tactic/core/simplify_tactic.h" diff --git a/src/tactic/smtlogics/qfaufbv_tactic.cpp b/src/tactic/smtlogics/qfaufbv_tactic.cpp index 6d44addf0..acad15fd6 100644 --- a/src/tactic/smtlogics/qfaufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfaufbv_tactic.cpp @@ -17,7 +17,6 @@ Notes: --*/ #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/bv/bit_blaster_tactic.h" diff --git a/src/tactic/smtlogics/qfauflia_tactic.cpp b/src/tactic/smtlogics/qfauflia_tactic.cpp index 9ca6b70ef..2f1879d58 100644 --- a/src/tactic/smtlogics/qfauflia_tactic.cpp +++ b/src/tactic/smtlogics/qfauflia_tactic.cpp @@ -21,7 +21,6 @@ Notes: #include "tactic/core/propagate_values_tactic.h" #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/smtlogics/smt_tactic.h" diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 90df4fe42..07784eb3b 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -20,7 +20,6 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/bv/bit_blaster_tactic.h" #include "tactic/bv/bv1_blaster_tactic.h" diff --git a/src/tactic/smtlogics/qfidl_tactic.cpp b/src/tactic/smtlogics/qfidl_tactic.cpp index 5c1ba5f44..c86789ed0 100644 --- a/src/tactic/smtlogics/qfidl_tactic.cpp +++ b/src/tactic/smtlogics/qfidl_tactic.cpp @@ -21,7 +21,6 @@ Notes: #include "tactic/core/propagate_values_tactic.h" #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/arith/normalize_bounds_tactic.h" #include "tactic/arith/fix_dl_var_tactic.h" diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index d116414ea..b8ebbd8a9 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -22,7 +22,6 @@ Notes: #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/arith/normalize_bounds_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" diff --git a/src/tactic/smtlogics/qfuf_tactic.cpp b/src/tactic/smtlogics/qfuf_tactic.cpp index d9f723d67..609107a48 100644 --- a/src/tactic/smtlogics/qfuf_tactic.cpp +++ b/src/tactic/smtlogics/qfuf_tactic.cpp @@ -21,7 +21,6 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/symmetry_reduce_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/smtlogics/smt_tactic.h" diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 98e09b56a..6ba3e8cc9 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -21,7 +21,6 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/bv/max_bv_sharing_tactic.h" #include "tactic/bv/bv_size_reduction_tactic.h" diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 3bf6b658d..daf020a14 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -20,7 +20,6 @@ Revision History: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "qe/lite/qe_lite.h" #include "qe/qsat.h" diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index 728e6397d..e8495c013 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -20,7 +20,6 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/solve_eqs2_tactic.h" #include "tactic/core/distribute_forall_tactic.h" #include "tactic/core/der_tactic.h" #include "tactic/core/reduce_args_tactic.h" From 95e07ffe8e96ed18fda51f0ccdabfbe5f32d8b68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Nov 2022 19:14:51 -0800 Subject: [PATCH 276/477] disable unsound context equality solving Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/solve_eqs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 0b6f12160..18928dca8 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -197,7 +197,7 @@ namespace euf { if (!m.inc()) return; - if (m_config.m_context_solve) { + if (m_config.m_context_solve && false) { old_fmls.reset(); m_subst_ids.reset(); eqs.reset(); From 3eeb59db34172f673d4ea54c1ec9ca191997fb5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Nov 2022 19:23:27 -0800 Subject: [PATCH 277/477] fix #6451 missing occurrence marking when there is an unsafe equality already Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/solve_context_eqs.cpp | 11 +++++++++-- src/ast/simplifiers/solve_eqs.cpp | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index 37836db27..1ccab0f6c 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -154,10 +154,12 @@ namespace euf { return e1.var->get_id() < e2.var->get_id(); }); unsigned j = 0; expr* last_var = nullptr; + bool was_unsafe = false; for (auto const& eq : eqs) { SASSERT(!m.is_bool(eq.var)); + if (eq.var != last_var) { m_contains_v.reset(); @@ -167,8 +169,11 @@ namespace euf { mark_occurs(m_todo, eq.var, m_contains_v); SASSERT(m_todo.empty()); last_var = eq.var; - if (m_contains_v.is_marked(eq.term)) + was_unsafe = false; + if (m_contains_v.is_marked(eq.term)) { + was_unsafe = true; continue; + } // then mark occurrences for (unsigned i = 0; i < m_fmls.size(); ++i) @@ -178,7 +183,9 @@ namespace euf { } else if (m_contains_v.is_marked(eq.term)) continue; - + else if (was_unsafe) + continue; + // subject to occurrences, check if equality is safe if (is_safe_eq(eq.orig)) eqs[j++] = eq; diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 18928dca8..0b6f12160 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -197,7 +197,7 @@ namespace euf { if (!m.inc()) return; - if (m_config.m_context_solve && false) { + if (m_config.m_context_solve) { old_fmls.reset(); m_subst_ids.reset(); eqs.reset(); From 48c0f8694facce9a645cf81beee2a9a7449450da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Nov 2022 20:01:00 -0800 Subject: [PATCH 278/477] euf-completion bug fix, streamline name to solve_eqs --- src/ast/simplifiers/euf_completion.cpp | 3 ++- src/tactic/core/solve_eqs_tactic.h | 15 ++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 0f03d7fe1..7c27a01bb 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -90,7 +90,8 @@ namespace euf { return; } - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + unsigned sz = m_fmls.size(); + for (unsigned i = m_qhead; i < sz; ++i) { auto [f, d] = m_fmls[i](); expr_dependency_ref dep(d, m); diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index fa095aad0..188f37f34 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -22,26 +22,19 @@ Author: #include "ast/simplifiers/solve_eqs.h" -class solve_eqs2_tactic_factory : public dependent_expr_simplifier_factory { +class solve_eqs_tactic_factory : public dependent_expr_simplifier_factory { public: dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { return alloc(euf::solve_eqs, m, s); } }; -inline tactic * mk_solve_eqs2_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs2_tactic_factory), "solve-eqs"); +inline tactic * mk_solve_eqs_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs_tactic_factory), "solve-eqs"); } -#if 1 -inline tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return mk_solve_eqs2_tactic(m, p); -} -#endif - - /* - ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs2_tactic(m, p)") + ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs_tactic(m, p)") */ From 041b5f9ef01be585c27796dda4f892e272b089b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 Nov 2022 20:01:37 -0800 Subject: [PATCH 279/477] rename away solve_eqs2 to solve_eqs Signed-off-by: Nikolaj Bjorner --- src/tactic/core/solve_eqs_tactic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 188f37f34..5d6da2e9a 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -3,7 +3,7 @@ Copyright (c) 2022 Microsoft Corporation Module Name: - solve_eqs2_tactic.h + solve_eqs_tactic.h Abstract: From bfae8b216278d74cc69d5a415527380d7a50fd75 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Nov 2022 05:47:28 -0800 Subject: [PATCH 280/477] set flat_and_or to false in bv rewriter --- src/smt/theory_bv.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 922eafcf6..adcafb2e4 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1489,6 +1489,7 @@ namespace smt { m_approximates_large_bvs(false) { memset(m_eq_activity, 0, sizeof(m_eq_activity)); memset(m_diseq_activity, 0, sizeof(m_diseq_activity)); + m_bb.set_flat_and_or(false); } theory_bv::~theory_bv() { From 9845c33236e944c3435b7303267d3acc5fc7b8e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Nov 2022 09:13:13 -0800 Subject: [PATCH 281/477] add shortcuts in rewriter, eliminate redundancies in dependent_expr tactic --- src/ast/rewriter/bool_rewriter.cpp | 12 +++-- src/ast/rewriter/bv_rewriter.cpp | 4 +- src/ast/rewriter/th_rewriter.cpp | 57 +++++++++++++++--------- src/ast/rewriter/th_rewriter.h | 1 + src/tactic/dependent_expr_state_tactic.h | 1 + 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 632b6c0f6..1e0b6318a 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -686,6 +686,10 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) app* bool_rewriter::mk_eq(expr* lhs, expr* rhs) { + if (m().are_distinct(lhs, rhs)) + return m().mk_false(); + if (lhs == rhs) + return m().mk_true(); // degrades simplification // if (lhs->get_id() > rhs->get_id()) std::swap(lhs, rhs); return m().mk_eq(lhs, rhs); @@ -785,7 +789,7 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args if (num_args == 2) { expr_ref tmp(m()); - result = m().mk_not(mk_eq(args[0], args[1])); + result = mk_not(mk_eq(args[0], args[1])); return BR_REWRITE2; // mk_eq may be dispatched to other rewriters. } @@ -827,7 +831,7 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args ptr_buffer new_diseqs; for (unsigned i = 0; i < num_args; i++) { for (unsigned j = i + 1; j < num_args; j++) - new_diseqs.push_back(m().mk_not(mk_eq(args[i], args[j]))); + new_diseqs.push_back(mk_not(mk_eq(args[i], args[j]))); } result = m().mk_and(new_diseqs); return BR_REWRITE3; @@ -937,13 +941,13 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re if (m().is_not(t, t1) && m().is_eq(t1, t1, t2) && e == t1) { expr_ref a(m()); mk_and(c, t2, a); - result = m().mk_not(m().mk_eq(t1, a)); + result = mk_not(mk_eq(t1, a)); return BR_REWRITE3; } if (m().is_not(t, t1) && m().is_eq(t1, t2, t1) && e == t1) { expr_ref a(m()); mk_and(c, t2, a); - result = m().mk_eq(t1, a); + result = mk_eq(t1, a); return BR_REWRITE3; } #endif diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 209f7a13b..c59423310 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -19,6 +19,7 @@ Notes: #include "params/bv_rewriter_params.hpp" #include "ast/rewriter/bv_rewriter.h" #include "ast/rewriter/poly_rewriter_def.h" +#include "ast/rewriter/bool_rewriter.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_lt.h" @@ -2386,7 +2387,8 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) { expr* a = nullptr, *b = nullptr, *c = nullptr; if (m().is_ite(lhs, a, b, c)) { - result = m().mk_ite(a, m().mk_eq(b, rhs), m().mk_eq(c, rhs)); + bool_rewriter rw(m()); + result = rw.mk_ite(a, rw.mk_eq(b, rhs), rw.mk_eq(c, rhs)); return BR_REWRITE2; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 9604f6d16..4c7d4dc49 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -183,22 +183,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { if (k == OP_EQ) { // theory dispatch for = SASSERT(num == 2); - family_id s_fid = args[0]->get_sort()->get_family_id(); - if (s_fid == m_a_rw.get_fid()) - st = m_a_rw.mk_eq_core(args[0], args[1], result); - else if (s_fid == m_bv_rw.get_fid()) - st = m_bv_rw.mk_eq_core(args[0], args[1], result); - else if (s_fid == m_dt_rw.get_fid()) - st = m_dt_rw.mk_eq_core(args[0], args[1], result); - else if (s_fid == m_f_rw.get_fid()) - st = m_f_rw.mk_eq_core(args[0], args[1], result); - else if (s_fid == m_ar_rw.get_fid()) - st = m_ar_rw.mk_eq_core(args[0], args[1], result); - else if (s_fid == m_seq_rw.get_fid()) - st = m_seq_rw.mk_eq_core(args[0], args[1], result); - if (st != BR_FAILED) - return st; - st = apply_tamagotchi(args[0], args[1], result); + st = reduce_eq(args[0], args[1], result); if (st != BR_FAILED) return st; } @@ -695,9 +680,35 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args) { expr_ref result(m()); proof_ref pr(m()); - if (BR_FAILED == reduce_app(f, num_args, args, result, pr)) { + if (BR_FAILED == reduce_app(f, num_args, args, result, pr)) result = m().mk_app(f, num_args, args); - } + return result; + } + + br_status reduce_eq(expr* a, expr* b, expr_ref& result) { + family_id s_fid = a->get_sort()->get_family_id(); + br_status st = BR_FAILED; + if (s_fid == m_a_rw.get_fid()) + st = m_a_rw.mk_eq_core(a, b, result); + else if (s_fid == m_bv_rw.get_fid()) + st = m_bv_rw.mk_eq_core(a, b, result); + else if (s_fid == m_dt_rw.get_fid()) + st = m_dt_rw.mk_eq_core(a, b, result); + else if (s_fid == m_f_rw.get_fid()) + st = m_f_rw.mk_eq_core(a, b, result); + else if (s_fid == m_ar_rw.get_fid()) + st = m_ar_rw.mk_eq_core(a, b, result); + else if (s_fid == m_seq_rw.get_fid()) + st = m_seq_rw.mk_eq_core(a, b, result); + if (st != BR_FAILED) + return st; + return apply_tamagotchi(a, b, result); + } + + expr_ref mk_eq(expr* a, expr* b) { + expr_ref result(m()); + if (BR_FAILED == reduce_eq(a, b, result)) + result = m().mk_eq(a, b); return result; } @@ -897,6 +908,10 @@ struct th_rewriter::imp : public rewriter_tpl { return m_cfg.mk_app(f, sz, args); } + expr_ref mk_eq(expr* a, expr* b) { + return m_cfg.mk_eq(a, b); + } + void set_solver(expr_solver* solver) { m_cfg.m_seq_rw.set_solver(solver); } @@ -928,7 +943,6 @@ void th_rewriter::set_flat_and_or(bool f) { m_imp->cfg().m_b_rw.set_flat_and_or(f); } - th_rewriter::~th_rewriter() { dealloc(m_imp); } @@ -941,7 +955,6 @@ unsigned th_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } - void th_rewriter::cleanup() { ast_manager & m = m_imp->m(); m_imp->~imp(); @@ -991,6 +1004,10 @@ expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) return m_imp->mk_app(f, num_args, args); } +expr_ref th_rewriter::mk_eq(expr* a, expr* b) { + return m_imp->mk_eq(a, b); +} + void th_rewriter::set_solver(expr_solver* solver) { m_imp->set_solver(solver); } diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index b84164abc..2c08c247d 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -51,6 +51,7 @@ public: expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args); expr_ref mk_app(func_decl* f, ptr_vector const& args) { return mk_app(f, args.size(), args.data()); } + expr_ref mk_eq(expr* a, expr* b); bool reduce_quantifier(quantifier * old_q, expr * new_body, diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index aaf744d5f..d3f77b773 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -99,6 +99,7 @@ public: if (!in->proofs_enabled()) m_simp->reduce(); m_goal->elim_true(); + m_goal->elim_redundancies(); m_goal->inc_depth(); if (in->models_enabled()) in->add(m_model_trail->get_model_converter().get()); From 255414f4a9558c2ce43fcfd097ef02c8e201e4db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Nov 2022 11:20:12 -0800 Subject: [PATCH 282/477] fix regression crash Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bool_rewriter.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 1e0b6318a..84552282b 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -647,11 +647,13 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) SASSERT(m().is_value(val)); if (m().are_distinct(val, e)) { - result = m().mk_and(mk_eq(t, val), cond); + mk_eq(t, val, result); + result = m().mk_and(result, cond); return BR_REWRITE2; } if (m().are_distinct(val, t)) { - result = m().mk_and(mk_eq(e, val), m().mk_not(cond)); + mk_eq(e, val, result); + result = m().mk_and(result, m().mk_not(cond)); return BR_REWRITE2; } if (m().are_equal(val, t)) { @@ -660,12 +662,14 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) return BR_DONE; } else { - result = m().mk_or(mk_eq(e, val), cond); + mk_eq(e, val, result); + result = m().mk_or(result, cond); } return BR_REWRITE2; } if (m().are_equal(val, e)) { - result = m().mk_or(mk_eq(t, val), m().mk_not(cond)); + mk_eq(t, val, result); + result = m().mk_or(result, m().mk_not(cond)); return BR_REWRITE2; } @@ -686,10 +690,6 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) app* bool_rewriter::mk_eq(expr* lhs, expr* rhs) { - if (m().are_distinct(lhs, rhs)) - return m().mk_false(); - if (lhs == rhs) - return m().mk_true(); // degrades simplification // if (lhs->get_id() > rhs->get_id()) std::swap(lhs, rhs); return m().mk_eq(lhs, rhs); @@ -761,7 +761,7 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { } if (unfolded) { - result = mk_eq(lhs, rhs); + result = m().mk_eq(lhs, rhs); return BR_REWRITE1; } @@ -789,7 +789,8 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args if (num_args == 2) { expr_ref tmp(m()); - result = mk_not(mk_eq(args[0], args[1])); + mk_eq(args[0], args[1], tmp); + mk_not(tmp, result); return BR_REWRITE2; // mk_eq may be dispatched to other rewriters. } @@ -828,10 +829,10 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args } if (m_blast_distinct && num_args < m_blast_distinct_threshold) { - ptr_buffer new_diseqs; + expr_ref_vector new_diseqs(m()); for (unsigned i = 0; i < num_args; i++) { for (unsigned j = i + 1; j < num_args; j++) - new_diseqs.push_back(mk_not(mk_eq(args[i], args[j]))); + new_diseqs.push_back(m().mk_not(m().mk_eq(args[i], args[j]))); } result = m().mk_and(new_diseqs); return BR_REWRITE3; From d70dbdad501f3782e99d4d364fc7424f1bda6a6f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Nov 2022 20:17:30 -0800 Subject: [PATCH 283/477] wip euf-completion - debugging --- src/ast/simplifiers/euf_completion.cpp | 98 ++++++++++++++++++++++---- src/ast/simplifiers/euf_completion.h | 4 ++ 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 7c27a01bb..bf3e4ce7a 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -58,22 +58,25 @@ namespace euf { } void completion::reduce() { - ++m_epoch; - add_egraph(); - map_canonical(); - read_egraph(); + do { + ++m_epoch; + m_has_new_eq = false; + add_egraph(); + map_canonical(); + read_egraph(); + } + while (m_has_new_eq); } void completion::add_egraph() { m_nodes.reset(); unsigned sz = m_fmls.size(); - expr* x, *y; for (unsigned i = m_qhead; i < sz; ++i) { auto [f,d] = m_fmls[i](); auto* n = mk_enode(f); - if (m.is_eq(f, x, y)) + if (m.is_eq(f)) m_egraph.merge(n->get_arg(0), n->get_arg(1), d); - if (m.is_not(f, x)) + if (m.is_not(f)) m_egraph.merge(n->get_arg(0), m_ff, d); else m_egraph.merge(n, m_tt, d); @@ -94,16 +97,39 @@ namespace euf { for (unsigned i = m_qhead; i < sz; ++i) { auto [f, d] = m_fmls[i](); + if (m.is_and(f)) + IF_VERBOSE(0, verbose_stream() << "is-and " << mk_bounded_pp(f, m) << "\n"); expr_dependency_ref dep(d, m); expr_ref g = canonize_fml(f, dep); if (g != f) { m_fmls.update(i, dependent_expr(m, g, dep)); m_stats.m_num_rewrites++; IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); + expr* x, * y; + if (m.is_eq(g, x, y) && find(x) != find(y)) + m_has_new_eq = true; + if (m.is_and(g) && !m_has_new_eq) + for (expr* arg : *to_app(g)) + if (m.is_eq(arg, x, y)) + m_has_new_eq |= find(x) != find(y); + else + m_has_new_eq = true; + if (m.is_and(g)) + IF_VERBOSE(0, verbose_stream() << mk_bounded_pp(g, m, 3) << "\n"); } CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } - advance_qhead(m_fmls.size()); + if (m_has_new_eq) + IF_VERBOSE(0, verbose_stream() << "new round\n"); + if (!m_has_new_eq) + advance_qhead(m_fmls.size()); + } + + enode* completion::find(expr* e) { + enode* r = m_egraph.find(e); + if (r) + return r; + return mk_enode(e); } enode* completion::mk_enode(expr* e) { @@ -139,23 +165,54 @@ namespace euf { expr_ref completion::canonize_fml(expr* f, expr_dependency_ref& d) { + auto is_nullary = [&](expr* e) { + return is_app(e) && to_app(e)->get_num_args() == 0; + }; expr* x, * y; if (m.is_eq(f, x, y)) { expr_ref x1 = canonize(x, d); expr_ref y1 = canonize(y, d); + if (is_nullary(x)) { + SASSERT(x1 == x); + x1 = get_canonical(x, d); + } + if (is_nullary(y)) { + SASSERT(y1 == y); + y1 = get_canonical(y, d); + } + + if (x == y) + return expr_ref(m.mk_true(), m); + if (x == x1 && y == y1) return expr_ref(f, m); + + if (is_nullary(x) && is_nullary(y)) + return mk_and(m_rewriter.mk_eq(x, x1), m_rewriter.mk_eq(y, x1)); + + if (x == x1 && is_nullary(x)) + return m_rewriter.mk_eq(y1, x1); + + if (y == y1 && is_nullary(y)) + return m_rewriter.mk_eq(x1, y1); + + if (is_nullary(x)) + return mk_and(m_rewriter.mk_eq(x, x1), m_rewriter.mk_eq(y1, x1)); + + if (is_nullary(y)) + return mk_and(m_rewriter.mk_eq(y, y1), m_rewriter.mk_eq(x1, y1)); + if (x1 == y1) return expr_ref(m.mk_true(), m); else { expr* c = get_canonical(x, d); if (c == x1) - return expr_ref(m.mk_eq(y1, c), m); + return m_rewriter.mk_eq(y1, c); else if (c == y1) - return expr_ref(m.mk_eq(x1, c), m); + return m_rewriter.mk_eq(x1, c); else - return expr_ref(m.mk_and(m.mk_eq(x1, c), m.mk_eq(y1, c)), m); + return mk_and(m_rewriter.mk_eq(x1, c), m_rewriter.mk_eq(y1, c)); } } @@ -167,6 +224,14 @@ namespace euf { return canonize(f, d); } + expr_ref completion::mk_and(expr* a, expr* b) { + if (m.is_true(a)) + return expr_ref(b, m); + if (m.is_true(b)) + return expr_ref(a, m); + return expr_ref(m.mk_and(a, b), m); + } + expr_ref completion::canonize(expr* f, expr_dependency_ref& d) { if (!is_app(f)) return expr_ref(f, m); // todo could normalize ground expressions under quantifiers @@ -188,7 +253,10 @@ namespace euf { enode* n = m_egraph.find(f); enode* r = n->get_root(); d = m.mk_join(d, explain_eq(n, r)); - d = m.mk_join(d, m_deps.get(r->get_id(), nullptr)); + d = m.mk_join(d, m_deps.get(r->get_id(), nullptr)); + if (!m_canonical.get(r->get_id())) + IF_VERBOSE(0, verbose_stream() << r->get_id() << " " << m_egraph.bpp(n) << " " << m_egraph.bpp(r) << "\n"); + SASSERT(m_canonical.get(r->get_id())); return m_canonical.get(r->get_id()); } @@ -214,6 +282,7 @@ namespace euf { old_value = nullptr; } }; + SASSERT(e); if (num_scopes() > 0) m_trail.push(vtrail(m_canonical, n->get_id())); m_canonical.setx(n->get_id(), e); @@ -263,6 +332,8 @@ namespace euf { rep = k; m_reps.setx(n->get_id(), rep, nullptr); + if (n->get_id() == 87507) + IF_VERBOSE(0, verbose_stream() << "set-canon " << n->get_id() << "\n"); TRACE("euf_completion", tout << "rep " << m_egraph.bpp(n) << " -> " << m_egraph.bpp(rep) << "\n"; for (enode* k : enode_class(n)) tout << m_egraph.bpp(k) << "\n";); m_todo.push_back(n->get_expr()); @@ -323,7 +394,8 @@ namespace euf { } } } - } + } + } diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h index 9e293ca0e..2cc0dcc58 100644 --- a/src/ast/simplifiers/euf_completion.h +++ b/src/ast/simplifiers/euf_completion.h @@ -40,10 +40,14 @@ namespace euf { unsigned_vector m_epochs; th_rewriter m_rewriter; stats m_stats; + bool m_has_new_eq = false; enode* mk_enode(expr* e); + enode* find(expr* e); + expr_ref mk_and(expr* a, expr* b); void add_egraph(); void map_canonical(); + void saturate(); void read_egraph(); expr_ref canonize(expr* f, expr_dependency_ref& dep); expr_ref canonize_fml(expr* f, expr_dependency_ref& dep); From 55ab7778f4b8e7653a0e9bb8d159962b70e9997a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Nov 2022 03:46:17 -0800 Subject: [PATCH 284/477] fix perf bug in new solve_eqs. --- src/ast/simplifiers/solve_context_eqs.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index 1ccab0f6c..dab09a7a9 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -150,13 +150,32 @@ namespace euf { for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) collect_nested_equalities(m_fmls[i], visited, eqs); + if (eqs.empty()) + return; + std::stable_sort(eqs.begin(), eqs.end(), [&](dependent_eq const& e1, dependent_eq const& e2) { return e1.var->get_id() < e2.var->get_id(); }); + + // quickly weed out variables that occur in more than two assertions. + unsigned_vector refcount; + { + expr_mark visited; + for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) { + visited.reset(); + expr* f = m_fmls[i].fml(); + for (expr* t : subterms::all(expr_ref(f, m), &m_todo, &visited)) + refcount.setx(t->get_id(), refcount.get(t->get_id(), 0) + 1, 0); + } + } + unsigned j = 0; expr* last_var = nullptr; bool was_unsafe = false; for (auto const& eq : eqs) { + if (refcount.get(eq.var->get_id(), 0) > 1) + continue; + SASSERT(!m.is_bool(eq.var)); From 98fc8c99db60f5ec8a79a4dbeaf029fca05befc3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Nov 2022 03:47:01 -0800 Subject: [PATCH 285/477] add shortcut to equality mk utility --- src/ast/rewriter/bool_rewriter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 84552282b..ffceec277 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -690,8 +690,10 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) app* bool_rewriter::mk_eq(expr* lhs, expr* rhs) { - // degrades simplification - // if (lhs->get_id() > rhs->get_id()) std::swap(lhs, rhs); + if (m().are_equal(lhs, rhs)) + return m().mk_true(); + if (m().are_distinct(lhs, rhs)) + return m().mk_false(); return m().mk_eq(lhs, rhs); } From 2c7799939e319ba48bc8e1d7a9d27d4bdbb13954 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Nov 2022 03:47:38 -0800 Subject: [PATCH 286/477] wip - tuning and fixes to euf-completion --- src/ast/simplifiers/euf_completion.cpp | 32 +++++++++++--------------- src/ast/simplifiers/euf_completion.h | 2 +- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index bf3e4ce7a..beaee4a27 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -74,8 +74,11 @@ namespace euf { for (unsigned i = m_qhead; i < sz; ++i) { auto [f,d] = m_fmls[i](); auto* n = mk_enode(f); - if (m.is_eq(f)) + if (m.is_eq(f)) { m_egraph.merge(n->get_arg(0), n->get_arg(1), d); + m_nodes.push_back(n->get_arg(0)); + m_nodes.push_back(n->get_arg(1)); + } if (m.is_not(f)) m_egraph.merge(n->get_arg(0), m_ff, d); else @@ -97,8 +100,6 @@ namespace euf { for (unsigned i = m_qhead; i < sz; ++i) { auto [f, d] = m_fmls[i](); - if (m.is_and(f)) - IF_VERBOSE(0, verbose_stream() << "is-and " << mk_bounded_pp(f, m) << "\n"); expr_dependency_ref dep(d, m); expr_ref g = canonize_fml(f, dep); if (g != f) { @@ -106,30 +107,25 @@ namespace euf { m_stats.m_num_rewrites++; IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); expr* x, * y; - if (m.is_eq(g, x, y) && find(x) != find(y)) + if (m.is_eq(g, x, y) && new_eq(x, y)) m_has_new_eq = true; if (m.is_and(g) && !m_has_new_eq) for (expr* arg : *to_app(g)) if (m.is_eq(arg, x, y)) - m_has_new_eq |= find(x) != find(y); - else + m_has_new_eq |= new_eq(x, y); + else if (!m.is_true(arg)) m_has_new_eq = true; - if (m.is_and(g)) - IF_VERBOSE(0, verbose_stream() << mk_bounded_pp(g, m, 3) << "\n"); } CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } - if (m_has_new_eq) - IF_VERBOSE(0, verbose_stream() << "new round\n"); if (!m_has_new_eq) advance_qhead(m_fmls.size()); } - enode* completion::find(expr* e) { - enode* r = m_egraph.find(e); - if (r) - return r; - return mk_enode(e); + bool completion::new_eq(expr* a, expr* b) { + enode* na = m_egraph.find(a); + enode* nb = m_egraph.find(b); + return !na || !nb || na->get_root() != nb->get_root(); } enode* completion::mk_enode(expr* e) { @@ -254,8 +250,6 @@ namespace euf { enode* r = n->get_root(); d = m.mk_join(d, explain_eq(n, r)); d = m.mk_join(d, m_deps.get(r->get_id(), nullptr)); - if (!m_canonical.get(r->get_id())) - IF_VERBOSE(0, verbose_stream() << r->get_id() << " " << m_egraph.bpp(n) << " " << m_egraph.bpp(r) << "\n"); SASSERT(m_canonical.get(r->get_id())); return m_canonical.get(r->get_id()); } @@ -320,6 +314,8 @@ namespace euf { void completion::map_canonical() { m_todo.reset(); enode_vector roots; + if (m_nodes.empty()) + return; for (unsigned i = 0; i < m_nodes.size(); ++i) { enode* n = m_nodes[i]->get_root(); if (n->is_marked1()) @@ -332,8 +328,6 @@ namespace euf { rep = k; m_reps.setx(n->get_id(), rep, nullptr); - if (n->get_id() == 87507) - IF_VERBOSE(0, verbose_stream() << "set-canon " << n->get_id() << "\n"); TRACE("euf_completion", tout << "rep " << m_egraph.bpp(n) << " -> " << m_egraph.bpp(rep) << "\n"; for (enode* k : enode_class(n)) tout << m_egraph.bpp(k) << "\n";); m_todo.push_back(n->get_expr()); diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h index 2cc0dcc58..b629399da 100644 --- a/src/ast/simplifiers/euf_completion.h +++ b/src/ast/simplifiers/euf_completion.h @@ -43,7 +43,7 @@ namespace euf { bool m_has_new_eq = false; enode* mk_enode(expr* e); - enode* find(expr* e); + bool new_eq(expr* a, expr* b); expr_ref mk_and(expr* a, expr* b); void add_egraph(); void map_canonical(); From 6662afdd2632cb2c2f313796fdd0746c28a7a9cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Nov 2022 22:15:02 -0800 Subject: [PATCH 287/477] perf improvements to solve-eqs and euf-completion --- src/ast/simplifiers/euf_completion.cpp | 70 ++++++++++++++++------- src/ast/simplifiers/euf_completion.h | 6 +- src/ast/simplifiers/solve_context_eqs.cpp | 54 ++++++++++++----- src/ast/simplifiers/solve_eqs.cpp | 50 ++++++++++++---- 4 files changed, 129 insertions(+), 51 deletions(-) diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index beaee4a27..9860b48b2 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -58,31 +58,43 @@ namespace euf { } void completion::reduce() { + unsigned rounds = 0; do { ++m_epoch; + ++rounds; m_has_new_eq = false; add_egraph(); map_canonical(); read_egraph(); + IF_VERBOSE(11, verbose_stream() << "(euf.completion :rounds " << rounds << ")\n"); } - while (m_has_new_eq); + while (m_has_new_eq && rounds <= 3); } void completion::add_egraph() { - m_nodes.reset(); + m_nodes_to_canonize.reset(); unsigned sz = m_fmls.size(); + auto add_children = [&](enode* n) { + for (auto* ch : enode_args(n)) + m_nodes_to_canonize.push_back(ch); + }; + for (unsigned i = m_qhead; i < sz; ++i) { auto [f,d] = m_fmls[i](); auto* n = mk_enode(f); if (m.is_eq(f)) { m_egraph.merge(n->get_arg(0), n->get_arg(1), d); - m_nodes.push_back(n->get_arg(0)); - m_nodes.push_back(n->get_arg(1)); + add_children(n->get_arg(0)); + add_children(n->get_arg(1)); } - if (m.is_not(f)) + if (m.is_not(f)) { m_egraph.merge(n->get_arg(0), m_ff, d); - else + add_children(n->get_arg(0)); + } + else { m_egraph.merge(n, m_tt, d); + add_children(n); + } } m_egraph.propagate(); } @@ -106,15 +118,7 @@ namespace euf { m_fmls.update(i, dependent_expr(m, g, dep)); m_stats.m_num_rewrites++; IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); - expr* x, * y; - if (m.is_eq(g, x, y) && new_eq(x, y)) - m_has_new_eq = true; - if (m.is_and(g) && !m_has_new_eq) - for (expr* arg : *to_app(g)) - if (m.is_eq(arg, x, y)) - m_has_new_eq |= new_eq(x, y); - else if (!m.is_true(arg)) - m_has_new_eq = true; + update_has_new_eq(g); } CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } @@ -122,12 +126,34 @@ namespace euf { advance_qhead(m_fmls.size()); } - bool completion::new_eq(expr* a, expr* b) { + bool completion::is_new_eq(expr* a, expr* b) { enode* na = m_egraph.find(a); enode* nb = m_egraph.find(b); + if (!na) + IF_VERBOSE(11, verbose_stream() << "not internalied " << mk_bounded_pp(a, m) << "\n"); + if (!nb) + IF_VERBOSE(11, verbose_stream() << "not internalied " << mk_bounded_pp(b, m) << "\n"); + if (na && nb && na->get_root() != nb->get_root()) + IF_VERBOSE(11, verbose_stream() << m_egraph.bpp(na) << " " << m_egraph.bpp(nb) << "\n"); return !na || !nb || na->get_root() != nb->get_root(); } + void completion::update_has_new_eq(expr* g) { + expr* x, * y; + if (m_has_new_eq) + return; + else if (m.is_eq(g, x, y)) + m_has_new_eq |= is_new_eq(x, y); + else if (m.is_and(g)) { + for (expr* arg : *to_app(g)) + update_has_new_eq(arg); + } + else if (m.is_not(g, g)) + m_has_new_eq |= is_new_eq(g, m.mk_false()); + else + m_has_new_eq |= is_new_eq(g, m.mk_true()); + } + enode* completion::mk_enode(expr* e) { m_todo.push_back(e); enode* n; @@ -138,7 +164,7 @@ namespace euf { continue; } if (!is_app(e)) { - m_nodes.push_back(m_egraph.mk(e, 0, 0, nullptr)); + m_nodes_to_canonize.push_back(m_egraph.mk(e, 0, 0, nullptr)); m_todo.pop_back(); continue; } @@ -152,7 +178,7 @@ namespace euf { m_todo.push_back(arg); } if (sz == m_todo.size()) { - m_nodes.push_back(m_egraph.mk(e, 0, m_args.size(), m_args.data())); + m_nodes_to_canonize.push_back(m_egraph.mk(e, 0, m_args.size(), m_args.data())); m_todo.pop_back(); } } @@ -314,10 +340,10 @@ namespace euf { void completion::map_canonical() { m_todo.reset(); enode_vector roots; - if (m_nodes.empty()) + if (m_nodes_to_canonize.empty()) return; - for (unsigned i = 0; i < m_nodes.size(); ++i) { - enode* n = m_nodes[i]->get_root(); + for (unsigned i = 0; i < m_nodes_to_canonize.size(); ++i) { + enode* n = m_nodes_to_canonize[i]->get_root(); if (n->is_marked1()) continue; n->mark1(); @@ -334,7 +360,7 @@ namespace euf { for (enode* arg : enode_args(n)) { arg = arg->get_root(); if (!arg->is_marked1()) - m_nodes.push_back(arg); + m_nodes_to_canonize.push_back(arg); } } for (enode* r : roots) diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h index b629399da..f02e33245 100644 --- a/src/ast/simplifiers/euf_completion.h +++ b/src/ast/simplifiers/euf_completion.h @@ -33,7 +33,7 @@ namespace euf { egraph m_egraph; enode* m_tt, *m_ff; ptr_vector m_todo; - enode_vector m_args, m_reps, m_nodes; + enode_vector m_args, m_reps, m_nodes_to_canonize; expr_ref_vector m_canonical, m_eargs; expr_dependency_ref_vector m_deps; unsigned m_epoch = 0; @@ -43,11 +43,11 @@ namespace euf { bool m_has_new_eq = false; enode* mk_enode(expr* e); - bool new_eq(expr* a, expr* b); + bool is_new_eq(expr* a, expr* b); + void update_has_new_eq(expr* g); expr_ref mk_and(expr* a, expr* b); void add_egraph(); void map_canonical(); - void saturate(); void read_egraph(); expr_ref canonize(expr* f, expr_dependency_ref& dep); expr_ref canonize_fml(expr* f, expr_dependency_ref& dep); diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index dab09a7a9..ef52d009c 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -147,7 +147,8 @@ namespace euf { void solve_context_eqs::collect_nested_equalities(dep_eq_vector& eqs) { expr_mark visited; - for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) + unsigned sz = m_fmls.size(); + for (unsigned i = m_solve_eqs.m_qhead; i < sz; ++i) collect_nested_equalities(m_fmls[i], visited, eqs); if (eqs.empty()) @@ -156,15 +157,37 @@ namespace euf { std::stable_sort(eqs.begin(), eqs.end(), [&](dependent_eq const& e1, dependent_eq const& e2) { return e1.var->get_id() < e2.var->get_id(); }); - // quickly weed out variables that occur in more than two assertions. - unsigned_vector refcount; + + // record the first and last occurrence of variables + // if the first and last occurrence coincide, the variable occurs in only one formula. + // otherwise it occurs in multiple formulas and should not be considered for solving. + unsigned_vector occurs1(m.get_num_asts() + 1, sz); + unsigned_vector occurs2(m.get_num_asts() + 1, sz); + + struct visitor { + unsigned_vector& occurrence; + unsigned i = 0; + unsigned sz = 0; + visitor(unsigned_vector& occurrence) : occurrence(occurrence), i(0), sz(0) {} + void operator()(expr* t) { + occurrence.setx(t->get_id(), i, sz); + } + }; + { - expr_mark visited; - for (unsigned i = m_solve_eqs.m_qhead; i < m_fmls.size(); ++i) { - visited.reset(); - expr* f = m_fmls[i].fml(); - for (expr* t : subterms::all(expr_ref(f, m), &m_todo, &visited)) - refcount.setx(t->get_id(), refcount.get(t->get_id(), 0) + 1, 0); + visitor visitor1(occurs1); + visitor visitor2(occurs2); + visitor1.sz = sz; + visitor2.sz = sz; + expr_fast_mark1 fast_visited; + for (unsigned i = 0; i < sz; ++i) { + visitor1.i = i; + quick_for_each_expr(visitor1, fast_visited, m_fmls[i].fml()); + } + fast_visited.reset(); + for (unsigned i = sz; i-- > 0; ) { + visitor2.i = i; + quick_for_each_expr(visitor2, fast_visited, m_fmls[i].fml()); } } @@ -172,13 +195,17 @@ namespace euf { expr* last_var = nullptr; bool was_unsafe = false; for (auto const& eq : eqs) { - - if (refcount.get(eq.var->get_id(), 0) > 1) + if (!eq.var) + continue; + unsigned occ1 = occurs1.get(eq.var->get_id(), sz); + unsigned occ2 = occurs2.get(eq.var->get_id(), sz); + if (occ1 >= sz) + continue; + if (occ1 != occ2) continue; SASSERT(!m.is_bool(eq.var)); - if (eq.var != last_var) { m_contains_v.reset(); @@ -195,8 +222,7 @@ namespace euf { } // then mark occurrences - for (unsigned i = 0; i < m_fmls.size(); ++i) - m_todo.push_back(m_fmls[i].fml()); + m_todo.push_back(m_fmls[occ1].fml()); mark_occurs(m_todo, eq.var, m_contains_v); SASSERT(m_todo.empty()); } diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 0b6f12160..f66f64b6d 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -75,13 +75,6 @@ namespace euf { return m_id2level[id] != UINT_MAX; }; - auto is_safe = [&](unsigned lvl, expr* t) { - for (auto* e : subterms::all(expr_ref(t, m), &m_todo, &m_visited)) - if (is_var(e) && m_id2level[var2id(e)] < lvl) - return false; - return true; - }; - unsigned init_level = UINT_MAX; unsigned_vector todo; @@ -94,26 +87,59 @@ namespace euf { init_level -= m_id2var.size() + 1; unsigned curr_level = init_level; todo.push_back(id); + while (!todo.empty()) { unsigned j = todo.back(); todo.pop_back(); if (is_explored(j)) continue; m_id2level[j] = curr_level++; + for (auto const& eq : m_next[j]) { auto const& [orig, v, t, d] = eq; SASSERT(j == var2id(v)); - if (!is_safe(curr_level, t)) + bool is_safe = true; + unsigned todo_sz = todo.size(); + + // determine if substitution is safe. + // all time-stamps must be at or above current level + // unexplored variables that are part of substitution are appended to work list. + SASSERT(m_todo.empty()); + m_todo.push_back(t); + expr_fast_mark1 visited; + while (!m_todo.empty()) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (visited.is_marked(e)) + continue; + visited.mark(e, true); + if (is_app(e)) { + for (expr* arg : *to_app(e)) + m_todo.push_back(arg); + } + else if (is_quantifier(e)) + m_todo.push_back(to_quantifier(e)->get_expr()); + if (!is_var(e)) + continue; + if (m_id2level[var2id(e)] < curr_level) { + is_safe = false; + break; + } + if (!is_explored(var2id(e))) + todo.push_back(var2id(e)); + } + m_todo.reset(); + + if (!is_safe) { + todo.shrink(todo_sz); continue; + } SASSERT(!occurs(v, t)); m_next[j][0] = eq; m_subst_ids.push_back(j); - for (expr* e : subterms::all(expr_ref(t, m), &m_todo, &m_visited)) - if (is_var(e) && !is_explored(var2id(e))) - todo.push_back(var2id(e)); break; } - } + } } } From 59b7845c7dc765a9c19074c43d288daccd753d68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Nov 2022 17:36:21 +0900 Subject: [PATCH 288/477] reset visited (fast mark) to not clash with occurs --- src/ast/euf/euf_egraph.cpp | 6 +++--- src/ast/euf/euf_egraph.h | 2 +- src/ast/simplifiers/euf_completion.cpp | 22 +++++++++++++--------- src/ast/simplifiers/solve_eqs.cpp | 3 ++- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index c8605b297..666a7fad6 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -451,7 +451,7 @@ namespace euf { add_literal(n1, false); if (n1->is_equality() && n1->value() == l_false) new_diseq(n1); - remove_parents(r1, r2); + remove_parents(r1); push_eq(r1, n1, r2->num_parents()); merge_justification(n1, n2, j); for (enode* c : enode_class(n1)) @@ -464,8 +464,8 @@ namespace euf { cb(r2, r1); } - void egraph::remove_parents(enode* r1, enode* r2) { - for (enode* p : enode_parents(r1)) { + void egraph::remove_parents(enode* r) { + for (enode* p : enode_parents(r)) { if (p->is_marked1()) continue; if (p->merge_enabled()) { diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index 53aaf481a..d6bcb9cd3 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -220,7 +220,7 @@ namespace euf { void merge_th_eq(enode* n, enode* root); void merge_justification(enode* n1, enode* n2, justification j); void reinsert_parents(enode* r1, enode* r2); - void remove_parents(enode* r1, enode* r2); + void remove_parents(enode* r); void unmerge_justification(enode* n1); void reinsert_equality(enode* p); void update_children(enode* n); diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 9860b48b2..ac1ecc47a 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -80,18 +80,22 @@ namespace euf { }; for (unsigned i = m_qhead; i < sz; ++i) { - auto [f,d] = m_fmls[i](); - auto* n = mk_enode(f); - if (m.is_eq(f)) { - m_egraph.merge(n->get_arg(0), n->get_arg(1), d); - add_children(n->get_arg(0)); - add_children(n->get_arg(1)); + expr* x, * y; + auto [f, d] = m_fmls[i](); + if (m.is_eq(f, x, y)) { + enode* a = mk_enode(x); + enode* b = mk_enode(y); + m_egraph.merge(a, b, d); + add_children(a); + add_children(b); } - if (m.is_not(f)) { - m_egraph.merge(n->get_arg(0), m_ff, d); - add_children(n->get_arg(0)); + else if (m.is_not(f, f)) { + enode* n = mk_enode(f); + m_egraph.merge(n, m_ff, d); + add_children(n); } else { + enode* n = mk_enode(f); m_egraph.merge(n, m_tt, d); add_children(n); } diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index f66f64b6d..5090e1b43 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -129,7 +129,8 @@ namespace euf { todo.push_back(var2id(e)); } m_todo.reset(); - + visited.reset(); + if (!is_safe) { todo.shrink(todo_sz); continue; From 7da91f4313980aebd98c21146962ef77cbd5a713 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:43:21 +0700 Subject: [PATCH 289/477] allow printing declarations with reverse variable order --- src/ast/ast_smt2_pp.cpp | 35 ++++++++++++++++++++--------------- src/ast/ast_smt2_pp.h | 2 +- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 6ed647a27..927660fbe 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -561,15 +561,18 @@ class smt2_printer { void pp_var(var * v) { format * f; - if (v->get_idx() < m_var_names.size()) { - symbol s = m_var_names[m_var_names.size() - v->get_idx() - 1]; + unsigned idx = v->get_idx(); + if (idx < m_var_names.size()) { + symbol s; + if (m_reverse && idx < m_arity) + s = m_var_names[m_var_names.size() - m_arity + idx]; + else + s = m_var_names[m_var_names.size() - idx - 1]; std::string vname; - if (is_smt2_quoted_symbol (s)) { - vname = mk_smt2_quoted_symbol (s); - } - else { - vname = s.str(); - } + if (is_smt2_quoted_symbol (s)) + vname = mk_smt2_quoted_symbol (s); + else + vname = s.str(); f = mk_string(m(), vname); } else { @@ -1139,9 +1142,13 @@ public: r = mk_seq1(m(), args, args+3, f2f(), cmd); } + bool m_reverse = false; + unsigned m_arity = 0; - void operator()(func_decl * f, expr * e, format_ref & r, char const* cmd) { + void operator()(func_decl * f, expr * e, format_ref & r, char const* cmd, bool reverse) { unsigned len; + flet _reverse(m_reverse, reverse); + m_arity = f->get_arity(); format * fname = m_env.pp_fdecl_name(f, len); register_var_names(f->get_arity()); format * args[4]; @@ -1202,9 +1209,9 @@ void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & pr(f, r, cmd); } -void mk_smt2_format(func_decl * f, expr * e, smt2_pp_environment & env, params_ref const & p, format_ref & r, char const* cmd) { +void mk_smt2_format(func_decl * f, expr * e, smt2_pp_environment & env, params_ref const & p, format_ref & r, char const* cmd, bool reverse) { smt2_printer pr(env, p); - pr(f, e, r, cmd); + pr(f, e, r, cmd, reverse); } void mk_smt2_format(unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p, @@ -1251,7 +1258,6 @@ std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environmen if (!f) return out << "null"; ast_manager & m = env.get_manager(); format_ref r(fm(m)); - sbuffer var_names; mk_smt2_format(f, env, p, r, cmd); if (indent > 0) r = mk_indent(m, indent, r.get()); @@ -1259,12 +1265,11 @@ std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environmen return out; } -std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p, unsigned indent, char const* cmd) { +std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p, unsigned indent, char const* cmd, bool reverse) { if (!f) return out << "null"; ast_manager & m = env.get_manager(); format_ref r(fm(m)); - sbuffer var_names; - mk_smt2_format(f, e, env, p, r, cmd); + mk_smt2_format(f, e, env, p, r, cmd, reverse); if (indent > 0) r = mk_indent(m, indent, r.get()); pp(out, r.get(), m, p); diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 47649b9b2..2b0b2f371 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -104,7 +104,7 @@ std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & e unsigned num_vars = 0, char const * var_prefix = nullptr); std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0); std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "declare-fun"); -std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "define-fun"); +std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "define-fun", bool reverse = false); std::ostream & ast_smt2_pp(std::ostream & out, symbol const& s, bool is_skolem, smt2_pp_environment & env, params_ref const& p = params_ref()); std::ostream & ast_smt2_pp_recdefs(std::ostream & out, vector> const& funs, smt2_pp_environment & env, params_ref const & p = params_ref()); From ba68652c72d5b61157b87d88dadee2948397e343 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:43:46 +0700 Subject: [PATCH 290/477] add destructive equality resolution to existentials --- src/ast/rewriter/der.cpp | 89 ++++++++++++++++++++++++++++++---------- src/ast/rewriter/der.h | 6 ++- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp index 93b7c6226..fd79529f9 100644 --- a/src/ast/rewriter/der.cpp +++ b/src/ast/rewriter/der.cpp @@ -81,14 +81,54 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) { } // VAR - if (is_var(e, num_decls)) { + if (is_var(e, num_decls)) return set_result(to_var(e), m.mk_false()); - } + // (not VAR) - if (is_neg_var(m, e, v, num_decls)) { + if (is_neg_var(m, e, v, num_decls)) return set_result(v, m.mk_true()); + + return false; +} + +bool der::is_var_eq(expr* e, unsigned num_decls, var*& v, expr_ref& t) { + expr* lhs, * rhs; + auto set_result = [&](var* w, expr* s) { + v = w; + t = s; + TRACE("der", tout << mk_pp(e, m) << "\n";); + return true; + }; + + // (= VAR t) + if (m.is_eq(e, lhs, rhs)) { + if (!is_var(lhs, num_decls)) + std::swap(lhs, rhs); + if (!is_var(lhs, num_decls)) + return false; + return set_result(to_var(lhs), rhs); } + + if (m.is_eq(e, lhs, rhs) && m.is_bool(lhs)) { + // (iff VAR t) case + if (!is_var(lhs, num_decls)) + std::swap(lhs, rhs); + if (is_var(lhs, num_decls)) { + m_new_exprs.push_back(rhs); + return set_result(to_var(lhs), rhs); + } + return false; + } + + // VAR + if (is_var(e, num_decls)) + return set_result(to_var(e), m.mk_true()); + + // (not VAR) + if (is_neg_var(m, e, v, num_decls)) + return set_result(v, m.mk_false()); + return false; } @@ -99,6 +139,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) { TRACE("der", tout << mk_pp(q, m) << "\n";); + auto k = q->get_kind(); // Keep applying it until r doesn't change anymore do { proof_ref curr_pr(m); @@ -106,14 +147,13 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) { reduce1(q, r, curr_pr); if (q != r) reduced = true; - if (m.proofs_enabled()) { - pr = m.mk_transitivity(pr, curr_pr); - } + if (m.proofs_enabled()) + pr = m.mk_transitivity(pr, curr_pr); } while (q != r && is_quantifier(r)); // Eliminate variables that have become unused - if (reduced && is_forall(r)) { + if (reduced && is_quantifier(r) && k == to_quantifier(r)->get_kind()) { quantifier * q = to_quantifier(r); r = elim_unused_vars(m, q, params_ref()); if (m.proofs_enabled()) { @@ -125,7 +165,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) { } void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { - if (!is_forall(q)) { + if (!is_forall(q) && !is_exists(q)) { pr = nullptr; r = q; return; @@ -136,14 +176,20 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { var * v = nullptr; expr_ref t(m); - if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t)) + if (is_forall(q) && is_var_diseq(e, num_decls, v, t) && !occurs(v, t)) r = m.mk_false(); + else if (is_exists(q) && is_var_eq(e, num_decls, v, t) && !occurs(v, t)) + r = m.mk_true(); else { - expr_ref_vector ors(m); - flatten_or(e, ors); - unsigned num_args = ors.size(); + expr_ref_vector literals(m); + if (is_forall(q)) + flatten_or(e, literals); + else + flatten_and(e, literals); + unsigned num_args = literals.size(); unsigned diseq_count = 0; unsigned largest_vinx = 0; + bool is_eq = false; m_map.reset(); m_pos2var.reset(); @@ -153,7 +199,8 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { // Find all disequalities for (unsigned i = 0; i < num_args; i++) { - if (is_var_diseq(ors.get(i), num_decls, v, t)) { + is_eq = is_forall(q) ? is_var_diseq(literals.get(i), num_decls, v, t) : is_var_eq(literals.get(i), num_decls, v, t); + if (is_eq) { unsigned idx = v->get_idx(); if (m_map.get(idx, nullptr) == nullptr) { m_map.reserve(idx + 1); @@ -174,7 +221,7 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { if (!m_order.empty()) { create_substitution(largest_vinx + 1); - apply_substitution(q, ors, r); + apply_substitution(q, literals, is_forall(q), r); } } else { @@ -185,9 +232,9 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { // Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses. // So, we must perform a occurs check here. - if (m.proofs_enabled()) { + if (m.proofs_enabled()) pr = r == q ? nullptr : m.mk_der(q, r); - } + } static void der_sort_vars(ptr_vector & vars, expr_ref_vector & definitions, unsigned_vector & order) { @@ -326,20 +373,20 @@ void der::create_substitution(unsigned sz) { } } -void der::apply_substitution(quantifier * q, expr_ref_vector& ors, expr_ref & r) { - unsigned num_args = ors.size(); +void der::apply_substitution(quantifier * q, expr_ref_vector& literals, bool is_or, expr_ref & r) { + unsigned num_args = literals.size(); // get a new expression m_new_args.reset(); - for(unsigned i = 0; i < num_args; i++) { + for (unsigned i = 0; i < num_args; i++) { int x = m_pos2var[i]; if (x != -1 && m_map.get(x) != nullptr) continue; // this is a disequality with definition (vanishes) - m_new_args.push_back(ors.get(i)); + m_new_args.push_back(literals.get(i)); } - expr_ref t(mk_or(m, m_new_args.size(), m_new_args.data()), m); + expr_ref t(is_or ? mk_or(m_new_args) : mk_and(m_new_args), m); expr_ref new_e = m_subst(t, m_subst_map); // don't forget to update the quantifier patterns diff --git a/src/ast/rewriter/der.h b/src/ast/rewriter/der.h index ec45994a9..bd21e54d0 100644 --- a/src/ast/rewriter/der.h +++ b/src/ast/rewriter/der.h @@ -131,7 +131,7 @@ class der { ptr_vector m_inx2var; unsigned_vector m_order; expr_ref_vector m_subst_map; - expr_ref_buffer m_new_args; + expr_ref_vector m_new_args; /** \brief Return true if e can be viewed as a variable disequality. @@ -145,9 +145,11 @@ class der { */ bool is_var_diseq(expr * e, unsigned num_decls, var *& v, expr_ref & t); + bool is_var_eq(expr* e, unsigned num_decls, var*& v, expr_ref& t); + void get_elimination_order(); void create_substitution(unsigned sz); - void apply_substitution(quantifier * q, expr_ref_vector& ors, expr_ref & r); + void apply_substitution(quantifier * q, expr_ref_vector& lits, bool is_or, expr_ref & r); void reduce1(quantifier * q, expr_ref & r, proof_ref & pr); From c2e9016d04b67cd9d33bb72be59960ccf0f4aa06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:44:52 +0700 Subject: [PATCH 291/477] display model-add parameters in correct order --- src/ast/converters/model_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/converters/model_converter.cpp b/src/ast/converters/model_converter.cpp index bba18ecd6..1033cc57b 100644 --- a/src/ast/converters/model_converter.cpp +++ b/src/ast/converters/model_converter.cpp @@ -26,7 +26,7 @@ Notes: void model_converter::display_add(std::ostream& out, smt2_pp_environment& env, ast_manager& m, func_decl* f, expr* e) { VERIFY(e); VERIFY(f->get_range() == e->get_sort()); - ast_smt2_pp(out, f, e, env, params_ref(), 0, "model-add") << "\n"; + ast_smt2_pp(out, f, e, env, params_ref(), 0, "model-add", true) << "\n"; } void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { From 41b40c3a51d1239d08698d0f8fd05a2d740e97c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:45:07 +0700 Subject: [PATCH 292/477] remove dead code --- src/ast/macros/macro_manager.cpp | 6 ------ src/ast/macros/macro_manager.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 032c724e1..bbe7f245c 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -175,12 +175,6 @@ namespace macro_manager_ns { /** \brief Mark all func_decls used in exprs as forbidden. */ -void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) { - expr_mark visited; - macro_manager_ns::proc p(m_forbidden_set, m_forbidden); - for (unsigned i = 0; i < n; i++) - for_each_expr(p, visited, exprs[i]); -} void macro_manager::mark_forbidden(unsigned n, justified_expr const * exprs) { expr_mark visited; diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index 57583b67b..a3c1a8d97 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -73,9 +73,7 @@ public: void push_scope(); void pop_scope(unsigned num_scopes); void reset(); - void mark_forbidden(unsigned n, expr * const * exprs); void mark_forbidden(unsigned n, justified_expr const * exprs); - void mark_forbidden(expr * e) { mark_forbidden(1, &e); } bool is_forbidden(func_decl * d) const { return m_forbidden_set.contains(d); } obj_hashtable const & get_forbidden_set() const { return m_forbidden_set; } void display(std::ostream & out); From dcc995f0e502b103ccb3f15b4012c0d6f2a8da4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:45:54 +0700 Subject: [PATCH 293/477] code simplification --- src/ast/converters/expr_inverter.cpp | 2 +- src/tactic/core/elim_uncnstr_tactic.cpp | 2 +- src/tactic/core/reduce_args_tactic.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 2c4c960a7..2874abd68 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -740,7 +740,7 @@ void iexpr_inverter::add_def(expr * v, expr * def) { return; SASSERT(uncnstr(v)); SASSERT(to_app(v)->get_num_args() == 0); - m_mc->add(to_app(v)->get_decl(), def); + m_mc->add(v, def); } void iexpr_inverter::add_defs(unsigned num, expr* const* args, expr* u, expr* identity) { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 60bdd2710..ed54b6768 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -121,7 +121,7 @@ class elim_uncnstr_tactic : public tactic { SASSERT(uncnstr(v)); SASSERT(to_app(v)->get_num_args() == 0); if (m_mc) - m_mc->add(to_app(v)->get_decl(), def); + m_mc->add(v, def); } void add_defs(unsigned num, expr * const * args, expr * u, expr * identity) { diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index b2a10fafa..785409e27 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -414,7 +414,7 @@ struct reduce_args_tactic::imp { for (auto const& [t, new_def] : *map) { f_mc->hide(new_def); SASSERT(new_def->get_arity() == new_args.size()); - app * new_t = m.mk_app(new_def, new_args.size(), new_args.data()); + app * new_t = m.mk_app(new_def, new_args); if (def == nullptr) { def = new_t; } @@ -429,7 +429,7 @@ struct reduce_args_tactic::imp { if (new_eqs.size() == 1) cond = new_eqs[0]; else - cond = m.mk_and(new_eqs.size(), new_eqs.data()); + cond = m.mk_and(new_eqs); def = m.mk_ite(cond, new_t, def); } } From a81a5ec68c6479155a7fe82bba27b74765342e1c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:46:31 +0700 Subject: [PATCH 294/477] add virtual function requirement to dependent_expr_state --- src/ast/simplifiers/dependent_expr_state.h | 1 + src/tactic/dependent_expr_state_tactic.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index fa4bbdd49..b94b422ad 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -46,6 +46,7 @@ public: virtual unsigned size() const = 0; virtual dependent_expr const& operator[](unsigned i) = 0; virtual void update(unsigned i, dependent_expr const& j) = 0; + virtual void add(dependent_expr const& j) = 0; virtual bool inconsistent() = 0; virtual model_reconstruction_trail& model_trail() = 0; diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index d3f77b773..efe28c30d 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -60,10 +60,16 @@ public: m_dep = dependent_expr(m, m_goal->form(i), m_goal->dep(i)); return m_dep; } + void update(unsigned i, dependent_expr const& j) override { auto [f, d] = j(); m_goal->update(i, f, nullptr, d); } + + void add(dependent_expr const& j) override { + auto [f, d] = j(); + m_goal->assert_expr(f, nullptr, d); + } bool inconsistent() override { return m_goal->inconsistent(); From d735faae4eaeb981694b8bf0229374a85f016305 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:50:37 +0700 Subject: [PATCH 295/477] add isolated hide/add model converter functions --- .../model_reconstruction_trail.cpp | 47 +++++-------------- .../simplifiers/model_reconstruction_trail.h | 33 ++++++++++--- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index a5f1cf8b0..55d04621f 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -30,8 +30,9 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorm_active) continue; - if (t->m_hide) + if (t->is_hide()) continue; + // updates that have no intersections with current variables are skipped if (!t->intersects(free_vars)) @@ -48,6 +49,9 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectoris_def()) + NOT_IMPLEMENTED_YET(); + rp->set_substitution(t->m_subst.get()); // rigid entries: // apply substitution to added in case of rigid model convertions @@ -63,48 +67,23 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vector rp = mk_default_expr_replacer(m, false); expr_substitution subst(m, true, false); rp->set_substitution(&subst); generic_model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); - bool first = true; - for (unsigned i = m_trail.size(); i-- > 0; ) { + for (unsigned i = 0; i < m_trail.size(); ++i) { auto* t = m_trail[i]; if (!t->m_active) continue; - - if (t->m_hide) { - mc->hide(t->m_hide); - continue; - } - - if (first) { - first = false; - for (auto const& [v, def] : t->m_subst->sub()) { - expr_dependency* dep = t->m_subst->dep(v); - subst.insert(v, def, dep); + else if (t->is_hide()) + mc->hide(t->m_decl); + else if (t->is_def()) + mc->add(t->m_decl, t->m_def); + else { + for (auto const& [v, def] : t->m_subst->sub()) mc->add(v, def); - } - continue; - } - - for (auto const& [v, def] : t->m_subst->sub()) { - auto [new_def, new_dep] = rp->replace_with_dep(def); - expr_dependency* dep = t->m_subst->dep(v); - new_dep = m.mk_join(dep, new_dep); - subst.insert(v, new_def, new_dep); - mc->add(v, new_def); - } - + } } return model_converter_ref(mc.get()); diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index eeef136ee..2ff11227e 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -35,22 +35,35 @@ class model_reconstruction_trail { struct entry { scoped_ptr m_subst; vector m_removed; - func_decl* m_hide = nullptr; + func_decl_ref m_decl; + expr_ref m_def; bool m_active = true; - entry(expr_substitution* s, vector const& rem) : - m_subst(s), m_removed(rem) {} - entry(func_decl* h) : m_hide(h) {} + entry(ast_manager& m, expr_substitution* s, vector const& rem) : + m_subst(s), m_removed(rem), m_decl(m), m_def(m) {} + + entry(ast_manager& m, func_decl* h) : m_decl(h, m), m_def(m) {} + + entry(ast_manager& m, func_decl* f, expr* def, vector const& rem) : + m_decl(f, m), m_def(def, m), m_removed(rem) {} bool is_loose() const { return !m_removed.empty(); } bool intersects(ast_mark const& free_vars) const { + if (is_hide()) + return false; + if (is_def()) + return free_vars.is_marked(m_decl); for (auto const& [k, v] : m_subst->sub()) if (free_vars.is_marked(k)) return true; return false; } + + bool is_hide() const { return m_decl && !m_def; } + bool is_def() const { return m_decl && m_def; } + bool is_subst() const { return !m_decl; } }; ast_manager& m; @@ -81,7 +94,7 @@ public: * add a new substitution to the trail */ void push(expr_substitution* s, vector const& removed) { - m_trail.push_back(alloc(entry, s, removed)); + m_trail.push_back(alloc(entry, m, s, removed)); m_trail_stack.push(push_back_vector(m_trail)); } @@ -89,7 +102,15 @@ public: * add declaration to hide */ void push(func_decl* f) { - m_trail.push_back(alloc(entry, f)); + m_trail.push_back(alloc(entry, m, f)); + m_trail_stack.push(push_back_vector(m_trail)); + } + + /** + * add definition + */ + void push(func_decl* f, expr* def, vector const& removed) { + m_trail.push_back(alloc(entry, m, f, def, removed)); m_trail_stack.push(push_back_vector(m_trail)); } From 771157696b451ded4040de9ab42467dc483f8445 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:51:20 +0700 Subject: [PATCH 296/477] new simplifier/tactic eliminate_predicates finds macros and eliminates predicates from formulas as pre-processing. --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/eliminate_predicates.cpp | 664 ++++++++++++++++++ src/ast/simplifiers/eliminate_predicates.h | 143 ++++ src/tactic/core/CMakeLists.txt | 1 + src/tactic/core/eliminate_predicates_tactic.h | 40 ++ 5 files changed, 849 insertions(+) create mode 100644 src/ast/simplifiers/eliminate_predicates.cpp create mode 100644 src/ast/simplifiers/eliminate_predicates.h create mode 100644 src/tactic/core/eliminate_predicates_tactic.h diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index 75aa1ec7a..b636b8b42 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -2,6 +2,7 @@ z3_add_component(simplifiers SOURCES bv_slice.cpp elim_unconstrained.cpp + eliminate_predicates.cpp euf_completion.cpp extract_eqs.cpp model_reconstruction_trail.cpp diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp new file mode 100644 index 000000000..57fe4b4f0 --- /dev/null +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -0,0 +1,664 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + eliminate_predicates.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-17. + +Notes: + +The simplifier +- detects macros of the form p(x) = q(x) + - other more general macro detection is TBD. + For example {~p, a} {~p, b} {p, ~a, ~b} {p, C} {~p, D} defines p as a conjunction + and we can obbtain {a, C}, {b, C} {~a, ~b, D } similar to propositional case. + Instead the case is handled by predicate elimination when p only occurs positively + outside of {~p, a} {~p, b} {p, ~a, ~b} + - other SMT-based macro detection could be made here as well. + The (legacy) macro finder is not very flexible and could be replaced + by a module building on this one. +- eliminates predicates p(x) that occur at most once in each clause and the + number of occurrences is small. + +Two sets of disabled functions are tracked: + +forbidden from macros vs forbidden from elimination + - forbidden from macros: uninterpreted functions in recursive definitions + predicates before m_qhead + arguments to as-array + - forbidden from elimination: + - forbidden from macros, + - occurs more than once in some clause, or in nested occurrence. + +--*/ + + +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_util.h" +#include "ast/for_each_ast.h" +#include "ast/recfun_decl_plugin.h" +#include "ast/occurs.h" +#include "ast/array_decl_plugin.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/simplifiers/eliminate_predicates.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/macros/macro_util.h" + + +/** +* Rewriting formulas using macro definitions. +*/ +struct eliminate_predicates::macro_expander_cfg : public default_rewriter_cfg { + ast_manager& m; + eliminate_predicates& ep; + expr_dependency_ref& m_used_macro_dependencies; + expr_ref_vector m_trail; + + macro_expander_cfg(ast_manager& m, eliminate_predicates& ep, expr_dependency_ref& deps) : + m(m), + ep(ep), + m_used_macro_dependencies(deps), + m_trail(m) + {} + + bool rewrite_patterns() const { return false; } + bool flat_assoc(func_decl* f) const { return false; } + br_status reduce_app(func_decl* f, unsigned num, expr* const* args, expr_ref& result, proof_ref& result_pr) { + result_pr = nullptr; + return BR_FAILED; + } + + /** + * adapted from macro_manager.cpp + */ + bool reduce_quantifier(quantifier* old_q, + expr* new_body, + expr* const* new_patterns, + expr* const* new_no_patterns, + expr_ref& result, + proof_ref& result_pr) { + + bool erase_patterns = false; + for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++) + if (old_q->get_pattern(i) != new_patterns[i]) + erase_patterns = true; + + for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++) + if (old_q->get_no_pattern(i) != new_no_patterns[i]) + erase_patterns = true; + + if (erase_patterns) + result = m.update_quantifier(old_q, 0, nullptr, 0, nullptr, new_body); + + if (erase_patterns && m.proofs_enabled()) + result_pr = m.mk_rewrite(old_q, result); + + return erase_patterns; + } + + bool get_subst(expr* _n, expr*& r, proof*& p) { + if (!is_app(_n)) + return false; + p = nullptr; + app* n = to_app(_n); + quantifier* q = nullptr; + func_decl* d = n->get_decl(), * d2 = nullptr; + app_ref head(m); + expr_ref def(m); + expr_dependency_ref dep(m); + if (ep.has_macro(d, head, def, dep)) { + unsigned num = head->get_num_args(); + ptr_buffer subst_args; + subst_args.resize(num, 0); + // TODO: we can exploit that variables occur in "non-standard" order + // that is in order (:var 0) (:var 1) (:var 2) + // then substitution just takes n->get_args() instead of this renaming. + for (unsigned i = 0; i < num; i++) { + var* v = to_var(head->get_arg(i)); + VERIFY(v->get_idx() < num); + unsigned nidx = num - v->get_idx() - 1; + SASSERT(subst_args[nidx] == 0); + subst_args[nidx] = n->get_arg(i); + } + var_subst s(m); + expr_ref rr = s(def, num, subst_args.data()); + r = rr; + m_trail.push_back(rr); + m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, dep); + return true; + } + + return false; + } +}; + +struct eliminate_predicates::macro_expander_rw : public rewriter_tpl { + eliminate_predicates::macro_expander_cfg m_cfg; + + macro_expander_rw(ast_manager& m, eliminate_predicates& ep, expr_dependency_ref& deps) : + rewriter_tpl(m, false, m_cfg), + m_cfg(m, ep, deps) + {} +}; + + +std::ostream& eliminate_predicates::clause::display(std::ostream& out) const { + ast_manager& m = m_dep.get_manager(); + for (sort* s : m_bound) + out << mk_pp(s, m) << " "; + for (auto const& [atom, sign] : m_literals) + out << (sign ? "~" : "") << mk_bounded_pp(atom, m) << " "; + return out; +} + +eliminate_predicates::eliminate_predicates(ast_manager& m, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), m_der(m), m_rewriter(m) {} + + +void eliminate_predicates::add_use_list(clause& cl) { + ast_mark seen; + for (auto const& [atom, sign] : cl.m_literals) { + if (!is_uninterp(atom)) { + m_to_exclude.push_back(atom); + continue; + } + + func_decl* p = to_app(atom)->get_decl(); + m_use_list.get(p, sign).push_back(&cl); + + if (!m_predicate_decls.is_marked(p)) { + m_predicates.push_back(p); + m_predicate_decls.mark(p, true); + } + if (seen.is_marked(p)) + m_to_exclude.push_back(atom); + else { + seen.mark(p, true); + m_to_exclude.append(to_app(atom)->get_num_args(), to_app(atom)->get_args()); + } + } +} + +/** +* cheap/simplistic heuristic to find definitions that are based on binary clauses +* (or (head x) (not (def x)) +* (or (not (head x)) (def x)) +*/ +bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep) { + if (m_disable_macro.is_marked(p)) + return false; + expr_mark binary_pos, binary_neg; + macro_util mutil(m); + obj_map deps; + auto is_def_predicate = [&](expr* atom) { + return is_app(atom) && to_app(atom)->get_decl() == p && mutil.is_macro_head(atom, p->get_arity()); + }; + auto add_def = [&](clause& cl, expr* atom1, bool sign1, expr* atom2, bool sign2) { + if (is_def_predicate(atom1) && !sign1) { + if (sign2) + binary_neg.mark(atom2); + else + binary_pos.mark(atom2); + if (cl.m_dep) + deps.insert(atom1, cl.m_dep); + } + }; + + for (auto* cl : m_use_list.get(p, false)) { + if (cl->m_alive && cl->m_literals.size() == 2) { + auto const& [atom1, sign1] = cl->m_literals[0]; + auto const& [atom2, sign2] = cl->m_literals[1]; + add_def(*cl, atom1, sign1, atom2, sign2); + add_def(*cl, atom2, sign2, atom1, sign1); + } + } + + auto is_def = [&](unsigned i, unsigned j, clause& cl) { + auto const& [atom1, sign1] = cl.m_literals[i]; + auto const& [atom2, sign2] = cl.m_literals[j]; + expr_dependency* d = nullptr; + if (is_def_predicate(atom1) && sign1) { + if (sign2 && binary_pos.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) { + head = to_app(atom1); + def = m.mk_not(atom2); + dep = cl.m_dep; + if (deps.find(atom1, d)) + dep = m.mk_join(dep, d); + return true; + } + if (!sign2 && binary_neg.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) { + head = to_app(atom1); + def = atom2; + dep = cl.m_dep; + if (deps.find(atom1, d)) + dep = m.mk_join(dep, d); + return true; + } + } + return false; + }; + + for (auto* cl : m_use_list.get(p, true)) { + if (cl->m_alive && cl->m_literals.size() == 2) { + if (is_def(0, 1, *cl)) + return true; + if (is_def(1, 0, *cl)) + return true; + } + } + return false; +} + +bool eliminate_predicates::is_macro_safe(expr* e) { + for (expr* arg : subterms::all(expr_ref(e, m))) + if (is_app(arg) && m_is_macro.is_marked(to_app(arg)->get_decl())) + return false; + return true; +} + +void eliminate_predicates::insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep) { + unsigned num = head->get_num_args(); + ptr_buffer vars, subst_args; + subst_args.resize(num, nullptr); + vars.resize(num, nullptr); + for (unsigned i = 0; i < num; i++) { + var* v = to_var(head->get_arg(i)); + var* w = m.mk_var(i, v->get_sort()); + unsigned idx = v->get_idx(); + VERIFY(idx < num); + SASSERT(subst_args[idx] == 0); + subst_args[idx] = w; + vars[i] = w; + } + var_subst sub(m, false); + def = sub(def, subst_args.size(), subst_args.data()); + head = m.mk_app(head->get_decl(), vars); + auto* info = alloc(macro_def, head, def, dep); + m_macros.insert(head->get_decl(), info); + m_fmls.model_trail().push(head->get_decl(), def, {}); + m_is_macro.mark(head->get_decl(), true); + TRACE("elim_predicates", tout << "insert " << head << " " << def << "\n"); + ++m_stats.m_num_macros; +} + +void eliminate_predicates::try_resolve_definition(func_decl* p) { + app_ref head(m); + expr_ref def(m); + expr_dependency_ref dep(m); + if (try_find_binary_definition(p, head, def, dep)) + insert_macro(head, def, dep); +} + +bool eliminate_predicates::has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep) { + macro_def* md = nullptr; + if (m_macros.find(p, md)) { + head = md->m_head; + def = md->m_def; + dep = md->m_dep; + return true; + } + return false; +} + +void eliminate_predicates::find_definitions() { + for (auto* p : m_predicates) + try_resolve_definition(p); +} + +void eliminate_predicates::rewrite(expr_ref& t) { + proof_ref pr(m); + m_der(t, t, pr); + m_rewriter(t); +} + +void eliminate_predicates::reduce_definitions() { + if (m_macros.empty()) + return; + + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + auto [f, d] = m_fmls[i](); + expr_ref fml(f, m), new_fml(m); + expr_dependency_ref dep(m); + while (true) { + macro_expander_rw macro_expander(m, *this, dep); + macro_expander(fml, new_fml); + if (new_fml == fml) + break; + rewrite(new_fml); + fml = new_fml; + } + if (fml != f) { + dep = m.mk_join(d, dep); + m_fmls.update(i, dependent_expr(m, fml, dep)); + } + } + reset(); + init_clauses(); +} + +void eliminate_predicates::try_resolve(func_decl* p) { + if (m_disable_elimination.is_marked(p)) + return; + if (m_disable_macro.is_marked(p)) + return; + + unsigned num_pos = 0, num_neg = 0; + for (auto* cl : m_use_list.get(p, false)) + if (cl->m_alive) + ++num_pos; + for (auto* cl : m_use_list.get(p, true)) + if (cl->m_alive) + ++num_neg; + + TRACE("elim_predicates", tout << "try resolve " << p->get_name() << " " << num_pos << " " << num_neg << "\n"); + IF_VERBOSE(0, verbose_stream() << "try resolve " << p->get_name() << " " << num_pos << " " << num_neg << "\n"); + // TODO - probe for a definition + // generally, probe for binary clause equivalences in binary implication graph + + if (num_pos >= 4 && num_neg >= 2) + return; + if (num_neg >= 4 && num_pos >= 2) + return; + if (num_neg >= 3 && num_pos >= 3) + return; + + for (auto* pos : m_use_list.get(p, false)) { + for (auto* neg : m_use_list.get(p, true)) { + clause* cl = resolve(p, *pos, *neg); + if (!cl) + continue; + m_clauses.push_back(cl); + add_use_list(*cl); + process_to_exclude(m_disable_elimination); + IF_VERBOSE(11, verbose_stream() << "resolve " << p->get_name() << "\n" << *pos << "\n" << *neg << "\n------\n" << *cl << "\n\n"); + } + } + + update_model(p); + + for (auto* pos : m_use_list.get(p, false)) + pos->m_alive = false; + for (auto* neg : m_use_list.get(p, true)) + neg->m_alive = false; + + ++m_stats.m_num_eliminated; +} + +// +// update model for p +// +// Example, ground case: +// {p, a} {p, b} {-p, c}, {-p, d} +// p <=> !(a & b) +// p <=> c & d +// +// Example non-ground cases +// {p(t)} {p(s)} {~p(u)} +// p(x) <=> (x = t or x = s) +// p(x) <=> x != u +// +// {p(t), a, b} +// p(x) <=> (x = t & !(a or b)) +// +// {~p(t), a, b} +// ~p(x) <=> (x = t & !(a or b)) +// p(x) <=> x = t => a or b +// + +void eliminate_predicates::update_model(func_decl* p) { + expr_ref_vector fmls(m); + expr_ref def(m); + unsigned numpos = 0, numneg = 0; + vector deleted; + for (auto* pos : m_use_list.get(p, false)) + if (pos->m_alive) + ++numpos; + for (auto* neg : m_use_list.get(p, true)) + if (neg->m_alive) + ++numneg; + + if (numpos < numneg) { + for (auto* pos : m_use_list.get(p, false)) + if (pos->m_alive) + fmls.push_back(create_residue_formula(p, *pos)); + def = mk_or(fmls); + } + else { + for (auto* neg : m_use_list.get(p, true)) + if (neg->m_alive) + fmls.push_back(mk_not(m, create_residue_formula(p, *neg))); + def = mk_and(fmls); + } + + IF_VERBOSE(0, verbose_stream() << p->get_name() << " " << def << "\n"); + rewrite(def); + m_fmls.model_trail().push(p, def, deleted); +} + +/** +* Convert a clause that contains p(t) into a definition for p +* forall y . (or p(t) C) +* Into +* exists y . x = t[y] & !(or C) +*/ + +expr_ref eliminate_predicates::create_residue_formula(func_decl* p, clause& cl) { + unsigned num_args = p->get_arity(); + unsigned num_bound = cl.m_bound.size(); + expr_ref_vector ors(m), ands(m); + expr_ref fml(m); + app_ref patom(m); + for (auto const& [atom, sign] : cl.m_literals) { + if (is_app(atom) && to_app(atom)->get_decl() == p) { + SASSERT(!patom); + patom = to_app(atom); + continue; + } + fml = sign ? m.mk_not(atom) : atom.get(); + ors.push_back(fml); + } + if (!ors.empty()) { + fml = mk_not(m, mk_or(ors)); + ands.push_back(fml); + } + for (unsigned i = 0; i < num_args; ++i) { + SASSERT(patom->get_arg(i)->get_sort() == p->get_domain(i)); + ands.push_back(m.mk_eq(patom->get_arg(i), m.mk_var(num_bound + i, p->get_domain(i)))); + } + fml = m.mk_and(ands); + if (num_bound > 0) { + svector names; + for (unsigned i = 0; i < num_bound; ++i) + names.push_back(symbol(i)); + fml = m.mk_exists(num_bound, cl.m_bound.data(), names.data(), fml, 1); + } + IF_VERBOSE(0, verbose_stream() << fml << "\n"); + return fml; +} + +/** +* Resolve p in clauses pos, neg where p occurs only once. +*/ +eliminate_predicates::clause* eliminate_predicates::resolve(func_decl* p, clause& pos, clause& neg) { + var_shifter sh(m); + expr_dependency_ref dep(m); + dep = m.mk_join(pos.m_dep, neg.m_dep); + expr_ref new_lit(m); + expr_ref_vector lits(m); + expr* plit = nullptr, * nlit = nullptr; + + for (auto const& [lit, sign] : pos.m_literals) + if (is_app(lit) && to_app(lit)->get_decl() == p) + plit = lit; + else + lits.push_back(sign ? m.mk_not(lit) : lit.get()); + for (auto const & [lit, sign] : neg.m_literals) { + if (is_app(lit) && to_app(lit)->get_decl() == p) + nlit = lit; + else { + sh(lit, pos.m_bound.size(), new_lit); + lits.push_back(sign ? m.mk_not(new_lit) : new_lit.get()); + } + } + sh(nlit, pos.m_bound.size(), new_lit); + for (unsigned i = 0; i < p->get_arity(); ++i) { + expr* a = to_app(plit)->get_arg(i); + expr* b = to_app(new_lit)->get_arg(i); + if (a != b) + lits.push_back(m.mk_not(m.mk_eq(a, b))); + } + + expr_ref cl = mk_or(lits); + ptr_vector bound; + bound.append(neg.m_bound); + bound.append(pos.m_bound); + if (!bound.empty()) { + svector names; + for (unsigned i = 0; i < bound.size(); ++i) + names.push_back(symbol(i)); + cl = m.mk_forall(bound.size(), bound.data(), names.data(), cl, 1); + } + rewrite(cl); + if (m.is_true(cl)) + return nullptr; + return init_clause(cl, dep, UINT_MAX); +} + +void eliminate_predicates::try_resolve() { + for (auto* f : m_predicates) + try_resolve(f); +} + +/** +* Process the terms m_to_exclude, walk all subterms. +* Uninterpreted function declarations in these terms are added to 'exclude_set' +* Uninterpreted function declarations from as-array terms are added to 'm_disable_macro' +*/ +void eliminate_predicates::process_to_exclude(ast_mark& exclude_set) { + ast_mark visited; + array_util a(m); + + struct proc { + array_util& a; + ast_mark& to_exclude; + ast_mark& to_disable; + proc(array_util& a, ast_mark& f, ast_mark& d) : + a(a), to_exclude(f), to_disable(d) {} + void operator()(func_decl* f) { + if (is_uninterp(f)) + to_exclude.mark(f, true); + } + void operator()(app* e) { + func_decl* f; + if (a.is_as_array(e, f) && is_uninterp(f)) + to_disable.mark(f, true); + } + void operator()(ast* s) {} + }; + proc proc(a, exclude_set, m_disable_macro); + + for (expr* e : m_to_exclude) + for_each_ast(proc, visited, e); + m_to_exclude.reset(); +} + + +eliminate_predicates::clause* eliminate_predicates::init_clause(unsigned i) { + auto [f, d] = m_fmls[i](); + return init_clause(f, d, i); +} + +/** +* Create a clause from a formula. +*/ +eliminate_predicates::clause* eliminate_predicates::init_clause(expr* f, expr_dependency* d, unsigned i) { + clause* cl = alloc(clause, m, d); + cl->m_fml = f; + cl->m_fml_index = i; + while (is_forall(f)) { + cl->m_bound.append(to_quantifier(f)->get_num_decls(), to_quantifier(f)->get_decl_sorts()); + f = to_quantifier(f)->get_expr(); + } + expr_ref_vector ors(m); + flatten_or(f, ors); + for (expr* lit : ors) { + bool sign = m.is_not(lit, lit); + cl->m_literals.push_back({ expr_ref(lit, m), sign }); + } + return cl; +} + +/** +* functions in the prefix of qhead are fully disabled +* Create clauses from the suffix, and process subeterms of clauses to be disabled from +* eliminations. +*/ +void eliminate_predicates::init_clauses() { + for (unsigned i = 0; i < m_qhead; ++i) + m_to_exclude.push_back(m_fmls[i].fml()); + recfun::util rec(m); + if (rec.has_rec_defs()) + for (auto& d : rec.get_rec_funs()) + m_to_exclude.push_back(rec.get_def(d).get_rhs()); + + process_to_exclude(m_disable_macro); + + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + clause* cl = init_clause(i); + add_use_list(*cl); + m_clauses.push_back(cl); + } + process_to_exclude(m_disable_elimination); +} + +/** +* Convert clauses to m_fmls +*/ +void eliminate_predicates::decompile() { + for (clause* cl : m_clauses) { + if (m_fmls.inconsistent()) + break; + if (cl->m_fml_index != UINT_MAX) { + if (cl->m_alive) + continue; + dependent_expr de(m, m.mk_true(), nullptr); + m_fmls.update(cl->m_fml_index, de); + } + else if (cl->m_alive) { + expr_ref new_cl = cl->m_fml; + dependent_expr de(m, new_cl, cl->m_dep); + m_fmls.add(de); + } + } +} + +void eliminate_predicates::reset() { + m_predicates.reset(); + m_predicate_decls.reset(); + m_to_exclude.reset(); + m_disable_macro.reset(); + m_disable_elimination.reset(); + m_is_macro.reset(); + for (auto const& [k, v] : m_macros) + dealloc(v); + m_macros.reset(); + m_clauses.reset(); + m_use_list.reset(); +} + + +void eliminate_predicates::reduce() { + reset(); + init_clauses(); + find_definitions(); + reduce_definitions(); + try_resolve(); + decompile(); + reset(); +} diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h new file mode 100644 index 000000000..5c7cf7e95 --- /dev/null +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -0,0 +1,143 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + eliminate_predicates.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +Notes: + + Eliminate predicates through Davis-Putnam rules + + (forall (x y) (or (P x) Q)) (forall (x y) (or (not (P x)) R)) +is converted to + (forall (x y) (or Q R)) +when P occurs only in positive or only in negative polarities and the +expansion does not increase the formula size. + +Macros are also eliminated + + +create clause abstractions, index into fmls, indicator if it was removed +map from predicates to clauses where they occur in unitary role. +process predicates to check if they can be eliminated, creating new clauses and updated use-list. + + +--*/ + + +#pragma once + +#include "util/scoped_ptr_vector.h" +#include "ast/rewriter/der.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/simplifiers/dependent_expr_state.h" + + +class eliminate_predicates : public dependent_expr_simplifier { + +public: + struct clause { + ptr_vector m_bound; // bound variables + vector> m_literals; // clause literals + expr_dependency_ref m_dep; // dependencies + expr_ref m_fml; // formula corresponding to clause + unsigned m_fml_index = UINT_MAX; // index of formula where clause came from + bool m_alive = true; + + clause(ast_manager& m, expr_dependency* d) : + m_dep(d, m), m_fml(m) + {} + + std::ostream& display(std::ostream& out) const; + }; +private: + struct stats { + unsigned m_num_eliminated = 0; + unsigned m_num_macros = 0; + void reset() { m_num_eliminated = 0; m_num_macros = 0; } + }; + + struct macro_def { + app_ref m_head; + expr_ref m_def; + expr_dependency_ref m_dep; + macro_def(app_ref& head, expr_ref& def, expr_dependency_ref& dep) : + m_head(head), m_def(def), m_dep(dep) {} + }; + + typedef ptr_vector clause_use_list; + + class use_list { + vector m_use_list; + unsigned index(func_decl* f, bool sign) const { return 2*f->get_small_id() + sign; } + void reserve(func_decl* f, bool sign) { + m_use_list.reserve(index(f, sign) + 3); + } + public: + clause_use_list& get(func_decl* f, bool sign) { reserve(f, sign); return m_use_list[index(f, sign)]; } + void reset() { m_use_list.reset(); } + }; + + scoped_ptr_vector m_clauses; + ast_mark m_disable_elimination, m_disable_macro, m_predicate_decls, m_is_macro; + ptr_vector m_predicates; + ptr_vector m_to_exclude; + stats m_stats; + use_list m_use_list; + der_rewriter m_der; + th_rewriter m_rewriter; + obj_map m_macros; + + struct macro_expander_cfg; + struct macro_expander_rw; + + void rewrite(expr_ref& t); + + clause* init_clause(unsigned i); + clause* init_clause(expr* f, expr_dependency* d, unsigned i); + clause* resolve(func_decl* p, clause& pos, clause& neg); + void add_use_list(clause& cl); + + bool try_find_binary_definition(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); + void try_resolve_definition(func_decl* p); + void insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep); + bool has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); + bool is_macro_safe(expr* e); + + void try_resolve(func_decl* p); + void update_model(func_decl* p); + expr_ref create_residue_formula(func_decl* p, clause& cl); + void process_to_exclude(ast_mark&); + + void init_clauses(); + void find_definitions(); + void reduce_definitions(); + void try_resolve(); + void decompile(); + void reset(); + +public: + + eliminate_predicates(ast_manager& m, dependent_expr_state& fmls); + + ~eliminate_predicates() override { reset(); } + + void reduce() override; + + void collect_statistics(statistics& st) const override { + st.update("elim-predicates", m_stats.m_num_eliminated); + st.update("elim-predicates-macros", m_stats.m_num_macros); + } + + void reset_statistics() override { m_stats.reset(); } +}; + + +inline std::ostream& operator<<(std::ostream& out, eliminate_predicates::clause const& c) { + return c.display(out); +} \ No newline at end of file diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 6bb6793fd..39e8def03 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -38,6 +38,7 @@ z3_add_component(core_tactics elim_term_ite_tactic.h elim_uncnstr_tactic.h elim_uncnstr2_tactic.h + eliminate_predicates_tactic.h euf_completion_tactic.h injectivity_tactic.h nnf_tactic.h diff --git a/src/tactic/core/eliminate_predicates_tactic.h b/src/tactic/core/eliminate_predicates_tactic.h new file mode 100644 index 000000000..3daffb1f3 --- /dev/null +++ b/src/tactic/core/eliminate_predicates_tactic.h @@ -0,0 +1,40 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + eliminate_predicates_tactic.h + +Abstract: + + Tactic for eliminating macros and predicates + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ +#pragma once + +#include "util/params.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/eliminate_predicates.h" + + +class eliminate_predicates_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(eliminate_predicates, m, s); + } +}; + +inline tactic * mk_eliminate_predicates_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(eliminate_predicates_tactic_factory), "elim-predicates"); +} + +/* + ADD_TACTIC("elim-predicates", "eliminate predicates.", "mk_eliminate_predicates_tactic(m, p)") +*/ + + From 3f1093322501908e919fa62b90444aa3620fad60 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:55:01 +0700 Subject: [PATCH 297/477] remove VERBOSE 0 --- src/ast/simplifiers/eliminate_predicates.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 57fe4b4f0..3b14c8fa5 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -357,7 +357,6 @@ void eliminate_predicates::try_resolve(func_decl* p) { ++num_neg; TRACE("elim_predicates", tout << "try resolve " << p->get_name() << " " << num_pos << " " << num_neg << "\n"); - IF_VERBOSE(0, verbose_stream() << "try resolve " << p->get_name() << " " << num_pos << " " << num_neg << "\n"); // TODO - probe for a definition // generally, probe for binary clause equivalences in binary implication graph @@ -436,7 +435,6 @@ void eliminate_predicates::update_model(func_decl* p) { def = mk_and(fmls); } - IF_VERBOSE(0, verbose_stream() << p->get_name() << " " << def << "\n"); rewrite(def); m_fmls.model_trail().push(p, def, deleted); } @@ -478,7 +476,6 @@ expr_ref eliminate_predicates::create_residue_formula(func_decl* p, clause& cl) names.push_back(symbol(i)); fml = m.mk_exists(num_bound, cl.m_bound.data(), names.data(), fml, 1); } - IF_VERBOSE(0, verbose_stream() << fml << "\n"); return fml; } From 251d49d13317998df7e353cdea889a71dbb3569b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 18:55:30 +0700 Subject: [PATCH 298/477] remove outdated comment --- src/ast/simplifiers/eliminate_predicates.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 3b14c8fa5..605ed1b10 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -357,8 +357,6 @@ void eliminate_predicates::try_resolve(func_decl* p) { ++num_neg; TRACE("elim_predicates", tout << "try resolve " << p->get_name() << " " << num_pos << " " << num_neg << "\n"); - // TODO - probe for a definition - // generally, probe for binary clause equivalences in binary implication graph if (num_pos >= 4 && num_neg >= 2) return; From c3c45f495a359975bb616375c3a7e0029f37c7ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 19:45:25 +0700 Subject: [PATCH 299/477] add some comments to elim_predicates --- src/ast/simplifiers/eliminate_predicates.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 605ed1b10..43486dcb0 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -18,9 +18,17 @@ The simplifier and we can obbtain {a, C}, {b, C} {~a, ~b, D } similar to propositional case. Instead the case is handled by predicate elimination when p only occurs positively outside of {~p, a} {~p, b} {p, ~a, ~b} + The SAT based definition detection scheme creates clauses + {a}, {b}, {~a,~b}, C, D and checks for an unsat core. + The core {a}, {b}, {~a, ~b} maps back to a definition for p + Then {p, C}, {~p, D} clauses are replaced based on the definition. + (a task for a "Kitten"?) + - Handle various permutations of variables that are arguments to p? - other SMT-based macro detection could be made here as well. The (legacy) macro finder is not very flexible and could be replaced by a module building on this one. + + - eliminates predicates p(x) that occur at most once in each clause and the number of occurrences is small. @@ -76,6 +84,7 @@ struct eliminate_predicates::macro_expander_cfg : public default_rewriter_cfg { /** * adapted from macro_manager.cpp + * Perhaps hoist and combine? */ bool reduce_quantifier(quantifier* old_q, expr* new_body, @@ -131,6 +140,7 @@ struct eliminate_predicates::macro_expander_cfg : public default_rewriter_cfg { r = rr; m_trail.push_back(rr); m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, dep); + // skip proof terms for simplifiers return true; } From 86f37024033d419fd65844db4a3cdc077e57c024 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2022 19:46:34 +0700 Subject: [PATCH 300/477] prevent re-declaration of enumeration sort names preventing redeclaration of all ADT cases is not part of this update. --- src/api/api_datatype.cpp | 10 +++++++++- src/ast/datatype_decl_plugin.cpp | 31 +++++++++++++++++-------------- src/ast/datatype_decl_plugin.h | 2 ++ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index f1c65b626..5802c1e64 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -102,6 +102,13 @@ extern "C" { sort* e; ptr_vector constrs; + symbol sname = to_symbol(name); + + if (mk_c(c)->get_dt_plugin()->is_declared(sname)) { + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + RETURN_Z3(nullptr); + } + for (unsigned i = 0; i < n; ++i) { symbol e_name(to_symbol(enum_names[i])); std::string recognizer_s("is_"); @@ -112,8 +119,9 @@ extern "C" { } + { - datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, n, constrs.data()); + datatype_decl * dt = mk_datatype_decl(dt_util, sname, 0, nullptr, n, constrs.data()); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, nullptr, sorts); del_datatype_decl(dt); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 041d6740a..d0214d44f 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -832,6 +832,10 @@ namespace datatype { bool util::is_declared(sort* s) const { return plugin().is_declared(s); } + + bool util::is_declared(symbol const& n) const { + return plugin().is_declared(n); + } void util::compute_datatype_size_functions(svector const& names) { map already_found; @@ -1087,11 +1091,9 @@ namespace datatype { sort * datatype = con->get_range(); def const& dd = get_def(datatype); symbol r; - for (constructor const* c : dd) { - if (c->name() == con->get_name()) { - r = c->recognizer(); - } - } + for (constructor const* c : dd) + if (c->name() == con->get_name()) + r = c->recognizer(); parameter ps[2] = { parameter(con), parameter(r) }; d = m.mk_func_decl(fid(), OP_DT_RECOGNISER, 2, ps, 1, &datatype); SASSERT(d); @@ -1142,17 +1144,15 @@ namespace datatype { } bool util::is_enum_sort(sort* s) { - if (!is_datatype(s)) { - return false; - } + if (!is_datatype(s)) + return false; bool r = false; if (m_is_enum.find(s, r)) return r; ptr_vector const& cnstrs = *get_datatype_constructors(s); r = true; - for (unsigned i = 0; r && i < cnstrs.size(); ++i) { - r = cnstrs[i]->get_arity() == 0; - } + for (unsigned i = 0; r && i < cnstrs.size(); ++i) + r = cnstrs[i]->get_arity() == 0; m_is_enum.insert(s, r); m_asts.push_back(s); return r; @@ -1284,11 +1284,14 @@ namespace datatype { unsigned idx = 0; def const& d = get_def(f->get_range()); for (constructor* c : d) { - if (c->name() == f->get_name()) { - return idx; - } + if (c->name() == f->get_name()) + return idx; ++idx; } + IF_VERBOSE(0, verbose_stream() << f->get_name() << "\n"); + for (constructor* c : d) + IF_VERBOSE(0, verbose_stream() << "!= " << c->name() << "\n"); + SASSERT(false); UNREACHABLE(); return 0; } diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 4561dfacf..7229636cb 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -253,6 +253,7 @@ namespace datatype { ptr_vector get_constructors(symbol const& s) const; ptr_vector get_accessors(symbol const& s) const; bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); } + bool is_declared(symbol const& n) const { return m_defs.contains(n); } unsigned get_axiom_base_id(symbol const& s) { return m_axiom_bases[s]; } util & u() const; @@ -375,6 +376,7 @@ namespace datatype { bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); void reset(); bool is_declared(sort* s) const; + bool is_declared(symbol const& n) const; void display_datatype(sort *s, std::ostream& strm); bool is_fully_interp(sort * s) const; sort_ref_vector datatype_params(sort * s) const; From fcaa85d7a8e48e78c739c40e7c16fb4898a83216 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Nov 2022 11:27:39 +0700 Subject: [PATCH 301/477] #6456 - elaborate on error message --- src/api/api_datatype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 5802c1e64..71d1de212 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -105,7 +105,7 @@ extern "C" { symbol sname = to_symbol(name); if (mk_c(c)->get_dt_plugin()->is_declared(sname)) { - SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); + SET_ERROR_CODE(Z3_INVALID_ARG, "enumeration sort name is already declared"); RETURN_Z3(nullptr); } From b9f34286a7fd23a89d7d8735daad67b2c2676f38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Nov 2022 11:36:45 +0700 Subject: [PATCH 302/477] generalize macro head detection and elaboration --- src/ast/simplifiers/eliminate_predicates.cpp | 59 +++++++++++++++++--- src/ast/simplifiers/eliminate_predicates.h | 2 + 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 43486dcb0..a46eda102 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -22,6 +22,7 @@ The simplifier {a}, {b}, {~a,~b}, C, D and checks for an unsat core. The core {a}, {b}, {~a, ~b} maps back to a definition for p Then {p, C}, {~p, D} clauses are replaced based on the definition. + Claim: {C, D} is a consequence when we have created resolvents {C,X}, {D,Y}, where X => p => Y => X (a task for a "Kitten"?) - Handle various permutations of variables that are arguments to p? - other SMT-based macro detection could be made here as well. @@ -45,6 +46,7 @@ forbidden from macros vs forbidden from elimination --*/ +#include "util/uint_set.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" #include "ast/ast_util.h" @@ -56,7 +58,6 @@ forbidden from macros vs forbidden from elimination #include "ast/rewriter/rewriter_def.h" #include "ast/simplifiers/eliminate_predicates.h" #include "ast/rewriter/th_rewriter.h" -#include "ast/macros/macro_util.h" /** @@ -195,6 +196,49 @@ void eliminate_predicates::add_use_list(clause& cl) { } } +/** +* Check that all arguments are distinct variables that are bound. +*/ + +bool eliminate_predicates::can_be_macro_head(app* head, unsigned num_bound) { + uint_set indices; + if (head->get_decl()->is_associative()) + return false; + for (expr* arg : *head) { + if (!is_var(arg)) + return false; + unsigned idx = to_var(arg)->get_idx(); + if (indices.contains(idx)) + return false; + if (idx >= num_bound) + return false; + indices.insert(idx); + } + return true; +} + +expr_ref eliminate_predicates::bind_free_variables_in_def(clause& cl, app* head, expr* def) { + unsigned num_bound = cl.m_bound.size(); + if (head->get_num_args() == num_bound) + return expr_ref(def, m); + + // head(x) <=> forall yx', x = x' => def(yx') + svector names; + expr_ref_vector ors(m); + expr_ref result(m); + ors.push_back(def); + + for (unsigned i = 0; i < num_bound; ++i) + names.push_back(symbol(i)); + for (expr* arg : *head) { + unsigned idx = to_var(arg)->get_idx(); + ors.push_back(m.mk_not(m.mk_eq(arg, m.mk_var(idx + num_bound, arg->get_sort())))); + } + result = mk_or(ors); + result = m.mk_forall(num_bound, cl.m_bound.data(), names.data(), result); + rewrite(result); + return result; +} /** * cheap/simplistic heuristic to find definitions that are based on binary clauses * (or (head x) (not (def x)) @@ -204,13 +248,12 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea if (m_disable_macro.is_marked(p)) return false; expr_mark binary_pos, binary_neg; - macro_util mutil(m); obj_map deps; - auto is_def_predicate = [&](expr* atom) { - return is_app(atom) && to_app(atom)->get_decl() == p && mutil.is_macro_head(atom, p->get_arity()); + auto is_def_predicate = [&](clause& cl, expr* atom) { + return is_app(atom) && to_app(atom)->get_decl() == p && can_be_macro_head(to_app(atom), cl.m_bound.size()); }; auto add_def = [&](clause& cl, expr* atom1, bool sign1, expr* atom2, bool sign2) { - if (is_def_predicate(atom1) && !sign1) { + if (is_def_predicate(cl, atom1) && !sign1) { if (sign2) binary_neg.mark(atom2); else @@ -233,10 +276,10 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea auto const& [atom1, sign1] = cl.m_literals[i]; auto const& [atom2, sign2] = cl.m_literals[j]; expr_dependency* d = nullptr; - if (is_def_predicate(atom1) && sign1) { + if (is_def_predicate(cl, atom1) && sign1) { if (sign2 && binary_pos.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) { head = to_app(atom1); - def = m.mk_not(atom2); + def = bind_free_variables_in_def(cl, head, m.mk_not(atom2)); dep = cl.m_dep; if (deps.find(atom1, d)) dep = m.mk_join(dep, d); @@ -244,7 +287,7 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea } if (!sign2 && binary_neg.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) { head = to_app(atom1); - def = atom2; + def = bind_free_variables_in_def(cl, head, atom2); dep = cl.m_dep; if (deps.find(atom1, d)) dep = m.mk_join(dep, d); diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index 5c7cf7e95..ff11bfd3f 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -107,6 +107,8 @@ private: void try_resolve_definition(func_decl* p); void insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep); bool has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); + expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def); + bool can_be_macro_head(app* head, unsigned num_bound); bool is_macro_safe(expr* e); void try_resolve(func_decl* p); From 0445d6f264a666ce38a96bf07ff980da2386ccee Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 20 Nov 2022 19:03:32 +0000 Subject: [PATCH 303/477] FPA->BV fix unused vars --- src/ast/fpa/fpa2bv_converter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 18baba57c..21c71c8a9 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3288,7 +3288,7 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex void fpa2bv_converter::mk_to_ieee_bv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_IEEE_BV, 0, nullptr, num, args), m); - mk_to_bv(f, num, args, true, result); + mk_to_bv(fu, num, args, true, result); } void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { @@ -3475,12 +3475,12 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg void fpa2bv_converter::mk_to_ubv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_UBV, 0, nullptr, num, args), m); - mk_to_bv(f, num, args, false, result); + mk_to_bv(fu, num, args, false, result); } void fpa2bv_converter::mk_to_sbv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_SBV, 0, nullptr, num, args), m); - mk_to_bv(f, num, args, true, result); + mk_to_bv(fu, num, args, true, result); } expr_ref fpa2bv_converter::nan_wrap(expr * n) { @@ -3529,7 +3529,7 @@ void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr void fpa2bv_converter::mk_to_real_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_REAL, 0, nullptr, num, args), m); - mk_to_real(f, num, args, result); + mk_to_real(fu, num, args, result); } void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { From 477b90228e57d619cd848c19feee646109c4a2c9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 20 Nov 2022 19:19:12 +0000 Subject: [PATCH 304/477] fix #6460: crash in mk_to_ieee_bv_i --- src/ast/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 21c71c8a9..c456da29b 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3288,7 +3288,7 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex void fpa2bv_converter::mk_to_ieee_bv_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_decl_ref fu(m.mk_func_decl(f->get_family_id(), OP_FPA_TO_IEEE_BV, 0, nullptr, num, args), m); - mk_to_bv(fu, num, args, true, result); + mk_to_ieee_bv(fu, num, args, result); } void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { From 5c5673bc09435a0477b6e168731d0d67fc3f7f2c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 07:55:49 +0700 Subject: [PATCH 305/477] make sure parser context within solver object has its parameters updated this is to enable use cases like: ``` from z3 import * s = Solver() OnClause(s, print) s.set("solver.proof.check", False) s.from_file("../satproof.smt2") ``` instead of setting global parameters before the proof replay is initialized. --- src/api/api_solver.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 94d72462f..b93fb42af 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -406,7 +406,11 @@ extern "C" { params.validate(r); to_solver_ref(s)->updt_params(params); } - to_solver(s)->m_params.append(params); + auto& solver = *to_solver(s); + solver.m_params.append(params); + + if (solver.m_cmd_context && solver.m_cmd_context->get_proof_cmds()) + solver.m_cmd_context->get_proof_cmds()->updt_params(solver.m_params); init_solver_log(c, s); @@ -937,8 +941,10 @@ extern "C" { install_proof_cmds(*solver.m_cmd_context); } - if (!solver.m_cmd_context->get_proof_cmds()) + if (!solver.m_cmd_context->get_proof_cmds()) { init_proof_cmds(*solver.m_cmd_context); + solver.m_cmd_context->get_proof_cmds()->updt_params(solver.m_params); + } solver.m_cmd_context->get_proof_cmds()->register_on_clause(user_context, _on_clause); Z3_CATCH; } From cd0d52acec68ce1c23553da9edc255e4c4cf5215 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 07:56:28 +0700 Subject: [PATCH 306/477] using C++11 features to simplify for-loops --- src/ast/macros/macro_util.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index a28d9c608..f7377061b 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -417,13 +417,11 @@ bool macro_util::is_quasi_macro_ok(expr * n, unsigned num_decls, expr * def) con if (is_app(n) && to_app(n)->get_family_id() == null_family_id && to_app(n)->get_num_args() >= num_decls) { - unsigned num_args = to_app(n)->get_num_args(); sbuffer found_vars; found_vars.resize(num_decls, false); unsigned num_found_vars = 0; expr_free_vars fv; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); + for (expr* arg : *to_app(n)) { if (occurs(to_app(n)->get_decl(), arg)) return false; else @@ -553,12 +551,9 @@ bool is_hint_head(expr * n, ptr_buffer & vars) { return false; if (to_app(n)->get_decl()->is_associative() || to_app(n)->get_family_id() != null_family_id) return false; - unsigned num_args = to_app(n)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); + for (expr * arg : *to_app(n)) if (is_var(arg)) vars.push_back(to_var(arg)); - } return !vars.empty(); } @@ -579,9 +574,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer const & vars) { return false; } else if (is_app(curr)) { - unsigned num_args = to_app(curr)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(curr)->get_arg(i); + for (expr * arg : *to_app(curr)) { if (is_ground(arg)) continue; if (visited.contains(arg)) @@ -611,13 +604,11 @@ bool is_hint_atom(expr * lhs, expr * rhs) { } void hint_to_macro_head(ast_manager & m, app * head, unsigned & num_decls, app_ref & new_head) { - unsigned num_args = head->get_num_args(); ptr_buffer new_args; sbuffer found_vars; found_vars.resize(num_decls, false); unsigned next_var_idx = num_decls; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = head->get_arg(i); + for (expr * arg : *head) { if (is_var(arg)) { unsigned idx = to_var(arg)->get_idx(); SASSERT(idx < num_decls); From c7781f346d5d723a8c9edfe6534d1a1b18067b2e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 07:59:04 +0700 Subject: [PATCH 307/477] move parameter sat.smt.proof to solver.proof.log this update breaks use cases that set sat.smt.proof to True. As it is such a new feature and the change affects possibly at most the tutorial it is made without compatibility layers. --- src/params/solver_params.pyg | 1 + src/sat/sat_config.cpp | 3 +-- src/sat/sat_config.h | 1 - src/sat/sat_params.pyg | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/params/solver_params.pyg b/src/params/solver_params.pyg index 9ff13864d..1c2be3213 100644 --- a/src/params/solver_params.pyg +++ b/src/params/solver_params.pyg @@ -8,6 +8,7 @@ def_module_params('solver', ('lemmas2console', BOOL, False, 'print lemmas during search'), ('instantiations2console', BOOL, False, 'print quantifier instantiations to the console'), ('axioms2files', BOOL, False, 'print negated theory axioms to separate files during search'), + ('proof.log', SYMBOL, '', 'log clause proof trail into a file'), ('proof.check', BOOL, True, 'check proof logs'), ('proof.save', BOOL, False, 'save proof log into a proof object that can be extracted using (get-proof)'), ('proof.trim', BOOL, False, 'trim and save proof into a proof object that an be extracted using (get-proof)'), diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 4ca223be6..eb2d0071d 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -197,7 +197,6 @@ namespace sat { m_drat_check_unsat = p.drat_check_unsat(); m_drat_check_sat = p.drat_check_sat(); m_drat_file = p.drat_file(); - m_smt_proof = p.smt_proof(); m_smt_proof_check = p.smt_proof_check(); m_smt_proof_check_rup = p.smt_proof_check_rup(); m_drat_disable = p.drat_disable(); @@ -206,7 +205,7 @@ namespace sat { (sp.lemmas2console() || m_drat_check_unsat || m_drat_file.is_non_empty_string() || - m_smt_proof.is_non_empty_string() || + sp.proof_log().is_non_empty_string() || m_smt_proof_check || m_drat_check_sat); m_drat_binary = p.drat_binary(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index ae19c63ea..8adfc13ed 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -178,7 +178,6 @@ namespace sat { bool m_drat_disable; bool m_drat_binary; symbol m_drat_file; - symbol m_smt_proof; bool m_smt_proof_check; bool m_smt_proof_check_rup; bool m_drat_check_unsat; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 7466a1126..20a415441 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -47,7 +47,6 @@ def_module_params('sat', ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.disable', BOOL, False, 'override anything that enables DRAT'), - ('smt.proof', SYMBOL, '', 'add SMT proof log to file'), ('smt.proof.check', BOOL, False, 'check SMT proof while it is created'), ('smt.proof.check_rup', BOOL, True, 'apply forward RUP proof checking'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), From 5374142e3e1b0edee4d5ace5cdf2ba1d3ab82738 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 07:59:32 +0700 Subject: [PATCH 308/477] continue updates for adding proof-log to smt core --- src/smt/params/smt_params.cpp | 2 ++ src/smt/params/smt_params.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 4e9afaa8d..8143bc31b 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -64,6 +64,7 @@ void smt_params::updt_local_params(params_ref const & _p) { m_axioms2files = sp.axioms2files(); m_lemmas2console = sp.lemmas2console(); m_instantiations2console = sp.instantiations2console(); + m_proof_log = sp.proof_log(); } void smt_params::updt_params(params_ref const & p) { @@ -126,6 +127,7 @@ void smt_params::display(std::ostream & out) const { DISPLAY_PARAM(m_ematching); DISPLAY_PARAM(m_induction); DISPLAY_PARAM(m_clause_proof); + DISPLAY_PARAM(m_proof_log); DISPLAY_PARAM(m_case_split_strategy); DISPLAY_PARAM(m_rel_case_split_order); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 62e1ec843..73f556eb8 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -112,6 +112,7 @@ struct smt_params : public preprocessor_params, bool m_ematching = true; bool m_induction = false; bool m_clause_proof = false; + symbol m_proof_log; // ----------------------------------- // From 6188c536ef852633571b34e74efe962b942f6ad7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 08:01:15 +0700 Subject: [PATCH 309/477] add logging of propagations to smt core log theory propagations with annotation "smt". It allows tracking theory propagations (when used in conflicts) in the clause logs similar to the new core. --- src/smt/qi_queue.cpp | 2 +- src/smt/smt_clause_proof.cpp | 80 ++++++++++++++++++++++++++--- src/smt/smt_clause_proof.h | 16 ++++-- src/smt/smt_conflict_resolution.cpp | 1 + src/smt/smt_context.cpp | 5 +- src/smt/smt_context.h | 4 +- src/smt/smt_internalizer.cpp | 4 +- 7 files changed, 95 insertions(+), 17 deletions(-) diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index cb28f87f8..582bcc664 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -304,7 +304,7 @@ namespace smt { } m_instances.push_back(pr1); } - else if (m_context.on_clause_active()) { + else if (m_context.clause_proof_active()) { expr_ref_vector bindings_e(m), args(m); arith_util a(m); expr_ref gen(a.mk_int(generation), m); diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index ad3d3818c..096a0994f 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -18,7 +18,17 @@ Revision History: #include "ast/ast_ll_pp.h" namespace smt { - clause_proof::clause_proof(context& ctx): ctx(ctx), m(ctx.get_manager()), m_lits(m) {} + + clause_proof::clause_proof(context& ctx): + ctx(ctx), m(ctx.get_manager()), m_lits(m), m_pp(m) { + auto proof_log = ctx.get_fparams().m_proof_log; + m_enabled = ctx.get_fparams().m_clause_proof || proof_log.is_non_empty_string(); + if (proof_log.is_non_empty_string()) { + m_pp_out = alloc(std::ofstream, proof_log.str()); + if (!*m_pp_out) + throw default_exception(std::string("Could not open file ") + proof_log.str()); + } + } clause_proof::status clause_proof::kind2st(clause_kind k) { switch (k) { @@ -42,7 +52,7 @@ namespace smt { r = j->mk_proof(ctx.get_cr()); if (r) return r; - if (!m_on_clause_active) + if (!is_enabled()) return nullptr; switch (st) { case status::assumption: @@ -60,7 +70,7 @@ namespace smt { } void clause_proof::add(clause& c) { - if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + if (!is_enabled()) return; justification* j = c.get_justification(); auto st = kind2st(c.get_kind()); @@ -70,7 +80,7 @@ namespace smt { } void clause_proof::add(unsigned n, literal const* lits, clause_kind k, justification* j) { - if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + if (!is_enabled()) return; auto st = kind2st(k); proof_ref pr(justification2proof(st, j), m); @@ -83,7 +93,7 @@ namespace smt { void clause_proof::shrink(clause& c, unsigned new_size) { - if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + if (!is_enabled()) return; m_lits.reset(); for (unsigned i = 0; i < new_size; ++i) @@ -97,7 +107,7 @@ namespace smt { } void clause_proof::add(literal lit, clause_kind k, justification* j) { - if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + if (!is_enabled()) return; m_lits.reset(); m_lits.push_back(ctx.literal2expr(lit)); @@ -107,7 +117,7 @@ namespace smt { } void clause_proof::add(literal lit1, literal lit2, clause_kind k, justification* j) { - if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + if (!is_enabled()) return; m_lits.reset(); m_lits.push_back(ctx.literal2expr(lit1)); @@ -117,21 +127,75 @@ namespace smt { update(st, m_lits, pr); } + void clause_proof::propagate(literal lit, justification const& jst, literal_vector const& ante) { + if (!is_enabled()) + return; + m_lits.reset(); + for (literal l : ante) + m_lits.push_back(ctx.literal2expr(~l)); + m_lits.push_back(ctx.literal2expr(lit)); + proof_ref pr(m.mk_app(symbol("smt"), 0, nullptr, m.mk_proof_sort()), m); + update(clause_proof::status::th_lemma, m_lits, pr); + } void clause_proof::del(clause& c) { update(c, status::deleted, justification2proof(status::deleted, nullptr)); } + std::ostream& clause_proof::display_literals(std::ostream& out, expr_ref_vector const& v) { + for (expr* e : v) + if (m.is_not(e, e)) + m_pp.display_expr_def(out << " (not ", e) << ")"; + else + m_pp.display_expr_def(out << " ", e); + return out; + } + + std::ostream& clause_proof::display_hint(std::ostream& out, proof* p) { + if (p) + m_pp.display_expr_def(out << " ", p); + return out; + } + + void clause_proof::declare(std::ostream& out, expr* e) { + m_pp.collect(e); + m_pp.display_decls(out); + m.is_not(e, e); + m_pp.define_expr(out, e); + } + void clause_proof::update(status st, expr_ref_vector& v, proof* p) { TRACE("clause_proof", tout << m_trail.size() << " " << st << " " << v << "\n";); if (ctx.get_fparams().m_clause_proof) m_trail.push_back(info(st, v, p)); if (m_on_clause_eh) m_on_clause_eh(m_on_clause_ctx, p, v.size(), v.data()); + if (m_pp_out) { + auto& out = *m_pp_out; + for (auto* e : v) + declare(out, e); + switch (st) { + case clause_proof::status::assumption: + display_literals(out << "(assume", v) << ")\n"; + break; + case clause_proof::status::lemma: + case clause_proof::status::th_lemma: + case clause_proof::status::th_assumption: + if (p) + declare(out, p); + display_hint(display_literals(out << "(infer", v), p) << ")\n"; + break; + case clause_proof::status::deleted: + display_literals(out << "(del", v) << ")\n"; + break; + default: + UNREACHABLE(); + } + } } void clause_proof::update(clause& c, status st, proof* p) { - if (!ctx.get_fparams().m_clause_proof && !m_on_clause_active) + if (!is_enabled()) return; m_lits.reset(); for (literal lit : c) diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index f15d0ffe0..42f283f1d 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -26,8 +26,10 @@ Revision History: --*/ #pragma once +#include "ast/ast_pp_util.h" #include "smt/smt_theory.h" #include "smt/smt_clause.h" +#include "smt/smt_justification.h" #include "tactic/user_propagator_base.h" namespace smt { @@ -55,13 +57,20 @@ namespace smt { ast_manager& m; expr_ref_vector m_lits; vector m_trail; - bool m_on_clause_active = false; + bool m_enabled = false; user_propagator::on_clause_eh_t m_on_clause_eh; void* m_on_clause_ctx = nullptr; + ast_pp_util m_pp; + scoped_ptr m_pp_out; + void update(status st, expr_ref_vector& v, proof* p); void update(clause& c, status st, proof* p); status kind2st(clause_kind k); proof* justification2proof(status st, justification* j); + void log(status st, proof* p); + void declare(std::ostream& out, expr* e); + std::ostream& display_literals(std::ostream& out, expr_ref_vector const& v); + std::ostream& display_hint(std::ostream& out, proof* p); public: clause_proof(context& ctx); void shrink(clause& c, unsigned new_size); @@ -69,13 +78,14 @@ namespace smt { void add(literal lit1, literal lit2, clause_kind k, justification* j); void add(clause& c); void add(unsigned n, literal const* lits, clause_kind k, justification* j); + void propagate(literal lit, justification const& j, literal_vector const& ante); void del(clause& c); proof_ref get_proof(bool inconsistent); - bool on_clause_active() const { return m_on_clause_active; } + bool is_enabled() const { return m_enabled; } void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) { m_on_clause_eh = on_clause; m_on_clause_ctx = ctx; - m_on_clause_active = !!m_on_clause_eh; + m_enabled |= !!m_on_clause_eh; } }; diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 45ff1900d..d075c0652 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -350,6 +350,7 @@ namespace smt { literal_vector & antecedents = m_tmp_literal_vector; antecedents.reset(); justification2literals_core(js, antecedents); + m_ctx.get_clause_proof().propagate(consequent, *js, antecedents); for (literal l : antecedents) process_antecedent(l, num_marks); (void)consequent; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 84b4906ca..a8d2f268d 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -284,7 +284,7 @@ namespace smt { TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; display_literal_smt2(tout, l) << "\n"; tout << "relevant: " << is_relevant_core(l) << " level: " << m_scope_lvl << " is atom " << d.is_atom() << "\n"; - /*display(tout, j);*/ + display(tout, j); ); TRACE("phase_selection", tout << "saving phase, is_pos: " << d.m_phase << " l: " << l << "\n";); @@ -639,7 +639,6 @@ namespace smt { if (val != l_true) { if (val == l_false && js.get_kind() == eq_justification::CONGRUENCE) m_dyn_ack_manager.cg_conflict_eh(n1->get_expr(), n2->get_expr()); - assign(literal(v), mk_justification(eq_propagation_justification(lhs, rhs))); } // It is not necessary to reinsert the equality to the congruence table @@ -1347,6 +1346,7 @@ namespace smt { TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v));); if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) { literal n_eq = literal(l.var(), true); + IF_VERBOSE(0, verbose_stream() << "eq-conflict @" << m_scope_lvl << "\n"); set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), n_eq); } } @@ -3732,6 +3732,7 @@ namespace smt { flet l(m_searching, true); TRACE("after_init_search", display(tout);); IF_VERBOSE(2, verbose_stream() << "(smt.searching)\n";); + log_stats(); TRACE("search_lite", tout << "searching...\n";); lbool status = l_undef; unsigned curr_lvl = m_scope_lvl; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 4a5f64926..2b3a343f7 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1706,7 +1706,9 @@ namespace smt { void get_units(expr_ref_vector& result); - bool on_clause_active() const { return m_clause_proof.on_clause_active(); } + bool clause_proof_active() const { return m_clause_proof.is_enabled(); } + + clause_proof& get_clause_proof() { return m_clause_proof; } void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) { m_clause_proof.register_on_clause(ctx, on_clause); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 63848418f..26e23d92d 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1593,7 +1593,7 @@ namespace smt { TRACE("gate_clause", tout << mk_ll_pp(pr, m);); mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); } - else if (m_clause_proof.on_clause_active()) { + else if (clause_proof_active()) { ptr_buffer new_lits; for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; @@ -1638,7 +1638,7 @@ namespace smt { } mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); } - else if (pr && on_clause_active()) + else if (pr && clause_proof_active()) // support logging of quantifier instantiations and other more detailed information mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); else From 11b712fee0d06a6457f901cc29eff7a819415543 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 08:02:02 +0700 Subject: [PATCH 310/477] switch to new configuration convention in solver object --- src/sat/smt/euf_proof.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 877375246..5fbd632cd 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -34,11 +34,11 @@ namespace euf { if (!get_config().m_lemmas2console && !s().get_config().m_smt_proof_check && !m_on_clause && - !s().get_config().m_smt_proof.is_non_empty_string()) + !m_config.m_proof_log.is_non_empty_string()) return; - if (s().get_config().m_smt_proof.is_non_empty_string()) - m_proof_out = alloc(std::ofstream, s().get_config().m_smt_proof.str(), std::ios_base::out); + if (m_config.m_proof_log.is_non_empty_string()) + m_proof_out = alloc(std::ofstream, m_config.m_proof_log.str(), std::ios_base::out); get_drat().set_clause_eh(*this); m_proof_initialized = true; } From 22353c2d6cd90186133654796564384b5b60bfba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 11:37:07 +0700 Subject: [PATCH 311/477] new core perf - add merge_tf and enable_cgc distinction perf fix for propagation behavior for equalities in the new core. The old behavior was not to allow congruence closure on equalities. The new behavior is to just not allow merging tf with equalities unless they appear somewhere in a foreign context (not under a Boolean operator) The change re-surfaces merge_tf and enable_cgc distinction from the old core. They can both be turned on or off. merge_enabled renamed to cgc_enabled The change is highly likely to introduce regressions in the new core. Change propagation of literals from congruence: - track antecedent enode. There are four ways to propagate literals from the egraph. - the literal is an equality and the two arguments are congruent - the antecedent is merged with node n and the antecedent has a Boolean variable assignment. - the antecedent is true or false, they are merged. - the merge_tf flag is toggled to true but the node n has not been merged with true/false --- src/ast/euf/euf_egraph.cpp | 108 +++++++++++++++---------- src/ast/euf/euf_egraph.h | 23 +++--- src/ast/euf/euf_enode.cpp | 4 +- src/ast/euf/euf_enode.h | 17 ++-- src/ast/rewriter/th_rewriter.cpp | 2 + src/ast/simplifiers/euf_completion.cpp | 7 +- src/sat/smt/arith_internalize.cpp | 2 +- src/sat/smt/euf_internalize.cpp | 47 +++-------- src/sat/smt/euf_solver.cpp | 93 ++++++++++++++------- src/sat/smt/euf_solver.h | 6 +- 10 files changed, 177 insertions(+), 132 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 666a7fad6..1448ee8d7 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -36,8 +36,10 @@ namespace euf { } m_expr2enode.setx(f->get_id(), n, nullptr); push_node(n); - for (unsigned i = 0; i < num_args; ++i) - set_merge_enabled(args[i], true); + for (unsigned i = 0; i < num_args; ++i) { + set_cgc_enabled(args[i], true); + set_merge_tf_enabled(args[i], true); + } return n; } @@ -78,9 +80,8 @@ namespace euf { void egraph::reinsert_equality(enode* p) { SASSERT(p->is_equality()); - if (p->value() != l_true && p->get_arg(0)->get_root() == p->get_arg(1)->get_root()) { - add_literal(p, true); - } + if (p->value() != l_true && p->get_arg(0)->get_root() == p->get_arg(1)->get_root()) + add_literal(p, nullptr); } void egraph::force_push() { @@ -116,18 +117,16 @@ namespace euf { m_on_make(n); if (num_args == 0) return n; - if (m.is_eq(f)) { + if (m.is_eq(f) && !m.is_iff(f)) { n->set_is_equality(); - update_children(n); reinsert_equality(n); } - else { - auto [n2, comm] = insert_table(n); - if (n2 == n) - update_children(n); - else - merge(n, n2, justification::congruence(comm, m_congruence_timestamp++)); - } + auto [n2, comm] = insert_table(n); + if (n2 == n) + update_children(n); + else + merge(n, n2, justification::congruence(comm, m_congruence_timestamp++)); + return n; } @@ -158,11 +157,11 @@ namespace euf { ++m_stats.m_num_th_diseqs; } - void egraph::add_literal(enode* n, bool is_eq) { + void egraph::add_literal(enode* n, enode* ante) { TRACE("euf_verbose", tout << "lit: " << n->get_expr_id() << "\n";); - m_new_lits.push_back(enode_bool_pair(n, is_eq)); + m_new_lits.push_back(enode_pair(n, ante)); m_updates.push_back(update_record(update_record::new_lit())); - if (is_eq) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits; + if (!ante) ++m_stats.m_num_eqs; else ++m_stats.m_num_lits; } void egraph::new_diseq(enode* n) { @@ -173,7 +172,7 @@ namespace euf { enode* r2 = arg2->get_root(); TRACE("euf", tout << "new-diseq: " << bpp(r1) << " " << bpp(r2) << ": " << r1->has_th_vars() << " " << r2->has_th_vars() << "\n";); if (r1 == r2) { - add_literal(n, true); + add_literal(n, nullptr); return; } if (!r1->has_th_vars()) @@ -264,10 +263,26 @@ namespace euf { root->del_th_var(tid); } - void egraph::set_merge_enabled(enode* n, bool enable_merge) { - if (enable_merge != n->merge_enabled()) { - toggle_merge_enabled(n, false); - m_updates.push_back(update_record(n, update_record::toggle_merge())); + void egraph::set_merge_tf_enabled(enode* n, bool enable_merge_tf) { + if (!m.is_bool(n->get_sort())) + return; + if (enable_merge_tf != n->merge_tf()) { + n->set_merge_tf(enable_merge_tf); + m_updates.push_back(update_record(n, update_record::toggle_merge_tf())); + if (enable_merge_tf && n->value() != l_undef && !m.is_value(n->get_root()->get_expr())) { + expr* b = n->value() == l_true ? m.mk_true() : m.mk_false(); + enode* tf = find(b); + if (!tf) + tf = mk(b, 0, 0, nullptr); + add_literal(n, tf); + } + } + } + + void egraph::set_cgc_enabled(enode* n, bool enable_merge) { + if (enable_merge != n->cgc_enabled()) { + toggle_cgc_enabled(n, false); + m_updates.push_back(update_record(n, update_record::toggle_cgc())); } } @@ -278,9 +293,9 @@ namespace euf { m_updates.push_back(update_record(n, update_record::set_relevant())); } - void egraph::toggle_merge_enabled(enode* n, bool backtracking) { - bool enable_merge = !n->merge_enabled(); - n->set_merge_enabled(enable_merge); + void egraph::toggle_cgc_enabled(enode* n, bool backtracking) { + bool enable_merge = !n->cgc_enabled(); + n->set_cgc_enabled(enable_merge); if (n->num_args() > 0) { if (enable_merge) { auto [n2, comm] = insert_table(n); @@ -290,7 +305,7 @@ namespace euf { else if (n->is_cgr()) erase_from_table(n); } - VERIFY(n->num_args() == 0 || !n->merge_enabled() || m_table.contains(n)); + VERIFY(n->num_args() == 0 || !n->cgc_enabled() || m_table.contains(n)); } void egraph::set_value(enode* n, lbool value, justification j) { @@ -300,6 +315,8 @@ namespace euf { n->set_value(value); n->m_lit_justification = j; m_updates.push_back(update_record(n, update_record::value_assignment())); + if (n->is_equality() && n->value() == l_false) + new_diseq(n); } } @@ -352,8 +369,11 @@ namespace euf { case update_record::tag_t::is_add_node: undo_node(); break; - case update_record::tag_t::is_toggle_merge: - toggle_merge_enabled(p.r1, true); + case update_record::tag_t::is_toggle_cgc: + toggle_cgc_enabled(p.r1, true); + break; + case update_record::tag_t::is_toggle_merge_tf: + p.r1->set_merge_tf(!p.r1->merge_tf()); break; case update_record::tag_t::is_set_parent: undo_eq(p.r1, p.n1, p.r2_num_parents); @@ -419,7 +439,7 @@ namespace euf { void egraph::merge(enode* n1, enode* n2, justification j) { - if (!n1->merge_enabled() && !n2->merge_enabled()) + if (!n1->cgc_enabled() && !n2->cgc_enabled()) return; SASSERT(n1->get_sort() == n2->get_sort()); enode* r1 = n1->get_root(); @@ -436,6 +456,7 @@ namespace euf { set_conflict(n1, n2, j); return; } + if (r1->value() != r2->value() && r1->value() != l_undef && r2->value() != l_undef) { SASSERT(m.is_bool(r1->get_expr())); set_conflict(n1, n2, j); @@ -448,9 +469,11 @@ namespace euf { } 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) - new_diseq(n1); + add_literal(n1, r2); + if (r2->value() != l_undef && n1->value() == l_undef) + add_literal(n1, r2); + else if (r1->value() != l_undef && n2->value() == l_undef) + add_literal(n2, r1); remove_parents(r1); push_eq(r1, n1, r2->num_parents()); merge_justification(n1, n2, j); @@ -468,7 +491,7 @@ namespace euf { for (enode* p : enode_parents(r)) { if (p->is_marked1()) continue; - if (p->merge_enabled()) { + if (p->cgc_enabled()) { if (!p->is_cgr()) continue; SASSERT(m_table.contains_ptr(p)); @@ -486,8 +509,8 @@ namespace euf { if (!p->is_marked1()) continue; p->unmark1(); - TRACE("euf", tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->merge_enabled() << "\n";); - if (p->merge_enabled()) { + TRACE("euf", tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->cgc_enabled() << "\n";); + if (p->cgc_enabled()) { auto [p_other, comm] = insert_table(p); SASSERT(m_table.contains_ptr(p) == (p_other == p)); TRACE("euf", tout << "other " << bpp(p_other) << "\n";); @@ -531,9 +554,9 @@ namespace euf { for (auto it = begin; it != end; ++it) { enode* p = *it; TRACE("euf", tout << "erase " << bpp(p) << "\n";); - SASSERT(!p->merge_enabled() || m_table.contains_ptr(p)); - SASSERT(!p->merge_enabled() || p->is_cgr()); - if (p->merge_enabled()) + SASSERT(!p->cgc_enabled() || m_table.contains_ptr(p)); + SASSERT(!p->cgc_enabled() || p->is_cgr()); + if (p->cgc_enabled()) erase_from_table(p); } @@ -541,7 +564,7 @@ namespace euf { c->m_root = r1; for (enode* p : enode_parents(r1)) - if (p->merge_enabled() && (p->is_cgr() || !p->congruent(p->m_cg))) + if (p->cgc_enabled() && (p->is_cgr() || !p->congruent(p->m_cg))) insert_table(p); r2->m_parents.shrink(r2_num_parents); unmerge_justification(n1); @@ -783,7 +806,7 @@ namespace euf { for (enode* n : m_nodes) n->invariant(*this); for (enode* n : m_nodes) - if (n->merge_enabled() && n->num_args() > 0 && (!m_table.find(n) || n->get_root() != m_table.find(n)->get_root())) { + if (n->cgc_enabled() && n->num_args() > 0 && (!m_table.find(n) || n->get_root() != m_table.find(n)->get_root())) { CTRACE("euf", !m_table.find(n), tout << "node is not in table\n";); CTRACE("euf", m_table.find(n), tout << "root " << bpp(n->get_root()) << " table root " << bpp(m_table.find(n)->get_root()) << "\n";); TRACE("euf", display(tout << bpp(n) << " is not closed under congruence\n");); @@ -818,7 +841,7 @@ namespace euf { } }; if (n->bool_var() != sat::null_bool_var) - out << "[b" << n->bool_var() << " := " << value_of() << (n->merge_tf() ? "" : " no merge") << "] "; + out << "[b" << n->bool_var() << " := " << value_of() << (n->cgc_enabled() ? "" : " no-cgc") << (n->merge_tf()? " merge-tf" : "") << "] "; if (n->has_th_vars()) { out << "[t"; for (auto const& v : enode_th_vars(n)) @@ -873,7 +896,8 @@ namespace euf { n2->set_value(n1->value()); n2->m_bool_var = n1->m_bool_var; n2->m_commutative = n1->m_commutative; - n2->m_merge_enabled = n1->m_merge_enabled; + n2->m_cgc_enabled = n1->m_cgc_enabled; + n2->m_merge_tf_enabled = n1->m_merge_tf_enabled; n2->m_is_equality = n1->m_is_equality; } for (unsigned i = 0; i < src.m_nodes.size(); ++i) { diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index d6bcb9cd3..1686be384 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -101,7 +101,8 @@ namespace euf { void reset() { memset(this, 0, sizeof(*this)); } }; struct update_record { - struct toggle_merge {}; + struct toggle_cgc {}; + struct toggle_merge_tf {}; struct add_th_var {}; struct replace_th_var {}; struct new_lit {}; @@ -114,7 +115,7 @@ namespace euf { struct lbl_set {}; struct update_children {}; struct set_relevant {}; - enum class tag_t { is_set_parent, is_add_node, is_toggle_merge, is_update_children, + enum class tag_t { is_set_parent, is_add_node, is_toggle_cgc, is_toggle_merge_tf, is_update_children, is_add_th_var, is_replace_th_var, is_new_lit, is_new_th_eq, is_lbl_hash, is_new_th_eq_qhead, is_new_lits_qhead, is_inconsistent, is_value_assignment, is_lbl_set, is_set_relevant }; @@ -136,8 +137,10 @@ namespace euf { tag(tag_t::is_set_parent), r1(r1), n1(n1), r2_num_parents(r2_num_parents) {} update_record(enode* n) : tag(tag_t::is_add_node), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {} - update_record(enode* n, toggle_merge) : - tag(tag_t::is_toggle_merge), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {} + update_record(enode* n, toggle_cgc) : + tag(tag_t::is_toggle_cgc), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {} + update_record(enode* n, toggle_merge_tf) : + tag(tag_t::is_toggle_merge_tf), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {} update_record(enode* n, unsigned id, add_th_var) : tag(tag_t::is_add_th_var), r1(n), n1(nullptr), r2_num_parents(id) {} update_record(enode* n, theory_id id, theory_var v, replace_th_var) : @@ -186,7 +189,7 @@ namespace euf { justification m_justification; unsigned m_new_lits_qhead = 0; unsigned m_new_th_eqs_qhead = 0; - svector m_new_lits; + svector m_new_lits; svector m_new_th_eqs; bool_vector m_th_propagates_diseqs; enode_vector m_todo; @@ -210,7 +213,7 @@ namespace euf { void add_th_diseqs(theory_id id, theory_var v1, enode* r); bool th_propagates_diseqs(theory_id id) const; - void add_literal(enode* n, bool is_eq); + void add_literal(enode* n, enode* ante); void undo_eq(enode* r1, enode* n1, unsigned r2_num_parents); void undo_add_th_var(enode* n, theory_id id); enode* mk_enode(expr* f, unsigned generation, unsigned num_args, enode * const* args); @@ -229,7 +232,7 @@ namespace euf { void push_to_lca(enode* a, enode* lca); void push_congruence(enode* n1, enode* n2, bool commutative); void push_todo(enode* n); - void toggle_merge_enabled(enode* n, bool backtracking); + void toggle_cgc_enabled(enode* n, bool backtracking); enode_bool_pair insert_table(enode* p); void erase_from_table(enode* p); @@ -289,7 +292,7 @@ namespace euf { void add_th_diseq(theory_id id, theory_var v1, theory_var v2, expr* eq); bool has_literal() const { return m_new_lits_qhead < m_new_lits.size(); } bool has_th_eq() const { return m_new_th_eqs_qhead < m_new_th_eqs.size(); } - enode_bool_pair get_literal() const { return m_new_lits[m_new_lits_qhead]; } + enode_pair get_literal() const { return m_new_lits[m_new_lits_qhead]; } th_eq get_th_eq() const { return m_new_th_eqs[m_new_th_eqs_qhead]; } void next_literal() { force_push(); SASSERT(m_new_lits_qhead < m_new_lits.size()); m_new_lits_qhead++; } void next_th_eq() { force_push(); SASSERT(m_new_th_eqs_qhead < m_new_th_eqs.size()); m_new_th_eqs_qhead++; } @@ -299,7 +302,9 @@ namespace euf { void add_th_var(enode* n, theory_var v, theory_id id); void set_th_propagates_diseqs(theory_id id); - void set_merge_enabled(enode* n, bool enable_merge); + void set_cgc_enabled(enode* n, bool enable_cgc); + void set_merge_tf_enabled(enode* n, bool enable_merge_tf); + void set_value(enode* n, lbool value, justification j); void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); } void set_relevant(enode* n); diff --git a/src/ast/euf/euf_enode.cpp b/src/ast/euf/euf_enode.cpp index 038325790..08df9f493 100644 --- a/src/ast/euf/euf_enode.cpp +++ b/src/ast/euf/euf_enode.cpp @@ -36,7 +36,7 @@ namespace euf { if (is_root()) { VERIFY(!m_target); for (enode* p : enode_parents(this)) { - if (!p->merge_enabled()) + if (!p->cgc_enabled()) continue; bool found = false; for (enode* arg : enode_args(p)) { @@ -49,7 +49,7 @@ namespace euf { if (c == this) continue; for (enode* p : enode_parents(c)) { - if (!p->merge_enabled()) + if (!p->cgc_enabled()) continue; bool found = false; for (enode* q : enode_parents(this)) { diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h index 18a1a86af..d9ae45074 100644 --- a/src/ast/euf/euf_enode.h +++ b/src/ast/euf/euf_enode.h @@ -48,7 +48,8 @@ namespace euf { bool m_mark3 = false; bool m_commutative = false; bool m_interpreted = false; - bool m_merge_enabled = true; + bool m_cgc_enabled = true; + bool m_merge_tf_enabled = false; bool m_is_equality = false; // Does the expression represent an equality bool m_is_relevant = false; lbool m_value = l_undef; // Assignment by SAT solver for Boolean node @@ -91,7 +92,7 @@ namespace euf { n->m_generation = generation, n->m_commutative = num_args == 2 && is_app(f) && to_app(f)->get_decl()->is_commutative(); n->m_num_args = num_args; - n->m_merge_enabled = true; + n->m_cgc_enabled = true; for (unsigned i = 0; i < num_args; ++i) { SASSERT(to_app(f)->get_arg(i) == args[i]->get_expr()); n->m_args[i] = args[i]; @@ -107,7 +108,7 @@ namespace euf { n->m_root = n; n->m_commutative = true; n->m_num_args = 2; - n->m_merge_enabled = true; + n->m_cgc_enabled = true; for (unsigned i = 0; i < num_args; ++i) n->m_args[i] = nullptr; return n; @@ -121,7 +122,7 @@ namespace euf { n->m_root = n; n->m_commutative = true; n->m_num_args = 2; - n->m_merge_enabled = true; + n->m_cgc_enabled = true; for (unsigned i = 0; i < num_args; ++i) n->m_args[i] = nullptr; return n; @@ -132,7 +133,8 @@ namespace euf { void add_th_var(theory_var v, theory_id id, region & r) { m_th_vars.add_var(v, id, r); } void replace_th_var(theory_var v, theory_id id) { m_th_vars.replace(v, id); } void del_th_var(theory_id id) { m_th_vars.del_var(id); } - void set_merge_enabled(bool m) { m_merge_enabled = m; } + void set_cgc_enabled(bool m) { m_cgc_enabled = m; } + void set_merge_tf(bool m) { m_merge_tf_enabled = m; } void set_value(lbool v) { m_value = v; } void set_justification(justification j) { m_justification = j; } void set_is_equality() { m_is_equality = true; } @@ -152,14 +154,13 @@ namespace euf { bool is_relevant() const { return m_is_relevant; } void set_relevant(bool b) { m_is_relevant = b; } lbool value() const { return m_value; } - bool value_conflict() const { return value() != l_undef && get_root()->value() != l_undef && value() != get_root()->value(); } sat::bool_var bool_var() const { return m_bool_var; } bool is_cgr() const { return this == m_cg; } enode* get_cg() const { return m_cg; } bool commutative() const { return m_commutative; } void mark_interpreted() { SASSERT(num_args() == 0); m_interpreted = true; } - bool merge_enabled() const { return m_merge_enabled; } - bool merge_tf() const { return merge_enabled() && (class_size() > 1 || num_parents() > 0 || num_args() > 0); } + bool cgc_enabled() const { return m_cgc_enabled; } + bool merge_tf() const { return m_merge_tf_enabled && (class_size() > 1 || num_parents() > 0 || num_args() > 0); } enode* get_arg(unsigned i) const { SASSERT(i < num_args()); return m_args[i]; } unsigned hash() const { return m_expr->get_id(); } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 4c7d4dc49..9bc8c22cf 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -707,6 +707,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_ref mk_eq(expr* a, expr* b) { expr_ref result(m()); + if (a->get_id() > b->get_id()) + std::swap(a, b); if (BR_FAILED == reduce_eq(a, b, result)) result = m().mk_eq(a, b); return result; diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index ac1ecc47a..1ca980d07 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -211,8 +211,8 @@ namespace euf { if (x == y) return expr_ref(m.mk_true(), m); - if (x == x1 && y == y1) - return expr_ref(f, m); + if (x == x1 && y == y1) + return m_rewriter.mk_eq(x, y); if (is_nullary(x) && is_nullary(y)) return mk_and(m_rewriter.mk_eq(x, x1), m_rewriter.mk_eq(y, x1)); @@ -268,7 +268,8 @@ namespace euf { m_eargs.push_back(get_canonical(arg, d)); change |= arg != m_eargs.back(); } - + if (m.is_eq(f)) + return m_rewriter.mk_eq(m_eargs.get(0), m_eargs.get(1)); if (!change) return expr_ref(f, m); else diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 04a3ae4ef..d35f79954 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -372,7 +372,7 @@ namespace arith { enode* n = ctx.get_enode(atom); theory_var w = mk_var(n); ctx.attach_th_var(n, this, w); - ctx.get_egraph().set_merge_enabled(n, false); + ctx.get_egraph().set_cgc_enabled(n, false); if (is_int(v) && !r.is_int()) r = (k == lp_api::upper_t) ? floor(r) : ceil(r); api_bound* b = mk_var_bound(lit, v, k, r); diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 9f747090a..3aaafa36c 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -74,10 +74,8 @@ namespace euf { } if (auto* ext = expr2solver(e)) return ext->internalize(e, sign, root); - if (!visit_rec(m, e, sign, root)) { - TRACE("euf", tout << "visit-rec\n";); + if (!visit_rec(m, e, sign, root)) return sat::null_literal; - } SASSERT(get_enode(e)); if (m.is_bool(e)) return literal(si.to_bool_var(e), sign); @@ -119,7 +117,7 @@ namespace euf { SASSERT(!get_enode(e)); if (auto* s = expr2solver(e)) s->internalize(e); - else + else attach_node(mk_enode(e, num, m_args.data())); return true; } @@ -188,6 +186,7 @@ namespace euf { return lit; } + set_bool_var2expr(v, e); enode* n = m_egraph.find(e); if (!n) @@ -195,8 +194,8 @@ namespace euf { CTRACE("euf", n->bool_var() != sat::null_bool_var && n->bool_var() != v, display(tout << bpp(n) << " " << n->bool_var() << " vs " << v << "\n")); SASSERT(n->bool_var() == sat::null_bool_var || n->bool_var() == v); m_egraph.set_bool_var(n, v); - if (m.is_eq(e) || m.is_or(e) || m.is_and(e) || m.is_not(e)) - m_egraph.set_merge_enabled(n, false); + if (si.is_bool_op(e)) + m_egraph.set_cgc_enabled(n, false); lbool val = s().value(lit); if (val != l_undef) m_egraph.set_value(n, val, justification::external(to_ptr(val == l_true ? lit : ~lit))); @@ -349,15 +348,6 @@ namespace euf { else if (m.is_eq(e, th, el) && !m.is_iff(e)) { sat::literal lit1 = expr2literal(e); s().set_phase(lit1); - expr_ref e2(m.mk_eq(el, th), m); - enode* n2 = m_egraph.find(e2); - if (n2) { - sat::literal lit2 = expr2literal(e2); - add_root(~lit1, lit2); - add_root(lit1, ~lit2); - s().add_clause(~lit1, lit2, mk_distinct_status(~lit1, lit2)); - s().add_clause(lit1, ~lit2, mk_distinct_status(lit1, ~lit2)); - } } } @@ -476,26 +466,15 @@ namespace euf { return n; } - euf::enode* solver::mk_enode(expr* e, unsigned n, enode* const* args) { - euf::enode* r = m_egraph.mk(e, m_generation, n, args); - for (unsigned i = 0; i < n; ++i) - ensure_merged_tf(args[i]); - return r; - } + euf::enode* solver::mk_enode(expr* e, unsigned num, enode* const* args) { - void solver::ensure_merged_tf(euf::enode* n) { - switch (n->value()) { - case l_undef: - break; - case l_true: - if (n->get_root() != mk_true()) - m_egraph.merge(n, mk_true(), to_ptr(sat::literal(n->bool_var()))); - break; - case l_false: - if (n->get_root() != mk_false()) - m_egraph.merge(n, mk_false(), to_ptr(~sat::literal(n->bool_var()))); - break; - } + if (si.is_bool_op(e)) + num = 0; + + enode* n = m_egraph.mk(e, m_generation, num, args); + if (si.is_bool_op(e)) + m_egraph.set_cgc_enabled(n, false); + return n; } } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 7b02509ee..9b346543f 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -316,13 +316,23 @@ namespace euf { SASSERT(!l.sign()); m_egraph.explain_eq(m_explain, cc, n->get_arg(0), n->get_arg(1)); break; - case constraint::kind_t::lit: + case constraint::kind_t::lit: { e = m_bool_var2expr[l.var()]; n = m_egraph.find(e); + enode* ante = j.node(); SASSERT(n); SASSERT(m.is_bool(n->get_expr())); - m_egraph.explain_eq(m_explain, cc, n, (l.sign() ? mk_false() : mk_true())); + SASSERT(ante->get_root() == n->get_root()); + m_egraph.explain_eq(m_explain, cc, n, ante); + if (!m.is_true(ante->get_expr()) && !m.is_false(ante->get_expr())) { + bool_var v = ante->bool_var(); + lbool val = ante->value(); + SASSERT(val != l_undef); + literal ante(v, val == l_false); + m_explain.push_back(to_ptr(ante)); + } break; + } default: IF_VERBOSE(0, verbose_stream() << (unsigned)j.kind() << "\n"); UNREACHABLE(); @@ -345,24 +355,30 @@ namespace euf { euf::enode* n = m_egraph.find(e); if (!n) return; - bool sign = l.sign(); - m_egraph.set_value(n, sign ? l_false : l_true, justification::external(to_ptr(l))); + bool sign = l.sign(); + lbool old_value = n->value(); + lbool new_value = sign ? l_false : l_true; + m_egraph.set_value(n, new_value, justification::external(to_ptr(l))); + if (old_value == l_undef && n->cgc_enabled()) { + for (enode* k : enode_class(n)) { + if (k->bool_var() == sat::null_bool_var) + continue; + if (k->value() == new_value) + continue; + auto& c = lit_constraint(n); + propagate(literal(k->bool_var(), sign), c.to_index()); + if (k->value() == l_undef) + m_egraph.set_value(k, new_value, justification::external(to_ptr(l))); + else + return; + } + } for (auto const& th : enode_th_vars(n)) m_id2solver[th.get_id()]->asserted(l); size_t* c = to_ptr(l); SASSERT(is_literal(c)); 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); @@ -374,9 +390,17 @@ namespace euf { m_egraph.new_diseq(n); else m_egraph.merge(n->get_arg(0), n->get_arg(1), c); - } + } } + constraint& solver::lit_constraint(enode* n) { + void* mem = get_region().allocate(sat::constraint_base::obj_size(sizeof(constraint))); + auto* c = new (sat::constraint_base::ptr2mem(mem)) constraint(n); + sat::constraint_base::initialize(mem, this); + return *c; + } + + bool solver::unit_propagate() { bool propagated = false; @@ -412,37 +436,44 @@ namespace euf { void solver::propagate_literals() { for (; m_egraph.has_literal() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_literal()) { - auto [n, is_eq] = m_egraph.get_literal(); + auto [n, ante] = m_egraph.get_literal(); expr* e = n->get_expr(); expr* a = nullptr, *b = nullptr; bool_var v = n->bool_var(); SASSERT(m.is_bool(e)); size_t cnstr; - literal lit; - if (is_eq) { + literal lit; + if (!ante) { VERIFY(m.is_eq(e, a, b)); cnstr = eq_constraint().to_index(); lit = literal(v, false); } 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); - cnstr = lit_constraint().to_index(); + // + // There are the following three cases for propagation of literals + // + // 1. n == ante is true from equallity, ante = true/false + // 2. n == ante is true from equality, value(ante) != l_undef + // 3. value(n) != l_undef, ante = true/false, merge_tf is set on n + // + lbool val = ante->value(); + if (val == l_undef) { + SASSERT(m.is_value(ante->get_expr())); + val = m.is_true(ante->get_expr()) ? l_true : l_false; + } + auto& c = lit_constraint(ante); + cnstr = c.to_index(); lit = literal(v, val == l_false); } unsigned lvl = s().scope_lvl(); - CTRACE("euf", s().value(lit) != l_true, tout << lit << " " << s().value(lit) << "@" << lvl << " " << is_eq << " " << mk_bounded_pp(a, m) << " = " << mk_bounded_pp(b, m) << "\n";); - if (s().value(lit) == l_false && m_ackerman) + CTRACE("euf", s().value(lit) != l_true, tout << lit << " " << s().value(lit) << "@" << lvl << " " << mk_bounded_pp(a, m) << " = " << mk_bounded_pp(b, m) << "\n";); + if (s().value(lit) == l_false && m_ackerman && a && b) m_ackerman->cg_conflict_eh(a, b); switch (s().value(lit)) { case l_true: + if (n->merge_tf() && !m.is_value(n->get_root()->get_expr())) + m_egraph.merge(n, ante, to_ptr(lit)); break; case l_undef: case l_false: @@ -889,7 +920,7 @@ namespace euf { if (m.is_eq(e) && !m.is_iff(e)) ok = false; euf::enode* n = get_enode(e); - if (n && n->merge_enabled()) + if (n && n->cgc_enabled()) ok = false; (void)ok; @@ -938,7 +969,7 @@ namespace euf { case constraint::kind_t::eq: return out << "euf equality propagation"; case constraint::kind_t::lit: - return out << "euf literal propagation"; + return out << "euf literal propagation " << m_egraph.bpp(c.node()) ; default: UNREACHABLE(); return out; diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index f935ad9ff..5b09e6a46 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -45,9 +45,12 @@ namespace euf { enum class kind_t { conflict, eq, lit }; private: kind_t m_kind; + enode* m_node = nullptr; public: constraint(kind_t k) : m_kind(k) {} + constraint(enode* n): m_kind(kind_t::lit), m_node(n) {} kind_t kind() const { return m_kind; } + enode* node() const { SASSERT(kind() == kind_t::lit); return m_node; } static constraint& from_idx(size_t z) { return *reinterpret_cast(sat::constraint_base::idx2mem(z)); } @@ -171,7 +174,6 @@ namespace euf { void add_not_distinct_axiom(app* e, euf::enode* const* args); void axiomatize_basic(enode* n); bool internalize_root(app* e, bool sign, ptr_vector const& args); - void ensure_merged_tf(euf::enode* n); euf::enode* mk_true(); euf::enode* mk_false(); @@ -250,7 +252,7 @@ namespace euf { constraint& mk_constraint(constraint*& c, constraint::kind_t k); constraint& conflict_constraint() { return mk_constraint(m_conflict, constraint::kind_t::conflict); } constraint& eq_constraint() { return mk_constraint(m_eq, constraint::kind_t::eq); } - constraint& lit_constraint() { return mk_constraint(m_lit, constraint::kind_t::lit); } + constraint& lit_constraint(enode* n); // user propagator void check_for_user_propagator() { From 9a2693bb72f8973f891618622fdfd0e78f831f41 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 16:39:20 +0700 Subject: [PATCH 312/477] tune euf-completion --- src/ast/rewriter/bool_rewriter.cpp | 4 ++ src/ast/rewriter/bool_rewriter.h | 10 +-- src/ast/rewriter/th_rewriter.cpp | 11 +++- src/ast/rewriter/th_rewriter.h | 1 + src/ast/simplifiers/euf_completion.cpp | 88 ++++++++++++++++++++++++-- src/ast/simplifiers/euf_completion.h | 1 + 6 files changed, 104 insertions(+), 11 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index ffceec277..5abfe01a6 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -780,6 +780,10 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { } } } + if (m_order_eq && lhs->get_id() > rhs->get_id()) { + result = m().mk_eq(rhs, lhs); + return BR_DONE; + } return BR_FAILED; } diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index 2cec0b2ce..8f2221a8c 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -52,10 +52,11 @@ Notes: class bool_rewriter { ast_manager & m_manager; hoist_rewriter m_hoist; - bool m_flat_and_or; - bool m_local_ctx; - bool m_elim_and; - bool m_blast_distinct; + bool m_flat_and_or = false; + bool m_local_ctx = false; + bool m_elim_and = false; + bool m_blast_distinct = false; + bool m_order_eq = false; unsigned m_blast_distinct_threshold; bool m_ite_extra_rules; unsigned m_local_ctx_limit; @@ -90,6 +91,7 @@ public: bool elim_and() const { return m_elim_and; } void set_elim_and(bool f) { m_elim_and = f; } void reset_local_ctx_cost() { m_local_ctx_cost = 0; } + void set_order_eq(bool f) { m_order_eq = f; } void updt_params(params_ref const & p); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 9bc8c22cf..456a7afba 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -707,9 +707,10 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_ref mk_eq(expr* a, expr* b) { expr_ref result(m()); - if (a->get_id() > b->get_id()) - std::swap(a, b); - if (BR_FAILED == reduce_eq(a, b, result)) + br_status st = reduce_eq(a, b, result); + if (BR_FAILED == st) + st = m_b_rw.mk_eq_core(a, b, result); + if (BR_FAILED == st) result = m().mk_eq(a, b); return result; } @@ -945,6 +946,10 @@ void th_rewriter::set_flat_and_or(bool f) { m_imp->cfg().m_b_rw.set_flat_and_or(f); } +void th_rewriter::set_order_eq(bool f) { + m_imp->cfg().m_b_rw.set_order_eq(f); +} + th_rewriter::~th_rewriter() { dealloc(m_imp); } diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index 2c08c247d..a3f003799 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -40,6 +40,7 @@ public: static void get_param_descrs(param_descrs & r); void set_flat_and_or(bool f); + void set_order_eq(bool f); unsigned get_cache_size() const; unsigned get_num_steps() const; diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 1ca980d07..2825f3244 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -43,6 +43,7 @@ Algorithm for extracting canonical form from an E-graph: #include "ast/ast_util.h" #include "ast/euf/euf_egraph.h" #include "ast/simplifiers/euf_completion.h" +#include "ast/shared_occs.h" namespace euf { @@ -55,20 +56,99 @@ namespace euf { m_rewriter(m) { m_tt = m_egraph.mk(m.mk_true(), 0, 0, nullptr); m_ff = m_egraph.mk(m.mk_false(), 0, 0, nullptr); + m_rewriter.set_order_eq(true); + m_rewriter.set_flat_and_or(false); } void completion::reduce() { - unsigned rounds = 0; - do { + + propagate_values(); + if (m_fmls.inconsistent()) + return; + m_has_new_eq = true; + for (unsigned rounds = 0; m_has_new_eq && rounds <= 3 && !m_fmls.inconsistent(); ++rounds) { ++m_epoch; - ++rounds; m_has_new_eq = false; add_egraph(); map_canonical(); read_egraph(); IF_VERBOSE(11, verbose_stream() << "(euf.completion :rounds " << rounds << ")\n"); } - while (m_has_new_eq && rounds <= 3); + } + + /** + * Propagate writes into values first. It is cheaper to propagate values directly than using + * the E-graph. The E-graph suffers from the following overhead: it prefers interpreted nodes + * as roots and therefore the "merge" function ignores the heuristic of choosing the node to appoint root + * as the one with the fewest parents. Merging a constant value with multiple terms then has a compounding + * quadratic time overhead since the parents of the value are removed and re-inserted into the congruence + * table repeatedly and with growing size (exceeding the n*log(n) overhead when choosing the root to + * have the fewest parents). + */ + void completion::propagate_values() { + shared_occs shared(m, true); + expr_substitution subst(m, true, false); + expr* x, * y; + expr_ref_buffer args(m); + auto add_shared = [&]() { + shared_occs_mark visited; + shared.reset(); + for (unsigned i = 0; i < m_fmls.size(); ++i) + shared(m_fmls[i].fml(), visited); + }; + + auto add_sub = [&](dependent_expr const& de) { + auto const& [f, dep] = de(); + if (m.is_not(f, x) && shared.is_shared(x)) + subst.insert(x, m.mk_false(), dep); + else if (shared.is_shared(f)) + subst.insert(f, m.mk_true(), dep); + if (m.is_eq(f, x, y) && m.is_value(x) && shared.is_shared(y)) + subst.insert(y, x, dep); + else if (m.is_eq(f, x, y) && m.is_value(y) && shared.is_shared(x)) + subst.insert(x, y, dep); + }; + + auto process_fml = [&](unsigned i) { + expr* f = m_fmls[i].fml(); + expr_dependency* dep = m_fmls[i].dep(); + expr_ref fml(m); + proof_ref pr(m); + m_rewriter(f, fml, pr); + if (fml != f) { + dep = m.mk_join(dep, m_rewriter.get_used_dependencies()); + m_fmls.update(i, dependent_expr(m, fml, dep)); + ++m_stats.m_num_rewrites; + } + m_rewriter.reset_used_dependencies(); + add_sub(m_fmls[i]); + }; + + unsigned rw = m_stats.m_num_rewrites + 1; + for (unsigned r = 0; r < 4 && rw != m_stats.m_num_rewrites; ++r) { + rw = m_stats.m_num_rewrites; + add_shared(); + subst.reset(); + m_rewriter.reset(); + m_rewriter.set_substitution(&subst); + for (unsigned i = 0; i < m_qhead; ++i) + add_sub(m_fmls[i]); + for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) + process_fml(i); + add_shared(); + subst.reset(); + m_rewriter.reset(); + m_rewriter.set_substitution(&subst); + for (unsigned i = 0; i < m_qhead; ++i) + add_sub(m_fmls[i]); + for (unsigned i = m_fmls.size(); i-- > m_qhead && !m_fmls.inconsistent();) + process_fml(i); + if (subst.empty()) + break; + } + + m_rewriter.set_substitution(nullptr); + m_rewriter.reset(); } void completion::add_egraph() { diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h index f02e33245..830f8655e 100644 --- a/src/ast/simplifiers/euf_completion.h +++ b/src/ast/simplifiers/euf_completion.h @@ -46,6 +46,7 @@ namespace euf { bool is_new_eq(expr* a, expr* b); void update_has_new_eq(expr* g); expr_ref mk_and(expr* a, expr* b); + void propagate_values(); void add_egraph(); void map_canonical(); void read_egraph(); From 0a28bacd0f6d46a8ac61229fe8bd118b158b1bba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 16:42:36 +0700 Subject: [PATCH 313/477] remove debug out --- src/smt/smt_context.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a8d2f268d..45c469bde 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1346,7 +1346,6 @@ namespace smt { TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v));); if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) { literal n_eq = literal(l.var(), true); - IF_VERBOSE(0, verbose_stream() << "eq-conflict @" << m_scope_lvl << "\n"); set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), n_eq); } } From 0a671f2f44f7a041db0948b7c53719a0396e1c9c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 17:21:51 +0700 Subject: [PATCH 314/477] fix #6464 --- src/smt/theory_bv.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index adcafb2e4..62b7a2a20 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1318,7 +1318,7 @@ namespace smt { SASSERT(consequent.var() != antecedent.var()); TRACE("bv_bit_prop", tout << "assigning: " << consequent << " @ " << ctx.get_scope_level(); tout << " using "; ctx.display_literal(tout, antecedent); - tout << " #" << get_enode(v1)->get_owner_id() << " #" << get_enode(v2)->get_owner_id() << " idx: " << idx << "\n"; + tout << " " << enode_pp(get_enode(v1), ctx) << " " << enode_pp(get_enode(v2), ctx) << " idx: " << idx << "\n"; tout << "propagate_eqc: " << propagate_eqc << "\n";); if (consequent == false_literal) { m_stats.m_num_conflicts++; @@ -1358,6 +1358,9 @@ namespace smt { // So, we need to propagate the assignment to other bits. bool_var bv = consequent.var(); atom * a = get_bv2a(bv); + CTRACE("bv", !a, tout << ctx.literal2expr(literal(bv, false)) << "\n"); + if (!a) + return; SASSERT(a->is_bit()); bit_atom * b = static_cast(a); var_pos_occ * curr = b->m_occs; From f87e187b629891cf1ec3e6e43d29f87457520c63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 17:52:14 +0700 Subject: [PATCH 315/477] #6429 --- src/ast/euf/euf_egraph.cpp | 7 ++++--- src/sat/smt/euf_model.cpp | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 1448ee8d7..037020a2e 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -158,6 +158,8 @@ namespace euf { } void egraph::add_literal(enode* n, enode* ante) { + if (n->bool_var() == sat::null_bool_var) + return; TRACE("euf_verbose", tout << "lit: " << n->get_expr_id() << "\n";); m_new_lits.push_back(enode_pair(n, ante)); m_updates.push_back(update_record(update_record::new_lit())); @@ -272,9 +274,8 @@ namespace euf { if (enable_merge_tf && n->value() != l_undef && !m.is_value(n->get_root()->get_expr())) { expr* b = n->value() == l_true ? m.mk_true() : m.mk_false(); enode* tf = find(b); - if (!tf) - tf = mk(b, 0, 0, nullptr); - add_literal(n, tf); + if (tf) + add_literal(n, tf); } } } diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index eef873afa..0fd021d70 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -348,6 +348,8 @@ namespace euf { continue; if (!is_relevant(n)) continue; + if (n->bool_var() == sat::null_bool_var) + continue; bool tt = l_true == s().value(n->bool_var()); if (tt && !mdl.is_false(e)) continue; From 4ac5e51e3ac7d986eee455f5cf4ccf9909046acf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Nov 2022 18:35:17 +0700 Subject: [PATCH 316/477] #6429 --- src/sat/smt/euf_solver.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 9b346543f..7473be61d 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -365,11 +365,12 @@ namespace euf { continue; if (k->value() == new_value) continue; + literal litk(k->bool_var(), sign); + if (s().value(litk) == l_true) + continue; auto& c = lit_constraint(n); - propagate(literal(k->bool_var(), sign), c.to_index()); - if (k->value() == l_undef) - m_egraph.set_value(k, new_value, justification::external(to_ptr(l))); - else + propagate(litk, c.to_index()); + if (s().value(litk) == l_false) return; } } @@ -591,15 +592,18 @@ namespace euf { euf::enode* n = m_egraph.nodes()[i]; if (!m.is_bool(n->get_expr()) || !is_shared(n)) continue; - if (n->value() == l_true && !m.is_true(n->get_root()->get_expr())) { + if (n->value() == l_true && n->cgc_enabled() && !m.is_true(n->get_root()->get_expr())) { + TRACE("euf", tout << "merge " << bpp(n) << "\n"); m_egraph.merge(n, mk_true(), to_ptr(sat::literal(n->bool_var()))); merged = true; } - if (n->value() == l_false && !m.is_false(n->get_root()->get_expr())) { + if (n->value() == l_false && n->cgc_enabled() && !m.is_false(n->get_root()->get_expr())) { + TRACE("euf", tout << "merge " << bpp(n) << "\n"); m_egraph.merge(n, mk_false(), to_ptr(~sat::literal(n->bool_var()))); merged = true; } } + CTRACE("euf", merged, tout << "shared bools merged\n"); return merged; } From eceeb295fc1f006b30c0932b3adad4173b65f327 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 14:41:50 +0700 Subject: [PATCH 317/477] fix #6457 --- src/ast/rewriter/bv_rewriter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index c59423310..972259bd7 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2388,7 +2388,9 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) { expr* a = nullptr, *b = nullptr, *c = nullptr; if (m().is_ite(lhs, a, b, c)) { bool_rewriter rw(m()); - result = rw.mk_ite(a, rw.mk_eq(b, rhs), rw.mk_eq(c, rhs)); + expr_ref e1(rw.mk_eq(b, rhs), m()); + expr_ref e2(rw.mk_eq(c, rhs), m()); + result = rw.mk_ite(a, e1, e2); return BR_REWRITE2; } From 15dc7b78a0747619b3e4ab0c800a08ec001fcc38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 15:09:13 +0700 Subject: [PATCH 318/477] Move merge_tf handling to euf_internalize literals true/false are not necessarily created when the merge flag is set. Also disable merge_tf for if-then-else expressions Perhaps even not insert children of if expressions into congruence table? --- src/ast/euf/euf_egraph.cpp | 12 ++---------- src/sat/smt/euf_internalize.cpp | 27 +++++++++++++++++++++++++++ src/sat/smt/euf_solver.h | 2 -- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 037020a2e..ad88f839f 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -36,10 +36,8 @@ namespace euf { } m_expr2enode.setx(f->get_id(), n, nullptr); push_node(n); - for (unsigned i = 0; i < num_args; ++i) { - set_cgc_enabled(args[i], true); - set_merge_tf_enabled(args[i], true); - } + for (unsigned i = 0; i < num_args; ++i) + set_cgc_enabled(args[i], true); return n; } @@ -271,12 +269,6 @@ namespace euf { if (enable_merge_tf != n->merge_tf()) { n->set_merge_tf(enable_merge_tf); m_updates.push_back(update_record(n, update_record::toggle_merge_tf())); - if (enable_merge_tf && n->value() != l_undef && !m.is_value(n->get_root()->get_expr())) { - expr* b = n->value() == l_true ? m.mk_true() : m.mk_false(); - enode* tf = find(b); - if (tf) - add_literal(n, tf); - } } } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 3aaafa36c..792ffcf1d 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -474,6 +474,33 @@ namespace euf { enode* n = m_egraph.mk(e, m_generation, num, args); if (si.is_bool_op(e)) m_egraph.set_cgc_enabled(n, false); + + // + // (if p th el) (non-Boolean case) produces clauses + // (=> p (= (if p th el) th)) + // and (=> (not p) (= (if p th el) el)) + // The clauses establish equalities between the ite term and + // the th or el sub-terms. + // + if (m.is_ite(e)) + num = 0; + + // + // To track congruences of Boolean children under non-Boolean + // functions set the merge_tf flag to true. + // + for (unsigned i = 0; i < num; ++i) { + if (!m.is_bool(args[i]->get_sort())) + continue; + bool was_enabled = args[i]->merge_tf(); + m_egraph.set_merge_tf_enabled(args[i], true); + if (!was_enabled && n->value() != l_undef && !m.is_value(n->get_root()->get_expr())) { + if (n->value() == l_true) + m_egraph.merge(n, mk_true(), to_ptr(sat::literal(n->bool_var()))); + else + m_egraph.merge(n, mk_false(), to_ptr(~sat::literal(n->bool_var()))); + } + } return n; } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 5b09e6a46..675ec1500 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -146,7 +146,6 @@ namespace euf { constraint* m_conflict = nullptr; constraint* m_eq = nullptr; - constraint* m_lit = nullptr; // proofs bool m_proof_initialized = false; @@ -266,7 +265,6 @@ namespace euf { ~solver() override { if (m_conflict) dealloc(sat::constraint_base::mem2base_ptr(m_conflict)); if (m_eq) dealloc(sat::constraint_base::mem2base_ptr(m_eq)); - if (m_lit) dealloc(sat::constraint_base::mem2base_ptr(m_lit)); m_trail.reset(); } From 5fe2ff84e9cac0ecabe2a7d86cdf36691f69dce4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 19:45:16 +0700 Subject: [PATCH 319/477] change functionality to not track ite terms for congruence closure --- src/sat/smt/euf_internalize.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 792ffcf1d..a1d383e45 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -468,12 +468,13 @@ namespace euf { euf::enode* solver::mk_enode(expr* e, unsigned num, enode* const* args) { + // + // Don't track congruences of Boolean connectives or arguments. + // The assignments to associated literals is sufficient + // + if (si.is_bool_op(e)) num = 0; - - enode* n = m_egraph.mk(e, m_generation, num, args); - if (si.is_bool_op(e)) - m_egraph.set_cgc_enabled(n, false); // // (if p th el) (non-Boolean case) produces clauses @@ -484,6 +485,10 @@ namespace euf { // if (m.is_ite(e)) num = 0; + + enode* n = m_egraph.mk(e, m_generation, num, args); + if (si.is_bool_op(e)) + m_egraph.set_cgc_enabled(n, false); // // To track congruences of Boolean children under non-Boolean From caf204ab95dbf1c5f88b3ce89a478248c88865ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 19:45:51 +0700 Subject: [PATCH 320/477] hoist macro-replacer as shared utility, update eliminate-predicates and model reconstruction --- src/ast/rewriter/CMakeLists.txt | 1 + src/ast/rewriter/macro_replacer.cpp | 142 ++++++++++ src/ast/rewriter/macro_replacer.h | 44 +++ src/ast/simplifiers/eliminate_predicates.cpp | 268 ++++++++++-------- .../model_reconstruction_trail.cpp | 30 +- .../simplifiers/model_reconstruction_trail.h | 13 +- 6 files changed, 367 insertions(+), 131 deletions(-) create mode 100644 src/ast/rewriter/macro_replacer.cpp create mode 100644 src/ast/rewriter/macro_replacer.h diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 4bd6d07c4..c785804c1 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -25,6 +25,7 @@ z3_add_component(rewriter hoist_rewriter.cpp inj_axiom.cpp label_rewriter.cpp + macro_replacer.cpp maximize_ac_sharing.cpp mk_simplified_app.cpp pb_rewriter.cpp diff --git a/src/ast/rewriter/macro_replacer.cpp b/src/ast/rewriter/macro_replacer.cpp new file mode 100644 index 000000000..da0131bf7 --- /dev/null +++ b/src/ast/rewriter/macro_replacer.cpp @@ -0,0 +1,142 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + macro_replacer.cpp + +Abstract: + + Abstract (functor) for applying macro replacement. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +Notes: + +--*/ + +#include "ast/rewriter/macro_replacer.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/var_subst.h" + +/** +* Rewriting formulas using macro definitions. +*/ +struct macro_replacer::macro_replacer_cfg : public default_rewriter_cfg { + ast_manager& m; + macro_replacer& ep; + expr_dependency_ref& m_used_macro_dependencies; + expr_ref_vector m_trail; + + macro_replacer_cfg(ast_manager& m, macro_replacer& ep, expr_dependency_ref& deps) : + m(m), + ep(ep), + m_used_macro_dependencies(deps), + m_trail(m) + {} + + bool rewrite_patterns() const { return false; } + bool flat_assoc(func_decl* f) const { return false; } + br_status reduce_app(func_decl* f, unsigned num, expr* const* args, expr_ref& result, proof_ref& result_pr) { + result_pr = nullptr; + return BR_FAILED; + } + + /** + * adapted from macro_manager.cpp + * Perhaps hoist and combine? + */ + bool reduce_quantifier(quantifier* old_q, + expr* new_body, + expr* const* new_patterns, + expr* const* new_no_patterns, + expr_ref& result, + proof_ref& result_pr) { + + bool erase_patterns = false; + for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++) + if (old_q->get_pattern(i) != new_patterns[i]) + erase_patterns = true; + + for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++) + if (old_q->get_no_pattern(i) != new_no_patterns[i]) + erase_patterns = true; + + if (erase_patterns) + result = m.update_quantifier(old_q, 0, nullptr, 0, nullptr, new_body); + + if (erase_patterns && m.proofs_enabled()) + result_pr = m.mk_rewrite(old_q, result); + + return erase_patterns; + } + + bool get_subst(expr* _n, expr*& r, proof*& p) { + if (!is_app(_n)) + return false; + p = nullptr; + app* n = to_app(_n); + quantifier* q = nullptr; + func_decl* d = n->get_decl(), * d2 = nullptr; + app_ref head(m); + expr_ref def(m); + expr_dependency_ref dep(m); + if (ep.has_macro(d, head, def, dep)) { + unsigned num = head->get_num_args(); + ptr_buffer subst_args; + subst_args.resize(num, 0); + for (unsigned i = 0; i < num; i++) { + var* v = to_var(head->get_arg(i)); + VERIFY(v->get_idx() < num); + unsigned nidx = num - v->get_idx() - 1; + SASSERT(!subst_args[nidx]); + subst_args[nidx] = n->get_arg(i); + } + var_subst s(m); + expr_ref rr = s(def, num, subst_args.data()); + r = rr; + m_trail.push_back(rr); + m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, dep); + // skip proof terms for simplifiers + return true; + } + + return false; + } +}; + +struct macro_replacer::macro_replacer_rw : public rewriter_tpl { + macro_replacer::macro_replacer_cfg m_cfg; + + macro_replacer_rw(ast_manager& m, macro_replacer& ep, expr_dependency_ref& deps) : + rewriter_tpl(m, false, m_cfg), + m_cfg(m, ep, deps) + {} +}; + + +void macro_replacer::insert(app* head, expr* def, expr_dependency* dep) { + func_decl* f = head->get_decl(); + m_trail.push_back(head); + m_trail.push_back(def); + m_deps.push_back(dep); + m_map.insert(f, std::tuple(head, def, dep)); +} + +void macro_replacer::operator()(expr* t, expr_ref& result, expr_dependency_ref& dep) { + macro_replacer_rw exp(m, *this, dep); + exp(t, result); +} + +bool macro_replacer::has_macro(func_decl* f, app_ref& head, expr_ref& def, expr_dependency_ref& dep) { + std::tuple v; + if (!m_map.find(f, v)) + return false; + auto const& [h, d, dp] = v; + head = h; + def = d; + dep = dp; + return true; +} diff --git a/src/ast/rewriter/macro_replacer.h b/src/ast/rewriter/macro_replacer.h new file mode 100644 index 000000000..a0cc5242b --- /dev/null +++ b/src/ast/rewriter/macro_replacer.h @@ -0,0 +1,44 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + macro_replacer.h + +Abstract: + + Abstract (functor) for applying macro replacement. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +Notes: + +--*/ +#pragma once + +#include "ast/ast.h" +#include "util/obj_hashtable.h" + + +class macro_replacer { + ast_manager& m; + ast_ref_vector m_trail; + expr_dependency_ref_vector m_deps; + obj_map> m_map; + struct macro_replacer_cfg; + struct macro_replacer_rw; + +public: + + macro_replacer(ast_manager& m): m(m), m_trail(m), m_deps(m) {} + + void insert(app* head, expr* def, expr_dependency* dep); + void operator()(expr* t, expr_ref& result, expr_dependency_ref& dep); + void operator()(expr* t, expr_ref & result) { expr_dependency_ref dep(m); (*this)(t, result, dep); } + void operator()(expr_ref & t) { expr_ref s(t, m); (*this)(s, t); } + + bool has_macro(func_decl* f, app_ref& head, expr_ref& def, expr_dependency_ref& d); +}; + diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index a46eda102..052a44397 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -58,105 +58,7 @@ forbidden from macros vs forbidden from elimination #include "ast/rewriter/rewriter_def.h" #include "ast/simplifiers/eliminate_predicates.h" #include "ast/rewriter/th_rewriter.h" - - -/** -* Rewriting formulas using macro definitions. -*/ -struct eliminate_predicates::macro_expander_cfg : public default_rewriter_cfg { - ast_manager& m; - eliminate_predicates& ep; - expr_dependency_ref& m_used_macro_dependencies; - expr_ref_vector m_trail; - - macro_expander_cfg(ast_manager& m, eliminate_predicates& ep, expr_dependency_ref& deps) : - m(m), - ep(ep), - m_used_macro_dependencies(deps), - m_trail(m) - {} - - bool rewrite_patterns() const { return false; } - bool flat_assoc(func_decl* f) const { return false; } - br_status reduce_app(func_decl* f, unsigned num, expr* const* args, expr_ref& result, proof_ref& result_pr) { - result_pr = nullptr; - return BR_FAILED; - } - - /** - * adapted from macro_manager.cpp - * Perhaps hoist and combine? - */ - bool reduce_quantifier(quantifier* old_q, - expr* new_body, - expr* const* new_patterns, - expr* const* new_no_patterns, - expr_ref& result, - proof_ref& result_pr) { - - bool erase_patterns = false; - for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++) - if (old_q->get_pattern(i) != new_patterns[i]) - erase_patterns = true; - - for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++) - if (old_q->get_no_pattern(i) != new_no_patterns[i]) - erase_patterns = true; - - if (erase_patterns) - result = m.update_quantifier(old_q, 0, nullptr, 0, nullptr, new_body); - - if (erase_patterns && m.proofs_enabled()) - result_pr = m.mk_rewrite(old_q, result); - - return erase_patterns; - } - - bool get_subst(expr* _n, expr*& r, proof*& p) { - if (!is_app(_n)) - return false; - p = nullptr; - app* n = to_app(_n); - quantifier* q = nullptr; - func_decl* d = n->get_decl(), * d2 = nullptr; - app_ref head(m); - expr_ref def(m); - expr_dependency_ref dep(m); - if (ep.has_macro(d, head, def, dep)) { - unsigned num = head->get_num_args(); - ptr_buffer subst_args; - subst_args.resize(num, 0); - // TODO: we can exploit that variables occur in "non-standard" order - // that is in order (:var 0) (:var 1) (:var 2) - // then substitution just takes n->get_args() instead of this renaming. - for (unsigned i = 0; i < num; i++) { - var* v = to_var(head->get_arg(i)); - VERIFY(v->get_idx() < num); - unsigned nidx = num - v->get_idx() - 1; - SASSERT(subst_args[nidx] == 0); - subst_args[nidx] = n->get_arg(i); - } - var_subst s(m); - expr_ref rr = s(def, num, subst_args.data()); - r = rr; - m_trail.push_back(rr); - m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, dep); - // skip proof terms for simplifiers - return true; - } - - return false; - } -}; - -struct eliminate_predicates::macro_expander_rw : public rewriter_tpl { - eliminate_predicates::macro_expander_cfg m_cfg; - - macro_expander_rw(ast_manager& m, eliminate_predicates& ep, expr_dependency_ref& deps) : - rewriter_tpl(m, false, m_cfg), - m_cfg(m, ep, deps) - {} -}; +#include "ast/rewriter/macro_replacer.h" std::ostream& eliminate_predicates::clause::display(std::ostream& out) const { @@ -200,10 +102,18 @@ void eliminate_predicates::add_use_list(clause& cl) { * Check that all arguments are distinct variables that are bound. */ -bool eliminate_predicates::can_be_macro_head(app* head, unsigned num_bound) { - uint_set indices; - if (head->get_decl()->is_associative()) +bool eliminate_predicates::can_be_macro_head(expr* _head, unsigned num_bound) { + if (!is_app(_head)) return false; + app* head = to_app(_head); + func_decl* f = head->get_decl(); + if (m_disable_macro.is_marked(f)) + return false; + if (m_is_macro.is_marked(f)) + return false; + if (f->is_associative()) + return false; + uint_set indices; for (expr* arg : *head) { if (!is_var(arg)) return false; @@ -315,7 +225,7 @@ bool eliminate_predicates::is_macro_safe(expr* e) { return true; } -void eliminate_predicates::insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep) { +void eliminate_predicates::insert_macro(app* head, expr* def, expr_dependency* dep) { unsigned num = head->get_num_args(); ptr_buffer vars, subst_args; subst_args.resize(num, nullptr); @@ -330,13 +240,17 @@ void eliminate_predicates::insert_macro(app_ref& head, expr_ref& def, expr_depen vars[i] = w; } var_subst sub(m, false); - def = sub(def, subst_args.size(), subst_args.data()); - head = m.mk_app(head->get_decl(), vars); - auto* info = alloc(macro_def, head, def, dep); + app_ref _head(m); + expr_ref _def(m); + expr_dependency_ref _dep(dep, m); + _def = sub(def, subst_args.size(), subst_args.data()); + _head = m.mk_app(head->get_decl(), vars); + + auto* info = alloc(macro_def, _head, _def, _dep); m_macros.insert(head->get_decl(), info); - m_fmls.model_trail().push(head->get_decl(), def, {}); + m_fmls.model_trail().push(head->get_decl(), _def, _dep, {}); // augment with definition for head m_is_macro.mark(head->get_decl(), true); - TRACE("elim_predicates", tout << "insert " << head << " " << def << "\n"); + TRACE("elim_predicates", tout << "insert " << _head << " " << _def << "\n"); ++m_stats.m_num_macros; } @@ -348,20 +262,124 @@ void eliminate_predicates::try_resolve_definition(func_decl* p) { insert_macro(head, def, dep); } -bool eliminate_predicates::has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep) { - macro_def* md = nullptr; - if (m_macros.find(p, md)) { - head = md->m_head; - def = md->m_def; - dep = md->m_dep; - return true; +/** +* Port of macros handled by macro_finder/macro_util +*/ +void eliminate_predicates::try_find_macro(clause& cl) { + if (!cl.m_alive) + return; + expr* x, * y; + auto can_be_def = [&](expr* _x, expr* y) { + if (!is_app(_x)) + return false; + app* x = to_app(_x); + return + can_be_macro_head(x, cl.m_bound.size()) && + is_macro_safe(y) && + x->get_num_args() == cl.m_bound.size() && + !occurs(x->get_decl(), y); + }; + // (= (f x) t) + if (cl.is_unit() && !cl.sign(0) && m.is_eq(cl.atom(0), x, y)) { + if (can_be_def(x, y)) { + insert_macro(to_app(x), y, cl.m_dep); + cl.m_alive = false; + return; + } + if (can_be_def(y, x)) { + insert_macro(to_app(y), x, cl.m_dep); + cl.m_alive = false; + return; + } } - return false; + // not (= (p x) t) -> (p x) = (not t) + if (cl.is_unit() && cl.sign(0) && m.is_iff(cl.atom(0), x, y)) { + if (can_be_def(x, y)) { + insert_macro(to_app(x), m.mk_not(y), cl.m_dep); + cl.m_alive = false; + return; + } + if (can_be_def(y, x)) { + insert_macro(to_app(y), m.mk_not(x), cl.m_dep); + cl.m_alive = false; + return; + } + } + + // pseudo-macros: + // (iff (= (f x) t) cond) + // rewrites to (f x) = (if cond t else (k x)) + // add clause (not (= (k x) t)) + // + // we will call them _conditioned_ macros + + auto can_be_conditioned = [&](expr* f, expr* t, expr* cond) { + return + can_be_def(f, t) && + !occurs(to_app(f)->get_decl(), cond) && + is_macro_safe(cond); + }; + + auto make_conditioned = [&](app* f, expr* t, expr* cond) { + func_decl* df = f->get_decl(); + app_ref def(m), k(m), fml(m); + func_decl_ref fn(m); + fn = m.mk_fresh_func_decl(df->get_arity(), df->get_domain(), df->get_range()); + m_fmls.model_trail().push(fn); // hide definition of fn + k = m.mk_app(fn, f->get_num_args(), f->get_args()); + def = m.mk_ite(cond, t, k); + insert_macro(f, def, cl.m_dep); + cl.m_alive = false; + fml = m.mk_not(m.mk_eq(k, t)); + init_clause(fml, cl.m_dep, UINT_MAX); + + }; + if (cl.is_unit() && !cl.sign(0) && m.is_iff(cl.atom(0), x, y)) { + expr* z, * u; + if (m.is_eq(x, z, u) && can_be_conditioned(z, u, y)) { + make_conditioned(to_app(z), u, y); + return; + } + if (m.is_eq(x, u, z) && can_be_conditioned(z, u, y)) { + make_conditioned(to_app(z), u, y); + return; + } + if (m.is_eq(y, z, u) && can_be_conditioned(z, u, x)) { + make_conditioned(to_app(z), u, x); + return; + } + if (m.is_eq(y, u, z) && can_be_conditioned(z, u, x)) { + make_conditioned(to_app(z), u, x); + return; + } + } + + // + // other macros handled by macro_finder: + // + + // arithmetic/bit-vectors + // (= (+ (f x) s) t) + // becomes (= (f x) (- t s)) + + // + // macro_finder also has: + // (>= (+ (f x) s) t) + // becomes (= (f x) (- t s (k x)) + // add (>= (k x) 0) + // why is this a real improvement? + // + // To review: quasi-macros + // (= (f x y (+ x y)) s), where x y are all bound variables. + // then ...? } + void eliminate_predicates::find_definitions() { for (auto* p : m_predicates) try_resolve_definition(p); + for (auto* cl : m_clauses) + try_find_macro(*cl); } void eliminate_predicates::rewrite(expr_ref& t) { @@ -374,13 +392,16 @@ void eliminate_predicates::reduce_definitions() { if (m_macros.empty()) return; + macro_replacer macro_expander(m); + for (auto const& [k, v] : m_macros) + macro_expander.insert(v->m_head, v->m_def, v->m_dep); + for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { auto [f, d] = m_fmls[i](); expr_ref fml(f, m), new_fml(m); expr_dependency_ref dep(m); while (true) { - macro_expander_rw macro_expander(m, *this, dep); - macro_expander(fml, new_fml); + macro_expander(fml, new_fml, dep); if (new_fml == fml) break; rewrite(new_fml); @@ -464,6 +485,7 @@ void eliminate_predicates::try_resolve(func_decl* p) { void eliminate_predicates::update_model(func_decl* p) { expr_ref_vector fmls(m); expr_ref def(m); + expr_dependency_ref dep(m); unsigned numpos = 0, numneg = 0; vector deleted; for (auto* pos : m_use_list.get(p, false)) @@ -475,19 +497,23 @@ void eliminate_predicates::update_model(func_decl* p) { if (numpos < numneg) { for (auto* pos : m_use_list.get(p, false)) - if (pos->m_alive) + if (pos->m_alive) { fmls.push_back(create_residue_formula(p, *pos)); + dep = m.mk_join(dep, pos->m_dep); + } def = mk_or(fmls); } else { for (auto* neg : m_use_list.get(p, true)) - if (neg->m_alive) + if (neg->m_alive) { fmls.push_back(mk_not(m, create_residue_formula(p, *neg))); + dep = m.mk_join(dep, neg->m_dep); + } def = mk_and(fmls); } rewrite(def); - m_fmls.model_trail().push(p, def, deleted); + m_fmls.model_trail().push(p, def, dep, deleted); } /** diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 55d04621f..8ccfbdf6e 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -13,6 +13,7 @@ Author: #include "ast/for_each_expr.h" +#include "ast/rewriter/macro_replacer.h" #include "ast/simplifiers/model_reconstruction_trail.h" #include "ast/converters/generic_model_converter.h" @@ -32,11 +33,10 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectoris_hide()) continue; - // updates that have no intersections with current variables are skipped if (!t->intersects(free_vars)) - continue; + continue; // loose entries that intersect with free vars are deleted from the trail // and their removed formulas are added to the resulting constraints. @@ -49,8 +49,29 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectoris_def()) - NOT_IMPLEMENTED_YET(); + + if (t->is_def()) { + macro_replacer mrp(m); + app_ref head(m); + func_decl* d = t->m_decl; + ptr_buffer args; + for (unsigned i = 0; i < d->get_arity(); ++i) + args.push_back(m.mk_var(i, d->get_domain(i))); + head = m.mk_app(d, args); + mrp.insert(head, t->m_def, t->m_dep); + dependent_expr de(m, t->m_def, t->m_dep); + add_vars(de, free_vars); + + for (auto& d : added) { + auto [f, dep1] = d(); + expr_ref g(m); + expr_dependency_ref dep2(m); + mrp(f, g, dep2); + d = dependent_expr(m, g, m.mk_join(dep1, dep2)); + } + continue; + } + rp->set_substitution(t->m_subst.get()); // rigid entries: @@ -59,6 +80,7 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorreplace_with_dep(f); d = dependent_expr(m, g, m.mk_join(dep1, dep2)); + add_vars(d, free_vars); } } } diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 2ff11227e..40db7dfba 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -37,16 +37,17 @@ class model_reconstruction_trail { vector m_removed; func_decl_ref m_decl; expr_ref m_def; + expr_dependency_ref m_dep; bool m_active = true; entry(ast_manager& m, expr_substitution* s, vector const& rem) : - m_subst(s), m_removed(rem), m_decl(m), m_def(m) {} + m_subst(s), m_removed(rem), m_decl(m), m_def(m), m_dep(m) {} - entry(ast_manager& m, func_decl* h) : m_decl(h, m), m_def(m) {} + entry(ast_manager& m, func_decl* h) : m_decl(h, m), m_def(m), m_dep(m) {} - entry(ast_manager& m, func_decl* f, expr* def, vector const& rem) : - m_decl(f, m), m_def(def, m), m_removed(rem) {} + entry(ast_manager& m, func_decl* f, expr* def, expr_dependency* dep, vector const& rem) : + m_decl(f, m), m_def(def, m), m_removed(rem), m_dep(dep, m) {} bool is_loose() const { return !m_removed.empty(); } @@ -109,8 +110,8 @@ public: /** * add definition */ - void push(func_decl* f, expr* def, vector const& removed) { - m_trail.push_back(alloc(entry, m, f, def, removed)); + void push(func_decl* f, expr* def, expr_dependency* dep, vector const& removed) { + m_trail.push_back(alloc(entry, m, f, def, dep, removed)); m_trail_stack.push(push_back_vector(m_trail)); } From 34791295829f35b6a3a2f880bcaa4ece25cf7e14 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 19:47:26 +0700 Subject: [PATCH 321/477] remove unused structs --- src/ast/simplifiers/eliminate_predicates.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index ff11bfd3f..b2d628602 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -92,9 +92,6 @@ private: der_rewriter m_der; th_rewriter m_rewriter; obj_map m_macros; - - struct macro_expander_cfg; - struct macro_expander_rw; void rewrite(expr_ref& t); From decb3d3907eaa7949b59ffb7b63b39a743ed2887 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 19:51:26 +0700 Subject: [PATCH 322/477] stashed header file --- src/ast/simplifiers/eliminate_predicates.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index b2d628602..f5d1cab96 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -54,6 +54,10 @@ public: {} std::ostream& display(std::ostream& out) const; + + expr* atom(unsigned i) const { return m_literals[i].first; } + bool sign(unsigned i) const { return m_literals[i].second; } + bool is_unit() const { return m_literals.size() == 1; } }; private: struct stats { @@ -102,11 +106,12 @@ private: bool try_find_binary_definition(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); void try_resolve_definition(func_decl* p); - void insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep); + void insert_macro(app* head, expr* def, expr_dependency* dep); bool has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def); - bool can_be_macro_head(app* head, unsigned num_bound); + bool can_be_macro_head(expr* head, unsigned num_bound); bool is_macro_safe(expr* e); + void try_find_macro(clause& cl); void try_resolve(func_decl* p); void update_model(func_decl* p); From a64c7c5d19b0475b1872cf9118816d28c553155d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 21:52:55 +0700 Subject: [PATCH 323/477] add incremental version of value propagate --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/euf_completion.cpp | 79 -------------- src/ast/simplifiers/euf_completion.h | 1 - src/ast/simplifiers/propagate_values.cpp | 115 +++++++++++++++++++++ src/ast/simplifiers/propagate_values.h | 45 ++++++++ src/tactic/core/CMakeLists.txt | 1 + src/tactic/core/elim_uncnstr2_tactic.h | 1 - src/tactic/core/propagate_values2_tactic.h | 41 ++++++++ 8 files changed, 203 insertions(+), 81 deletions(-) create mode 100644 src/ast/simplifiers/propagate_values.cpp create mode 100644 src/ast/simplifiers/propagate_values.h create mode 100644 src/tactic/core/propagate_values2_tactic.h diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index b636b8b42..9361937f7 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(simplifiers euf_completion.cpp extract_eqs.cpp model_reconstruction_trail.cpp + propagate_values.cpp solve_context_eqs.cpp solve_eqs.cpp COMPONENT_DEPENDENCIES diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 2825f3244..b768180cf 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -61,10 +61,6 @@ namespace euf { } void completion::reduce() { - - propagate_values(); - if (m_fmls.inconsistent()) - return; m_has_new_eq = true; for (unsigned rounds = 0; m_has_new_eq && rounds <= 3 && !m_fmls.inconsistent(); ++rounds) { ++m_epoch; @@ -76,81 +72,6 @@ namespace euf { } } - /** - * Propagate writes into values first. It is cheaper to propagate values directly than using - * the E-graph. The E-graph suffers from the following overhead: it prefers interpreted nodes - * as roots and therefore the "merge" function ignores the heuristic of choosing the node to appoint root - * as the one with the fewest parents. Merging a constant value with multiple terms then has a compounding - * quadratic time overhead since the parents of the value are removed and re-inserted into the congruence - * table repeatedly and with growing size (exceeding the n*log(n) overhead when choosing the root to - * have the fewest parents). - */ - void completion::propagate_values() { - shared_occs shared(m, true); - expr_substitution subst(m, true, false); - expr* x, * y; - expr_ref_buffer args(m); - auto add_shared = [&]() { - shared_occs_mark visited; - shared.reset(); - for (unsigned i = 0; i < m_fmls.size(); ++i) - shared(m_fmls[i].fml(), visited); - }; - - auto add_sub = [&](dependent_expr const& de) { - auto const& [f, dep] = de(); - if (m.is_not(f, x) && shared.is_shared(x)) - subst.insert(x, m.mk_false(), dep); - else if (shared.is_shared(f)) - subst.insert(f, m.mk_true(), dep); - if (m.is_eq(f, x, y) && m.is_value(x) && shared.is_shared(y)) - subst.insert(y, x, dep); - else if (m.is_eq(f, x, y) && m.is_value(y) && shared.is_shared(x)) - subst.insert(x, y, dep); - }; - - auto process_fml = [&](unsigned i) { - expr* f = m_fmls[i].fml(); - expr_dependency* dep = m_fmls[i].dep(); - expr_ref fml(m); - proof_ref pr(m); - m_rewriter(f, fml, pr); - if (fml != f) { - dep = m.mk_join(dep, m_rewriter.get_used_dependencies()); - m_fmls.update(i, dependent_expr(m, fml, dep)); - ++m_stats.m_num_rewrites; - } - m_rewriter.reset_used_dependencies(); - add_sub(m_fmls[i]); - }; - - unsigned rw = m_stats.m_num_rewrites + 1; - for (unsigned r = 0; r < 4 && rw != m_stats.m_num_rewrites; ++r) { - rw = m_stats.m_num_rewrites; - add_shared(); - subst.reset(); - m_rewriter.reset(); - m_rewriter.set_substitution(&subst); - for (unsigned i = 0; i < m_qhead; ++i) - add_sub(m_fmls[i]); - for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) - process_fml(i); - add_shared(); - subst.reset(); - m_rewriter.reset(); - m_rewriter.set_substitution(&subst); - for (unsigned i = 0; i < m_qhead; ++i) - add_sub(m_fmls[i]); - for (unsigned i = m_fmls.size(); i-- > m_qhead && !m_fmls.inconsistent();) - process_fml(i); - if (subst.empty()) - break; - } - - m_rewriter.set_substitution(nullptr); - m_rewriter.reset(); - } - void completion::add_egraph() { m_nodes_to_canonize.reset(); unsigned sz = m_fmls.size(); diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h index 830f8655e..f02e33245 100644 --- a/src/ast/simplifiers/euf_completion.h +++ b/src/ast/simplifiers/euf_completion.h @@ -46,7 +46,6 @@ namespace euf { bool is_new_eq(expr* a, expr* b); void update_has_new_eq(expr* g); expr_ref mk_and(expr* a, expr* b); - void propagate_values(); void add_egraph(); void map_canonical(); void read_egraph(); diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp new file mode 100644 index 000000000..5979f1f2a --- /dev/null +++ b/src/ast/simplifiers/propagate_values.cpp @@ -0,0 +1,115 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + propagate_values.h + +Abstract: + + relatively cheap value propagation + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +Notes: + + Incremental version of propagate_values_tactic + +--*/ + +#include "params/tactic_params.hpp" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/shared_occs.h" +#include "ast/simplifiers/propagate_values.h" + +propagate_values::propagate_values(ast_manager& m, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_rewriter(m) { + m_rewriter.set_order_eq(true); + m_rewriter.set_flat_and_or(false); +} + +void propagate_values::reduce() { + shared_occs shared(m, true); + expr_substitution subst(m, true, false); + expr* x, * y; + expr_ref_buffer args(m); + auto add_shared = [&]() { + shared_occs_mark visited; + shared.reset(); + for (unsigned i = 0; i < m_fmls.size(); ++i) + shared(m_fmls[i].fml(), visited); + }; + + auto add_sub = [&](dependent_expr const& de) { + auto const& [f, dep] = de(); + if (m.is_not(f, x) && shared.is_shared(x)) + subst.insert(x, m.mk_false(), dep); + else if (shared.is_shared(f)) + subst.insert(f, m.mk_true(), dep); + if (m.is_eq(f, x, y) && m.is_value(x) && shared.is_shared(y)) + subst.insert(y, x, dep); + else if (m.is_eq(f, x, y) && m.is_value(y) && shared.is_shared(x)) + subst.insert(x, y, dep); + }; + + auto process_fml = [&](unsigned i) { + expr* f = m_fmls[i].fml(); + expr_dependency* dep = m_fmls[i].dep(); + expr_ref fml(m); + proof_ref pr(m); + m_rewriter(f, fml, pr); + if (fml != f) { + dep = m.mk_join(dep, m_rewriter.get_used_dependencies()); + m_fmls.update(i, dependent_expr(m, fml, dep)); + ++m_stats.m_num_rewrites; + } + m_rewriter.reset_used_dependencies(); + add_sub(m_fmls[i]); + }; + + unsigned rw = m_stats.m_num_rewrites + 1; + for (unsigned r = 0; r < m_max_rounds && rw != m_stats.m_num_rewrites; ++r) { + rw = m_stats.m_num_rewrites; + add_shared(); + subst.reset(); + m_rewriter.reset(); + m_rewriter.set_substitution(&subst); + for (unsigned i = 0; i < m_qhead; ++i) + add_sub(m_fmls[i]); + for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) + process_fml(i); + add_shared(); + subst.reset(); + m_rewriter.reset(); + m_rewriter.set_substitution(&subst); + for (unsigned i = 0; i < m_qhead; ++i) + add_sub(m_fmls[i]); + for (unsigned i = m_fmls.size(); i-- > m_qhead && !m_fmls.inconsistent();) + process_fml(i); + if (subst.empty()) + break; + } + + m_rewriter.set_substitution(nullptr); + m_rewriter.reset(); + + advance_qhead(m_fmls.size()); +} + +void propagate_values::collect_statistics(statistics& st) const { + st.update("propagate-values-rewrites", m_stats.m_num_rewrites); +} + +void propagate_values::updt_params(params_ref const& p) { + tactic_params tp(p); + m_max_rounds = p.get_uint("max_rounds", tp.propagate_values_max_rounds()); +} + +void propagate_values::collect_param_descrs(param_descrs& r) { + th_rewriter::get_param_descrs(r); + r.insert("max_rounds", CPK_UINT, "(default: 4) maximum number of rounds."); +} \ No newline at end of file diff --git a/src/ast/simplifiers/propagate_values.h b/src/ast/simplifiers/propagate_values.h new file mode 100644 index 000000000..3219f9796 --- /dev/null +++ b/src/ast/simplifiers/propagate_values.h @@ -0,0 +1,45 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + propagate_values.h + +Abstract: + + relatively cheap value propagation + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +Notes: + incremental version of propagate_values_tactic, to be replaced + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" + + +class propagate_values : public dependent_expr_simplifier { + + struct stats { + unsigned m_num_rewrites = 0; + void reset() { memset(this, 0, sizeof(*this)); } + }; + + th_rewriter m_rewriter; + stats m_stats; + unsigned m_max_rounds = 4; + +public: + propagate_values(ast_manager& m, dependent_expr_state& fmls); + void reduce() override; + void collect_statistics(statistics& st) const override; + void reset_statistics() override { m_stats.reset(); } + void updt_params(params_ref const& p) override; + void collect_param_descrs(param_descrs& r) override; +}; diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 39e8def03..bc8c4ab71 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -45,6 +45,7 @@ z3_add_component(core_tactics occf_tactic.h pb_preprocess_tactic.h propagate_values_tactic.h + propagate_values2_tactic.h reduce_args_tactic.h simplify_tactic.h solve_eqs_tactic.h diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h index 65b5d3426..d9f6196f2 100644 --- a/src/tactic/core/elim_uncnstr2_tactic.h +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -20,7 +20,6 @@ Author: #include "tactic/tactic.h" #include "tactic/dependent_expr_state_tactic.h" #include "ast/simplifiers/elim_unconstrained.h" -#include "ast/simplifiers/elim_unconstrained.h" class elim_uncnstr2_tactic_factory : public dependent_expr_simplifier_factory { public: diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h new file mode 100644 index 000000000..2ca534a49 --- /dev/null +++ b/src/tactic/core/propagate_values2_tactic.h @@ -0,0 +1,41 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + propagate_values2_tactic.h + +Abstract: + + Tactic for propagating equalities (= t v) where v is a value + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#include "util/params.h" +#pragma once + +#include "util/params.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/propagate_values.h" + +class propagate_values2_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(propagate_values, m, s); + } +}; + +inline tactic * mk_propagate_values2_tactic(ast_manager & m, params_ref const & p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(propagate_values2_tactic_factory), "propagate-values2"); +} + + +/* + ADD_TACTIC("propagate-valuesx2", "propagate constants.", "mk_propagate_values2_tactic(m, p)") +*/ + From 1815812889c484b79d8a57e97834c0d8a8deb47a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 22:05:30 +0700 Subject: [PATCH 324/477] fix typo in name of tactic --- src/tactic/core/propagate_values2_tactic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h index 2ca534a49..ab9646128 100644 --- a/src/tactic/core/propagate_values2_tactic.h +++ b/src/tactic/core/propagate_values2_tactic.h @@ -36,6 +36,6 @@ inline tactic * mk_propagate_values2_tactic(ast_manager & m, params_ref const & /* - ADD_TACTIC("propagate-valuesx2", "propagate constants.", "mk_propagate_values2_tactic(m, p)") + ADD_TACTIC("propagate-values2", "propagate constants.", "mk_propagate_values2_tactic(m, p)") */ From b0247d8201cc7c1076c411618882034a9a5fe49b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 22:20:25 +0700 Subject: [PATCH 325/477] add exception handling for rewriter exceptions --- src/tactic/dependent_expr_state_tactic.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index efe28c30d..f16bb0ff3 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -102,8 +102,13 @@ public: statistics_report sreport(*this); tactic_report report(name(), *in); m_goal = in.get(); - if (!in->proofs_enabled()) - m_simp->reduce(); + try { + if (!in->proofs_enabled()) + m_simp->reduce(); + } + catch (rewriter_exception& ex) { + throw tactic_exception(ex.msg()); + } m_goal->elim_true(); m_goal->elim_redundancies(); m_goal->inc_depth(); From eb812e47bea4a9aee8de58a7a1796d08ec8e064f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 22:46:35 +0700 Subject: [PATCH 326/477] cleanup --- src/ast/shared_occs.h | 7 ++--- src/ast/simplifiers/propagate_values.cpp | 39 ++++++++++++------------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/ast/shared_occs.h b/src/ast/shared_occs.h index 59ff99569..649a29e98 100644 --- a/src/ast/shared_occs.h +++ b/src/ast/shared_occs.h @@ -32,11 +32,8 @@ public: void reset_mark(ast * n) { n->reset_mark_so(); } void mark(ast * n) { if (is_marked(n)) return; n->mark_so(true); m_to_unmark.push_back(n); } void reset() { - ptr_buffer::iterator it = m_to_unmark.begin(); - ptr_buffer::iterator end = m_to_unmark.end(); - for (; it != end; ++it) { - reset_mark(*it); - } + for (auto* t : m_to_unmark) + reset_mark(t); m_to_unmark.reset(); } void mark(ast * n, bool flag) { if (flag) mark(n); else reset_mark(n); } diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 5979f1f2a..b7bd6eb37 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -36,7 +36,7 @@ void propagate_values::reduce() { shared_occs shared(m, true); expr_substitution subst(m, true, false); expr* x, * y; - expr_ref_buffer args(m); + auto add_shared = [&]() { shared_occs_mark visited; shared.reset(); @@ -50,15 +50,16 @@ void propagate_values::reduce() { subst.insert(x, m.mk_false(), dep); else if (shared.is_shared(f)) subst.insert(f, m.mk_true(), dep); - if (m.is_eq(f, x, y) && m.is_value(x) && shared.is_shared(y)) - subst.insert(y, x, dep); - else if (m.is_eq(f, x, y) && m.is_value(y) && shared.is_shared(x)) - subst.insert(x, y, dep); + if (m.is_eq(f, x, y)) { + if (m.is_value(x) && shared.is_shared(y)) + subst.insert(y, x, dep); + else if (m.is_value(y) && shared.is_shared(x)) + subst.insert(x, y, dep); + } }; auto process_fml = [&](unsigned i) { - expr* f = m_fmls[i].fml(); - expr_dependency* dep = m_fmls[i].dep(); + auto [f, dep] = m_fmls[i](); expr_ref fml(m); proof_ref pr(m); m_rewriter(f, fml, pr); @@ -70,24 +71,23 @@ void propagate_values::reduce() { m_rewriter.reset_used_dependencies(); add_sub(m_fmls[i]); }; + + auto init_sub = [&]() { + add_shared(); + subst.reset(); + m_rewriter.reset(); + m_rewriter.set_substitution(&subst); + for (unsigned i = 0; i < m_qhead; ++i) + add_sub(m_fmls[i]); + }; unsigned rw = m_stats.m_num_rewrites + 1; for (unsigned r = 0; r < m_max_rounds && rw != m_stats.m_num_rewrites; ++r) { rw = m_stats.m_num_rewrites; - add_shared(); - subst.reset(); - m_rewriter.reset(); - m_rewriter.set_substitution(&subst); - for (unsigned i = 0; i < m_qhead; ++i) - add_sub(m_fmls[i]); + init_sub(); for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) process_fml(i); - add_shared(); - subst.reset(); - m_rewriter.reset(); - m_rewriter.set_substitution(&subst); - for (unsigned i = 0; i < m_qhead; ++i) - add_sub(m_fmls[i]); + init_sub(); for (unsigned i = m_fmls.size(); i-- > m_qhead && !m_fmls.inconsistent();) process_fml(i); if (subst.empty()) @@ -107,6 +107,7 @@ void propagate_values::collect_statistics(statistics& st) const { void propagate_values::updt_params(params_ref const& p) { tactic_params tp(p); m_max_rounds = p.get_uint("max_rounds", tp.propagate_values_max_rounds()); + m_rewriter.updt_params(p); } void propagate_values::collect_param_descrs(param_descrs& r) { From cb789f6ca8abb33fdc546452729732047ca337c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2022 23:44:35 +0700 Subject: [PATCH 327/477] add arithmetical macros Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/eliminate_predicates.cpp | 111 ++++++++++++++++++- src/ast/simplifiers/eliminate_predicates.h | 1 - src/ast/simplifiers/propagate_values.cpp | 3 +- 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 052a44397..afa07a3a3 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -52,6 +52,8 @@ forbidden from macros vs forbidden from elimination #include "ast/ast_util.h" #include "ast/for_each_ast.h" #include "ast/recfun_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "ast/arith_decl_plugin.h" #include "ast/occurs.h" #include "ast/array_decl_plugin.h" #include "ast/rewriter/var_subst.h" @@ -331,9 +333,11 @@ void eliminate_predicates::try_find_macro(clause& cl) { insert_macro(f, def, cl.m_dep); cl.m_alive = false; fml = m.mk_not(m.mk_eq(k, t)); - init_clause(fml, cl.m_dep, UINT_MAX); - + clause* new_cl = init_clause(fml, cl.m_dep, UINT_MAX); + add_use_list(*new_cl); + m_clauses.push_back(new_cl); }; + if (cl.is_unit() && !cl.sign(0) && m.is_iff(cl.atom(0), x, y)) { expr* z, * u; if (m.is_eq(x, z, u) && can_be_conditioned(z, u, y)) { @@ -357,10 +361,111 @@ void eliminate_predicates::try_find_macro(clause& cl) { // // other macros handled by macro_finder: // - // arithmetic/bit-vectors // (= (+ (f x) s) t) // becomes (= (f x) (- t s)) + // + // TBD: + // (= (+ (* -1 (f x)) x) t) + // becomes (= (f x) (- (- t s))) + + bv_util bv(m); + arith_util a(m); + auto is_add = [&](expr * e) { + rational n; + return a.is_add(e) || bv.is_bv_add(e); + }; + + auto sub = [&](expr* t, expr* s) { + if (a.is_int_real(t)) + return expr_ref(a.mk_sub(t, s), m); + else + return expr_ref(bv.mk_bv_sub(t, s), m); + }; + + auto subtract = [&](expr* t, app* s, unsigned i) { + expr_ref result(t, m); + unsigned j = 0; + for (expr* arg : *s) { + ++j; + if (i != j) + result = sub(result, arg); + } + return result; + }; + + auto uminus = [&](expr* t) { + if (a.is_int_real(t)) + return expr_ref(a.mk_uminus(t), m); + else + return expr_ref(bv.mk_bv_neg(t), m); + }; + + auto is_inverse = [&](expr*& t) { + expr* x, * y; + rational n; + if (a.is_mul(t, x, y) && a.is_numeral(x, n) && n == -1) { + t = y; + return true; + } + if (bv.is_bv_mul(t, x, y) && bv.is_numeral(x, n) && n + 1 == rational::power_of_two(bv.get_bv_size(t))) { + t = y; + return true; + } + return false; + }; + + auto find_arith_macro = [&](expr* x, expr* y) { + if (!is_add(x)) + return false; + + if (!is_macro_safe(y)) + return false; + + unsigned i = 0; + for (expr* arg : *to_app(x)) { + ++i; + bool inv = is_inverse(arg); + if (!can_be_macro_head(arg, cl.m_bound.size())) + continue; + app* head = to_app(arg); + func_decl* f = head->get_decl(); + if (head->get_num_args() != cl.m_bound.size()) + continue; + if (occurs(f, y)) + continue; + unsigned j = 0; + for (expr* arg2 : *head) { + ++j; + if (i == j) + continue; + if (occurs(f, arg2)) + goto next; + if (!is_macro_safe(arg2)) + goto next; + } + { + // arg = y - x - arg; + expr_ref y1 = subtract(y, to_app(x), i); + if (inv) + y1 = uminus(y1); + insert_macro(to_app(arg), y1, cl.m_dep); + cl.m_alive = false; + return true; + } + next: + ; + } + return false; + }; + + if (cl.is_unit() && !cl.sign(0) && m.is_eq(cl.atom(0), x, y)) { + if (find_arith_macro(x, y)) + return; + if (find_arith_macro(y, x)) + return; + } + // // macro_finder also has: diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index f5d1cab96..6afd0886a 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -107,7 +107,6 @@ private: bool try_find_binary_definition(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); void try_resolve_definition(func_decl* p); void insert_macro(app* head, expr* def, expr_dependency* dep); - bool has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep); expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def); bool can_be_macro_head(expr* head, unsigned num_bound); bool is_macro_safe(expr* e); diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index b7bd6eb37..6a179674b 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -96,7 +96,6 @@ void propagate_values::reduce() { m_rewriter.set_substitution(nullptr); m_rewriter.reset(); - advance_qhead(m_fmls.size()); } @@ -113,4 +112,4 @@ void propagate_values::updt_params(params_ref const& p) { void propagate_values::collect_param_descrs(param_descrs& r) { th_rewriter::get_param_descrs(r); r.insert("max_rounds", CPK_UINT, "(default: 4) maximum number of rounds."); -} \ No newline at end of file +} From db74e23de1efe92170f3e6e9083516e6af652bc1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 11:07:31 +0700 Subject: [PATCH 328/477] make card2bv a simplifier --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/card2bv.cpp | 61 ++++++++++ src/ast/simplifiers/card2bv.h | 42 +++++++ src/ast/simplifiers/elim_unconstrained.cpp | 2 +- src/ast/simplifiers/eliminate_predicates.cpp | 2 +- .../simplifiers/model_reconstruction_trail.h | 2 +- src/tactic/arith/CMakeLists.txt | 1 - src/tactic/arith/card2bv_tactic.cpp | 105 ------------------ src/tactic/arith/card2bv_tactic.h | 95 +++------------- 9 files changed, 120 insertions(+), 191 deletions(-) create mode 100644 src/ast/simplifiers/card2bv.cpp create mode 100644 src/ast/simplifiers/card2bv.h delete mode 100644 src/tactic/arith/card2bv_tactic.cpp diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index 9361937f7..d10bf87e7 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(simplifiers SOURCES bv_slice.cpp + card2bv.cpp elim_unconstrained.cpp eliminate_predicates.cpp euf_completion.cpp diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp new file mode 100644 index 000000000..d9c387c5a --- /dev/null +++ b/src/ast/simplifiers/card2bv.cpp @@ -0,0 +1,61 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + card2bv.cpp + +Abstract: + + convert cardinality constraints to bit-vectors + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + + +#include "ast/simplifiers/card2bv.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/pb2bv_rewriter.h" + +card2bv::card2bv(ast_manager& m, params_ref const& p, dependent_expr_state& fmls) : + dependent_expr_simplifier(m, fmls), m_params(p) {} + +void card2bv::reduce() { + th_rewriter rw1(m, m_params); + pb2bv_rewriter rw2(m, m_params); + + expr_ref new_f1(m), new_f2(m); + proof_ref new_pr(m); + for (unsigned idx = 0; !m_fmls.inconsistent() && idx < m_fmls.size(); idx++) { + auto [f, d] = m_fmls[idx](); + rw1(f, new_f1); + rw2(false, new_f1, new_f2, new_pr); + if (new_f2 != f) { + TRACE("card2bv", tout << "Rewriting " << new_f1 << "\n" << new_f2 << "\n"); + m_fmls.update(idx, dependent_expr(m, new_f2, d)); + ++m_stats.m_num_rewrites; + } + } + + expr_ref_vector fmls(m); + rw2.flush_side_constraints(fmls); + for (expr* e : fmls) + m_fmls.add(dependent_expr(m, e, nullptr)); + + func_decl_ref_vector const& fns = rw2.fresh_constants(); + for (func_decl* f : fns) + m_fmls.model_trail().hide(f); +} + +void card2bv::collect_statistics(statistics& st) const { + st.update("card2bv-rewrites", m_stats.m_num_rewrites); +} + +void card2bv::collect_param_descrs(param_descrs& r) { + r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints for solver"); + pb2bv_rewriter rw(m, m_params); + rw.collect_param_descrs(r); +} diff --git a/src/ast/simplifiers/card2bv.h b/src/ast/simplifiers/card2bv.h new file mode 100644 index 000000000..e089fa84c --- /dev/null +++ b/src/ast/simplifiers/card2bv.h @@ -0,0 +1,42 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + card2bv.h + +Abstract: + + convert cardinality constraints to bit-vectors + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" + + +class card2bv : public dependent_expr_simplifier { + + struct stats { + unsigned m_num_rewrites = 0; + void reset() { memset(this, 0, sizeof(*this)); } + }; + + stats m_stats; + params_ref m_params; + +public: + card2bv(ast_manager& m, params_ref const& p, dependent_expr_state& fmls); + void reduce() override; + void collect_statistics(statistics& st) const override; + void reset_statistics() override { m_stats.reset(); } + void updt_params(params_ref const& p) override { m_params.append(p); } + void collect_param_descrs(param_descrs& r) override; +}; diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index d590f3e59..52dc95f05 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -285,7 +285,7 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< for (auto const& entry : mc.entries()) { switch (entry.m_instruction) { case generic_model_converter::instruction::HIDE: - trail.push(entry.m_f); + trail.hide(entry.m_f); break; case generic_model_converter::instruction::ADD: break; diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index afa07a3a3..6d1288c5d 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -327,7 +327,7 @@ void eliminate_predicates::try_find_macro(clause& cl) { app_ref def(m), k(m), fml(m); func_decl_ref fn(m); fn = m.mk_fresh_func_decl(df->get_arity(), df->get_domain(), df->get_range()); - m_fmls.model_trail().push(fn); // hide definition of fn + m_fmls.model_trail().hide(fn); // hide definition of fn k = m.mk_app(fn, f->get_num_args(), f->get_args()); def = m.mk_ite(cond, t, k); insert_macro(f, def, cl.m_dep); diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 40db7dfba..906aaa738 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -102,7 +102,7 @@ public: /** * add declaration to hide */ - void push(func_decl* f) { + void hide(func_decl* f) { m_trail.push_back(alloc(entry, m, f)); m_trail_stack.push(push_back_vector(m_trail)); } diff --git a/src/tactic/arith/CMakeLists.txt b/src/tactic/arith/CMakeLists.txt index cb025b206..d5c7557e6 100644 --- a/src/tactic/arith/CMakeLists.txt +++ b/src/tactic/arith/CMakeLists.txt @@ -6,7 +6,6 @@ z3_add_component(arith_tactics bound_propagator.cpp bv2int_rewriter.cpp bv2real_rewriter.cpp - card2bv_tactic.cpp degree_shift_tactic.cpp diff_neq_tactic.cpp eq2bv_tactic.cpp diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp deleted file mode 100644 index 4f79a887d..000000000 --- a/src/tactic/arith/card2bv_tactic.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - card2bv_tactic.cpp - -Abstract: - - Tactic for converting Pseudo-Boolean constraints to BV - -Author: - - Nikolaj Bjorner (nbjorner) 2014-03-20 - -Notes: - ---*/ -#include "tactic/tactical.h" -#include "ast/ast_smt2_pp.h" -#include "tactic/arith/card2bv_tactic.h" -#include "ast/rewriter/pb2bv_rewriter.h" -#include "ast/ast_util.h" -#include "ast/ast_pp.h" -#include "ast/converters/generic_model_converter.h" - -class card2bv_tactic : public tactic { - ast_manager & m; - params_ref m_params; - -public: - - card2bv_tactic(ast_manager & m, params_ref const & p): - m(m), - m_params(p) { - } - - tactic * translate(ast_manager & m) override { - return alloc(card2bv_tactic, m, m_params); - } - - char const* name() const override { return "card2bv"; } - - void updt_params(params_ref const & p) override { - m_params.append(p); - } - - void collect_param_descrs(param_descrs & r) override { - r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints for solver"); - pb2bv_rewriter rw(m, m_params); - rw.collect_param_descrs(r); - } - - - void operator()(goal_ref const & g, - goal_ref_buffer & result) override { - TRACE("card2bv-before", g->display(tout);); - result.reset(); - tactic_report report("card2bv", *g); - th_rewriter rw1(m, m_params); - pb2bv_rewriter rw2(m, m_params); - - if (g->inconsistent()) { - result.push_back(g.get()); - return; - } - - expr_ref new_f1(m), new_f2(m); - for (unsigned idx = 0; !g->inconsistent() && idx < g->size(); idx++) { - proof_ref new_pr1(m), new_pr2(m); - rw1(g->form(idx), new_f1, new_pr1); - TRACE("card2bv", tout << "Rewriting " << new_f1 << "\n" << new_pr1 << std::endl;); - rw2(false, new_f1, new_f2, new_pr2); - TRACE("card2bv", tout << "Rewriting " << new_f2 << "\n" << new_pr2 << std::endl;); - if (m.proofs_enabled()) { - new_pr1 = m.mk_transitivity(new_pr1, new_pr2); - new_pr1 = m.mk_modus_ponens(g->pr(idx), new_pr1); - } - g->update(idx, new_f2, new_pr1, g->dep(idx)); - } - expr_ref_vector fmls(m); - rw2.flush_side_constraints(fmls); - for (expr* e : fmls) { - g->assert_expr(e); - } - - func_decl_ref_vector const& fns = rw2.fresh_constants(); - if (!fns.empty()) { - generic_model_converter* filter = alloc(generic_model_converter, m, "card2bv"); - for (func_decl* f : fns) filter->hide(f); - g->add(filter); - } - - g->inc_depth(); - result.push_back(g.get()); - } - - void cleanup() override { - } -}; - -tactic * mk_card2bv_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(card2bv_tactic, m, p)); -} - diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 81296f18d..95282d93c 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -13,95 +13,26 @@ Author: Nikolaj Bjorner (nbjorner) 2014-03-20 -Notes: - --*/ #pragma once + #include "util/params.h" -#include "ast/pb_decl_plugin.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/rewriter/rewriter.h" -#include -#include "util/sorting_network.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/card2bv.h" - -class ast_manager; -class tactic; - -namespace pb { - - class card2bv_rewriter { - public: - typedef expr* pliteral; - typedef ptr_vector pliteral_vector; - private: - ast_manager& m; - arith_util au; - pb_util pb; - bv_util bv; - psort_nw m_sort; - expr_ref_vector m_lemmas; - expr_ref_vector m_trail; - - unsigned get_num_bits(func_decl* f); - void mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); - br_status mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); - expr* negate(expr* e); - expr* mk_ite(expr* c, expr* hi, expr* lo); - bool is_or(func_decl* f); - bool is_and(func_decl* f); - bool is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result); - expr_ref mk_atmost1(unsigned sz, expr * const* args); - void mk_at_most_1_small(bool last, unsigned n, pliteral const* xs, expr_ref_vector& result, expr_ref_vector& ors); - - public: - card2bv_rewriter(ast_manager& m); - br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result); - void mk_assert(func_decl * f, unsigned sz, expr * const* args, expr_ref & result, expr_ref_vector& lemmas); - - // definitions used for sorting network - pliteral mk_false() { return m.mk_false(); } - pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } - pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, pliteral lit); - pliteral fresh(); - pliteral trail(pliteral l); - void mk_clause(unsigned n, pliteral const* lits); - - }; - - struct card2bv_rewriter_cfg : public default_rewriter_cfg { - card2bv_rewriter m_r; - bool rewrite_patterns() const { return false; } - bool flat_assoc(func_decl * f) const { return false; } - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = nullptr; - return m_r.mk_app_core(f, num, args, result); - } - card2bv_rewriter_cfg(ast_manager & m):m_r(m) {} - }; - - class card_pb_rewriter : public rewriter_tpl { - card2bv_rewriter_cfg m_cfg; - pb_util pb; - expr_ref_vector m_lemmas; - public: - card_pb_rewriter(ast_manager & m): - rewriter_tpl(m, false, m_cfg), - m_cfg(m), - pb(m), - m_lemmas(m) {} - - void rewrite(expr* e, expr_ref& result); - - expr_ref_vector& lemmas() { return m_lemmas; } - }; +class card2bv_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(card2bv, m, p, s); + } }; -tactic * mk_card2bv_tactic(ast_manager & m, params_ref const & p = params_ref()); +inline tactic* mk_card2bv_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(card2bv_tactic_factory), "card2bv"); +} + /* ADD_TACTIC("card2bv", "convert pseudo-boolean constraints to bit-vectors.", "mk_card2bv_tactic(m, p)") */ From 5af6e1a046c803fbae472e84dc1f8e5c341b827d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 11:38:41 +0700 Subject: [PATCH 329/477] make max_bv_sharing a simplifier --- src/ast/simplifiers/CMakeLists.txt | 1 + .../simplifiers/max_bv_sharing.cpp} | 98 ++++++------------- src/ast/simplifiers/max_bv_sharing.h | 25 +++++ src/tactic/bv/CMakeLists.txt | 1 - src/tactic/bv/max_bv_sharing_tactic.h | 17 +++- 5 files changed, 68 insertions(+), 74 deletions(-) rename src/{tactic/bv/max_bv_sharing_tactic.cpp => ast/simplifiers/max_bv_sharing.cpp} (79%) create mode 100644 src/ast/simplifiers/max_bv_sharing.h diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index d10bf87e7..d5a8fd2a4 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(simplifiers eliminate_predicates.cpp euf_completion.cpp extract_eqs.cpp + max_bv_sharing.cpp model_reconstruction_trail.cpp propagate_values.cpp solve_context_eqs.cpp diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/ast/simplifiers/max_bv_sharing.cpp similarity index 79% rename from src/tactic/bv/max_bv_sharing_tactic.cpp rename to src/ast/simplifiers/max_bv_sharing.cpp index 2bc99806e..b28b5ebdb 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -3,7 +3,7 @@ Copyright (c) 2011 Microsoft Corporation Module Name: - max_bv_sharing_tactic.cpp + max_bv_sharing.cpp Abstract: @@ -12,7 +12,7 @@ Abstract: This rewriter is particularly useful for reducing the number of Adders and Multipliers before "bit-blasting". -Author: +Author Leonardo de Moura (leonardo) 2011-12-29. @@ -23,9 +23,10 @@ Revision History: #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" #include "util/obj_pair_hashtable.h" +#include "ast/simplifiers/dependent_expr_state.h" #include "ast/ast_lt.h" -class max_bv_sharing_tactic : public tactic { +class max_bv_sharing : public dependent_expr_simplifier { struct rw_cfg : public default_rewriter_cfg { typedef std::pair expr_pair; @@ -224,64 +225,22 @@ class max_bv_sharing_tactic : public tactic { } }; - struct imp { - rw m_rw; - unsigned m_num_steps; + rw m_rw; + unsigned m_num_steps = 0; - imp(ast_manager & m, params_ref const & p): - m_rw(m, p) { - } - - ast_manager & m() const { return m_rw.m(); } - - void operator()(goal_ref const & g, - goal_ref_buffer & result) { - tactic_report report("max-bv-sharing", *g); - bool produce_proofs = g->proofs_enabled(); - - expr_ref new_curr(m()); - proof_ref new_pr(m()); - unsigned size = g->size(); - for (unsigned idx = 0; idx < size; idx++) { - if (g->inconsistent()) - break; - expr * curr = g->form(idx); - m_rw(curr, new_curr, new_pr); - m_num_steps += m_rw.get_num_steps(); - - if (produce_proofs) { - proof * pr = g->pr(idx); - new_pr = m().mk_modus_ponens(pr, new_pr); - } - g->update(idx, new_curr, new_pr, g->dep(idx)); - } - m_rw.cfg().cleanup(); - g->inc_depth(); - result.push_back(g.get()); - } - }; - - imp * m_imp; + params_ref m_params; + public: - max_bv_sharing_tactic(ast_manager & m, params_ref const & p): - m_params(p) { - m_imp = alloc(imp, m, p); - } - - tactic * translate(ast_manager & m) override { - return alloc(max_bv_sharing_tactic, m, m_params); - } - - ~max_bv_sharing_tactic() override { - dealloc(m_imp); - } - - char const* name() const override { return "max_bv_sharing"; } + max_bv_sharing(ast_manager & m, params_ref const & p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_params(p), + m_rw(m, p) { + } void updt_params(params_ref const & p) override { m_params.append(p); - m_imp->m_rw.cfg().updt_params(m_params); + m_rw.cfg().updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { @@ -290,21 +249,22 @@ public: r.insert("max_args", CPK_UINT, "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); } - - void operator()(goal_ref const & in, - goal_ref_buffer & result) override { - (*m_imp)(in, result); - } - - void cleanup() override { - ast_manager & m = m_imp->m(); - params_ref p = std::move(m_params); - m_imp->~imp(); - new (m_imp) imp(m, p); - } + + void reduce() override { + expr_ref new_curr(m); + proof_ref new_pr(m); + for (unsigned idx = 0; idx < m_fmls.size() && !m_fmls.inconsistent(); idx++) { + auto [curr, d] = m_fmls[idx](); + m_rw(curr, new_curr, new_pr); + // Proof reconstruction: new_pr = m.mk_modus_ponens(old_pr, new_pr); + m_num_steps += m_rw.get_num_steps(); + m_fmls.update(idx, dependent_expr(m, new_curr, d)); + } + m_rw.cfg().cleanup(); + } }; -tactic * mk_max_bv_sharing_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(max_bv_sharing_tactic, m, p)); +dependent_expr_simplifier * mk_max_bv_sharing(ast_manager & m, params_ref const & p, dependent_expr_state& fmls) { + return alloc(max_bv_sharing, m, p, fmls); } diff --git a/src/ast/simplifiers/max_bv_sharing.h b/src/ast/simplifiers/max_bv_sharing.h new file mode 100644 index 000000000..bfc8f4472 --- /dev/null +++ b/src/ast/simplifiers/max_bv_sharing.h @@ -0,0 +1,25 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + max_bv_sharing.h + +Abstract: + + Rewriter for "maximing" the number of shared terms. + The idea is to rewrite AC terms to maximize sharing. + This rewriter is particularly useful for reducing + the number of Adders and Multipliers before "bit-blasting". + +Author: + + Leonardo de Moura (leonardo) 2011-12-29. + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" + +dependent_expr_simplifier * mk_max_bv_sharing(ast_manager & m, params_ref const & p, dependent_expr_state& fmls); diff --git a/src/tactic/bv/CMakeLists.txt b/src/tactic/bv/CMakeLists.txt index 653571265..50dd941e0 100644 --- a/src/tactic/bv/CMakeLists.txt +++ b/src/tactic/bv/CMakeLists.txt @@ -11,7 +11,6 @@ z3_add_component(bv_tactics bv_slice_tactic.cpp dt2bv_tactic.cpp elim_small_bv_tactic.cpp - max_bv_sharing_tactic.cpp COMPONENT_DEPENDENCIES bit_blaster core_tactics diff --git a/src/tactic/bv/max_bv_sharing_tactic.h b/src/tactic/bv/max_bv_sharing_tactic.h index 00de41256..ebd050aa5 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.h +++ b/src/tactic/bv/max_bv_sharing_tactic.h @@ -21,11 +21,20 @@ Revision History: --*/ #pragma once -#include "util/params.h" -class ast_manager; -class tactic; +#include "ast/simplifiers/max_bv_sharing.h" +#include "tactic/dependent_expr_state_tactic.h" + +class max_bv_sharing_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return mk_max_bv_sharing(m, p, s); + } +}; + +inline tactic* mk_max_bv_sharing_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(max_bv_sharing_tactic_factory), "max-bv-sharing"); +} -tactic * mk_max_bv_sharing_tactic(ast_manager & m, params_ref const & p = params_ref()); /* ADD_TACTIC("max-bv-sharing", "use heuristics to maximize the sharing of bit-vector expressions such as adders and multipliers.", "mk_max_bv_sharing_tactic(m, p)") */ From 8184e7fe0a24cb06f2f56e9b3702c12764b4b12e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 11:42:16 +0700 Subject: [PATCH 330/477] keep track of qhead --- src/ast/simplifiers/card2bv.cpp | 4 +++- src/ast/simplifiers/max_bv_sharing.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index d9c387c5a..145ea71f5 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -29,7 +29,7 @@ void card2bv::reduce() { expr_ref new_f1(m), new_f2(m); proof_ref new_pr(m); - for (unsigned idx = 0; !m_fmls.inconsistent() && idx < m_fmls.size(); idx++) { + for (unsigned idx = m_qhead; !m_fmls.inconsistent() && idx < m_fmls.size(); idx++) { auto [f, d] = m_fmls[idx](); rw1(f, new_f1); rw2(false, new_f1, new_f2, new_pr); @@ -48,6 +48,8 @@ void card2bv::reduce() { func_decl_ref_vector const& fns = rw2.fresh_constants(); for (func_decl* f : fns) m_fmls.model_trail().hide(f); + + advance_qhead(m_fmls.size()); } void card2bv::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index b28b5ebdb..ca11f9a1b 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -253,7 +253,7 @@ public: void reduce() override { expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = 0; idx < m_fmls.size() && !m_fmls.inconsistent(); idx++) { + for (unsigned idx = m_qhead; idx < m_fmls.size() && !m_fmls.inconsistent(); idx++) { auto [curr, d] = m_fmls[idx](); m_rw(curr, new_curr, new_pr); // Proof reconstruction: new_pr = m.mk_modus_ponens(old_pr, new_pr); @@ -261,6 +261,7 @@ public: m_fmls.update(idx, dependent_expr(m, new_curr, d)); } m_rw.cfg().cleanup(); + advance_qhead(m_fmls.size()); } }; From e95b0bd2cd7bdb15fdc8b6e52437fbe5c811d9e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 11:47:38 +0700 Subject: [PATCH 331/477] remove include of tactical --- src/ast/simplifiers/max_bv_sharing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index ca11f9a1b..86021fea6 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -19,7 +19,7 @@ Author Revision History: --*/ -#include "tactic/tactical.h" + #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" #include "util/obj_pair_hashtable.h" From f0570fbc0ef7e6179f5a5ccff1701ebd11e88871 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 11:48:44 +0700 Subject: [PATCH 332/477] remove tactic exception dependency --- src/ast/simplifiers/max_bv_sharing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index 86021fea6..2abacb7f7 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -62,7 +62,7 @@ class max_bv_sharing : public dependent_expr_simplifier { bool max_steps_exceeded(unsigned num_steps) const { if (memory::get_allocation_size() > m_max_memory) - throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + throw rewriter_exception(Z3_MAX_MEMORY_MSG); return num_steps > m_max_steps; } From a152f9cfd6470674fba04cffbb84e01348009fa6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 13:37:16 +0700 Subject: [PATCH 333/477] port bit-blaster to simplifiers inc_sat_solver uses bit-blaster, card2bv and max_bv_sharing. By turning these into simplifiers it will be possible to remove dependencies on tactics and goals in inc_sat_simplifier and instead use a modular and general incremental pre-processing infrastructure. --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/bit_blaster.cpp | 80 +++++++++++++++++++++++++++++ src/ast/simplifiers/bit_blaster.h | 51 ++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 src/ast/simplifiers/bit_blaster.cpp create mode 100644 src/ast/simplifiers/bit_blaster.h diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index d5a8fd2a4..042c29a0e 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(simplifiers SOURCES + bit_blaster.cpp bv_slice.cpp card2bv.cpp elim_unconstrained.cpp diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp new file mode 100644 index 000000000..ceb3c56a6 --- /dev/null +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -0,0 +1,80 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + bit_blaster.cpp + +Abstract: + + Apply bit-blasting + +Author: + + Leonardo (leonardo) 2011-10-25 + +--*/ + +#include "ast/simplifiers/bit_blaster.h" + + +void bit_blaster::updt_params(params_ref const & p) { + m_params.append(p); + m_rewriter.updt_params(m_params); +} + +void bit_blaster::collect_param_descrs(param_descrs & r) { + insert_max_memory(r); + insert_max_steps(r); + r.insert("blast_mul", CPK_BOOL, "(default: true) bit-blast multipliers (and dividers, remainders)."); + r.insert("blast_add", CPK_BOOL, "(default: true) bit-blast adders."); + r.insert("blast_quant", CPK_BOOL, "(default: false) bit-blast quantified variables."); + r.insert("blast_full", CPK_BOOL, "(default: false) bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms."); +} + +void bit_blaster::reduce() { + m_rewriter.start_rewrite(); + expr_ref new_curr(m); + proof_ref new_pr(m); + bool change = false; + for (unsigned idx = m_qhead; idx < m_fmls.size(); idx++) { + if (m_fmls.inconsistent()) + break; + auto [curr, d] = m_fmls[idx](); + m_rewriter(curr, new_curr, new_pr); + m_num_steps += m_rewriter.get_num_steps(); + if (curr != new_curr) { + change = true; + TRACE("bit_blaster", tout << mk_pp(curr, m) << " -> " << new_curr << "\n";); + m_fmls.update(idx, dependent_expr(m, new_curr, d)); + } + } + + if (change) { + obj_map const2bits; + ptr_vector newbits; + m_rewriter.end_rewrite(const2bits, newbits); + for (auto* f : newbits) + m_fmls.model_trail().hide(f); + for (auto const& [f, v] : const2bits) + m_fmls.model_trail().push(f, v, nullptr, {}); + } + m_rewriter.cleanup(); + + advance_qhead(m_fmls.size()); +} + + +void bit_blaster::collect_statistics(statistics& st) const { + st.update("bit-blaster-num-steps", m_num_steps); +} + +void bit_blaster::push() { + m_rewriter.push(); + dependent_expr_simplifier::push(); +} + +void bit_blaster::pop(unsigned n) { + dependent_expr_simplifier::pop(n); + m_rewriter.pop(n); +} diff --git a/src/ast/simplifiers/bit_blaster.h b/src/ast/simplifiers/bit_blaster.h new file mode 100644 index 000000000..70446918b --- /dev/null +++ b/src/ast/simplifiers/bit_blaster.h @@ -0,0 +1,51 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + bit_blaster.h + +Abstract: + + Apply bit-blasting + +Author: + + Leonardo (leonardo) 2011-10-25 + +--*/ +#include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" +#include "ast/ast_pp.h" +#include "model/model_pp.h" +#include "ast/rewriter/rewriter_types.h" +#include "ast/simplifiers/dependent_expr_state.h" + + +class bit_blaster : public dependent_expr_simplifier { + + bit_blaster_rewriter m_rewriter; + unsigned m_num_steps = 0; + params_ref m_params; + +public: + bit_blaster(ast_manager & m, params_ref const & p, dependent_expr_state& s): + dependent_expr_simplifier(m, s), + m_rewriter(m, p) { + updt_params(p); + } + + void updt_params(params_ref const & p) override; + void collect_param_descrs(param_descrs & r) override; + void reduce() override; + void collect_statistics(statistics& st) const override; + void push() override; + void pop(unsigned n) override; + + /* + * Expose the bit-blaster rewriter so that assumptions and implied bit-vectors can be reconstructed + * after bit-blasting. + */ + bit_blaster_rewriter& rewriter() { return m_rewriter; } + +}; + From 4e9f21c2a1cf3aa53efe8d23361ce86a2aa7573c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 15:16:14 +0700 Subject: [PATCH 334/477] add rewriter and seq simplifiers --- scripts/mk_project.py | 24 ++++---- src/CMakeLists.txt | 2 +- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/card2bv.cpp | 2 +- src/ast/simplifiers/rewriter_simplifier.h | 53 +++++++++++++++++ src/ast/simplifiers/seq_simplifier.h | 72 +++++++++++++++++++++++ 6 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 src/ast/simplifiers/rewriter_simplifier.h create mode 100644 src/ast/simplifiers/seq_simplifier.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index e9f54be05..497aa350f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -20,26 +20,27 @@ def init_project_def(): add_lib('simplex', ['util'], 'math/simplex') add_lib('hilbert', ['util'], 'math/hilbert') add_lib('automata', ['util'], 'math/automata') + add_lib('params', ['util']) + add_lib('smt_params', ['params'], 'smt/params') add_lib('realclosure', ['interval'], 'math/realclosure') add_lib('subpaving', ['interval'], 'math/subpaving') add_lib('ast', ['util', 'polynomial']) - add_lib('euf', ['ast', 'util'], 'ast/euf') - add_lib('params', ['util']) - add_lib('smt_params', ['params'], 'smt/params') + add_lib('parser_util', ['ast'], 'parsers/util') + add_lib('euf', ['ast'], 'ast/euf') add_lib('grobner', ['ast', 'dd', 'simplex'], 'math/grobner') add_lib('sat', ['params', 'util', 'dd', 'grobner']) add_lib('nlsat', ['polynomial', 'sat']) add_lib('lp', ['util', 'nlsat', 'grobner', 'interval', 'smt_params'], 'math/lp') add_lib('rewriter', ['ast', 'polynomial', 'automata', 'params'], 'ast/rewriter') - add_lib('macros', ['rewriter'], 'ast/macros') - add_lib('model', ['rewriter', 'macros']) - add_lib('converters', ['model'], 'ast/converters') - add_lib('simplifiers', ['euf', 'rewriter', 'converters'], 'ast/simplifiers') + add_lib('bit_blaster', ['rewriter'], 'ast/rewriter/bit_blaster') add_lib('normal_forms', ['rewriter'], 'ast/normal_forms') - add_lib('tactic', ['ast', 'model', 'simplifiers']) - add_lib('substitution', ['ast', 'rewriter'], 'ast/substitution') - add_lib('parser_util', ['ast'], 'parsers/util') - add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') + add_lib('substitution', ['rewriter'], 'ast/substitution') + add_lib('proofs', ['rewriter'], 'ast/proofs') + add_lib('macros', ['rewriter'], 'ast/macros') + add_lib('model', ['macros']) + add_lib('converters', ['model'], 'ast/converters') + add_lib('simplifiers', ['euf', 'rewriter', 'bit_blaster', 'converters'], 'ast/simplifiers') + add_lib('tactic', ['simplifiers']) add_lib('solver', ['params', 'model', 'tactic', 'proofs']) add_lib('cmd_context', ['solver', 'rewriter', 'params']) add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') @@ -47,7 +48,6 @@ def init_project_def(): add_lib('aig_tactic', ['tactic'], 'tactic/aig') add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') - add_lib('bit_blaster', ['rewriter', 'params'], 'ast/rewriter/bit_blaster') add_lib('core_tactics', ['tactic', 'macros', 'normal_forms', 'rewriter', 'pattern'], 'tactic/core') add_lib('arith_tactics', ['core_tactics', 'sat'], 'tactic/arith') add_lib('mbp', ['model', 'simplex'], 'qe/mbp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd4fa04b5..dadd70bba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,6 +46,7 @@ add_subdirectory(math/subpaving) add_subdirectory(ast) add_subdirectory(params) add_subdirectory(ast/rewriter) +add_subdirectory(ast/rewriter/bit_blaster) add_subdirectory(ast/normal_forms) add_subdirectory(ast/macros) add_subdirectory(model) @@ -71,7 +72,6 @@ add_subdirectory(qe/mbp) add_subdirectory(qe/lite) add_subdirectory(solver/assertions) add_subdirectory(ast/pattern) -add_subdirectory(ast/rewriter/bit_blaster) add_subdirectory(math/lp) add_subdirectory(sat/smt) add_subdirectory(sat/tactic) diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index 042c29a0e..c488a6269 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -15,4 +15,5 @@ z3_add_component(simplifiers COMPONENT_DEPENDENCIES euf rewriter + bit_blaster ) diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index 145ea71f5..2da9b6e44 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -49,7 +49,7 @@ void card2bv::reduce() { for (func_decl* f : fns) m_fmls.model_trail().hide(f); - advance_qhead(m_fmls.size()); + advance_qhead(m_fmls.size()); } void card2bv::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h new file mode 100644 index 000000000..938e30b83 --- /dev/null +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -0,0 +1,53 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + rewriter_simplifier.h + +Abstract: + + rewriter simplifier + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" + + +class rewriter_simplifier : public dependent_expr_simplifier { + + unsigned m_num_steps = 0; + params_ref m_params; + +public: + rewriter_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls) { + updt_params(p); + } + + void reduce() override { + m_num_steps = 0; + expr_ref new_curr(m); + proof_ref new_pr(m); + for (unsigned idx = m_qhead; idx < m_fmls.size(); idx++) { + if (m_fmls.inconsistent()) + break; + auto [f, d] = m_fmls[i](); + m_rewriter(f, new_curr, new_pr); + m_num_steps += m_rewriter.get_num_steps(); + m_fmls.update(idx, dependent_expr(m, new_curr, d)); + } + advance_qhead(m_fmls.size()); + } + void collect_statistics(statistics& st) const override { st.update("simplifier", m_num_steps); } + void reset_statistics() override { m_stats.reset(); } + void updt_params(params_ref const& p) override { m_params.append(p); m_rewriter.updt_params(m_params); } + void collect_param_descrs(param_descrs& r) override { th_rewriter::get_param_descrs(r); } +}; diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h new file mode 100644 index 000000000..5a3a7da60 --- /dev/null +++ b/src/ast/simplifiers/seq_simplifier.h @@ -0,0 +1,72 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + seq_simplifier.h + +Abstract: + + create a simplifier from a sequence of simplifiers + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" + + +class seq_simplifier : public dependent_expr_simplifier { + scoped_ptr_vector m_simplifiers; + +public: + seq_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls) { + } + + void add_simplifier(dependent_expr_simplifier* s) { + m_simplifiers.push_back(s); + } + + void reduce() override { + for (auto* s : m_simplifiers) { + if (m_fmls.inconsistent()) + break; + s->reduce(); + } + } + + void collect_statistics(statistics& st) const override { + for (auto* s : m_simplifiers) + s->collect_statistics(st); + } + + void reset_statistics() override { + for (auto* s : m_simplifiers) + s->reset_statistics(st); + } + + void updt_params(params_ref const& p) override { + for (auto* s : m_simplifiers) + s->updt_params(p); + } + + void collect_param_descrs(param_descrs& r) override { + for (auto* s : m_simplifiers) + s->collect_param_descrs(r); + } + + void push() override { + for (auto* s : m_simplifiers) + s->push(); + } + + void pop(unsigned n) override { + for (auto* s : m_simplifiers) + s->pop(n); + } +}; From 6454014119cd03f64754406e4f917ed1ddac4e92 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Nov 2022 15:28:38 +0700 Subject: [PATCH 335/477] enable incrementality for model reconstruction --- .../model_reconstruction_trail.cpp | 41 +++++++++++-------- .../simplifiers/model_reconstruction_trail.h | 6 +++ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 8ccfbdf6e..cfc65ce67 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -18,9 +18,12 @@ Author: #include "ast/converters/generic_model_converter.h" +// accumulate a set of dependent exprs, updating m_trail to exclude loose +// substitutions that use variables from the dependent expressions. +// TODO: add filters to skip sections of the trail that do not touch the current free variables. + void model_reconstruction_trail::replay(dependent_expr const& d, vector& added) { - // accumulate a set of dependent exprs, updating m_trail to exclude loose - // substitutions that use variables from the dependent expressions. + ast_mark free_vars; scoped_ptr rp = mk_default_expr_replacer(m, false); add_vars(d, free_vars); @@ -47,8 +50,7 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorm_active)); t->m_active = false; continue; - } - + } if (t->is_def()) { macro_replacer mrp(m); @@ -72,7 +74,6 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorset_substitution(t->m_subst.get()); // rigid entries: // apply substitution to added in case of rigid model convertions @@ -89,25 +90,29 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vector rp = mk_default_expr_replacer(m, false); - expr_substitution subst(m, true, false); - rp->set_substitution(&subst); generic_model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); - for (unsigned i = 0; i < m_trail.size(); ++i) { + unsigned i = 0; + append(*mc, i); + return model_converter_ref(mc.get()); +} + +/** +* Append model conversions starting at index i +*/ +void model_reconstruction_trail::append(generic_model_converter& mc, unsigned& i) { + for (; i < m_trail.size(); ++i) { auto* t = m_trail[i]; if (!t->m_active) continue; - else if (t->is_hide()) - mc->hide(t->m_decl); - else if (t->is_def()) - mc->add(t->m_decl, t->m_def); + else if (t->is_hide()) + mc.hide(t->m_decl); + else if (t->is_def()) + mc.add(t->m_decl, t->m_def); else { for (auto const& [v, def] : t->m_subst->sub()) - mc->add(v, def); - } + mc.add(v, def); + } } - return model_converter_ref(mc.get()); - } + diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 906aaa738..6aa91e550 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -29,6 +29,7 @@ Author: #include "ast/rewriter/expr_replacer.h" #include "ast/simplifiers/dependent_expr.h" #include "ast/converters/model_converter.h" +#include "ast/converters/generic_model_converter.h" class model_reconstruction_trail { @@ -125,5 +126,10 @@ public: * retrieve the current model converter corresponding to chaining substitutions from the trail. */ model_converter_ref get_model_converter(); + + /** + * Append new updates to model converter, update the current index into the trail in the process. + */ + void append(generic_model_converter& mc, unsigned& index); }; From 85f9c7eefaa721ea9eeb6484f310681db257967b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Nov 2022 11:45:56 +0700 Subject: [PATCH 336/477] replace restore_size_trail by more generic restore_vector other updates: - change signature of advance_qhead to simplify call sites - have model reconstruction replay work on a tail of dependent_expr state, while adding formulas to the tail. --- .../converters/generic_model_converter.cpp | 1 - src/ast/converters/generic_model_converter.h | 3 +- src/ast/converters/model_converter.h | 4 +++ src/ast/simplifiers/bit_blaster.cpp | 2 +- src/ast/simplifiers/bv_slice.cpp | 2 +- src/ast/simplifiers/card2bv.cpp | 2 +- src/ast/simplifiers/dependent_expr_state.h | 3 +- src/ast/simplifiers/elim_unconstrained.cpp | 2 +- src/ast/simplifiers/euf_completion.cpp | 2 +- src/ast/simplifiers/max_bv_sharing.cpp | 2 +- .../model_reconstruction_trail.cpp | 33 +++++++++++-------- .../simplifiers/model_reconstruction_trail.h | 17 +++++++--- src/ast/simplifiers/propagate_values.cpp | 5 +-- src/ast/simplifiers/propagate_values.h | 2 +- src/ast/simplifiers/seq_simplifier.h | 1 + src/ast/simplifiers/solve_eqs.cpp | 2 +- src/sat/sat_solver.h | 1 + src/sat/smt/arith_solver.cpp | 4 +-- src/sat/smt/bv_solver.cpp | 2 +- src/sat/smt/euf_proof.cpp | 16 ++++----- src/sat/smt/euf_solver.cpp | 2 +- src/smt/theory_arith_aux.h | 4 +-- src/smt/theory_lra.cpp | 2 +- src/tactic/core/propagate_values2_tactic.h | 2 +- src/util/trail.h | 23 ++++++------- 25 files changed, 80 insertions(+), 59 deletions(-) diff --git a/src/ast/converters/generic_model_converter.cpp b/src/ast/converters/generic_model_converter.cpp index f805e169b..50c3b071a 100644 --- a/src/ast/converters/generic_model_converter.cpp +++ b/src/ast/converters/generic_model_converter.cpp @@ -36,7 +36,6 @@ generic_model_converter::~generic_model_converter() { void generic_model_converter::add(func_decl * d, expr* e) { VERIFY(e); VERIFY(d->get_range() == e->get_sort()); - m_first_idx.insert_if_not_there(d, m_entries.size()); m_entries.push_back(entry(d, e, m, ADD)); } diff --git a/src/ast/converters/generic_model_converter.h b/src/ast/converters/generic_model_converter.h index 85e8d0390..0706b181f 100644 --- a/src/ast/converters/generic_model_converter.h +++ b/src/ast/converters/generic_model_converter.h @@ -35,7 +35,6 @@ private: ast_manager& m; std::string m_orig; vector m_entries; - obj_map m_first_idx; expr_ref simplify_def(entry const& e); @@ -71,6 +70,8 @@ public: void get_units(obj_map& units) override; vector const& entries() const { return m_entries; } + + void shrink(unsigned j) { m_entries.shrink(j); } }; typedef ref generic_model_converter_ref; diff --git a/src/ast/converters/model_converter.h b/src/ast/converters/model_converter.h index 335e0d276..164becc09 100644 --- a/src/ast/converters/model_converter.h +++ b/src/ast/converters/model_converter.h @@ -101,6 +101,10 @@ typedef sref_buffer model_converter_ref_buffer; model_converter * concat(model_converter * mc1, model_converter * mc2); +inline model_converter * concat(model_converter * mc1, model_converter * mc2, model_converter* mc3) { + return concat(mc1, concat(mc2, mc3)); +} + model_converter * model2model_converter(model * m); model_converter * model_and_labels2model_converter(model * m, labels_vec const &r); diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp index ceb3c56a6..218765d28 100644 --- a/src/ast/simplifiers/bit_blaster.cpp +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -61,7 +61,7 @@ void bit_blaster::reduce() { } m_rewriter.cleanup(); - advance_qhead(m_fmls.size()); + advance_qhead(); } diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp index 75e0a890c..995231b34 100644 --- a/src/ast/simplifiers/bv_slice.cpp +++ b/src/ast/simplifiers/bv_slice.cpp @@ -24,7 +24,7 @@ namespace bv { void slice::reduce() { process_eqs(); apply_subst(); - advance_qhead(m_fmls.size()); + advance_qhead(); } void slice::process_eqs() { diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index 2da9b6e44..44bc8e589 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -49,7 +49,7 @@ void card2bv::reduce() { for (func_decl* f : fns) m_fmls.model_trail().hide(f); - advance_qhead(m_fmls.size()); + advance_qhead(); } void card2bv::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index b94b422ad..90b95ab7d 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -69,7 +69,7 @@ protected: unsigned num_scopes() const { return m_trail.get_num_scopes(); } - void advance_qhead(unsigned sz) { if (num_scopes() > 0) m_trail.push(value_trail(m_qhead)); m_qhead = sz; } + void advance_qhead() { if (num_scopes() > 0) m_trail.push(value_trail(m_qhead)); m_qhead = m_fmls.size(); } public: dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {} virtual ~dependent_expr_simplifier() {} @@ -80,6 +80,7 @@ public: virtual void reset_statistics() {} virtual void updt_params(params_ref const& p) {} virtual void collect_param_descrs(param_descrs& r) {} + unsigned qhead() const { return m_qhead; } }; /** diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 52dc95f05..ac5cc339d 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -302,5 +302,5 @@ void elim_unconstrained::reduce() { vector old_fmls; assert_normalized(old_fmls); update_model_trail(*mc, old_fmls); - advance_qhead(m_fmls.size()); + advance_qhead(); } diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index b768180cf..5056d818c 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -128,7 +128,7 @@ namespace euf { CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } if (!m_has_new_eq) - advance_qhead(m_fmls.size()); + advance_qhead(); } bool completion::is_new_eq(expr* a, expr* b) { diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index 2abacb7f7..3003a47a0 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -261,7 +261,7 @@ public: m_fmls.update(idx, dependent_expr(m, new_curr, d)); } m_rw.cfg().cleanup(); - advance_qhead(m_fmls.size()); + advance_qhead(); } }; diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index cfc65ce67..19c7d9381 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -15,6 +15,7 @@ Author: #include "ast/for_each_expr.h" #include "ast/rewriter/macro_replacer.h" #include "ast/simplifiers/model_reconstruction_trail.h" +#include "ast/simplifiers/dependent_expr_state.h" #include "ast/converters/generic_model_converter.h" @@ -22,13 +23,11 @@ Author: // substitutions that use variables from the dependent expressions. // TODO: add filters to skip sections of the trail that do not touch the current free variables. -void model_reconstruction_trail::replay(dependent_expr const& d, vector& added) { - +void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st) { ast_mark free_vars; scoped_ptr rp = mk_default_expr_replacer(m, false); - add_vars(d, free_vars); - - added.push_back(d); + for (unsigned i = qhead; i < st.size(); ++i) + add_vars(st[i], free_vars); for (auto& t : m_trail) { if (!t->m_active) @@ -44,9 +43,10 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectoris_loose()) { - added.append(t->m_removed); - for (auto r : t->m_removed) - add_vars(r, free_vars); + for (auto r : t->m_removed) { + add_vars(r, free_vars); + st.add(r); + } m_trail_stack.push(value_trail(t->m_active)); t->m_active = false; continue; @@ -64,12 +64,12 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorm_def, t->m_dep); add_vars(de, free_vars); - for (auto& d : added) { - auto [f, dep1] = d(); + for (unsigned i = qhead; i < st.size(); ++i) { + auto [f, dep1] = st[i](); expr_ref g(m); expr_dependency_ref dep2(m); mrp(f, g, dep2); - d = dependent_expr(m, g, m.mk_join(dep1, dep2)); + st.update(i, dependent_expr(m, g, m.mk_join(dep1, dep2))); } continue; } @@ -77,11 +77,12 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vectorset_substitution(t->m_subst.get()); // rigid entries: // apply substitution to added in case of rigid model convertions - for (auto& d : added) { - auto [f, dep1] = d(); + for (unsigned i = qhead; i < st.size(); ++i) { + auto [f, dep1] = st[i](); auto [g, dep2] = rp->replace_with_dep(f); - d = dependent_expr(m, g, m.mk_join(dep1, dep2)); + dependent_expr d(m, g, m.mk_join(dep1, dep2)); add_vars(d, free_vars); + st.update(i, d); } } } @@ -116,3 +117,7 @@ void model_reconstruction_trail::append(generic_model_converter& mc, unsigned& i } +void model_reconstruction_trail::append(generic_model_converter& mc) { + m_trail_stack.push(value_trail(m_trail_index)); + append(mc, m_trail_index); +} diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 6aa91e550..5ad204bf7 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -31,6 +31,8 @@ Author: #include "ast/converters/model_converter.h" #include "ast/converters/generic_model_converter.h" +class dependent_expr_state; + class model_reconstruction_trail { struct entry { @@ -41,7 +43,6 @@ class model_reconstruction_trail { expr_dependency_ref m_dep; bool m_active = true; - entry(ast_manager& m, expr_substitution* s, vector const& rem) : m_subst(s), m_removed(rem), m_decl(m), m_def(m), m_dep(m) {} @@ -71,6 +72,7 @@ class model_reconstruction_trail { ast_manager& m; trail_stack& m_trail_stack; scoped_ptr_vector m_trail; + unsigned m_trail_index = 0; void add_vars(dependent_expr const& d, ast_mark& free_vars) { for (expr* t : subterms::all(expr_ref(d.fml(), d.get_manager()))) @@ -87,6 +89,10 @@ class model_reconstruction_trail { return any_of(added, [&](dependent_expr const& d) { return intersects(free_vars, d); }); } + /** + * Append new updates to model converter, update the current index into the trail in the process. + */ + void append(generic_model_converter& mc, unsigned& index); public: model_reconstruction_trail(ast_manager& m, trail_stack& tr): @@ -120,16 +126,17 @@ public: * register a new depedent expression, update the trail * by removing substitutions that are not equivalence preserving. */ - void replay(dependent_expr const& d, vector& added); - + void replay(unsigned qhead, dependent_expr_state& fmls); + /** * retrieve the current model converter corresponding to chaining substitutions from the trail. */ model_converter_ref get_model_converter(); + /** - * Append new updates to model converter, update the current index into the trail in the process. + * Append new updates to model converter, update m_trail_index in the process. */ - void append(generic_model_converter& mc, unsigned& index); + void append(generic_model_converter& mc); }; diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 6a179674b..6d6bc976f 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -25,11 +25,12 @@ Notes: #include "ast/shared_occs.h" #include "ast/simplifiers/propagate_values.h" -propagate_values::propagate_values(ast_manager& m, dependent_expr_state& fmls): +propagate_values::propagate_values(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): dependent_expr_simplifier(m, fmls), m_rewriter(m) { m_rewriter.set_order_eq(true); m_rewriter.set_flat_and_or(false); + updt_params(p); } void propagate_values::reduce() { @@ -96,7 +97,7 @@ void propagate_values::reduce() { m_rewriter.set_substitution(nullptr); m_rewriter.reset(); - advance_qhead(m_fmls.size()); + advance_qhead(); } void propagate_values::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/propagate_values.h b/src/ast/simplifiers/propagate_values.h index 3219f9796..d263377b1 100644 --- a/src/ast/simplifiers/propagate_values.h +++ b/src/ast/simplifiers/propagate_values.h @@ -36,7 +36,7 @@ class propagate_values : public dependent_expr_simplifier { unsigned m_max_rounds = 4; public: - propagate_values(ast_manager& m, dependent_expr_state& fmls); + propagate_values(ast_manager& m, params_ref const& p, dependent_expr_state& fmls); void reduce() override; void collect_statistics(statistics& st) const override; void reset_statistics() override { m_stats.reset(); } diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h index 5a3a7da60..4288a3475 100644 --- a/src/ast/simplifiers/seq_simplifier.h +++ b/src/ast/simplifiers/seq_simplifier.h @@ -38,6 +38,7 @@ public: break; s->reduce(); } + advance_qhead(); } void collect_statistics(statistics& st) const override { diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 5090e1b43..1bea283ac 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -237,7 +237,7 @@ namespace euf { save_subst(old_fmls); } - advance_qhead(m_fmls.size()); + advance_qhead(); } void solve_eqs::save_subst(vector const& old_fmls) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 982a84307..227568f3d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -485,6 +485,7 @@ namespace sat { // ----------------------- public: lbool check(unsigned num_lits = 0, literal const* lits = nullptr); + lbool check(literal_vector const& lits) { return check(lits.size(), lits.data()); } // retrieve model if solver return sat model const & get_model() const { return m_model; } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 8be98edfb..a69f3604e 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -893,11 +893,11 @@ namespace arith { theory_var other = m_model_eqs.insert_if_not_there(v); TRACE("arith", tout << "insert: v" << v << " := " << get_value(v) << " found: v" << other << "\n";); if (!is_equal(other, v)) - m_assume_eq_candidates.push_back(std::make_pair(v, other)); + m_assume_eq_candidates.push_back({ v, other }); } if (m_assume_eq_candidates.size() > old_sz) - ctx.push(restore_size_trail, false>(m_assume_eq_candidates, old_sz)); + ctx.push(restore_vector(m_assume_eq_candidates, old_sz)); return delayed_assume_eqs(); } diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index a5a35878e..a0bcea43b 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -419,7 +419,7 @@ namespace bv { } ctx.push(value_trail(m_lit_tail)); - ctx.push(restore_size_trail(m_proof_literals)); + ctx.push(restore_vector(m_proof_literals)); sat::literal_vector lits; switch (c.m_kind) { diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 5fbd632cd..ac9e81311 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -84,7 +84,7 @@ namespace euf { return nullptr; push(value_trail(m_lit_tail)); push(value_trail(m_cc_tail)); - push(restore_size_trail(m_proof_literals)); + push(restore_vector(m_proof_literals)); if (conseq != sat::null_literal) m_proof_literals.push_back(~conseq); m_proof_literals.append(r); @@ -101,8 +101,8 @@ namespace euf { SASSERT(a->get_decl() == b->get_decl()); push(value_trail(m_lit_tail)); push(value_trail(m_cc_tail)); - push(restore_size_trail(m_proof_literals)); - push(restore_size_trail(m_explain_cc, m_explain_cc.size())); + push(restore_vector(m_proof_literals)); + push(restore_vector(m_explain_cc)); for (auto lit : ante) m_proof_literals.push_back(~lit); @@ -121,7 +121,7 @@ namespace euf { return nullptr; push(value_trail(m_lit_tail)); push(value_trail(m_cc_tail)); - push(restore_size_trail(m_proof_literals)); + push(restore_vector(m_proof_literals)); for (unsigned i = 0; i < 3; ++i) m_proof_literals.push_back(~clause[i]); @@ -171,7 +171,7 @@ namespace euf { if (!use_drat()) return nullptr; push(value_trail(m_lit_tail)); - push(restore_size_trail(m_proof_literals)); + push(restore_vector(m_proof_literals)); for (unsigned i = 0; i < nl; ++i) m_proof_literals.push_back(~lits[i]); @@ -190,7 +190,7 @@ namespace euf { if (!use_drat()) return nullptr; push(value_trail(m_lit_tail)); - push(restore_size_trail(m_proof_literals)); + push(restore_vector(m_proof_literals)); for (unsigned i = 0; i < nl; ++i) if (sat::null_literal != lits[i]) { @@ -203,11 +203,11 @@ namespace euf { } push(value_trail(m_eq_tail)); - push(restore_size_trail(m_proof_eqs)); + push(restore_vector(m_proof_eqs)); m_proof_eqs.append(ne, eqs); push(value_trail(m_deq_tail)); - push(restore_size_trail(m_proof_deqs)); + push(restore_vector(m_proof_deqs)); m_proof_deqs.append(nd, deqs); m_lit_head = m_lit_tail; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 7473be61d..865608339 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -225,7 +225,7 @@ namespace euf { m_egraph.begin_explain(); m_explain.reset(); if (use_drat() && !probing) { - push(restore_size_trail(m_explain_cc, m_explain_cc.size())); + push(restore_vector(m_explain_cc)); } auto* ext = sat::constraint_base::to_extension(idx); th_proof_hint* hint = nullptr; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 593c32d83..d5eca0bc4 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -2223,12 +2223,12 @@ namespace smt { continue; } TRACE("func_interp_bug", tout << "adding to assume_eq queue #" << n->get_owner_id() << " #" << n2->get_owner_id() << "\n";); - m_assume_eq_candidates.push_back(std::make_pair(other, v)); + m_assume_eq_candidates.push_back({ other , v }); result = true; } if (result) - ctx.push_trail(restore_size_trail, false>(m_assume_eq_candidates, old_sz)); + ctx.push_trail(restore_vector(m_assume_eq_candidates, old_sz)); return delayed_assume_eqs(); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 4075f39dd..1309724d2 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1515,7 +1515,7 @@ public: } if (num_candidates > 0) { - ctx().push_trail(restore_size_trail, false>(m_assume_eq_candidates, old_sz)); + ctx().push_trail(restore_vector(m_assume_eq_candidates, old_sz)); } return delayed_assume_eqs(); diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h index ab9646128..58e263e80 100644 --- a/src/tactic/core/propagate_values2_tactic.h +++ b/src/tactic/core/propagate_values2_tactic.h @@ -26,7 +26,7 @@ Author: class propagate_values2_tactic_factory : public dependent_expr_simplifier_factory { public: dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(propagate_values, m, s); + return alloc(propagate_values, m, p, s); } }; diff --git a/src/util/trail.h b/src/util/trail.h index 20a525cf7..1aa7e4441 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -98,20 +98,21 @@ public: } }; -template -class restore_size_trail : public trail { - vector & m_vector; - unsigned m_old_size; +template +class restore_vector : public trail { + V& m_vector; + unsigned m_old_size; public: - restore_size_trail(vector & v, unsigned sz): + restore_vector(V& v): m_vector(v), - m_old_size(sz) { - } - restore_size_trail(vector & v): + m_old_size(v.size()) + {} + + restore_vector(V& v, unsigned sz): m_vector(v), - m_old_size(v.size()) { - } - + m_old_size(sz) + {} + void undo() override { m_vector.shrink(m_old_size); } From 500626e814f680a42d5cf6c18b1024faec581bd2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Nov 2022 12:13:00 +0700 Subject: [PATCH 337/477] add sat-smt-preprocess module self-contained pre-processing initialization --- src/ast/simplifiers/rewriter_simplifier.h | 14 +++-- src/ast/simplifiers/seq_simplifier.h | 2 +- src/sat/sat_solver/CMakeLists.txt | 1 + src/sat/sat_solver/sat_smt_preprocess.cpp | 69 +++++++++++++++++++++++ src/sat/sat_solver/sat_smt_preprocess.h | 25 ++++++++ 5 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 src/sat/sat_solver/sat_smt_preprocess.cpp create mode 100644 src/sat/sat_solver/sat_smt_preprocess.h diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h index 938e30b83..23ebb4f84 100644 --- a/src/ast/simplifiers/rewriter_simplifier.h +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -25,10 +25,12 @@ class rewriter_simplifier : public dependent_expr_simplifier { unsigned m_num_steps = 0; params_ref m_params; + th_rewriter m_rewriter; public: rewriter_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): - dependent_expr_simplifier(m, fmls) { + dependent_expr_simplifier(m, fmls), + m_rewriter(m) { updt_params(p); } @@ -39,15 +41,15 @@ public: for (unsigned idx = m_qhead; idx < m_fmls.size(); idx++) { if (m_fmls.inconsistent()) break; - auto [f, d] = m_fmls[i](); - m_rewriter(f, new_curr, new_pr); + auto d = m_fmls[idx]; + m_rewriter(d.fml(), new_curr, new_pr); m_num_steps += m_rewriter.get_num_steps(); - m_fmls.update(idx, dependent_expr(m, new_curr, d)); + m_fmls.update(idx, dependent_expr(m, new_curr, d.dep())); } - advance_qhead(m_fmls.size()); + advance_qhead(); } void collect_statistics(statistics& st) const override { st.update("simplifier", m_num_steps); } - void reset_statistics() override { m_stats.reset(); } + void reset_statistics() override { m_num_steps = 0; } void updt_params(params_ref const& p) override { m_params.append(p); m_rewriter.updt_params(m_params); } void collect_param_descrs(param_descrs& r) override { th_rewriter::get_param_descrs(r); } }; diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h index 4288a3475..0d5483b71 100644 --- a/src/ast/simplifiers/seq_simplifier.h +++ b/src/ast/simplifiers/seq_simplifier.h @@ -48,7 +48,7 @@ public: void reset_statistics() override { for (auto* s : m_simplifiers) - s->reset_statistics(st); + s->reset_statistics(); } void updt_params(params_ref const& p) override { diff --git a/src/sat/sat_solver/CMakeLists.txt b/src/sat/sat_solver/CMakeLists.txt index 45a673367..924937b94 100644 --- a/src/sat/sat_solver/CMakeLists.txt +++ b/src/sat/sat_solver/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(sat_solver SOURCES inc_sat_solver.cpp + sat_smt_preprocess.cpp COMPONENT_DEPENDENCIES aig_tactic arith_tactics diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp new file mode 100644 index 000000000..7efe0cadc --- /dev/null +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -0,0 +1,69 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + sat_smt_preprocess.cpp + +Abstract: + + SAT pre-process + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-28 + +--*/ + +#include "sat/sat_params.hpp" +#include "sat/sat_solver/sat_smt_preprocess.h" +#include "ast/simplifiers/bit_blaster.h" +#include "ast/simplifiers/max_bv_sharing.h" +#include "ast/simplifiers/card2bv.h" +#include "ast/simplifiers/propagate_values.h" +#include "ast/simplifiers/rewriter_simplifier.h" +#include "ast/simplifiers/solve_eqs.h" +#include "ast/simplifiers/eliminate_predicates.h" + +void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dependent_expr_state& st) { + params_ref simp1_p = p; + simp1_p.set_bool("som", true); + simp1_p.set_bool("pull_cheap_ite", true); + simp1_p.set_bool("push_ite_bv", false); + simp1_p.set_bool("local_ctx", true); + simp1_p.set_uint("local_ctx_limit", 10000000); + simp1_p.set_bool("flat", true); // required by som + simp1_p.set_bool("hoist_mul", false); // required by som + simp1_p.set_bool("elim_and", true); + simp1_p.set_bool("blast_distinct", true); + simp1_p.set_bool("flat_and_or", false); + + params_ref simp2_p = p; + simp2_p.set_bool("flat", false); + simp2_p.set_bool("flat_and_or", false); + + sat_params sp(p); + if (sp.euf()) { + s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); + s.add_simplifier(alloc(propagate_values, m, p, st)); + // + // add: + // solve_eqs + // elim_predicates + // elim_uncnstr + // euf_completion? + // + // add: make it externally configurable + // + } + else { + s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); + s.add_simplifier(alloc(propagate_values, m, p, st)); + s.add_simplifier(alloc(card2bv, m, p, st)); + s.add_simplifier(alloc(rewriter_simplifier, m, simp1_p, st)); + s.add_simplifier(mk_max_bv_sharing(m, p, st)); + s.add_simplifier(alloc(bit_blaster, m, p, st)); + s.add_simplifier(alloc(rewriter_simplifier, m, simp2_p, st)); + } +} + diff --git a/src/sat/sat_solver/sat_smt_preprocess.h b/src/sat/sat_solver/sat_smt_preprocess.h new file mode 100644 index 000000000..e7b40a8a3 --- /dev/null +++ b/src/sat/sat_solver/sat_smt_preprocess.h @@ -0,0 +1,25 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + sat_smt_preprocess.h + +Abstract: + + SAT pre-process initialization + It collects the functionality associated with + initializing pre-processing for the sat-smt solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-28 + +--*/ + +#pragma once + +#include "ast/simplifiers/seq_simplifier.h" + +void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dependent_expr_state& st); + From 82d9e4a4fc09e401995865487de22c905a3dbb3d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Nov 2022 15:04:12 +0700 Subject: [PATCH 338/477] update goal2sat interface to use explicit initialization --- src/ast/simplifiers/dependent_expr.h | 10 ++++++++++ src/sat/sat_solver/inc_sat_solver.cpp | 6 ++++-- src/sat/sat_solver/sat_smt_preprocess.cpp | 5 +++-- src/sat/tactic/goal2sat.cpp | 13 +++++++++---- src/sat/tactic/goal2sat.h | 5 +++-- 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index f789bf332..4d16bc2bb 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -18,6 +18,7 @@ Author: #pragma once #include "ast/ast.h" +#include "ast/ast_translation.h" class dependent_expr { ast_manager& m; @@ -32,6 +33,15 @@ public: m.inc_ref(fml); m.inc_ref(d); } + + dependent_expr(ast_translation& tr, dependent_expr const& src) : + m(tr.to()) { + m_fml = tr(src.fml()); + m.inc_ref(m_fml); + expr_dependency_translation dtr(tr); + m_dep = dtr(src.dep()); + m.inc_ref(m_dep); + } dependent_expr& operator=(dependent_expr const& other) { SASSERT(&m == &other.m); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6fb936435..41b8e609c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -721,7 +721,8 @@ private: if (m_solver.inconsistent()) return l_false; m_pc.reset(); - m_goal2sat(m, sz, fmls, m_params, m_solver, m_map, m_dep2asm, is_incremental()); + m_goal2sat.init(m, m_params, m_solver, m_map, m_dep2asm, is_incremental()); + m_goal2sat(sz, fmls); if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); m_sat_mc->flush_smc(m_solver, m_map); return check_uninterpreted(); @@ -798,7 +799,8 @@ private: fmls.append(sz, asms); for (unsigned i = 0; i < get_num_assumptions(); ++i) fmls.push_back(get_assumption(i)); - m_goal2sat.assumptions(m, fmls.size(), fmls.data(), m_params, m_solver, m_map, m_dep2asm, is_incremental()); + m_goal2sat.init(m, m_params, m_solver, m_map, m_dep2asm, is_incremental()); + m_goal2sat.assumptions(fmls.size(), fmls.data()); extract_assumptions(fmls.size(), fmls.data()); return l_true; } diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index 7efe0cadc..72c7c5232 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -15,8 +15,7 @@ Author: --*/ -#include "sat/sat_params.hpp" -#include "sat/sat_solver/sat_smt_preprocess.h" + #include "ast/simplifiers/bit_blaster.h" #include "ast/simplifiers/max_bv_sharing.h" #include "ast/simplifiers/card2bv.h" @@ -24,6 +23,8 @@ Author: #include "ast/simplifiers/rewriter_simplifier.h" #include "ast/simplifiers/solve_eqs.h" #include "ast/simplifiers/eliminate_predicates.h" +#include "sat/sat_params.hpp" +#include "sat/sat_solver/sat_smt_preprocess.h" void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dependent_expr_state& st) { params_ref simp1_p = p; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 97a766df9..0f23527dd 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1060,16 +1060,21 @@ void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver_core (*m_imp)(g); } -void goal2sat::operator()(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external) { - init(m, p, t, map, dep2asm, default_external); +void goal2sat::operator()(unsigned n, expr* const* fmls) { + SASSERT(m_imp); (*m_imp)(n, fmls); } -void goal2sat::assumptions(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external) { - init(m, p, t, map, dep2asm, default_external); +void goal2sat::assumptions(unsigned n, expr* const* fmls) { + SASSERT(m_imp); m_imp->assumptions(n, fmls); } +sat::literal goal2sat::internalize(expr* a) { + SASSERT(m_imp); + return m_imp->internalize(a); +} + void goal2sat::get_interpreted_funs(func_decl_ref_vector& funs) { if (m_imp) diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 5f85d59ce..d68467868 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -67,12 +67,13 @@ public: */ void operator()(goal const & g, params_ref const & p, sat::solver_core & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false); - void operator()(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external = false); + void operator()(unsigned n, expr* const* fmls); void init(ast_manager& m, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external); + void assumptions(unsigned n, expr* const* fmls); - void assumptions(ast_manager& m, unsigned n, expr* const* fmls, params_ref const & p, sat::solver_core & t, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external = false); + sat::literal internalize(expr* a); void get_interpreted_funs(func_decl_ref_vector& funs); From ac023935a326c8ef33383422ccf406ccdf571062 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Nov 2022 15:06:31 +0700 Subject: [PATCH 339/477] introduce sat-smt-solver in an iteration of inc-sat-solver introduce sat-smt-solver to allow incremental pre-processing. The aim is to allow incrementally handling formulas while at the same time retaining the main benefits of global in/pre-processing that change models. Previous incremental solving capabilities have been limited to use pre-processing that does not require model conversion. --- src/sat/sat_solver/CMakeLists.txt | 1 + src/sat/sat_solver/sat_smt_solver.cpp | 774 ++++++++++++++++++ src/sat/sat_solver/sat_smt_solver.h | 25 + src/tactic/portfolio/smt_strategic_solver.cpp | 1 + 4 files changed, 801 insertions(+) create mode 100644 src/sat/sat_solver/sat_smt_solver.cpp create mode 100644 src/sat/sat_solver/sat_smt_solver.h diff --git a/src/sat/sat_solver/CMakeLists.txt b/src/sat/sat_solver/CMakeLists.txt index 924937b94..725ca16f7 100644 --- a/src/sat/sat_solver/CMakeLists.txt +++ b/src/sat/sat_solver/CMakeLists.txt @@ -2,6 +2,7 @@ z3_add_component(sat_solver SOURCES inc_sat_solver.cpp sat_smt_preprocess.cpp + sat_smt_solver.cpp COMPONENT_DEPENDENCIES aig_tactic arith_tactics diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp new file mode 100644 index 000000000..3ea0543ec --- /dev/null +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -0,0 +1,774 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_smt_solver.cpp + +Abstract: + + incremental solver based on SAT core. + It uses the ast/simplifiers to allow incremental pre-processing that + produce model converters. + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-28 + +Notes: + + - proper handling of dependencies + pre-processing + - literals used in dependencies should not be eliminated by pre-processing routines + This has to be enforced. + - add translation for preprocess state. + - If the pre-processors are stateful, they need to be properly translated. + - add back get_consequences, maybe or just have them handled by inc_sat_solver + - could also port the layered solver used by smtfd and used by get_consequences to simplifiers + + - port various pre-processing to simplifiers + - qe-lite, fm-elimination, ite-lifting, other from asserted_formulas + +--*/ + + +#include "util/gparams.h" +#include "ast/ast_pp.h" +#include "ast/ast_translation.h" +#include "ast/ast_util.h" +#include "solver/solver.h" +#include "solver/parallel_params.hpp" +#include "solver/parallel_tactic.h" +#include "model/model_smt2_pp.h" +#include "model/model_evaluator.h" +#include "sat/sat_solver.h" +#include "sat/sat_solver/sat_smt_preprocess.h" +#include "sat/sat_params.hpp" +#include "sat/smt/euf_solver.h" +#include "sat/tactic/goal2sat.h" +#include "sat/tactic/sat2goal.h" +#include "sat/tactic/sat_tactic.h" +#include "sat/sat_simplifier_params.hpp" + +// incremental SAT solver. +class sat_smt_solver : public solver { + + struct dep_expr_state : public dependent_expr_state { + sat_smt_solver& s; + model_reconstruction_trail m_reconstruction_trail; + dep_expr_state(sat_smt_solver& s):s(s), m_reconstruction_trail(s.m, m_trail) {} + ~dep_expr_state() override {} + virtual unsigned size() const override { return s.m_fmls.size(); } + dependent_expr const& operator[](unsigned i) override { return s.m_fmls[i]; } + void update(unsigned i, dependent_expr const& j) override { s.m_fmls[i] = j; } + void add(dependent_expr const& j) override { s.m_fmls.push_back(j); } + bool inconsistent() override { return s.m_solver.inconsistent(); } + model_reconstruction_trail& model_trail() override { return m_reconstruction_trail; } + void append(generic_model_converter& mc) { model_trail().append(mc); } + void replay(unsigned qhead) { m_reconstruction_trail.replay(qhead, *this); } + }; + + struct dependency2assumptions { + ast_manager& m; + trail_stack& m_trail; + expr_ref_vector m_refs; + obj_map m_dep2orig; // map original dependency to uninterpeted literal + + u_map m_lit2dep; // map from literal assumption to original expression + obj_map m_dep2lit; // map uninterpreted literal to sat literal + sat::literal_vector m_literals; + uint_set m_seen; + + dependency2assumptions(ast_manager& m, trail_stack& t): + m(m), + m_trail(t), + m_refs(m) + {} + + void reset() { + m_seen.reset(); + m_literals.reset(); + m_dep2lit.reset(); + m_lit2dep.reset(); + } + + // inserted incrementally + void insert(expr* orig, expr* lit) { + m_trail.push(restore_vector(m_refs)); + m_trail.push(insert_obj_map(m_dep2orig, lit)); + m_refs.push_back(lit); + m_refs.push_back(orig); + m_dep2orig.insert(lit, orig); + } + + // inserted on every check-sat + void insert(expr* dep, sat::literal lit) { + if (m_seen.contains(lit.index())) + return; + m_seen.insert(lit.index()); + m_literals.push_back(lit); + m_dep2lit.insert(dep, lit); + m_lit2dep.insert(lit.index(), dep); + } + + expr* lit2orig(sat::literal lit) { + expr* e = m_lit2dep[lit.index()]; + m_dep2orig.find(e, e); + return e; + } + + void copy(ast_translation& tr, dependency2assumptions const& src) { + for (auto const& [k, v] : src.m_dep2orig) + m_dep2orig.insert(tr(k), tr(v)); + } + }; + + mutable sat::solver m_solver; + params_ref m_params; + vector m_fmls; + dep_expr_state m_preprocess_state; + seq_simplifier m_preprocess; + trail_stack& m_trail; + dependency2assumptions m_dep; + goal2sat m_goal2sat; + expr_ref_vector m_assumptions, m_core, m_ors, m_aux_fmls; + atom2bool_var m_map; + generic_model_converter_ref m_mc; + unsigned m_mc_size = 0; + mutable model_converter_ref m_cached_mc; + mutable ref m_sat_mc; + std::string m_unknown = "no reason given"; + // access formulas after they have been pre-processed and handled by the sat solver. + // this allows to access the internal state of the SAT solver and carry on partial results. + bool m_internalized_converted = false; // have internalized formulas been converted back + expr_ref_vector m_internalized_fmls; // formulas in internalized format + + bool is_internalized() const { return m_preprocess.qhead() == m_fmls.size(); } + +public: + sat_smt_solver(ast_manager& m, params_ref const& p): + solver(m), + m_preprocess_state(*this), + m_preprocess(m, p, m_preprocess_state), + m_trail(m_preprocess_state.m_trail), + m_dep(m, m_trail), + m_solver(p, m.limit()), + m_assumptions(m), + m_core(m), + m_ors(m), + m_aux_fmls(m), + m_map(m), + m_internalized_fmls(m) { + updt_params(p); + init_preprocess(); + m_solver.set_incremental(true); + m_mc = alloc(generic_model_converter, m, "sat-smt-solver"); + } + + solver* translate(ast_manager& dst_m, params_ref const& p) override { + if (m_trail.get_num_scopes() > 0) + throw default_exception("Cannot translate sat solver at non-base level"); + + ast_translation tr(m, dst_m); + m_solver.pop_to_base_level(); + sat_smt_solver* result = alloc(sat_smt_solver, dst_m, p); + auto* ext = get_euf(); + if (ext) { + auto& si = result->m_goal2sat.si(dst_m, m_params, result->m_solver, result->m_map, result->m_dep.m_dep2lit, true); + euf::solver::scoped_set_translate st(*ext, dst_m, si); + result->m_solver.copy(m_solver); + } + else { + result->m_solver.copy(m_solver); + } + // TODO: copy preprocess state + for (auto const& [k, v] : m_dep.m_dep2orig) result->m_dep.insert(tr(v), tr(k)); + for (dependent_expr const& f : m_fmls) result->m_fmls.push_back(dependent_expr(tr, f)); + for (expr* f : m_assumptions) result->m_assumptions.push_back(tr(f)); + for (auto & kv : m_map) result->m_map.insert(tr(kv.m_key), kv.m_value); + for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); + if (m_mc) result->m_mc = dynamic_cast(m_mc->translate(tr)); + result->m_dep.copy(tr, m_dep); + result->m_mc_size = m_mc_size; + if (m_sat_mc) result->m_sat_mc = dynamic_cast(m_sat_mc->translate(tr)); + result->m_internalized_converted = m_internalized_converted; + return result; + } + + void set_progress_callback(progress_callback * callback) override {} + + void init_check_sat() { + m_solver.pop_to_base_level(); + m_core.reset(); + m_dep.reset(); + m_cached_mc = nullptr; + init_reason_unknown(); + m_internalized_converted = false; + } + + lbool check_sat_core(unsigned sz, expr * const * _assumptions) override { + init_check_sat(); + + if (m_solver.inconsistent()) + return l_false; + + expr_ref_vector assumptions(m); + for (unsigned i = 0; i < sz; ++i) + assumptions.push_back(ensure_literal(_assumptions[i])); + TRACE("sat", tout << _assumptions << "\n";); + lbool r = internalize_formulas(); + if (r != l_true) + return r; + + internalize_assumptions(assumptions); + + try { + r = m_solver.check(m_dep.m_literals); + } + catch (z3_exception& ex) { + IF_VERBOSE(1, verbose_stream() << "exception: " << ex.msg() << "\n";); + if (m.inc()) { + set_reason_unknown(std::string("(sat.giveup ") + ex.msg() + ')'); + return l_undef; + } + r = l_undef; + } + switch (r) { + case l_true: + check_assumptions(); + break; + case l_false: + extract_core(); + break; + default: + set_reason_unknown(m_solver.get_reason_unknown()); + break; + } + return r; + } + + void push() override { + try { + internalize_formulas(); + } + catch (...) { + push_internal(); + throw; + } + push_internal(); + } + + void push_internal() { + m_trail.push_scope(); + m_solver.user_push(); + m_goal2sat.user_push(); + m_map.push(); + m_preprocess_state.push(); + m_preprocess.push(); + } + + void pop(unsigned n) override { + if (n > m_trail.get_num_scopes()) // allow inc_sat_solver to + n = m_trail.get_num_scopes(); // take over for another solver. + + m_preprocess.pop(n); + m_preprocess_state.pop(n); + m_map.pop(n); + m_goal2sat.user_pop(n); + m_solver.user_pop(n); + m_trail.pop_scope(n); + m_mc->shrink(m_mc_size); + } + + void set_phase(expr* e) override { + bool is_not = m.is_not(e, e); + sat::bool_var b = m_map.to_bool_var(e); + if (b != sat::null_bool_var) + m_solver.set_phase(sat::literal(b, is_not)); + } + + class sat_phase : public phase, public sat::literal_vector {}; + + phase* get_phase() override { + sat_phase* p = alloc(sat_phase); + for (unsigned v = m_solver.num_vars(); v-- > 0; ) + p->push_back(sat::literal(v, !m_solver.get_phase(v))); + return p; + } + + void set_phase(phase* p) override { + for (auto lit : *static_cast(p)) + m_solver.set_phase(lit); + } + + void move_to_front(expr* e) override { + m.is_not(e, e); + sat::bool_var b = m_map.to_bool_var(e); + if (b != sat::null_bool_var) + m_solver.move_to_front(b); + } + + unsigned get_scope_level() const override { + return m_trail.get_num_scopes(); + } + + bool is_literal(expr* a) const { + m.is_not(a, a); + return is_uninterp_const(a); + } + + /* + * Ensure dependencies are literals so that pre-processing can apply to them. + */ + expr* ensure_literal(expr* a) { + if (is_literal(a)) + return a; + expr* new_dep = m.mk_fresh_const("dep", m.mk_bool_sort()); + expr* fml = m.mk_iff(new_dep, a); + m_fmls.push_back(dependent_expr(m, fml, nullptr)); + m_dep.insert(a, new_dep); + return new_dep; + } + + void assert_expr_core2(expr * t, expr * a) override { + a = ensure_literal(a); + m_fmls.push_back(dependent_expr(m, t, m.mk_leaf(a))); + } + + void assert_expr_core(expr * t) override { + m_fmls.push_back(dependent_expr(m, t, nullptr)); + } + + ast_manager& get_manager() const override { return m; } + + void set_produce_models(bool f) override {} + + void collect_param_descrs(param_descrs & r) override { + solver::collect_param_descrs(r); + goal2sat::collect_param_descrs(r); + sat::solver::collect_param_descrs(r); + m_preprocess.collect_param_descrs(r); + } + + void updt_params(params_ref const & p) override { + m_params.append(p); + sat_params sp(p); + m_params.set_bool("keep_cardinality_constraints", sp.cardinality_solver()); + m_params.set_sym("pb.solver", sp.pb_solver()); + m_solver.updt_params(m_params); + m_solver.set_incremental(true); + m_preprocess.updt_params(m_params); + if (sp.euf()) + ensure_euf(); + } + + void collect_statistics(statistics & st) const override { + m_preprocess.collect_statistics(st); + m_solver.collect_statistics(st); + } + + void get_unsat_core(expr_ref_vector & r) override { + r.reset(); + r.append(m_core.size(), m_core.data()); + } + + void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { + unsigned sz = vars.size(); + depth.resize(sz); + for (unsigned i = 0; i < sz; ++i) { + auto bv = m_map.to_bool_var(vars[i]); + depth[i] = bv == sat::null_bool_var ? UINT_MAX : m_solver.lvl(bv); + } + } + + expr_ref_vector get_trail(unsigned max_level) override { + expr_ref_vector result(m), lit2expr(m); + unsigned sz = m_solver.trail_size(); + lit2expr.resize(m_solver.num_vars() * 2); + m_map.mk_inv(lit2expr); + for (unsigned i = 0; i < sz; ++i) { + sat::literal lit = m_solver.trail_literal(i); + if (m_solver.lvl(lit) > max_level) + continue; + expr_ref e(lit2expr.get(lit.index()), m); + if (e) + result.push_back(e); + } + return result; + } + + proof * get_proof_core() override { + return nullptr; + } + + expr_ref_vector last_cube(bool is_sat) { + expr_ref_vector result(m); + result.push_back(is_sat ? m.mk_true() : m.mk_false()); + return result; + } + + expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) override { + if (!is_internalized()) { + lbool r = internalize_formulas(); + if (r != l_true) { + IF_VERBOSE(0, verbose_stream() << "internalize produced " << r << "\n"); + return expr_ref_vector(m); + } + } + convert_internalized(); + if (m_solver.inconsistent()) + return last_cube(false); + obj_hashtable _vs; + for (expr* v : vs) + _vs.insert(v); + sat::bool_var_vector vars; + for (auto& kv : m_map) + if (_vs.empty() || _vs.contains(kv.m_key)) + vars.push_back(kv.m_value); + sat::literal_vector lits; + lbool result = m_solver.cube(vars, lits, backtrack_level); + expr_ref_vector fmls(m); + expr_ref_vector lit2expr(m); + lit2expr.resize(m_solver.num_vars() * 2); + m_map.mk_inv(lit2expr); + for (sat::literal l : lits) { + expr* e = lit2expr.get(l.index()); + SASSERT(e); + fmls.push_back(e); + } + vs.reset(); + for (sat::bool_var v : vars) { + expr* x = lit2expr[sat::literal(v, false).index()].get(); + if (x) + vs.push_back(x); + } + switch (result) { + case l_true: + return last_cube(true); + case l_false: + return last_cube(false); + default: + break; + } + if (lits.empty()) + set_reason_unknown(m_solver.get_reason_unknown()); + return fmls; + } + + + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { + sat::literal_vector ls; + u_map lit2var; + for (expr * e : vars) { + expr* atom = e;; + bool neg = m.is_not(e, atom); + sat::bool_var v = m_map.to_bool_var(atom); + if (v != sat::null_bool_var) { + sat::literal lit(v, neg); + ls.push_back(lit); + lit2var.insert(lit.index(), e); + } + } + vector ls_mutexes; + m_solver.find_mutexes(ls, ls_mutexes); + for (sat::literal_vector const& ls_mutex : ls_mutexes) { + expr_ref_vector mutex(m); + for (sat::literal l : ls_mutex) + mutex.push_back(lit2var.find(l.index())); + mutexes.push_back(mutex); + } + return l_true; + } + + void init_reason_unknown() { + m_unknown = "no reason given"; + } + + std::string reason_unknown() const override { + return m_unknown; + } + + void set_reason_unknown(char const* msg) override { + m_unknown = msg; + } + + void set_reason_unknown(std::string &&msg) { + m_unknown = std::move(msg); + } + + void get_labels(svector & r) override { + } + + unsigned get_num_assertions() const override { + const_cast(this)->convert_internalized(); + if (is_internalized() && m_internalized_converted) + return m_internalized_fmls.size(); + else + return m_fmls.size(); + } + + expr * get_assertion(unsigned idx) const override { + if (is_internalized() && m_internalized_converted) + return m_internalized_fmls[idx]; + return m_fmls[idx].fml(); + } + + unsigned get_num_assumptions() const override { + return m_assumptions.size(); + } + + expr * get_assumption(unsigned idx) const override { + return m_assumptions[idx]; + } + + model_converter_ref get_model_converter() const override { + const_cast(this)->convert_internalized(); + if (m_cached_mc) + return m_cached_mc; + if (is_internalized() && m_internalized_converted) { + if (m_sat_mc) m_sat_mc->flush_smc(m_solver, m_map); + m_cached_mc = concat(solver::get_model_converter().get(), m_mc.get(), m_sat_mc.get()); + TRACE("sat", m_cached_mc->display(tout);); + return m_cached_mc; + } + else { + return solver::get_model_converter(); + } + } + + void convert_internalized() { + m_solver.pop_to_base_level(); + if (!is_internalized() && m_preprocess.qhead() > 0) + internalize_formulas(); + if (!is_internalized() || m_internalized_converted) + return; + sat2goal s2g; + m_cached_mc = nullptr; + goal g(m, false, true, false); + s2g(m_solver, m_map, m_params, g, m_sat_mc); + m_internalized_fmls.reset(); + g.get_formulas(m_internalized_fmls); + TRACE("sat", m_solver.display(tout); tout << m_internalized_fmls << "\n";); + m_internalized_converted = true; + } + + void init_preprocess() { + ::init_preprocess(m, m_params, m_preprocess, m_preprocess_state); + } + + euf::solver* get_euf() { + return dynamic_cast(m_solver.get_extension()); + } + + void init_goal2sat() { + m_goal2sat.init(m, m_params, m_solver, m_map, m_dep.m_dep2lit, true); + } + + euf::solver* ensure_euf() { + init_goal2sat(); + return m_goal2sat.ensure_euf(); + } + + void register_on_clause(void* ctx, user_propagator::on_clause_eh_t& on_clause) override { + ensure_euf()->register_on_clause(ctx, on_clause); + } + + void user_propagate_init( + void* ctx, + user_propagator::push_eh_t& push_eh, + user_propagator::pop_eh_t& pop_eh, + user_propagator::fresh_eh_t& fresh_eh) override { + ensure_euf()->user_propagate_init(ctx, push_eh, pop_eh, fresh_eh); + } + + void user_propagate_register_fixed(user_propagator::fixed_eh_t& fixed_eh) override { + ensure_euf()->user_propagate_register_fixed(fixed_eh); + } + + void user_propagate_register_final(user_propagator::final_eh_t& final_eh) override { + ensure_euf()->user_propagate_register_final(final_eh); + } + + void user_propagate_register_eq(user_propagator::eq_eh_t& eq_eh) override { + ensure_euf()->user_propagate_register_eq(eq_eh); + } + + void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh) override { + ensure_euf()->user_propagate_register_diseq(diseq_eh); + } + + void user_propagate_register_expr(expr* e) override { + ensure_euf()->user_propagate_register_expr(e); + } + + void user_propagate_register_created(user_propagator::created_eh_t& r) override { + ensure_euf()->user_propagate_register_created(r); + } + +private: + + void add_assumption(expr* a) { + init_goal2sat(); + m_dep.insert(a, m_goal2sat.internalize(a)); + } + + void internalize_assumptions(expr_ref_vector const& asms) { + for (expr* a : asms) + add_assumption(a); + for (expr* a : m_assumptions) + add_assumption(a); + } + + lbool internalize_formulas() { + + if (is_internalized()) + return l_true; + + unsigned qhead = m_preprocess.qhead(); + m_trail.push(restore_vector(m_assumptions)); + m_trail.push(restore_vector(m_fmls)); + m_trail.push(value_trail(m_mc_size)); + + m_internalized_converted = false; + + m_preprocess_state.replay(qhead); + m_preprocess.reduce(); + m_preprocess_state.append(*m_mc); + m_solver.pop_to_base_level(); + m_aux_fmls.reset(); + for (; qhead < m_fmls.size(); ++qhead) + add_with_dependency(m_fmls[qhead]); + init_goal2sat(); + m_goal2sat(m_aux_fmls.size(), m_aux_fmls.data()); + if (!m_sat_mc) + m_sat_mc = alloc(sat2goal::mc, m); + m_sat_mc->flush_smc(m_solver, m_map); + return m.inc() ? l_true : l_undef; + } + + ptr_vector m_deps; + void add_with_dependency(dependent_expr const& de) { + if (!de.dep()) { + m_aux_fmls.push_back(de.fml()); + return; + } + m_deps.reset(); + m.linearize(de.dep(), m_deps); + m_ors.reset(); + m_ors.push_back(de.fml()); + flatten_or(m_ors); + for (expr* d : m_deps) { + SASSERT(m.is_bool(d)); + SASSERT(is_literal(d)); + m_assumptions.push_back(d); + m_ors.push_back(mk_not(m, d)); + } + m_aux_fmls.push_back(mk_or(m_ors)); + } + + void extract_core() { + m_core.reset(); + if (m_dep.m_literals.empty()) + return; + for (sat::literal c : m_solver.get_core()) + m_core.push_back(m_dep.lit2orig(c)); + TRACE("sat", + tout << "core: " << m_solver.get_core() << "\n"; + tout << "core: " << m_core << "\n"; + m_solver.display(tout)); + } + + void check_assumptions() { + sat::model const& ll_m = m_solver.get_model(); + for (auto const& [k, lit] : m_dep.m_dep2lit) { + if (sat::value_at(lit, ll_m) == l_true) + continue; + IF_VERBOSE(0, verbose_stream() << mk_pp(k, m) << " does not evaluate to true\n"; + verbose_stream() << m_dep.m_literals << "\n"; + m_solver.display_assignment(verbose_stream()); + m_solver.display(verbose_stream());); + throw default_exception("bad state"); + } + } + + void get_model_core(model_ref & mdl) override { + TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); + mdl = nullptr; + if (!m_solver.model_is_current()) + return; + if (m_fmls.size() > m_preprocess.qhead()) + return; + TRACE("sat", m_solver.display_model(tout);); + CTRACE("sat", m_sat_mc, m_sat_mc->display(tout);); + sat::model ll_m = m_solver.get_model(); + mdl = alloc(model, m); + if (m_sat_mc) + (*m_sat_mc)(ll_m); + expr_ref_vector var2expr(m); + m_map.mk_var_inv(var2expr); + + for (unsigned v = 0; v < var2expr.size(); ++v) { + expr * n = var2expr.get(v); + if (!n || !is_uninterp_const(n)) { + continue; + } + switch (sat::value_at(v, ll_m)) { + case l_true: + mdl->register_decl(to_app(n)->get_decl(), m.mk_true()); + break; + case l_false: + mdl->register_decl(to_app(n)->get_decl(), m.mk_false()); + break; + default: + break; + } + } + + TRACE("sat", m_solver.display(tout);); + if (m_sat_mc) + (*m_sat_mc)(mdl); + m_goal2sat.update_model(mdl); + TRACE("sat", m_mc->display(tout);); + (*m_mc)(mdl); + + TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); + + if (!gparams::get_ref().get_bool("model_validate", false)) { + return; + } + IF_VERBOSE(1, verbose_stream() << "Verifying solution\n";); + model_evaluator eval(*mdl); + eval.set_model_completion(true); + bool all_true = true; + for (dependent_expr const& d : m_fmls) { + if (has_quantifiers(d.fml())) + continue; + expr_ref tmp(m); + eval(d.fml(), tmp); + if (m.limit().is_canceled()) + return; + CTRACE("sat", !m.is_true(tmp), + tout << "Evaluation failed: " << mk_pp(d.fml(), m) << " to " << tmp << "\n"; + model_smt2_pp(tout, m, *(mdl.get()), 0);); + if (m.is_false(tmp)) { + IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(d.fml(), m) << "\n"); + IF_VERBOSE(0, verbose_stream() << "evaluated to " << tmp << "\n"); + all_true = false; + } + } + if (!all_true) { + IF_VERBOSE(0, verbose_stream() << m_params << "\n"); + IF_VERBOSE(0, if (m_mc) m_mc->display(verbose_stream() << "mc0\n")); + IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n"); + exit(0); + } + else { + IF_VERBOSE(1, verbose_stream() << "solution verified\n"); + } + } +}; + + +solver* mk_sat_smt_solver(ast_manager& m, params_ref const& p) { + return alloc(sat_smt_solver, m, p); +} + diff --git a/src/sat/sat_solver/sat_smt_solver.h b/src/sat/sat_solver/sat_smt_solver.h new file mode 100644 index 000000000..6d784b401 --- /dev/null +++ b/src/sat/sat_solver/sat_smt_solver.h @@ -0,0 +1,25 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_smt_solver.h + +Abstract: + + incremental solver based on SAT core. + +Author: + + Nikolaj Bjorner (nbjorner) 2014-7-30 + +Notes: + +--*/ + +#pragma once + +#include "solver/solver.h" + +solver* mk_sat_smt_solver(ast_manager& m, params_ref const& p); + diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index b521095be..1a9fc0f56 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -40,6 +40,7 @@ Notes: #include "muz/fp/horn_tactic.h" #include "smt/smt_solver.h" #include "sat/sat_solver/inc_sat_solver.h" +#include "sat/sat_solver/sat_smt_solver.h" #include "ast/rewriter/bv_rewriter.h" #include "solver/solver2tactic.h" #include "solver/parallel_tactic.h" From dd1ca8f6bd1e2bc8dada167eb0056cfd4abc3dd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Nov 2022 16:36:02 +0700 Subject: [PATCH 340/477] move qhead to attribute on the state instead of the simplifier, - add sat.smt option to enable the new incremental core (it is not ready for mainstream consumption as cloning and other features are not implemented and it hasn't been tested in any detail yet). - move "name" into attribute on simplifier so it can be reused for diagnostics by the seq-simplifier. --- src/ast/simplifiers/bit_blaster.cpp | 4 +-- src/ast/simplifiers/bit_blaster.h | 2 +- src/ast/simplifiers/bv_slice.cpp | 5 ++- src/ast/simplifiers/bv_slice.h | 2 +- src/ast/simplifiers/card2bv.cpp | 4 +-- src/ast/simplifiers/card2bv.h | 1 + src/ast/simplifiers/dependent_expr_state.h | 18 +++++++--- src/ast/simplifiers/elim_unconstrained.cpp | 7 ++-- src/ast/simplifiers/elim_unconstrained.h | 2 ++ src/ast/simplifiers/eliminate_predicates.cpp | 6 ++-- src/ast/simplifiers/eliminate_predicates.h | 2 ++ src/ast/simplifiers/euf_completion.cpp | 6 ++-- src/ast/simplifiers/euf_completion.h | 1 + src/ast/simplifiers/max_bv_sharing.cpp | 5 +-- src/ast/simplifiers/propagate_values.cpp | 7 ++-- src/ast/simplifiers/propagate_values.h | 1 + src/ast/simplifiers/rewriter_simplifier.h | 5 +-- src/ast/simplifiers/seq_simplifier.h | 36 +++++++++++++++++-- src/ast/simplifiers/solve_context_eqs.cpp | 2 +- src/ast/simplifiers/solve_eqs.cpp | 6 ++-- src/ast/simplifiers/solve_eqs.h | 2 ++ src/sat/sat_params.pyg | 9 ++--- src/sat/sat_solver/sat_smt_preprocess.cpp | 2 +- src/sat/sat_solver/sat_smt_solver.cpp | 30 ++++++++-------- src/sat/smt/q_mbi.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 2 +- src/solver/solver.h | 2 +- src/tactic/arith/card2bv_tactic.h | 2 +- src/tactic/bv/bv_slice_tactic.cpp | 2 +- src/tactic/bv/max_bv_sharing_tactic.h | 2 +- src/tactic/core/elim_uncnstr2_tactic.h | 2 +- src/tactic/core/eliminate_predicates_tactic.h | 4 +-- src/tactic/core/euf_completion_tactic.cpp | 2 +- src/tactic/core/propagate_values2_tactic.h | 2 +- src/tactic/core/solve_eqs_tactic.h | 2 +- src/tactic/dependent_expr_state_tactic.h | 12 +++---- src/tactic/portfolio/smt_strategic_solver.cpp | 16 ++++++--- 37 files changed, 132 insertions(+), 85 deletions(-) diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp index 218765d28..dc086c628 100644 --- a/src/ast/simplifiers/bit_blaster.cpp +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -37,7 +37,7 @@ void bit_blaster::reduce() { expr_ref new_curr(m); proof_ref new_pr(m); bool change = false; - for (unsigned idx = m_qhead; idx < m_fmls.size(); idx++) { + for (unsigned idx = m_fmls.qhead(); idx < m_fmls.size(); idx++) { if (m_fmls.inconsistent()) break; auto [curr, d] = m_fmls[idx](); @@ -60,8 +60,6 @@ void bit_blaster::reduce() { m_fmls.model_trail().push(f, v, nullptr, {}); } m_rewriter.cleanup(); - - advance_qhead(); } diff --git a/src/ast/simplifiers/bit_blaster.h b/src/ast/simplifiers/bit_blaster.h index 70446918b..231a1ca68 100644 --- a/src/ast/simplifiers/bit_blaster.h +++ b/src/ast/simplifiers/bit_blaster.h @@ -33,7 +33,7 @@ public: m_rewriter(m, p) { updt_params(p); } - + char const* name() const override { return "bit-blaster"; } void updt_params(params_ref const & p) override; void collect_param_descrs(param_descrs & r) override; void reduce() override; diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp index 995231b34..14d6edb99 100644 --- a/src/ast/simplifiers/bv_slice.cpp +++ b/src/ast/simplifiers/bv_slice.cpp @@ -24,11 +24,10 @@ namespace bv { void slice::reduce() { process_eqs(); apply_subst(); - advance_qhead(); } void slice::process_eqs() { - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { auto const [f, d] = m_fmls[i](); process_eq(f); } @@ -137,7 +136,7 @@ namespace bv { expr_ref_vector cache(m), pin(m); ptr_vector todo, args; expr* c; - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { auto const [f, d] = m_fmls[i](); todo.push_back(f); pin.push_back(f); diff --git a/src/ast/simplifiers/bv_slice.h b/src/ast/simplifiers/bv_slice.h index cc0f48cfc..3bf514ac3 100644 --- a/src/ast/simplifiers/bv_slice.h +++ b/src/ast/simplifiers/bv_slice.h @@ -47,7 +47,7 @@ namespace bv { public: slice(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_bv(m), m_rewriter(m) {} - + char const* name() const override { return "bv-slice"; } void push() override { dependent_expr_simplifier::push(); } void pop(unsigned n) override { dependent_expr_simplifier::pop(n); } void reduce() override; diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index 44bc8e589..3feb86474 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -29,7 +29,7 @@ void card2bv::reduce() { expr_ref new_f1(m), new_f2(m); proof_ref new_pr(m); - for (unsigned idx = m_qhead; !m_fmls.inconsistent() && idx < m_fmls.size(); idx++) { + for (unsigned idx = m_fmls.qhead(); !m_fmls.inconsistent() && idx < m_fmls.size(); idx++) { auto [f, d] = m_fmls[idx](); rw1(f, new_f1); rw2(false, new_f1, new_f2, new_pr); @@ -48,8 +48,6 @@ void card2bv::reduce() { func_decl_ref_vector const& fns = rw2.fresh_constants(); for (func_decl* f : fns) m_fmls.model_trail().hide(f); - - advance_qhead(); } void card2bv::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/card2bv.h b/src/ast/simplifiers/card2bv.h index e089fa84c..4c081c8cd 100644 --- a/src/ast/simplifiers/card2bv.h +++ b/src/ast/simplifiers/card2bv.h @@ -34,6 +34,7 @@ class card2bv : public dependent_expr_simplifier { public: card2bv(ast_manager& m, params_ref const& p, dependent_expr_state& fmls); + char const* name() const override { return "card2bv"; } void reduce() override; void collect_statistics(statistics& st) const override; void reset_statistics() override { m_stats.reset(); } diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 90b95ab7d..54ee5626b 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -41,6 +41,7 @@ Author: abstract interface to state updated by simplifiers. */ class dependent_expr_state { + unsigned m_qhead = 0; public: virtual ~dependent_expr_state() {} virtual unsigned size() const = 0; @@ -53,8 +54,15 @@ public: trail_stack m_trail; void push() { m_trail.push_scope(); } void pop(unsigned n) { m_trail.pop_scope(n); } - - + unsigned qhead() const { return m_qhead; } + void advance_qhead() { m_qhead = size(); } + unsigned num_exprs() { + expr_fast_mark1 visited; + unsigned r = 0; + for (unsigned i = 0; i < size(); i++) + r += get_num_exprs((*this)[i].fml(), visited); + return r; + } }; /** @@ -65,14 +73,13 @@ protected: ast_manager& m; dependent_expr_state& m_fmls; trail_stack& m_trail; - unsigned m_qhead = 0; // pointer into last processed formula in m_fmls unsigned num_scopes() const { return m_trail.get_num_scopes(); } - void advance_qhead() { if (num_scopes() > 0) m_trail.push(value_trail(m_qhead)); m_qhead = m_fmls.size(); } public: dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {} virtual ~dependent_expr_simplifier() {} + virtual char const* name() const = 0; virtual void push() { } virtual void pop(unsigned n) { } virtual void reduce() = 0; @@ -80,7 +87,8 @@ public: virtual void reset_statistics() {} virtual void updt_params(params_ref const& p) {} virtual void collect_param_descrs(param_descrs& r) {} - unsigned qhead() const { return m_qhead; } + ast_manager& get_manager() { return m; } + dependent_expr_state& get_fmls() { return m_fmls; } }; /** diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index ac5cc339d..93a84dba6 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -138,7 +138,7 @@ void elim_unconstrained::init_nodes() { // freeze subterms before the already processed head terms.reset(); - for (unsigned i = 0; i < m_qhead; ++i) + for (unsigned i = 0; i < m_fmls.qhead(); ++i) terms.push_back(m_fmls[i].fml()); for (expr* e : subterms::all(terms)) m_frozen.mark(e, true); @@ -216,7 +216,7 @@ void elim_unconstrained::gc(expr* t) { */ void elim_unconstrained::reconstruct_terms() { expr_ref_vector terms(m); - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) + for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) terms.push_back(m_fmls[i].fml()); for (expr* e : subterms_postorder::all(terms)) { @@ -250,7 +250,7 @@ void elim_unconstrained::reconstruct_terms() { void elim_unconstrained::assert_normalized(vector& old_fmls) { unsigned sz = m_fmls.size(); - for (unsigned i = m_qhead; i < sz; ++i) { + for (unsigned i = m_fmls.qhead(); i < sz; ++i) { auto [f, d] = m_fmls[i](); node& n = get_node(f); expr* g = n.m_term; @@ -302,5 +302,4 @@ void elim_unconstrained::reduce() { vector old_fmls; assert_normalized(old_fmls); update_model_trail(*mc, old_fmls); - advance_qhead(); } diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 89f28fe33..b66d0b727 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -71,6 +71,8 @@ public: elim_unconstrained(ast_manager& m, dependent_expr_state& fmls); + char const* name() const override { return "elim-unconstrained"; } + void reduce() override; void collect_statistics(statistics& st) const override { st.update("elim-unconstrained", m_stats.m_num_eliminated); } diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 6d1288c5d..fa615048f 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -501,7 +501,7 @@ void eliminate_predicates::reduce_definitions() { for (auto const& [k, v] : m_macros) macro_expander.insert(v->m_head, v->m_def, v->m_dep); - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { auto [f, d] = m_fmls[i](); expr_ref fml(f, m), new_fml(m); expr_dependency_ref dep(m); @@ -779,7 +779,7 @@ eliminate_predicates::clause* eliminate_predicates::init_clause(expr* f, expr_de * eliminations. */ void eliminate_predicates::init_clauses() { - for (unsigned i = 0; i < m_qhead; ++i) + for (unsigned i = 0; i < m_fmls.qhead(); ++i) m_to_exclude.push_back(m_fmls[i].fml()); recfun::util rec(m); if (rec.has_rec_defs()) @@ -788,7 +788,7 @@ void eliminate_predicates::init_clauses() { process_to_exclude(m_disable_macro); - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) { + for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { clause* cl = init_clause(i); add_use_list(*cl); m_clauses.push_back(cl); diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index 6afd0886a..ca4110e99 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -129,6 +129,8 @@ public: eliminate_predicates(ast_manager& m, dependent_expr_state& fmls); ~eliminate_predicates() override { reset(); } + + char const* name() const override { return "elim-predicates"; } void reduce() override; diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 5056d818c..f077f1918 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -80,7 +80,7 @@ namespace euf { m_nodes_to_canonize.push_back(ch); }; - for (unsigned i = m_qhead; i < sz; ++i) { + for (unsigned i = m_fmls.qhead(); i < sz; ++i) { expr* x, * y; auto [f, d] = m_fmls[i](); if (m.is_eq(f, x, y)) { @@ -114,7 +114,7 @@ namespace euf { } unsigned sz = m_fmls.size(); - for (unsigned i = m_qhead; i < sz; ++i) { + for (unsigned i = m_fmls.qhead(); i < sz; ++i) { auto [f, d] = m_fmls[i](); expr_dependency_ref dep(d, m); @@ -127,8 +127,6 @@ namespace euf { } CTRACE("euf_completion", g != f, tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } - if (!m_has_new_eq) - advance_qhead(); } bool completion::is_new_eq(expr* a, expr* b) { diff --git a/src/ast/simplifiers/euf_completion.h b/src/ast/simplifiers/euf_completion.h index f02e33245..da0fb7276 100644 --- a/src/ast/simplifiers/euf_completion.h +++ b/src/ast/simplifiers/euf_completion.h @@ -58,6 +58,7 @@ namespace euf { expr_dependency* explain_conflict(); public: completion(ast_manager& m, dependent_expr_state& fmls); + char const* name() const override { return "euf-reduce"; } void push() override { m_egraph.push(); dependent_expr_simplifier::push(); } void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_egraph.pop(n); } void reduce() override; diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index 3003a47a0..4744c473c 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -250,10 +250,12 @@ public: "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); } + char const* name() const override { return "max-bv-sharing"; } + void reduce() override { expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = m_qhead; idx < m_fmls.size() && !m_fmls.inconsistent(); idx++) { + for (unsigned idx = m_fmls.qhead(); idx < m_fmls.size() && !m_fmls.inconsistent(); idx++) { auto [curr, d] = m_fmls[idx](); m_rw(curr, new_curr, new_pr); // Proof reconstruction: new_pr = m.mk_modus_ponens(old_pr, new_pr); @@ -261,7 +263,6 @@ public: m_fmls.update(idx, dependent_expr(m, new_curr, d)); } m_rw.cfg().cleanup(); - advance_qhead(); } }; diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 6d6bc976f..2572cc310 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -78,7 +78,7 @@ void propagate_values::reduce() { subst.reset(); m_rewriter.reset(); m_rewriter.set_substitution(&subst); - for (unsigned i = 0; i < m_qhead; ++i) + for (unsigned i = 0; i < m_fmls.qhead(); ++i) add_sub(m_fmls[i]); }; @@ -86,10 +86,10 @@ void propagate_values::reduce() { for (unsigned r = 0; r < m_max_rounds && rw != m_stats.m_num_rewrites; ++r) { rw = m_stats.m_num_rewrites; init_sub(); - for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) + for (unsigned i = m_fmls.qhead(); i < m_fmls.size() && !m_fmls.inconsistent(); ++i) process_fml(i); init_sub(); - for (unsigned i = m_fmls.size(); i-- > m_qhead && !m_fmls.inconsistent();) + for (unsigned i = m_fmls.size(); i-- > m_fmls.qhead() && !m_fmls.inconsistent();) process_fml(i); if (subst.empty()) break; @@ -97,7 +97,6 @@ void propagate_values::reduce() { m_rewriter.set_substitution(nullptr); m_rewriter.reset(); - advance_qhead(); } void propagate_values::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/propagate_values.h b/src/ast/simplifiers/propagate_values.h index d263377b1..9ad59d1b3 100644 --- a/src/ast/simplifiers/propagate_values.h +++ b/src/ast/simplifiers/propagate_values.h @@ -37,6 +37,7 @@ class propagate_values : public dependent_expr_simplifier { public: propagate_values(ast_manager& m, params_ref const& p, dependent_expr_state& fmls); + char const* name() const override { return "propagate-values2"; } void reduce() override; void collect_statistics(statistics& st) const override; void reset_statistics() override { m_stats.reset(); } diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h index 23ebb4f84..f956ec808 100644 --- a/src/ast/simplifiers/rewriter_simplifier.h +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -33,12 +33,14 @@ public: m_rewriter(m) { updt_params(p); } + + char const* name() const override { return "simplifier"; } void reduce() override { m_num_steps = 0; expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = m_qhead; idx < m_fmls.size(); idx++) { + for (unsigned idx = m_fmls.qhead(); idx < m_fmls.size(); idx++) { if (m_fmls.inconsistent()) break; auto d = m_fmls[idx]; @@ -46,7 +48,6 @@ public: m_num_steps += m_rewriter.get_num_steps(); m_fmls.update(idx, dependent_expr(m, new_curr, d.dep())); } - advance_qhead(); } void collect_statistics(statistics& st) const override { st.update("simplifier", m_num_steps); } void reset_statistics() override { m_num_steps = 0; } diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h index 0d5483b71..0fa5990dd 100644 --- a/src/ast/simplifiers/seq_simplifier.h +++ b/src/ast/simplifiers/seq_simplifier.h @@ -17,16 +17,46 @@ Author: #pragma once +#include "util/stopwatch.h" #include "ast/simplifiers/dependent_expr_state.h" class seq_simplifier : public dependent_expr_simplifier { scoped_ptr_vector m_simplifiers; + struct collect_stats { + stopwatch m_watch; + double m_start_memory = 0; + dependent_expr_simplifier& s; + collect_stats(dependent_expr_simplifier& s) : + m_start_memory(static_cast(memory::get_allocation_size()) / static_cast(1024 * 1024)), + s(s) { + m_watch.start(); + } + ~collect_stats() { + m_watch.stop(); + double end_memory = static_cast(memory::get_allocation_size()) / static_cast(1024 * 1024); + IF_VERBOSE(10, + statistics st; + verbose_stream() << "(" << s.name() + << " :num-exprs " << s.get_fmls().num_exprs() + << " :num-asts " << s.get_manager().get_num_asts() + << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() + << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory + << " :after-memory " << std::fixed << std::setprecision(2) << end_memory + << ")" << "\n"; + s.collect_statistics(st); + verbose_stream() << st); + } + }; + public: + seq_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): dependent_expr_simplifier(m, fmls) { } + + char const* name() const override { return "and-then"; } void add_simplifier(dependent_expr_simplifier* s) { m_simplifiers.push_back(s); @@ -36,9 +66,11 @@ public: for (auto* s : m_simplifiers) { if (m_fmls.inconsistent()) break; + if (!m.inc()) + break; + collect_stats _cs(*s); s->reduce(); - } - advance_qhead(); + } } void collect_statistics(statistics& st) const override { diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index ef52d009c..7eaa8ad2f 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -148,7 +148,7 @@ namespace euf { void solve_context_eqs::collect_nested_equalities(dep_eq_vector& eqs) { expr_mark visited; unsigned sz = m_fmls.size(); - for (unsigned i = m_solve_eqs.m_qhead; i < sz; ++i) + for (unsigned i = m_fmls.qhead(); i < sz; ++i) collect_nested_equalities(m_fmls[i], visited, eqs); if (eqs.empty()) diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 1bea283ac..f6055af50 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -34,7 +34,7 @@ namespace euf { void solve_eqs::get_eqs(dep_eq_vector& eqs) { for (extract_eq* ex : m_extract_plugins) - for (unsigned i = m_qhead; i < m_fmls.size(); ++i) + for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) ex->get_eqs(m_fmls[i], eqs); } @@ -187,7 +187,7 @@ namespace euf { scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); - for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { + for (unsigned i = m_fmls.qhead(); i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { auto [f, d] = m_fmls[i](); auto [new_f, new_dep] = rp->replace_with_dep(f); m_rewriter(new_f); @@ -236,8 +236,6 @@ namespace euf { apply_subst(old_fmls); save_subst(old_fmls); } - - advance_qhead(); } void solve_eqs::save_subst(vector const& old_fmls) { diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index a2afd6e58..4b2905b2a 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -68,6 +68,8 @@ namespace euf { solve_eqs(ast_manager& m, dependent_expr_state& fmls); + char const* name() const override { return "solve-eqs"; } + void reduce() override; void updt_params(params_ref const& p) override; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 20a415441..f9d7c643a 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -47,6 +47,7 @@ def_module_params('sat', ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.disable', BOOL, False, 'override anything that enables DRAT'), + ('smt', BOOL, False, 'use the SAT solver based incremental SMT core'), ('smt.proof.check', BOOL, False, 'check SMT proof while it is created'), ('smt.proof.check_rup', BOOL, True, 'apply forward RUP proof checking'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), @@ -73,11 +74,11 @@ def_module_params('sat', ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), ('local_search_dbg_flips', BOOL, False, 'write debug information for number of flips'), ('binspr', BOOL, False, 'enable SPR inferences of binary propagation redundant clauses. This inprocessing step eliminates models'), - ('anf', BOOL, False, 'enable ANF based simplification in-processing'), - ('anf.delay', UINT, 2, 'delay ANF simplification by in-processing round'), + ('anf', BOOL, False, 'enable ANF based simplification in-processing'), + ('anf.delay', UINT, 2, 'delay ANF simplification by in-processing round'), ('anf.exlin', BOOL, False, 'enable extended linear simplification'), - ('cut', BOOL, False, 'enable AIG based simplification in-processing'), - ('cut.delay', UINT, 2, 'delay cut simplification by in-processing round'), + ('cut', BOOL, False, 'enable AIG based simplification in-processing'), + ('cut.delay', UINT, 2, 'delay cut simplification by in-processing round'), ('cut.aig', BOOL, False, 'extract aigs (and ites) from cluases for cut simplification'), ('cut.lut', BOOL, False, 'extract luts from clauses for cut simplification'), ('cut.xor', BOOL, False, 'extract xors from clauses for cut simplification'), diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index 72c7c5232..f05fc098f 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -44,7 +44,7 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep simp2_p.set_bool("flat_and_or", false); sat_params sp(p); - if (sp.euf()) { + if (sp.euf() || sp.smt()) { s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); s.add_simplifier(alloc(propagate_values, m, p, st)); // diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index 3ea0543ec..2d95dab69 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -130,7 +130,7 @@ class sat_smt_solver : public solver { trail_stack& m_trail; dependency2assumptions m_dep; goal2sat m_goal2sat; - expr_ref_vector m_assumptions, m_core, m_ors, m_aux_fmls; + expr_ref_vector m_assumptions, m_core, m_ors, m_aux_fmls, m_internalized_fmls; atom2bool_var m_map; generic_model_converter_ref m_mc; unsigned m_mc_size = 0; @@ -140,9 +140,8 @@ class sat_smt_solver : public solver { // access formulas after they have been pre-processed and handled by the sat solver. // this allows to access the internal state of the SAT solver and carry on partial results. bool m_internalized_converted = false; // have internalized formulas been converted back - expr_ref_vector m_internalized_fmls; // formulas in internalized format - bool is_internalized() const { return m_preprocess.qhead() == m_fmls.size(); } + bool is_internalized() const { return m_preprocess_state.qhead() == m_fmls.size(); } public: sat_smt_solver(ast_manager& m, params_ref const& p): @@ -152,16 +151,12 @@ public: m_trail(m_preprocess_state.m_trail), m_dep(m, m_trail), m_solver(p, m.limit()), - m_assumptions(m), - m_core(m), - m_ors(m), - m_aux_fmls(m), + m_assumptions(m), m_core(m), m_ors(m), m_aux_fmls(m), m_internalized_fmls(m), m_map(m), - m_internalized_fmls(m) { + m_mc(alloc(generic_model_converter, m, "sat-smt-solver")) { updt_params(p); init_preprocess(); m_solver.set_incremental(true); - m_mc = alloc(generic_model_converter, m, "sat-smt-solver"); } solver* translate(ast_manager& dst_m, params_ref const& p) override { @@ -214,7 +209,7 @@ public: expr_ref_vector assumptions(m); for (unsigned i = 0; i < sz; ++i) assumptions.push_back(ensure_literal(_assumptions[i])); - TRACE("sat", tout << _assumptions << "\n";); + TRACE("sat", tout << assumptions << "\n";); lbool r = internalize_formulas(); if (r != l_true) return r; @@ -267,8 +262,7 @@ public: } void pop(unsigned n) override { - if (n > m_trail.get_num_scopes()) // allow inc_sat_solver to - n = m_trail.get_num_scopes(); // take over for another solver. + n = std::min(n, m_trail.get_num_scopes()); // allow sat_smt_solver to take over for another solver. m_preprocess.pop(n); m_preprocess_state.pop(n); @@ -357,7 +351,7 @@ public: m_solver.updt_params(m_params); m_solver.set_incremental(true); m_preprocess.updt_params(m_params); - if (sp.euf()) + if (sp.smt()) ensure_euf(); } @@ -537,7 +531,7 @@ public: void convert_internalized() { m_solver.pop_to_base_level(); - if (!is_internalized() && m_preprocess.qhead() > 0) + if (!is_internalized() && m_preprocess_state.qhead() > 0) internalize_formulas(); if (!is_internalized() || m_internalized_converted) return; @@ -623,15 +617,19 @@ private: if (is_internalized()) return l_true; - unsigned qhead = m_preprocess.qhead(); + unsigned qhead = m_preprocess_state.qhead(); m_trail.push(restore_vector(m_assumptions)); m_trail.push(restore_vector(m_fmls)); m_trail.push(value_trail(m_mc_size)); + TRACE("sat", tout << "qhead " << qhead << "\n"); m_internalized_converted = false; m_preprocess_state.replay(qhead); m_preprocess.reduce(); + if (!m.inc()) + return l_undef; + m_preprocess_state.advance_qhead(); m_preprocess_state.append(*m_mc); m_solver.pop_to_base_level(); m_aux_fmls.reset(); @@ -695,7 +693,7 @@ private: mdl = nullptr; if (!m_solver.model_is_current()) return; - if (m_fmls.size() > m_preprocess.qhead()) + if (m_fmls.size() > m_preprocess_state.qhead()) return; TRACE("sat", m_solver.display_model(tout);); CTRACE("sat", m_sat_mc, m_sat_mc->display(tout);); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 2c9b87c13..6f2db37e1 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -629,7 +629,7 @@ namespace q { void mbqi::init_solver() { if (!m_solver) - m_solver = mk_smt2_solver(m, m_no_drat_params); + m_solver = mk_smt2_solver(m, m_no_drat_params, symbol::null); } void mbqi::init_search() { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 0f23527dd..865c5f15d 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -99,7 +99,7 @@ struct goal2sat::imp : public sat::sat_internalizer { sat_params sp(p); m_ite_extra = p.get_bool("ite_extra", true); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_euf = sp.euf(); + m_euf = sp.euf() || sp.smt(); } void throw_op_not_handled(std::string const& s) { diff --git a/src/solver/solver.h b/src/solver/solver.h index 4ffdd5092..957cb7c8e 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -35,7 +35,7 @@ public: solver_factory * mk_smt_strategic_solver_factory(symbol const & logic = symbol::null); -solver* mk_smt2_solver(ast_manager& m, params_ref const& p); +solver* mk_smt2_solver(ast_manager& m, params_ref const& p, symbol const& logic = symbol::null); /** \brief Abstract interface for making solvers available in the Z3 diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 95282d93c..63cb021d7 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -30,7 +30,7 @@ public: }; inline tactic* mk_card2bv_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(card2bv_tactic_factory), "card2bv"); + return alloc(dependent_expr_state_tactic, m, p, alloc(card2bv_tactic_factory)); } /* diff --git a/src/tactic/bv/bv_slice_tactic.cpp b/src/tactic/bv/bv_slice_tactic.cpp index 040068e39..17d69c7b1 100644 --- a/src/tactic/bv/bv_slice_tactic.cpp +++ b/src/tactic/bv/bv_slice_tactic.cpp @@ -29,5 +29,5 @@ public: }; tactic* mk_bv_slice_tactic(ast_manager& m, params_ref const& p) { - return alloc(dependent_expr_state_tactic, m, p, alloc(bv_slice_factory), "bv-slice"); + return alloc(dependent_expr_state_tactic, m, p, alloc(bv_slice_factory)); } diff --git a/src/tactic/bv/max_bv_sharing_tactic.h b/src/tactic/bv/max_bv_sharing_tactic.h index ebd050aa5..3521b4a04 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.h +++ b/src/tactic/bv/max_bv_sharing_tactic.h @@ -32,7 +32,7 @@ public: }; inline tactic* mk_max_bv_sharing_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(max_bv_sharing_tactic_factory), "max-bv-sharing"); + return alloc(dependent_expr_state_tactic, m, p, alloc(max_bv_sharing_tactic_factory)); } /* diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h index d9f6196f2..e7226a8f0 100644 --- a/src/tactic/core/elim_uncnstr2_tactic.h +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -29,7 +29,7 @@ public: }; inline tactic * mk_elim_uncnstr2_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(elim_uncnstr2_tactic_factory), "elim-uncnstr2"); + return alloc(dependent_expr_state_tactic, m, p, alloc(elim_uncnstr2_tactic_factory)); } diff --git a/src/tactic/core/eliminate_predicates_tactic.h b/src/tactic/core/eliminate_predicates_tactic.h index 3daffb1f3..de2291260 100644 --- a/src/tactic/core/eliminate_predicates_tactic.h +++ b/src/tactic/core/eliminate_predicates_tactic.h @@ -17,9 +17,9 @@ Author: #pragma once #include "util/params.h" +#include "ast/simplifiers/eliminate_predicates.h" #include "tactic/tactic.h" #include "tactic/dependent_expr_state_tactic.h" -#include "ast/simplifiers/eliminate_predicates.h" class eliminate_predicates_tactic_factory : public dependent_expr_simplifier_factory { @@ -30,7 +30,7 @@ public: }; inline tactic * mk_eliminate_predicates_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(eliminate_predicates_tactic_factory), "elim-predicates"); + return alloc(dependent_expr_state_tactic, m, p, alloc(eliminate_predicates_tactic_factory)); } /* diff --git a/src/tactic/core/euf_completion_tactic.cpp b/src/tactic/core/euf_completion_tactic.cpp index bdd940f17..d229df62f 100644 --- a/src/tactic/core/euf_completion_tactic.cpp +++ b/src/tactic/core/euf_completion_tactic.cpp @@ -28,5 +28,5 @@ public: }; tactic * mk_euf_completion_tactic(ast_manager& m, params_ref const& p) { - return alloc(dependent_expr_state_tactic, m, p, alloc(euf_completion_tactic_factory), "euf-completion"); + return alloc(dependent_expr_state_tactic, m, p, alloc(euf_completion_tactic_factory)); } diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h index 58e263e80..834e8bebd 100644 --- a/src/tactic/core/propagate_values2_tactic.h +++ b/src/tactic/core/propagate_values2_tactic.h @@ -31,7 +31,7 @@ public: }; inline tactic * mk_propagate_values2_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(propagate_values2_tactic_factory), "propagate-values2"); + return alloc(dependent_expr_state_tactic, m, p, alloc(propagate_values2_tactic_factory)); } diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 5d6da2e9a..76a738660 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -30,7 +30,7 @@ public: }; inline tactic * mk_solve_eqs_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs_tactic_factory), "solve-eqs"); + return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs_tactic_factory)); } /* diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index f16bb0ff3..dda114c24 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -22,7 +22,6 @@ Author: class dependent_expr_state_tactic : public tactic, public dependent_expr_state { ast_manager& m; params_ref m_params; - std::string m_name; trail_stack m_trail; goal_ref m_goal; dependent_expr m_dep; @@ -42,10 +41,9 @@ class dependent_expr_state_tactic : public tactic, public dependent_expr_state { public: - dependent_expr_state_tactic(ast_manager& m, params_ref const& p, dependent_expr_simplifier_factory* f, char const* name): + dependent_expr_state_tactic(ast_manager& m, params_ref const& p, dependent_expr_simplifier_factory* f): m(m), m_params(p), - m_name(name), m_factory(f), m_simp(nullptr), m_dep(m, m.mk_true(), nullptr) @@ -79,7 +77,7 @@ public: return *m_model_trail; } - char const* name() const override { return m_name.c_str(); } + char const* name() const override { return m_simp?m_simp->name():"null"; } void updt_params(params_ref const & p) override { m_params.append(p); @@ -93,7 +91,7 @@ public: } tactic * translate(ast_manager & m) override { - return alloc(dependent_expr_state_tactic, m, m_params, m_factory.get(), name()); + return alloc(dependent_expr_state_tactic, m, m_params, m_factory.get()); } void operator()(goal_ref const & in, @@ -105,10 +103,12 @@ public: try { if (!in->proofs_enabled()) m_simp->reduce(); + if (m.inc()) + advance_qhead(); } catch (rewriter_exception& ex) { throw tactic_exception(ex.msg()); - } + } m_goal->elim_true(); m_goal->elim_redundancies(); m_goal->inc_depth(); diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 1a9fc0f56..8acfbe40d 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -47,6 +47,7 @@ Notes: #include "solver/parallel_params.hpp" #include "params/tactic_params.hpp" #include "parsers/smt2/smt2parser.h" +#include "sat/sat_params.hpp" @@ -114,6 +115,15 @@ static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p return nullptr; } +solver* mk_smt2_solver(ast_manager& m, params_ref const& p, symbol const& logic) { + sat_params sp(p); + if (sp.smt()) + return mk_sat_smt_solver(m, p); + if (sp.euf()) + return mk_inc_sat_solver(m, p); + return mk_smt_solver(m, p, logic); +} + static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { bv_rewriter rw(m); solver* s = mk_special_solver_for_logic(m, p, logic); @@ -123,7 +133,7 @@ static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol if (!s && tp.default_tactic() == "sat") s = mk_inc_sat_solver(m, p); if (!s) - s = mk_smt_solver(m, p, logic); + s = mk_smt2_solver(m, p, logic); return s; } @@ -170,6 +180,4 @@ solver_factory * mk_smt_strategic_solver_factory(symbol const & logic) { return alloc(smt_strategic_solver_factory, logic); } -solver* mk_smt2_solver(ast_manager& m, params_ref const& p) { - return mk_inc_sat_solver(m, p); -} + From 73a652cf4b60bc382b676da2b96a8b5bd359e342 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Nov 2022 16:42:42 +0700 Subject: [PATCH 341/477] some fixes to backtracking restore points in new solver --- src/ast/simplifiers/dependent_expr_state.h | 2 +- src/sat/sat_solver/sat_smt_solver.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 54ee5626b..a65492a58 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -55,7 +55,7 @@ public: void push() { m_trail.push_scope(); } void pop(unsigned n) { m_trail.pop_scope(n); } unsigned qhead() const { return m_qhead; } - void advance_qhead() { m_qhead = size(); } + void advance_qhead() { if (m_trail.get_num_scopes() > 0) m_trail.push(value_trail(m_qhead)); m_qhead = size(); } unsigned num_exprs() { expr_fast_mark1 visited; unsigned r = 0; diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index 2d95dab69..91a2bfec2 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -259,6 +259,9 @@ public: m_map.push(); m_preprocess_state.push(); m_preprocess.push(); + m_trail.push(restore_vector(m_assumptions)); + m_trail.push(restore_vector(m_fmls)); + m_trail.push(value_trail(m_mc_size)); } void pop(unsigned n) override { @@ -618,9 +621,6 @@ private: return l_true; unsigned qhead = m_preprocess_state.qhead(); - m_trail.push(restore_vector(m_assumptions)); - m_trail.push(restore_vector(m_fmls)); - m_trail.push(value_trail(m_mc_size)); TRACE("sat", tout << "qhead " << qhead << "\n"); m_internalized_converted = false; From bec3acd14618120a2606b35f606132f5063c5821 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 08:35:29 +0700 Subject: [PATCH 342/477] consolidate freeze functionality into dependent_expr_state rename size() to qtail() and introduce shortcuts ensure tactic goals are not updated if they are in inconsistent state (because indices could be invalidated) --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/bit_blaster.cpp | 2 +- src/ast/simplifiers/bv_slice.cpp | 4 +- src/ast/simplifiers/card2bv.cpp | 2 +- src/ast/simplifiers/dependent_expr_state.cpp | 109 ++++++++++++++++++ src/ast/simplifiers/dependent_expr_state.h | 52 +++++++-- src/ast/simplifiers/elim_unconstrained.cpp | 31 ++--- src/ast/simplifiers/elim_unconstrained.h | 1 - src/ast/simplifiers/eliminate_predicates.cpp | 37 ++---- src/ast/simplifiers/eliminate_predicates.h | 2 +- src/ast/simplifiers/euf_completion.cpp | 8 +- src/ast/simplifiers/extract_eqs.cpp | 2 +- src/ast/simplifiers/max_bv_sharing.cpp | 2 +- .../model_reconstruction_trail.cpp | 6 +- src/ast/simplifiers/propagate_values.cpp | 8 +- src/ast/simplifiers/rewriter_simplifier.h | 2 +- src/ast/simplifiers/seq_simplifier.h | 1 + src/ast/simplifiers/solve_context_eqs.cpp | 4 +- src/ast/simplifiers/solve_eqs.cpp | 4 +- src/sat/sat_solver/sat_smt_solver.cpp | 31 +++-- src/tactic/dependent_expr_state_tactic.h | 7 +- 21 files changed, 223 insertions(+), 93 deletions(-) create mode 100644 src/ast/simplifiers/dependent_expr_state.cpp diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index c488a6269..9d894627a 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(simplifiers bit_blaster.cpp bv_slice.cpp card2bv.cpp + dependent_expr_state.cpp elim_unconstrained.cpp eliminate_predicates.cpp euf_completion.cpp diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp index dc086c628..72ee19eca 100644 --- a/src/ast/simplifiers/bit_blaster.cpp +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -37,7 +37,7 @@ void bit_blaster::reduce() { expr_ref new_curr(m); proof_ref new_pr(m); bool change = false; - for (unsigned idx = m_fmls.qhead(); idx < m_fmls.size(); idx++) { + for (unsigned idx = qhead(); idx < qtail(); idx++) { if (m_fmls.inconsistent()) break; auto [curr, d] = m_fmls[idx](); diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp index 14d6edb99..cc8b4fd85 100644 --- a/src/ast/simplifiers/bv_slice.cpp +++ b/src/ast/simplifiers/bv_slice.cpp @@ -27,7 +27,7 @@ namespace bv { } void slice::process_eqs() { - for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { + for (unsigned i = qhead(); i < qtail(); ++i) { auto const [f, d] = m_fmls[i](); process_eq(f); } @@ -136,7 +136,7 @@ namespace bv { expr_ref_vector cache(m), pin(m); ptr_vector todo, args; expr* c; - for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { + for (unsigned i = qhead(); i < qtail(); ++i) { auto const [f, d] = m_fmls[i](); todo.push_back(f); pin.push_back(f); diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index 3feb86474..d20b4a6c5 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -29,7 +29,7 @@ void card2bv::reduce() { expr_ref new_f1(m), new_f2(m); proof_ref new_pr(m); - for (unsigned idx = m_fmls.qhead(); !m_fmls.inconsistent() && idx < m_fmls.size(); idx++) { + for (unsigned idx = qhead(); !m_fmls.inconsistent() && idx < qtail(); idx++) { auto [f, d] = m_fmls[idx](); rw1(f, new_f1); rw2(false, new_f1, new_f2, new_pr); diff --git a/src/ast/simplifiers/dependent_expr_state.cpp b/src/ast/simplifiers/dependent_expr_state.cpp new file mode 100644 index 000000000..5219d25da --- /dev/null +++ b/src/ast/simplifiers/dependent_expr_state.cpp @@ -0,0 +1,109 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + dependent_expr_state.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-2. + +--*/ + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/recfun_decl_plugin.h" +#include "ast/for_each_ast.h" + +unsigned dependent_expr_state::num_exprs() { + expr_fast_mark1 visited; + unsigned r = 0; + for (unsigned i = 0; i < qtail(); i++) + r += get_num_exprs((*this)[i].fml(), visited); + return r; +} + +void dependent_expr_state::freeze(func_decl* f) { + if (m_frozen.is_marked(f)) + return; + m_frozen_trail.push_back(f); + m_frozen.mark(f, true); +} + +void dependent_expr_state::freeze(expr* term) { + if (is_app(term)) + freeze(to_app(term)->get_decl()); +} + +/** +* Freeze functions appearing as sub-expressions of 'e'. +* The only_as_array flag indicates whether to only freeze occurrences of as-array +* from elimination. +*/ +void dependent_expr_state::freeze_terms(expr* e, bool only_as_array, ast_mark& visited) { + auto& m = m_frozen_trail.get_manager(); + struct proc { + bool only_as_array; + array_util a; + dependent_expr_state& st; + proc(ast_manager& m, bool o, dependent_expr_state& d) : + only_as_array(o), a(m), st(d) {} + void operator()(func_decl* f) { + if (!only_as_array) + st.freeze(f); + if (a.is_as_array(f, f) && is_uninterp(f)) + st.freeze(f); + } + void operator()(ast* s) {} + }; + proc proc(m, only_as_array, *this); + for_each_ast(proc, visited, e); +} + +/** +* Freeze all functions used in recursive definitions +*/ + +void dependent_expr_state::freeze_recfun() { + if (m_recfun_frozen) + return; + m_recfun_frozen = true; + auto& m = m_frozen_trail.get_manager(); + recfun::util rec(m); + ast_mark visited; + for (func_decl* f : rec.get_rec_funs()) + freeze_terms(rec.get_def(f).get_rhs(), false, visited); +} + +/** +* The current qhead is to be updated to qtail. +* Before this update, freeze all functions appearing in formulas. +*/ +void dependent_expr_state::freeze_prefix() { + ast_mark visited; + for (unsigned i = qhead(); i < qtail(); ++i) + freeze_terms((*this)[i].fml(), false, visited); +} + +/** +* Freeze functions in the unprocessed suffix that appear in dependencies and in as-array. +*/ +void dependent_expr_state::freeze_suffix() { + if (m_suffix_frozen) + return; + m_suffix_frozen = true; + auto& m = m_frozen_trail.get_manager(); + freeze_recfun(); + ast_mark visited; + ptr_vector es; + for (unsigned i = qhead(); i < qtail(); ++i) { + auto d = (*this)[i]; + if (d.dep()) { + es.reset(); + m.linearize(d.dep(), es); + for (expr* e : es) + freeze_terms(e, false, visited); + } + freeze_terms(d.fml(), true, visited); + } +} diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index a65492a58..4c9b21f0a 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -42,27 +42,54 @@ Author: */ class dependent_expr_state { unsigned m_qhead = 0; + bool m_suffix_frozen = false; + bool m_recfun_frozen = false; + ast_mark m_frozen; + func_decl_ref_vector m_frozen_trail; + void freeze_prefix(); + void freeze_recfun(); + void freeze_terms(expr* term, bool only_as_array, ast_mark& visited); + void freeze(expr* term); + void freeze(func_decl* f); + struct thaw : public trail { + unsigned sz; + dependent_expr_state& st; + thaw(dependent_expr_state& st) : sz(st.m_frozen_trail.size()), st(st) {} + void undo() override { + for (unsigned i = st.m_frozen_trail.size(); i-- > sz; ) + st.m_frozen.mark(st.m_frozen_trail.get(i), false); + st.m_frozen_trail.shrink(sz); + } + }; public: + dependent_expr_state(ast_manager& m) : m_frozen_trail(m) {} virtual ~dependent_expr_state() {} - virtual unsigned size() const = 0; + unsigned qhead() const { return m_qhead; } + virtual unsigned qtail() const = 0; virtual dependent_expr const& operator[](unsigned i) = 0; virtual void update(unsigned i, dependent_expr const& j) = 0; virtual void add(dependent_expr const& j) = 0; virtual bool inconsistent() = 0; virtual model_reconstruction_trail& model_trail() = 0; + virtual void flatten_suffix() {} trail_stack m_trail; - void push() { m_trail.push_scope(); } - void pop(unsigned n) { m_trail.pop_scope(n); } - unsigned qhead() const { return m_qhead; } - void advance_qhead() { if (m_trail.get_num_scopes() > 0) m_trail.push(value_trail(m_qhead)); m_qhead = size(); } - unsigned num_exprs() { - expr_fast_mark1 visited; - unsigned r = 0; - for (unsigned i = 0; i < size(); i++) - r += get_num_exprs((*this)[i].fml(), visited); - return r; + void push() { + m_trail.push_scope(); + m_trail.push(value_trail(m_qhead)); + m_trail.push(thaw(*this)); } + void pop(unsigned n) { m_trail.pop_scope(n); } + + void advance_qhead() { freeze_prefix(); m_suffix_frozen = false; m_qhead = qtail(); } + unsigned num_exprs(); + + /** + * Freeze internal functions + */ + bool frozen(func_decl* f) const { return m_frozen.is_marked(f); } + bool frozen(expr* f) const { return is_app(f) && m_frozen.is_marked(to_app(f)->get_decl()); } + void freeze_suffix(); }; /** @@ -76,6 +103,9 @@ protected: unsigned num_scopes() const { return m_trail.get_num_scopes(); } + unsigned qhead() const { return m_fmls.qhead(); } + unsigned qtail() const { return m_fmls.qtail(); } + public: dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {} virtual ~dependent_expr_simplifier() {} diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 93a84dba6..41305b745 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -48,7 +48,7 @@ Author: elim_unconstrained::elim_unconstrained(ast_manager& m, dependent_expr_state& fmls) : dependent_expr_simplifier(m, fmls), m_inverter(m), m_lt(*this), m_heap(1024, m_lt), m_trail(m) { std::function is_var = [&](expr* e) { - return is_uninterp_const(e) && !m_frozen.is_marked(e) && get_node(e).m_refcount <= 1; + return is_uninterp_const(e) && !m_fmls.frozen(e) && get_node(e).m_refcount <= 1; }; m_inverter.set_is_var(is_var); } @@ -121,12 +121,14 @@ expr* elim_unconstrained::get_parent(unsigned n) const { * initialize node structure */ void elim_unconstrained::init_nodes() { + + m_fmls.freeze_suffix(); + expr_ref_vector terms(m); - for (unsigned i = 0; i < m_fmls.size(); ++i) + for (unsigned i = qhead(); i < qtail(); ++i) terms.push_back(m_fmls[i].fml()); m_trail.append(terms); m_heap.reset(); - m_frozen.reset(); m_root.reset(); // initialize nodes for terms in the original goal @@ -135,23 +137,6 @@ void elim_unconstrained::init_nodes() { // top-level terms have reference count > 0 for (expr* e : terms) inc_ref(e); - - // freeze subterms before the already processed head - terms.reset(); - for (unsigned i = 0; i < m_fmls.qhead(); ++i) - terms.push_back(m_fmls[i].fml()); - for (expr* e : subterms::all(terms)) - m_frozen.mark(e, true); - - // freeze subterms that occur with recursive function definitions - recfun::util rec(m); - if (rec.has_rec_defs()) { - for (func_decl* f : rec.get_rec_funs()) { - expr* rhs = rec.get_def(f).get_rhs(); - for (expr* t : subterms::all(expr_ref(rhs, m))) - m_frozen.mark(t); - } - } } /** @@ -216,7 +201,7 @@ void elim_unconstrained::gc(expr* t) { */ void elim_unconstrained::reconstruct_terms() { expr_ref_vector terms(m); - for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) + for (unsigned i = qhead(); i < qtail(); ++i) terms.push_back(m_fmls[i].fml()); for (expr* e : subterms_postorder::all(terms)) { @@ -249,8 +234,8 @@ void elim_unconstrained::reconstruct_terms() { void elim_unconstrained::assert_normalized(vector& old_fmls) { - unsigned sz = m_fmls.size(); - for (unsigned i = m_fmls.qhead(); i < sz; ++i) { + unsigned sz = qtail(); + for (unsigned i = qhead(); i < sz; ++i) { auto [f, d] = m_fmls[i](); node& n = get_node(f); expr* g = n.m_term; diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index b66d0b727..9da0f3fc2 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -45,7 +45,6 @@ class elim_unconstrained : public dependent_expr_simplifier { heap m_heap; expr_ref_vector m_trail; ptr_vector m_args; - expr_mark m_frozen; stats m_stats; unsigned_vector m_root; diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index fa615048f..d71d2180a 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -109,7 +109,7 @@ bool eliminate_predicates::can_be_macro_head(expr* _head, unsigned num_bound) { return false; app* head = to_app(_head); func_decl* f = head->get_decl(); - if (m_disable_macro.is_marked(f)) + if (m_fmls.frozen(f)) return false; if (m_is_macro.is_marked(f)) return false; @@ -157,7 +157,7 @@ expr_ref eliminate_predicates::bind_free_variables_in_def(clause& cl, app* head, * (or (not (head x)) (def x)) */ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep) { - if (m_disable_macro.is_marked(p)) + if (m_fmls.frozen(p)) return false; expr_mark binary_pos, binary_neg; obj_map deps; @@ -501,7 +501,7 @@ void eliminate_predicates::reduce_definitions() { for (auto const& [k, v] : m_macros) macro_expander.insert(v->m_head, v->m_def, v->m_dep); - for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { + for (unsigned i = qhead(); i < qtail(); ++i) { auto [f, d] = m_fmls[i](); expr_ref fml(f, m), new_fml(m); expr_dependency_ref dep(m); @@ -524,7 +524,7 @@ void eliminate_predicates::reduce_definitions() { void eliminate_predicates::try_resolve(func_decl* p) { if (m_disable_elimination.is_marked(p)) return; - if (m_disable_macro.is_marked(p)) + if (m_fmls.frozen(p)) return; unsigned num_pos = 0, num_neg = 0; @@ -717,30 +717,20 @@ void eliminate_predicates::try_resolve() { /** * Process the terms m_to_exclude, walk all subterms. * Uninterpreted function declarations in these terms are added to 'exclude_set' -* Uninterpreted function declarations from as-array terms are added to 'm_disable_macro' */ void eliminate_predicates::process_to_exclude(ast_mark& exclude_set) { ast_mark visited; - array_util a(m); - struct proc { - array_util& a; ast_mark& to_exclude; - ast_mark& to_disable; - proc(array_util& a, ast_mark& f, ast_mark& d) : - a(a), to_exclude(f), to_disable(d) {} + proc(ast_mark& f) : + to_exclude(f) {} void operator()(func_decl* f) { if (is_uninterp(f)) to_exclude.mark(f, true); } - void operator()(app* e) { - func_decl* f; - if (a.is_as_array(e, f) && is_uninterp(f)) - to_disable.mark(f, true); - } void operator()(ast* s) {} }; - proc proc(a, exclude_set, m_disable_macro); + proc proc(exclude_set); for (expr* e : m_to_exclude) for_each_ast(proc, visited, e); @@ -779,16 +769,10 @@ eliminate_predicates::clause* eliminate_predicates::init_clause(expr* f, expr_de * eliminations. */ void eliminate_predicates::init_clauses() { - for (unsigned i = 0; i < m_fmls.qhead(); ++i) - m_to_exclude.push_back(m_fmls[i].fml()); - recfun::util rec(m); - if (rec.has_rec_defs()) - for (auto& d : rec.get_rec_funs()) - m_to_exclude.push_back(rec.get_def(d).get_rhs()); - - process_to_exclude(m_disable_macro); - for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) { + m_fmls.freeze_suffix(); + + for (unsigned i = qhead(); i < qtail(); ++i) { clause* cl = init_clause(i); add_use_list(*cl); m_clauses.push_back(cl); @@ -821,7 +805,6 @@ void eliminate_predicates::reset() { m_predicates.reset(); m_predicate_decls.reset(); m_to_exclude.reset(); - m_disable_macro.reset(); m_disable_elimination.reset(); m_is_macro.reset(); for (auto const& [k, v] : m_macros) diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index ca4110e99..a8d4fff48 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -88,7 +88,7 @@ private: }; scoped_ptr_vector m_clauses; - ast_mark m_disable_elimination, m_disable_macro, m_predicate_decls, m_is_macro; + ast_mark m_disable_elimination, m_predicate_decls, m_is_macro; ptr_vector m_predicates; ptr_vector m_to_exclude; stats m_stats; diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index f077f1918..78be41c1a 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -74,13 +74,13 @@ namespace euf { void completion::add_egraph() { m_nodes_to_canonize.reset(); - unsigned sz = m_fmls.size(); + unsigned sz = qtail(); auto add_children = [&](enode* n) { for (auto* ch : enode_args(n)) m_nodes_to_canonize.push_back(ch); }; - for (unsigned i = m_fmls.qhead(); i < sz; ++i) { + for (unsigned i = qhead(); i < sz; ++i) { expr* x, * y; auto [f, d] = m_fmls[i](); if (m.is_eq(f, x, y)) { @@ -113,8 +113,8 @@ namespace euf { return; } - unsigned sz = m_fmls.size(); - for (unsigned i = m_fmls.qhead(); i < sz; ++i) { + unsigned sz = qtail(); + for (unsigned i = qhead(); i < sz; ++i) { auto [f, d] = m_fmls[i](); expr_dependency_ref dep(d, m); diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index d65f9b167..fdb889ee3 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -258,7 +258,7 @@ namespace euf { if (!m_enabled) return; m_nonzero.reset(); - for (unsigned i = 0; i < fmls.size(); ++i) + for (unsigned i = 0; i < fmls.qtail(); ++i) add_pos(fmls[i].fml()); } diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index 4744c473c..3ac27302a 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -255,7 +255,7 @@ public: void reduce() override { expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = m_fmls.qhead(); idx < m_fmls.size() && !m_fmls.inconsistent(); idx++) { + for (unsigned idx = qhead(); idx < qtail() && !m_fmls.inconsistent(); idx++) { auto [curr, d] = m_fmls[idx](); m_rw(curr, new_curr, new_pr); // Proof reconstruction: new_pr = m.mk_modus_ponens(old_pr, new_pr); diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 19c7d9381..18af7449f 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -26,7 +26,7 @@ Author: void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st) { ast_mark free_vars; scoped_ptr rp = mk_default_expr_replacer(m, false); - for (unsigned i = qhead; i < st.size(); ++i) + for (unsigned i = qhead; i < st.qtail(); ++i) add_vars(st[i], free_vars); for (auto& t : m_trail) { @@ -64,7 +64,7 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st dependent_expr de(m, t->m_def, t->m_dep); add_vars(de, free_vars); - for (unsigned i = qhead; i < st.size(); ++i) { + for (unsigned i = qhead; i < st.qtail(); ++i) { auto [f, dep1] = st[i](); expr_ref g(m); expr_dependency_ref dep2(m); @@ -77,7 +77,7 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st rp->set_substitution(t->m_subst.get()); // rigid entries: // apply substitution to added in case of rigid model convertions - for (unsigned i = qhead; i < st.size(); ++i) { + for (unsigned i = qhead; i < st.qtail(); ++i) { auto [f, dep1] = st[i](); auto [g, dep2] = rp->replace_with_dep(f); dependent_expr d(m, g, m.mk_join(dep1, dep2)); diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 2572cc310..928e8a787 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -41,7 +41,7 @@ void propagate_values::reduce() { auto add_shared = [&]() { shared_occs_mark visited; shared.reset(); - for (unsigned i = 0; i < m_fmls.size(); ++i) + for (unsigned i = 0; i < qtail(); ++i) shared(m_fmls[i].fml(), visited); }; @@ -78,7 +78,7 @@ void propagate_values::reduce() { subst.reset(); m_rewriter.reset(); m_rewriter.set_substitution(&subst); - for (unsigned i = 0; i < m_fmls.qhead(); ++i) + for (unsigned i = 0; i < qhead(); ++i) add_sub(m_fmls[i]); }; @@ -86,10 +86,10 @@ void propagate_values::reduce() { for (unsigned r = 0; r < m_max_rounds && rw != m_stats.m_num_rewrites; ++r) { rw = m_stats.m_num_rewrites; init_sub(); - for (unsigned i = m_fmls.qhead(); i < m_fmls.size() && !m_fmls.inconsistent(); ++i) + for (unsigned i = qhead(); i < qtail() && !m_fmls.inconsistent(); ++i) process_fml(i); init_sub(); - for (unsigned i = m_fmls.size(); i-- > m_fmls.qhead() && !m_fmls.inconsistent();) + for (unsigned i = qtail(); i-- > qhead() && !m_fmls.inconsistent();) process_fml(i); if (subst.empty()) break; diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h index f956ec808..bb9fd0d22 100644 --- a/src/ast/simplifiers/rewriter_simplifier.h +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -40,7 +40,7 @@ public: m_num_steps = 0; expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = m_fmls.qhead(); idx < m_fmls.size(); idx++) { + for (unsigned idx = qhead(); idx < qtail(); idx++) { if (m_fmls.inconsistent()) break; auto d = m_fmls[idx]; diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h index 0fa5990dd..326b3d09e 100644 --- a/src/ast/simplifiers/seq_simplifier.h +++ b/src/ast/simplifiers/seq_simplifier.h @@ -70,6 +70,7 @@ public: break; collect_stats _cs(*s); s->reduce(); + m_fmls.flatten_suffix(); } } diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index 7eaa8ad2f..e87381825 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -42,7 +42,7 @@ namespace euf { bool solve_context_eqs::is_safe_eq(expr* e) { m_and_pos.reset(); m_and_neg.reset(); m_or_pos.reset(); m_or_neg.reset(); - for (unsigned i = 0; i < m_fmls.size(); ++i) + for (unsigned i = 0; i < m_fmls.qtail(); ++i) if (!is_safe_eq(m_fmls[i].fml(), e)) return false; return true; @@ -147,7 +147,7 @@ namespace euf { void solve_context_eqs::collect_nested_equalities(dep_eq_vector& eqs) { expr_mark visited; - unsigned sz = m_fmls.size(); + unsigned sz = m_fmls.qtail(); for (unsigned i = m_fmls.qhead(); i < sz; ++i) collect_nested_equalities(m_fmls[i], visited, eqs); diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index f6055af50..e2fbc0c9a 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -34,7 +34,7 @@ namespace euf { void solve_eqs::get_eqs(dep_eq_vector& eqs) { for (extract_eq* ex : m_extract_plugins) - for (unsigned i = m_fmls.qhead(); i < m_fmls.size(); ++i) + for (unsigned i = qhead(); i < qtail(); ++i) ex->get_eqs(m_fmls[i], eqs); } @@ -187,7 +187,7 @@ namespace euf { scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); - for (unsigned i = m_fmls.qhead(); i < m_fmls.size() && !m_fmls.inconsistent(); ++i) { + for (unsigned i = qhead(); i < qtail() && !m_fmls.inconsistent(); ++i) { auto [f, d] = m_fmls[i](); auto [new_f, new_dep] = rp->replace_with_dep(f); m_rewriter(new_f); diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index 91a2bfec2..69cc7ed17 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -17,9 +17,6 @@ Author: Notes: - - proper handling of dependencies + pre-processing - - literals used in dependencies should not be eliminated by pre-processing routines - This has to be enforced. - add translation for preprocess state. - If the pre-processors are stateful, they need to be properly translated. - add back get_consequences, maybe or just have them handled by inc_sat_solver @@ -55,9 +52,9 @@ class sat_smt_solver : public solver { struct dep_expr_state : public dependent_expr_state { sat_smt_solver& s; model_reconstruction_trail m_reconstruction_trail; - dep_expr_state(sat_smt_solver& s):s(s), m_reconstruction_trail(s.m, m_trail) {} + dep_expr_state(sat_smt_solver& s):dependent_expr_state(s.m), s(s), m_reconstruction_trail(s.m, m_trail) {} ~dep_expr_state() override {} - virtual unsigned size() const override { return s.m_fmls.size(); } + virtual unsigned qtail() const override { return s.m_fmls.size(); } dependent_expr const& operator[](unsigned i) override { return s.m_fmls[i]; } void update(unsigned i, dependent_expr const& j) override { s.m_fmls[i] = j; } void add(dependent_expr const& j) override { s.m_fmls.push_back(j); } @@ -65,6 +62,28 @@ class sat_smt_solver : public solver { model_reconstruction_trail& model_trail() override { return m_reconstruction_trail; } void append(generic_model_converter& mc) { model_trail().append(mc); } void replay(unsigned qhead) { m_reconstruction_trail.replay(qhead, *this); } + void flatten_suffix() override { + expr_mark seen; + unsigned j = qhead(); + for (unsigned i = qhead(); i < qtail(); ++i) { + expr* f = s.m_fmls[i].fml(); + if (seen.is_marked(f)) + continue; + seen.mark(f, true); + if (s.m.is_true(f)) + continue; + if (s.m.is_and(f)) { + auto* d = s.m_fmls[i].dep(); + for (expr* arg : *to_app(f)) + s.m_fmls.push_back(dependent_expr(s.m, arg, d)); + continue; + } + if (i != j) + s.m_fmls[j] = s.m_fmls[i]; + ++j; + } + s.m_fmls.shrink(j); + } }; struct dependency2assumptions { @@ -253,7 +272,6 @@ public: } void push_internal() { - m_trail.push_scope(); m_solver.user_push(); m_goal2sat.user_push(); m_map.push(); @@ -272,7 +290,6 @@ public: m_map.pop(n); m_goal2sat.user_pop(n); m_solver.user_pop(n); - m_trail.pop_scope(n); m_mc->shrink(m_mc_size); } diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index dda114c24..3afc0fc9f 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -42,6 +42,7 @@ class dependent_expr_state_tactic : public tactic, public dependent_expr_state { public: dependent_expr_state_tactic(ast_manager& m, params_ref const& p, dependent_expr_simplifier_factory* f): + dependent_expr_state(m), m(m), m_params(p), m_factory(f), @@ -52,7 +53,7 @@ public: /** * size(), [](), update() and inconsisent() implement the abstract interface of dependent_expr_state */ - unsigned size() const override { return m_goal->size(); } + unsigned qtail() const override { return m_goal->size(); } dependent_expr const& operator[](unsigned i) override { m_dep = dependent_expr(m, m_goal->form(i), m_goal->dep(i)); @@ -60,11 +61,15 @@ public: } void update(unsigned i, dependent_expr const& j) override { + if (inconsistent()) + return; auto [f, d] = j(); m_goal->update(i, f, nullptr, d); } void add(dependent_expr const& j) override { + if (inconsistent()) + return; auto [f, d] = j(); m_goal->assert_expr(f, nullptr, d); } From b084821a0cbf2dca5c14872be9686bc6e261ffe4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 13:41:40 +0700 Subject: [PATCH 343/477] wip - dependent expr simpliifer - simplify iterator over current indices - add more simplifiers used by asserted_formulas - improve diagnostics printing --- src/ast/rewriter/macro_replacer.cpp | 23 ++- src/ast/rewriter/macro_replacer.h | 5 +- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/bit2int.h | 44 ++++++ src/ast/simplifiers/bv_elim.h | 43 +++++ src/ast/simplifiers/dependent_expr.h | 17 ++ src/ast/simplifiers/dependent_expr_state.cpp | 12 +- src/ast/simplifiers/dependent_expr_state.h | 31 +++- src/ast/simplifiers/distribute_forall.h | 45 ++++++ src/ast/simplifiers/elim_bounds.h | 45 ++++++ src/ast/simplifiers/eliminate_predicates.cpp | 57 +++++-- src/ast/simplifiers/eliminate_predicates.h | 3 +- .../model_reconstruction_trail.cpp | 39 ++++- .../simplifiers/model_reconstruction_trail.h | 2 + src/ast/simplifiers/propagate_values.cpp | 6 +- src/ast/simplifiers/pull_nested_quantifiers.h | 46 ++++++ src/ast/simplifiers/refine_inj_axiom.h | 44 ++++++ src/ast/simplifiers/rewriter_simplifier.h | 6 +- src/ast/simplifiers/seq_simplifier.h | 6 +- src/ast/simplifiers/solve_eqs.cpp | 7 +- src/ast/simplifiers/solve_eqs.h | 6 + src/qe/lite/qe_lite.cpp | 148 +++++------------- src/qe/lite/qe_lite.h | 3 + src/sat/sat_solver/sat_smt_preprocess.cpp | 38 ++++- src/sat/sat_solver/sat_smt_solver.cpp | 34 ++-- 25 files changed, 553 insertions(+), 158 deletions(-) create mode 100644 src/ast/simplifiers/bit2int.h create mode 100644 src/ast/simplifiers/bv_elim.h create mode 100644 src/ast/simplifiers/distribute_forall.h create mode 100644 src/ast/simplifiers/elim_bounds.h create mode 100644 src/ast/simplifiers/pull_nested_quantifiers.h create mode 100644 src/ast/simplifiers/refine_inj_axiom.h diff --git a/src/ast/rewriter/macro_replacer.cpp b/src/ast/rewriter/macro_replacer.cpp index da0131bf7..d8389ae6a 100644 --- a/src/ast/rewriter/macro_replacer.cpp +++ b/src/ast/rewriter/macro_replacer.cpp @@ -125,9 +125,28 @@ void macro_replacer::insert(app* head, expr* def, expr_dependency* dep) { m_map.insert(f, std::tuple(head, def, dep)); } -void macro_replacer::operator()(expr* t, expr_ref& result, expr_dependency_ref& dep) { - macro_replacer_rw exp(m, *this, dep); +void macro_replacer::operator()(expr* t, expr_dependency* dep_in, expr_ref& result, expr_dependency_ref& dep_out) { + expr_dependency_ref _dep_in(dep_in, m); + macro_replacer_rw exp(m, *this, dep_out); exp(t, result); + if (!dep_in) + return; + // update dependencies if needed + m_dep_exprs.reset(); + m.linearize(dep_in, m_dep_exprs); + unsigned sz = m_trail.size(); + for (expr*& d : m_dep_exprs) { + exp(d, result); + if (result != d) { + d = result.get(); + m_trail.push_back(result); + } + } + if (sz != m_trail.size()) { + dep_in = m.mk_join(m_dep_exprs.size(), m_dep_exprs.data()); + m_trail.shrink(sz); + } + dep_out = m.mk_join(dep_in, dep_out); } bool macro_replacer::has_macro(func_decl* f, app_ref& head, expr_ref& def, expr_dependency_ref& dep) { diff --git a/src/ast/rewriter/macro_replacer.h b/src/ast/rewriter/macro_replacer.h index a0cc5242b..8513a7549 100644 --- a/src/ast/rewriter/macro_replacer.h +++ b/src/ast/rewriter/macro_replacer.h @@ -26,6 +26,7 @@ class macro_replacer { ast_manager& m; ast_ref_vector m_trail; expr_dependency_ref_vector m_deps; + ptr_vector m_dep_exprs; obj_map> m_map; struct macro_replacer_cfg; struct macro_replacer_rw; @@ -35,8 +36,8 @@ public: macro_replacer(ast_manager& m): m(m), m_trail(m), m_deps(m) {} void insert(app* head, expr* def, expr_dependency* dep); - void operator()(expr* t, expr_ref& result, expr_dependency_ref& dep); - void operator()(expr* t, expr_ref & result) { expr_dependency_ref dep(m); (*this)(t, result, dep); } + void operator()(expr* t, expr_dependency* d, expr_ref& result, expr_dependency_ref& dep); + void operator()(expr* t, expr_ref & result) { expr_dependency_ref dep(m); (*this)(t, nullptr, result, dep); } void operator()(expr_ref & t) { expr_ref s(t, m); (*this)(s, t); } bool has_macro(func_decl* f, app_ref& head, expr_ref& def, expr_dependency_ref& d); diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index 9d894627a..c6a8469ee 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -17,4 +17,5 @@ z3_add_component(simplifiers euf rewriter bit_blaster + normal_forms ) diff --git a/src/ast/simplifiers/bit2int.h b/src/ast/simplifiers/bit2int.h new file mode 100644 index 000000000..7d07029d2 --- /dev/null +++ b/src/ast/simplifiers/bit2int.h @@ -0,0 +1,44 @@ + +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bit2int.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/bit2int.h" + + +class bit2int_simplifier : public dependent_expr_simplifier { + bit2int m_rewriter; + +public: + bit2int_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_rewriter(m) { + } + + char const* name() const override { return "bit2int"; } + + void reduce() override { + expr_ref r(m); + proof_ref pr(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + if (!has_quantifiers(d.fml())) + continue; + m_rewriter(d.fml(), r, pr); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } +}; + diff --git a/src/ast/simplifiers/bv_elim.h b/src/ast/simplifiers/bv_elim.h new file mode 100644 index 000000000..6f045fc54 --- /dev/null +++ b/src/ast/simplifiers/bv_elim.h @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + bv_elim.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/bv_elim.h" + + +namespace bv { +class elim_simplifier : public dependent_expr_simplifier { + bv_elim_rw m_rewriter; + +public: + elim_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_rewriter(m) { + } + + char const* name() const override { return "bv-elim"; } + + void reduce() override { + expr_ref r(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + if (!has_quantifiers(d.fml())) + continue; + m_rewriter(d.fml(), r); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } +}; +} diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index 4d16bc2bb..ddf119070 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -18,6 +18,7 @@ Author: #pragma once #include "ast/ast.h" +#include "ast/ast_pp.h" #include "ast/ast_translation.h" class dependent_expr { @@ -88,4 +89,20 @@ public: std::tuple operator()() const { return { m_fml, m_dep }; } + + std::ostream& display(std::ostream& out) const { + return out << mk_pp(m_fml, m); + if (m_dep) { + out << "\n <- "; + ptr_vector deps; + m.linearize(m_dep, deps); + for (expr* arg : deps) + out << mk_pp(arg, m) << " "; + } + return out; + } }; + +inline std::ostream& operator<<(std::ostream& out, dependent_expr const& d) { + return d.display(out); +} \ No newline at end of file diff --git a/src/ast/simplifiers/dependent_expr_state.cpp b/src/ast/simplifiers/dependent_expr_state.cpp index 5219d25da..40528fe99 100644 --- a/src/ast/simplifiers/dependent_expr_state.cpp +++ b/src/ast/simplifiers/dependent_expr_state.cpp @@ -24,7 +24,7 @@ unsigned dependent_expr_state::num_exprs() { } void dependent_expr_state::freeze(func_decl* f) { - if (m_frozen.is_marked(f)) + if (m_frozen.is_marked(f) || !is_uninterp(f)) return; m_frozen_trail.push_back(f); m_frozen.mark(f, true); @@ -107,3 +107,13 @@ void dependent_expr_state::freeze_suffix() { freeze_terms(d.fml(), true, visited); } } + +bool dependent_expr_state::has_quantifiers() { + if (m_has_quantifiers != l_undef) + return m_has_quantifiers == l_true; + bool found = false; + for (unsigned i = qhead(); i < qtail(); ++i) + found |= ::has_quantifiers((*this)[i].fml()); + m_has_quantifiers = found ? l_true : l_false; + return m_has_quantifiers == l_true; +} diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 4c9b21f0a..d8539d604 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -44,6 +44,7 @@ class dependent_expr_state { unsigned m_qhead = 0; bool m_suffix_frozen = false; bool m_recfun_frozen = false; + lbool m_has_quantifiers = l_undef; ast_mark m_frozen; func_decl_ref_vector m_frozen_trail; void freeze_prefix(); @@ -81,7 +82,7 @@ public: } void pop(unsigned n) { m_trail.pop_scope(n); } - void advance_qhead() { freeze_prefix(); m_suffix_frozen = false; m_qhead = qtail(); } + void advance_qhead() { freeze_prefix(); m_suffix_frozen = false; m_has_quantifiers = l_undef; m_qhead = qtail(); } unsigned num_exprs(); /** @@ -90,8 +91,16 @@ public: bool frozen(func_decl* f) const { return m_frozen.is_marked(f); } bool frozen(expr* f) const { return is_app(f) && m_frozen.is_marked(to_app(f)->get_decl()); } void freeze_suffix(); + + virtual std::ostream& display(std::ostream& out) const { return out; } + + bool has_quantifiers(); }; +inline std::ostream& operator<<(std::ostream& out, dependent_expr_state& st) { + return st.display(out); +} + /** Shared interface of simplifiers. */ @@ -105,6 +114,26 @@ protected: unsigned qhead() const { return m_fmls.qhead(); } unsigned qtail() const { return m_fmls.qtail(); } + struct iterator { + dependent_expr_simplifier& s; + unsigned m_index = 0; + bool at_end = false; + unsigned index() const { return at_end ? s.qtail() : m_index; } + iterator(dependent_expr_simplifier& s, unsigned i) : s(s), m_index(i), at_end(i == s.qtail()) {} + bool operator==(iterator const& other) const { return index() == other.index(); } + bool operator!=(iterator const& other) const { return !(*this == other); } + iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent()) at_end = true; else ++m_index; return *this; } + unsigned operator*() const { return m_index; } + }; + + struct index_set { + dependent_expr_simplifier& s; + iterator begin() { return iterator(s, s.qhead()); } + iterator end() { return iterator(s, s.qtail()); } + index_set(dependent_expr_simplifier& s) : s(s) {} + }; + + index_set indices() { return index_set(*this); } public: dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {} diff --git a/src/ast/simplifiers/distribute_forall.h b/src/ast/simplifiers/distribute_forall.h new file mode 100644 index 000000000..82709d29f --- /dev/null +++ b/src/ast/simplifiers/distribute_forall.h @@ -0,0 +1,45 @@ + +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + distribute_forall.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/distribute_forall.h" + + +class distribute_forall_simplifier : public dependent_expr_simplifier { + distribute_forall m_dist; + +public: + distribute_forall_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_dist(m) { + } + + char const* name() const override { return "distribute-forall"; } + + void reduce() override { + if (!m_fmls.has_quantifiers()) + return; + expr_ref r(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + if (!has_quantifiers(d.fml())) + continue; + m_dist(d.fml(), r); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } +}; + diff --git a/src/ast/simplifiers/elim_bounds.h b/src/ast/simplifiers/elim_bounds.h new file mode 100644 index 000000000..d6631adfd --- /dev/null +++ b/src/ast/simplifiers/elim_bounds.h @@ -0,0 +1,45 @@ + +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + elim_bounds.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/elim_bounds.h" + + +class elim_bounds_simplifier : public dependent_expr_simplifier { + elim_bounds_rw m_rewriter; + +public: + elim_bounds_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_rewriter(m) { + } + + char const* name() const override { return "cheap-fourier-motzkin"; } + + void reduce() override { + if (!m_fmls.has_quantifiers()) + return; + expr_ref r(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + if (!has_quantifiers(d.fml())) + continue; + m_rewriter(d.fml(), r); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } +}; + diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index d71d2180a..eb7006da6 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -129,6 +129,38 @@ bool eliminate_predicates::can_be_macro_head(expr* _head, unsigned num_bound) { return true; } +/** + * a quasi macro head is of the form + * f(x,x) where x is the only bound variable + * f(x,y,x+y+3,1) where x, y are the only bound variables + */ + +bool eliminate_predicates::can_be_quasi_macro_head(expr* head, unsigned num_bound) { + if (!is_app(_head)) + return false; + app* head = to_app(_head); + func_decl* f = head->get_decl(); + if (m_fmls.frozen(f)) + return false; + if (m_is_macro.is_marked(f)) + return false; + if (f->is_associative()) + return false; + uint_set indices; + for (expr* arg : *head) { + if (!is_var(arg)) + return continue; + unsigned idx = to_var(arg)->get_idx(); + if (indices.contains(idx)) + return continue; + if (idx >= num_bound) + return false; + indices.insert(idx); + } + return indices.size() == num_bound; +} + + expr_ref eliminate_predicates::bind_free_variables_in_def(clause& cl, app* head, expr* def) { unsigned num_bound = cl.m_bound.size(); if (head->get_num_args() == num_bound) @@ -365,7 +397,6 @@ void eliminate_predicates::try_find_macro(clause& cl) { // (= (+ (f x) s) t) // becomes (= (f x) (- t s)) // - // TBD: // (= (+ (* -1 (f x)) x) t) // becomes (= (f x) (- (- t s))) @@ -473,10 +504,13 @@ void eliminate_predicates::try_find_macro(clause& cl) { // becomes (= (f x) (- t s (k x)) // add (>= (k x) 0) // why is this a real improvement? - // + // + + // // To review: quasi-macros - // (= (f x y (+ x y)) s), where x y are all bound variables. - // then ...? + // (= (f x y (+ x y)) s), where x y are all bound variables. + // then replace (f x y z) by (if (= z (+ x y)) s (f' x y)) + // } @@ -501,21 +535,18 @@ void eliminate_predicates::reduce_definitions() { for (auto const& [k, v] : m_macros) macro_expander.insert(v->m_head, v->m_def, v->m_dep); - for (unsigned i = qhead(); i < qtail(); ++i) { + for (unsigned i : indices()) { auto [f, d] = m_fmls[i](); expr_ref fml(f, m), new_fml(m); - expr_dependency_ref dep(m); + expr_dependency_ref dep(d, m); while (true) { - macro_expander(fml, new_fml, dep); + macro_expander(fml, dep, new_fml, dep); if (new_fml == fml) break; rewrite(new_fml); fml = new_fml; } - if (fml != f) { - dep = m.mk_join(d, dep); - m_fmls.update(i, dependent_expr(m, fml, dep)); - } + m_fmls.update(i, dependent_expr(m, fml, dep)); } reset(); init_clauses(); @@ -772,7 +803,7 @@ void eliminate_predicates::init_clauses() { m_fmls.freeze_suffix(); - for (unsigned i = qhead(); i < qtail(); ++i) { + for (unsigned i : indices()) { clause* cl = init_clause(i); add_use_list(*cl); m_clauses.push_back(cl); @@ -816,6 +847,8 @@ void eliminate_predicates::reset() { void eliminate_predicates::reduce() { + if (!m_fmls.has_quantifiers()) + return; reset(); init_clauses(); find_definitions(); diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index a8d4fff48..d91922f9e 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -109,6 +109,7 @@ private: void insert_macro(app* head, expr* def, expr_dependency* dep); expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def); bool can_be_macro_head(expr* head, unsigned num_bound); + bool can_be_quasi_macro_head(expr* head, unsigned num_bound); bool is_macro_safe(expr* e); void try_find_macro(clause& cl); @@ -145,4 +146,4 @@ public: inline std::ostream& operator<<(std::ostream& out, eliminate_predicates::clause const& c) { return c.display(out); -} \ No newline at end of file +} diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 18af7449f..0436822d1 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -68,8 +68,9 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st auto [f, dep1] = st[i](); expr_ref g(m); expr_dependency_ref dep2(m); - mrp(f, g, dep2); - st.update(i, dependent_expr(m, g, m.mk_join(dep1, dep2))); + mrp(f, dep1, g, dep2); + CTRACE("simplifier", f != g, tout << "updated " << mk_pp(g, m) << "\n"); + st.update(i, dependent_expr(m, g, dep2)); } continue; } @@ -77,10 +78,28 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st rp->set_substitution(t->m_subst.get()); // rigid entries: // apply substitution to added in case of rigid model convertions + ptr_vector dep_exprs; + expr_ref_vector trail(m); for (unsigned i = qhead; i < st.qtail(); ++i) { auto [f, dep1] = st[i](); auto [g, dep2] = rp->replace_with_dep(f); + if (dep1) { + dep_exprs.reset(); + trail.reset(); + m.linearize(dep1, dep_exprs); + for (auto*& d : dep_exprs) { + auto [h, dep3] = rp->replace_with_dep(d); + if (h != d) { + trail.push_back(h); + d = h; + dep2 = m.mk_join(dep2, dep3); + } + } + if (!trail.empty()) + dep1 = m.mk_join(dep_exprs.size(), dep_exprs.data()); + } dependent_expr d(m, g, m.mk_join(dep1, dep2)); + CTRACE("simplifier", f != g, tout << "updated " << mk_pp(g, m) << "\n"); add_vars(d, free_vars); st.update(i, d); } @@ -121,3 +140,19 @@ void model_reconstruction_trail::append(generic_model_converter& mc) { m_trail_stack.push(value_trail(m_trail_index)); append(mc, m_trail_index); } + +std::ostream& model_reconstruction_trail::display(std::ostream& out) const { + for (auto* t : m_trail) { + if (!t->m_active) + continue; + else if (t->is_hide()) + out << "hide " << t->m_decl->get_name() << "\n"; + else if (t->is_def()) + out << t->m_decl->get_name() << " <- " << mk_pp(t->m_def, m) << "\n"; + else { + for (auto const& [v, def] : t->m_subst->sub()) + out << mk_pp(v, m) << " <- " << mk_pp(def, m) << "\n"; + } + } + return out; +} \ No newline at end of file diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 5ad204bf7..4ef58f790 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -138,5 +138,7 @@ public: * Append new updates to model converter, update m_trail_index in the process. */ void append(generic_model_converter& mc); + + std::ostream& display(std::ostream& out) const; }; diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 928e8a787..0a3cfb5ee 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -83,13 +83,13 @@ void propagate_values::reduce() { }; unsigned rw = m_stats.m_num_rewrites + 1; - for (unsigned r = 0; r < m_max_rounds && rw != m_stats.m_num_rewrites; ++r) { + for (unsigned r = 0; r < m_max_rounds && m.inc() && rw != m_stats.m_num_rewrites; ++r) { rw = m_stats.m_num_rewrites; init_sub(); - for (unsigned i = qhead(); i < qtail() && !m_fmls.inconsistent(); ++i) + for (unsigned i = qhead(); i < qtail() && m.inc() && !m_fmls.inconsistent(); ++i) process_fml(i); init_sub(); - for (unsigned i = qtail(); i-- > qhead() && !m_fmls.inconsistent();) + for (unsigned i = qtail(); i-- > qhead() && m.inc() && !m_fmls.inconsistent();) process_fml(i); if (subst.empty()) break; diff --git a/src/ast/simplifiers/pull_nested_quantifiers.h b/src/ast/simplifiers/pull_nested_quantifiers.h new file mode 100644 index 000000000..a113c36c2 --- /dev/null +++ b/src/ast/simplifiers/pull_nested_quantifiers.h @@ -0,0 +1,46 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + pull_nested_quantifiers.h + +Abstract: + + pull nested quantifiers + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/normal_forms/pull_quant.h" + + +class pull_nested_quantifiers_simplifier : public dependent_expr_simplifier { + pull_nested_quant m_pull; + +public: + pull_nested_quantifiers_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_pull(m) { + } + + char const* name() const override { return "pull-nested-quantifiers"; } + + void reduce() override { + if (!m_fmls.has_quantifiers()) + return; + expr_ref new_curr(m); + proof_ref new_pr(m); + for (unsigned idx : indices()) { + auto d = m_fmls[idx]; + m_pull(d.fml(), new_curr, new_pr); + m_fmls.update(idx, dependent_expr(m, new_curr, d.dep())); + } + } +}; diff --git a/src/ast/simplifiers/refine_inj_axiom.h b/src/ast/simplifiers/refine_inj_axiom.h new file mode 100644 index 000000000..2333ba690 --- /dev/null +++ b/src/ast/simplifiers/refine_inj_axiom.h @@ -0,0 +1,44 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + refine_inj_axiom.h + +Abstract: + + refine injectivity axiom + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/inj_axiom.h" + + + +class refine_inj_axiom_simplifier : public dependent_expr_simplifier { + +public: + refine_inj_axiom_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls) { + } + + char const* name() const override { return "refine-injectivity"; } + + void reduce() override { + if (!m_fmls.has_quantifiers()) + return; + expr_ref r(m); + for (unsigned idx : indices()) { + expr* f = m_fmls[idx].fml(); + if (is_quantifier(f) && simplify_inj_axiom(m, to_quantifier(f), r)) + m_fmls.update(idx, dependent_expr(m, r, m_fmls[idx].dep())); + } + } +}; diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h index bb9fd0d22..be54ca005 100644 --- a/src/ast/simplifiers/rewriter_simplifier.h +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -40,16 +40,14 @@ public: m_num_steps = 0; expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = qhead(); idx < qtail(); idx++) { - if (m_fmls.inconsistent()) - break; + for (unsigned idx : indices()) { auto d = m_fmls[idx]; m_rewriter(d.fml(), new_curr, new_pr); m_num_steps += m_rewriter.get_num_steps(); m_fmls.update(idx, dependent_expr(m, new_curr, d.dep())); } } - void collect_statistics(statistics& st) const override { st.update("simplifier", m_num_steps); } + void collect_statistics(statistics& st) const override { st.update("simplifier-steps", m_num_steps); } void reset_statistics() override { m_num_steps = 0; } void updt_params(params_ref const& p) override { m_params.append(p); m_rewriter.updt_params(m_params); } void collect_param_descrs(param_descrs& r) override { th_rewriter::get_param_descrs(r); } diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h index 326b3d09e..0e93f62f9 100644 --- a/src/ast/simplifiers/seq_simplifier.h +++ b/src/ast/simplifiers/seq_simplifier.h @@ -46,7 +46,8 @@ class seq_simplifier : public dependent_expr_simplifier { << " :after-memory " << std::fixed << std::setprecision(2) << end_memory << ")" << "\n"; s.collect_statistics(st); - verbose_stream() << st); + if (st.size() > 0) + st.display_smt2(verbose_stream())); } }; @@ -63,14 +64,17 @@ public: } void reduce() override { + TRACE("simplifier", tout << m_fmls << "\n"); for (auto* s : m_simplifiers) { if (m_fmls.inconsistent()) break; if (!m.inc()) break; + s->reset_statistics(); collect_stats _cs(*s); s->reduce(); m_fmls.flatten_suffix(); + TRACE("simplifier", tout << s->name() << "\n" << m_fmls << "\n"); } } diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index e2fbc0c9a..94b089c80 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -34,7 +34,7 @@ namespace euf { void solve_eqs::get_eqs(dep_eq_vector& eqs) { for (extract_eq* ex : m_extract_plugins) - for (unsigned i = qhead(); i < qtail(); ++i) + for (unsigned i : indices()) ex->get_eqs(m_fmls[i], eqs); } @@ -99,6 +99,9 @@ namespace euf { auto const& [orig, v, t, d] = eq; SASSERT(j == var2id(v)); bool is_safe = true; + if (m_fmls.frozen(v)) + continue; + unsigned todo_sz = todo.size(); // determine if substitution is safe. @@ -187,7 +190,7 @@ namespace euf { scoped_ptr rp = mk_default_expr_replacer(m, false); rp->set_substitution(m_subst.get()); - for (unsigned i = qhead(); i < qtail() && !m_fmls.inconsistent(); ++i) { + for (unsigned i : indices()) { auto [f, d] = m_fmls[i](); auto [new_f, new_dep] = rp->replace_with_dep(f); m_rewriter(new_f); diff --git a/src/ast/simplifiers/solve_eqs.h b/src/ast/simplifiers/solve_eqs.h index 4b2905b2a..c8fbe3a40 100644 --- a/src/ast/simplifiers/solve_eqs.h +++ b/src/ast/simplifiers/solve_eqs.h @@ -32,6 +32,10 @@ namespace euf { struct stats { unsigned m_num_steps = 0; unsigned m_num_elim_vars = 0; + void reset() { + m_num_steps = 0; + m_num_elim_vars = 0; + } }; struct config { @@ -78,5 +82,7 @@ namespace euf { void collect_statistics(statistics& st) const override; + void reset_statistics() override { m_stats.reset(); } + }; } diff --git a/src/qe/lite/qe_lite.cpp b/src/qe/lite/qe_lite.cpp index 6d337c12f..2ea11b6b9 100644 --- a/src/qe/lite/qe_lite.cpp +++ b/src/qe/lite/qe_lite.cpp @@ -35,6 +35,8 @@ Revision History: #include "tactic/tactical.h" #include "qe/mbp/mbp_solve_plugin.h" #include "qe/lite/qe_lite.h" +#include "tactic/dependent_expr_state_tactic.h" + namespace qel { @@ -2407,122 +2409,50 @@ void qe_lite::operator()(uint_set const& index_set, bool index_of_bound, expr_re } namespace { -class qe_lite_tactic : public tactic { - ast_manager& m; - params_ref m_params; - qe_lite m_qe; + class qe_lite_simplifier : public dependent_expr_simplifier { + params_ref m_params; + qe_lite m_qe; + public: + qe_lite_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& st) : + dependent_expr_simplifier(m, st), + m_qe(m, p, true) { + updt_params(p); + } - void checkpoint() { - tactic::checkpoint(m); - } + char const* name() const override { return "qe-lite"; } -#if 0 - void debug_diff(expr* a, expr* b) { - ptr_vector as, bs; - as.push_back(a); - bs.push_back(b); - expr* a1, *a2, *b1, *b2; - while (!as.empty()) { - a = as.back(); - b = bs.back(); - as.pop_back(); - bs.pop_back(); - if (a == b) { - continue; - } - else if (is_forall(a) && is_forall(b)) { - as.push_back(to_quantifier(a)->get_expr()); - bs.push_back(to_quantifier(b)->get_expr()); - } - else if (m.is_and(a, a1, a2) && m.is_and(b, b1, b2)) { - as.push_back(a1); - as.push_back(a2); - bs.push_back(b1); - bs.push_back(b2); - } - else if (m.is_eq(a, a1, a2) && m.is_eq(b, b1, b2)) { - as.push_back(a1); - as.push_back(a2); - bs.push_back(b1); - bs.push_back(b2); - } - else { - TRACE("qe", tout << mk_pp(a, m) << " != " << mk_pp(b, m) << "\n";); + void updt_params(params_ref const& p) override { + m_params.append(p); + } + + void reduce() override { + if (!m_fmls.has_quantifiers()) + return; + proof_ref new_pr(m); + expr_ref new_f(m); + for (unsigned i : indices()) { + expr* f = m_fmls[i].fml(); + if (!has_quantifiers(f)) + continue; + new_f = f; + m_qe(new_f, new_pr); + m_fmls.update(i, dependent_expr(m, new_f, m_fmls[i].dep())); } } - } -#endif + }; -public: - qe_lite_tactic(ast_manager & m, params_ref const & p): - m(m), - m_params(p), - m_qe(m, p, true) {} - - char const* name() const override { return "qe_lite"; } - - tactic * translate(ast_manager & m) override { - return alloc(qe_lite_tactic, m, m_params); - } - - void updt_params(params_ref const & p) override { - m_params.append(p); - // m_imp->updt_params(p); - } - - void collect_param_descrs(param_descrs & r) override { - // m_imp->collect_param_descrs(r); - } - - void operator()(goal_ref const & g, - goal_ref_buffer & result) override { - tactic_report report("qe-lite", *g); - proof_ref new_pr(m); - expr_ref new_f(m); - - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - checkpoint(); - if (g->inconsistent()) - break; - expr * f = g->form(i); - if (!has_quantifiers(f)) - continue; - new_f = f; - m_qe(new_f, new_pr); - if (new_pr) { - expr* fact = m.get_fact(new_pr); - if (to_app(fact)->get_arg(0) != to_app(fact)->get_arg(1)) { - new_pr = m.mk_modus_ponens(g->pr(i), new_pr); - } - else { - new_pr = g->pr(i); - } - } - if (f != new_f) { - TRACE("qe", tout << mk_pp(f, m) << "\n" << new_f << "\n" << new_pr << "\n";); - g->update(i, new_f, new_pr, g->dep(i)); - } + class qe_lite_tactic_factory : public dependent_expr_simplifier_factory { + public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(qe_lite_simplifier, m, p, s); } - g->inc_depth(); - result.push_back(g.get()); - } - - void collect_statistics(statistics & st) const override { - // m_imp->collect_statistics(st); - } - - void reset_statistics() override { - // m_imp->reset_statistics(); - } - - void cleanup() override { - m_qe.~qe_lite(); - new (&m_qe) qe_lite(m, m_params, true); - } -}; + }; } tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p) { - return alloc(qe_lite_tactic, m, p); + return alloc(dependent_expr_state_tactic, m, p, alloc(qe_lite_tactic_factory)); +} + +dependent_expr_simplifier* mk_qe_lite_simplifer(ast_manager& m, params_ref const& p, dependent_expr_state& st) { + return alloc(qe_lite_simplifier, m, p, st); } diff --git a/src/qe/lite/qe_lite.h b/src/qe/lite/qe_lite.h index 47af8552a..9a4d4c0f6 100644 --- a/src/qe/lite/qe_lite.h +++ b/src/qe/lite/qe_lite.h @@ -23,6 +23,7 @@ Revision History: #include "ast/ast.h" #include "util/uint_set.h" #include "util/params.h" +#include "ast/simplifiers/dependent_expr_state.h" class tactic; @@ -70,3 +71,5 @@ tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p = params_ref()) /* ADD_TACTIC("qe-light", "apply light-weight quantifier elimination.", "mk_qe_lite_tactic(m, p)") */ + +dependent_expr_simplifier* mk_qe_lite_simplifer(ast_manager& m, params_ref const& p, dependent_expr_state& st); diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index f05fc098f..dfacf3fba 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -22,9 +22,19 @@ Author: #include "ast/simplifiers/propagate_values.h" #include "ast/simplifiers/rewriter_simplifier.h" #include "ast/simplifiers/solve_eqs.h" +#include "ast/simplifiers/bv_slice.h" #include "ast/simplifiers/eliminate_predicates.h" +#include "ast/simplifiers/elim_unconstrained.h" +#include "ast/simplifiers/pull_nested_quantifiers.h" +#include "ast/simplifiers/distribute_forall.h" +#include "ast/simplifiers/refine_inj_axiom.h" +#include "ast/simplifiers/elim_bounds.h" +#include "ast/simplifiers/bit2int.h" +#include "ast/simplifiers/bv_elim.h" #include "sat/sat_params.hpp" +#include "smt/params/smt_params.h" #include "sat/sat_solver/sat_smt_preprocess.h" +#include "qe/lite/qe_lite.h" void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dependent_expr_state& st) { params_ref simp1_p = p; @@ -44,18 +54,38 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep simp2_p.set_bool("flat_and_or", false); sat_params sp(p); + smt_params smtp(p); if (sp.euf() || sp.smt()) { s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); s.add_simplifier(alloc(propagate_values, m, p, st)); + s.add_simplifier(alloc(euf::solve_eqs, m, st)); + s.add_simplifier(alloc(elim_unconstrained, m, st)); + if (smtp.m_macro_finder || smtp.m_quasi_macros) s.add_simplifier(alloc(eliminate_predicates, m, st)); + if (smtp.m_qe_lite) s.add_simplifier(mk_qe_lite_simplifer(m, p, st)); + if (smtp.m_pull_nested_quantifiers) s.add_simplifier(alloc(pull_nested_quantifiers_simplifier, m, p, st)); + if (smtp.m_max_bv_sharing) s.add_simplifier(mk_max_bv_sharing(m, p, st)); + if (smtp.m_refine_inj_axiom) s.add_simplifier(alloc(refine_inj_axiom_simplifier, m, p, st)); + if (smtp.m_bv_size_reduce) s.add_simplifier(alloc(bv::slice, m, st)); + if (smtp.m_distribute_forall) s.add_simplifier(alloc(distribute_forall_simplifier, m, p, st)); + if (smtp.m_eliminate_bounds) s.add_simplifier(alloc(elim_bounds_simplifier, m, p, st)); + if (smtp.m_simplify_bit2int) s.add_simplifier(alloc(bit2int_simplifier, m, p, st)); + if (smtp.m_bb_quantifiers) s.add_simplifier(alloc(bv::elim_simplifier, m, p, st)); // // add: - // solve_eqs - // elim_predicates - // elim_uncnstr // euf_completion? // - // add: make it externally configurable + // add: make it externally programmable // +#if 0 + ?? if (!invoke(m_lift_ite)) return; + m_lift_ite.m_functor.set_conservative(m_smt_params.m_lift_ite == lift_ite_kind::LI_CONSERVATIVE); + m_ng_lift_ite.m_functor.set_conservative(m_smt_params.m_ng_lift_ite == lift_ite_kind::LI_CONSERVATIVE); + ?? if (!invoke(m_ng_lift_ite)) return; + if (!invoke(m_elim_term_ite)) return; + if (!invoke(m_apply_quasi_macros)) return; + if (!invoke(m_flatten_clauses)) return; +#endif + } else { s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index 69cc7ed17..c544df6fa 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -60,6 +60,17 @@ class sat_smt_solver : public solver { void add(dependent_expr const& j) override { s.m_fmls.push_back(j); } bool inconsistent() override { return s.m_solver.inconsistent(); } model_reconstruction_trail& model_trail() override { return m_reconstruction_trail; } + std::ostream& display(std::ostream& out) const override { + unsigned i = 0; + for (auto const& d : s.m_fmls) { + if (i == qhead()) + out << "---- head ---\n"; + out << d << "\n"; + ++i; + } + m_reconstruction_trail.display(out); + return out; + } void append(generic_model_converter& mc) { model_trail().append(mc); } void replay(unsigned qhead) { m_reconstruction_trail.replay(qhead, *this); } void flatten_suffix() override { @@ -421,12 +432,10 @@ public: } expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) override { - if (!is_internalized()) { - lbool r = internalize_formulas(); - if (r != l_true) { - IF_VERBOSE(0, verbose_stream() << "internalize produced " << r << "\n"); - return expr_ref_vector(m); - } + lbool r = internalize_formulas(); + if (r != l_true) { + IF_VERBOSE(0, verbose_stream() << "internalize produced " << r << "\n"); + return expr_ref_vector(m); } convert_internalized(); if (m_solver.inconsistent()) @@ -551,8 +560,7 @@ public: void convert_internalized() { m_solver.pop_to_base_level(); - if (!is_internalized() && m_preprocess_state.qhead() > 0) - internalize_formulas(); + internalize_formulas(); if (!is_internalized() || m_internalized_converted) return; sat2goal s2g; @@ -723,9 +731,8 @@ private: for (unsigned v = 0; v < var2expr.size(); ++v) { expr * n = var2expr.get(v); - if (!n || !is_uninterp_const(n)) { - continue; - } + if (!n || !is_uninterp_const(n)) + continue; switch (sat::value_at(v, ll_m)) { case l_true: mdl->register_decl(to_app(n)->get_decl(), m.mk_true()); @@ -747,9 +754,8 @@ private: TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); - if (!gparams::get_ref().get_bool("model_validate", false)) { - return; - } + if (!gparams::get_ref().get_bool("model_validate", false)) + return; IF_VERBOSE(1, verbose_stream() << "Verifying solution\n";); model_evaluator eval(*mdl); eval.set_model_completion(true); From 7b9dfb8e1e439ac8194246f23f4a8708c17a4562 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 13:43:40 +0700 Subject: [PATCH 344/477] update dependencies for python build --- scripts/mk_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 497aa350f..2da7b0f21 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -39,7 +39,7 @@ def init_project_def(): add_lib('macros', ['rewriter'], 'ast/macros') add_lib('model', ['macros']) add_lib('converters', ['model'], 'ast/converters') - add_lib('simplifiers', ['euf', 'rewriter', 'bit_blaster', 'converters'], 'ast/simplifiers') + add_lib('simplifiers', ['euf', 'normal_forms', 'bit_blaster', 'converters'], 'ast/simplifiers') add_lib('tactic', ['simplifiers']) add_lib('solver', ['params', 'model', 'tactic', 'proofs']) add_lib('cmd_context', ['solver', 'rewriter', 'params']) From c1ff3d31920d6b5474fc4faa008bddb40c05a381 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 13:46:00 +0700 Subject: [PATCH 345/477] wip - adding quasi macro detection --- src/ast/simplifiers/eliminate_predicates.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index eb7006da6..700f96ce3 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -135,7 +135,7 @@ bool eliminate_predicates::can_be_macro_head(expr* _head, unsigned num_bound) { * f(x,y,x+y+3,1) where x, y are the only bound variables */ -bool eliminate_predicates::can_be_quasi_macro_head(expr* head, unsigned num_bound) { +bool eliminate_predicates::can_be_quasi_macro_head(expr* _head, unsigned num_bound) { if (!is_app(_head)) return false; app* head = to_app(_head); @@ -149,15 +149,15 @@ bool eliminate_predicates::can_be_quasi_macro_head(expr* head, unsigned num_boun uint_set indices; for (expr* arg : *head) { if (!is_var(arg)) - return continue; + continue; unsigned idx = to_var(arg)->get_idx(); if (indices.contains(idx)) - return continue; + continue; if (idx >= num_bound) return false; indices.insert(idx); } - return indices.size() == num_bound; + return indices.num_elems() == num_bound; } From 23c53c6820b2d0c786dc416dab9a50473a7bbde3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 19:36:13 +0900 Subject: [PATCH 346/477] fix build --- src/ast/simplifiers/dependent_expr_state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index d8539d604..a5f31b70c 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -118,7 +118,7 @@ protected: dependent_expr_simplifier& s; unsigned m_index = 0; bool at_end = false; - unsigned index() const { return at_end ? s.qtail() : m_index; } + unsigned index() const { return at_end ? s.qtail() : std::min(m_index, s.qtail()); } iterator(dependent_expr_simplifier& s, unsigned i) : s(s), m_index(i), at_end(i == s.qtail()) {} bool operator==(iterator const& other) const { return index() == other.index(); } bool operator!=(iterator const& other) const { return !(*this == other); } From edb0fc394b8578d35661a5308eec919ae180d20c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 23:15:32 +0900 Subject: [PATCH 347/477] rewrite some simplifiers --- src/ast/simplifiers/bit_blaster.cpp | 8 +- src/ast/simplifiers/bv_slice.cpp | 4 +- src/ast/simplifiers/card2bv.cpp | 2 +- src/ast/simplifiers/dependent_expr_state.h | 2 +- src/ast/simplifiers/elim_term_ite.h | 49 +++++ src/ast/simplifiers/elim_unconstrained.cpp | 7 +- src/ast/simplifiers/max_bv_sharing.cpp | 244 ++------------------- src/ast/simplifiers/propagate_values.cpp | 2 +- 8 files changed, 81 insertions(+), 237 deletions(-) create mode 100644 src/ast/simplifiers/elim_term_ite.h diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp index 72ee19eca..a1988a930 100644 --- a/src/ast/simplifiers/bit_blaster.cpp +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -37,13 +37,11 @@ void bit_blaster::reduce() { expr_ref new_curr(m); proof_ref new_pr(m); bool change = false; - for (unsigned idx = qhead(); idx < qtail(); idx++) { - if (m_fmls.inconsistent()) - break; + for (unsigned idx : indices()) { auto [curr, d] = m_fmls[idx](); - m_rewriter(curr, new_curr, new_pr); - m_num_steps += m_rewriter.get_num_steps(); + m_rewriter(curr, new_curr, new_pr); if (curr != new_curr) { + m_num_steps += m_rewriter.get_num_steps(); change = true; TRACE("bit_blaster", tout << mk_pp(curr, m) << " -> " << new_curr << "\n";); m_fmls.update(idx, dependent_expr(m, new_curr, d)); diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp index cc8b4fd85..7ffa56a29 100644 --- a/src/ast/simplifiers/bv_slice.cpp +++ b/src/ast/simplifiers/bv_slice.cpp @@ -27,7 +27,7 @@ namespace bv { } void slice::process_eqs() { - for (unsigned i = qhead(); i < qtail(); ++i) { + for (unsigned i : indices()) { auto const [f, d] = m_fmls[i](); process_eq(f); } @@ -136,7 +136,7 @@ namespace bv { expr_ref_vector cache(m), pin(m); ptr_vector todo, args; expr* c; - for (unsigned i = qhead(); i < qtail(); ++i) { + for (unsigned i : indices()) { auto const [f, d] = m_fmls[i](); todo.push_back(f); pin.push_back(f); diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index d20b4a6c5..58774e1c6 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -29,7 +29,7 @@ void card2bv::reduce() { expr_ref new_f1(m), new_f2(m); proof_ref new_pr(m); - for (unsigned idx = qhead(); !m_fmls.inconsistent() && idx < qtail(); idx++) { + for (unsigned idx : indices()) { auto [f, d] = m_fmls[idx](); rw1(f, new_f1); rw2(false, new_f1, new_f2, new_pr); diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index a5f31b70c..9f27a336c 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -7,7 +7,7 @@ Module Name: Abstract: - abstraction for simplification of depenent expression states. + abstraction for simplification of dependent expression states. A dependent_expr_state is an interface to a set of dependent expressions. Dependent expressions are formulas together with a set of dependencies that are coarse grained proof hints or justifications for them. Input assumptions can be self-justified. diff --git a/src/ast/simplifiers/elim_term_ite.h b/src/ast/simplifiers/elim_term_ite.h new file mode 100644 index 000000000..e34b0b457 --- /dev/null +++ b/src/ast/simplifiers/elim_term_ite.h @@ -0,0 +1,49 @@ + +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + elim_term_ite.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/elim_term_ite.h" + + +class elim_term_ite_simplifier : public dependent_expr_simplifier { + elim_term_ite m_elim; + +public: + elim_term_ite_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_elim_term_ite(m) { + } + + char const* name() const override { return "distribute-forall"; } + + void reduce() override { + if (!m_fmls.has_quantifiers()) + return; + expr_ref r(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + if (!has_quantifiers(d.fml())) + continue; + m_rewriter(d.fml(), r); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } + + void push() override { dependent_expr_simplifier::push(); m_rewriter.push(); } + + void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_rewriter.pop(n); } +}; + diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 41305b745..9d40a5f21 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -125,7 +125,7 @@ void elim_unconstrained::init_nodes() { m_fmls.freeze_suffix(); expr_ref_vector terms(m); - for (unsigned i = qhead(); i < qtail(); ++i) + for (unsigned i : indices()) terms.push_back(m_fmls[i].fml()); m_trail.append(terms); m_heap.reset(); @@ -201,7 +201,7 @@ void elim_unconstrained::gc(expr* t) { */ void elim_unconstrained::reconstruct_terms() { expr_ref_vector terms(m); - for (unsigned i = qhead(); i < qtail(); ++i) + for (unsigned i : indices()) terms.push_back(m_fmls[i].fml()); for (expr* e : subterms_postorder::all(terms)) { @@ -234,8 +234,7 @@ void elim_unconstrained::reconstruct_terms() { void elim_unconstrained::assert_normalized(vector& old_fmls) { - unsigned sz = qtail(); - for (unsigned i = qhead(); i < sz; ++i) { + for (unsigned i : indices()) { auto [f, d] = m_fmls[i](); node& n = get_node(f); expr* g = n.m_term; diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index 3ac27302a..c12fa4410 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -20,234 +20,26 @@ Revision History: --*/ -#include "ast/bv_decl_plugin.h" -#include "ast/rewriter/rewriter_def.h" -#include "util/obj_pair_hashtable.h" +#include "ast/rewriter/maximize_ac_sharing.h" #include "ast/simplifiers/dependent_expr_state.h" -#include "ast/ast_lt.h" class max_bv_sharing : public dependent_expr_simplifier { - - struct rw_cfg : public default_rewriter_cfg { - typedef std::pair expr_pair; - typedef obj_pair_hashtable set; - bv_util m_util; - set m_add_apps; - set m_mul_apps; - set m_xor_apps; - set m_or_apps; - unsigned long long m_max_memory; - unsigned m_max_steps; - unsigned m_max_args; + + maximize_bv_sharing_rw m_rewriter; + unsigned m_num_steps = 0; - ast_manager & m() const { return m_util.get_manager(); } - - rw_cfg(ast_manager & m, params_ref const & p): - m_util(m) { - updt_params(p); - } - - void cleanup() { - m_add_apps.finalize(); - m_mul_apps.finalize(); - m_or_apps.finalize(); - m_xor_apps.finalize(); - } - - void updt_params(params_ref const & p) { - m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_max_steps = p.get_uint("max_steps", UINT_MAX); - m_max_args = p.get_uint("max_args", 128); - } - - bool max_steps_exceeded(unsigned num_steps) const { - if (memory::get_allocation_size() > m_max_memory) - throw rewriter_exception(Z3_MAX_MEMORY_MSG); - return num_steps > m_max_steps; - } - - set & f2set(func_decl * f) { - switch (f->get_decl_kind()) { - case OP_BADD: return m_add_apps; - case OP_BMUL: return m_mul_apps; - case OP_BXOR: return m_xor_apps; - case OP_BOR: return m_or_apps; - default: - UNREACHABLE(); - return m_or_apps; // avoid compilation error - } - } - - expr * reuse(set & s, func_decl * f, expr * arg1, expr * arg2) { - if (s.contains(expr_pair(arg1, arg2))) - return m().mk_app(f, arg1, arg2); - if (s.contains(expr_pair(arg2, arg1))) - return m().mk_app(f, arg2, arg1); - return nullptr; - } - - struct ref_count_lt { - bool operator()(expr * t1, expr * t2) const { - if (t1->get_ref_count() < t2->get_ref_count()) - return true; - return (t1->get_ref_count() == t2->get_ref_count()) && lt(t1, t2); - } - }; - - br_status reduce_ac_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set & s = f2set(f); - - if (num_args == 2) { - if (!m_util.is_numeral(args[0]) && !m_util.is_numeral(args[1])) - s.insert(expr_pair(args[0], args[1])); - return BR_FAILED; - } - - ptr_buffer _args; - bool first = false; - expr * num = nullptr; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (num == nullptr && m_util.is_numeral(arg)) { - if (i == 0) first = true; - num = arg; - } - else { - _args.push_back(arg); - } - } - num_args = _args.size(); - - - // std::sort(_args.begin(), _args.end(), ref_count_lt()); - // std::sort(_args.begin(), _args.end(), ast_to_lt()); - - try_to_reuse: - if (num_args > 1 && num_args < m_max_args) { - for (unsigned i = 0; i < num_args - 1; i++) { - for (unsigned j = i + 1; j < num_args; j++) { - expr * r = reuse(s, f, _args[i], _args[j]); - if (r != nullptr) { - TRACE("bv_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); - _args[i] = r; - SASSERT(num_args > 1); - for (unsigned w = j; w < num_args - 1; w++) { - _args[w] = _args[w+1]; - } - num_args--; - goto try_to_reuse; - } - } - } - } - - // TODO: - // some benchmarks are more efficiently solved using a tree-like structure (better sharing) - // other benchmarks are more efficiently solved using a chain-like structure (better propagation for arguments "closer to the output"). - // - // One possible solution is to do a global analysis that finds a good order that increases sharing without affecting - // propagation. - // - // Another cheap trick is to create an option, and try both for a small amount of time. -#if 0 - SASSERT(num_args > 0); - if (num_args == 1) { - result = _args[0]; - } - else { - // ref_count_lt is not a total order on expr's - std::stable_sort(_args.c_ptr(), _args.c_ptr() + num_args, ref_count_lt()); - result = m().mk_app(f, _args[0], _args[1]); - for (unsigned i = 2; i < num_args; i++) { - result = m().mk_app(f, result.get(), _args[i]); - } - } - if (num != 0) { - if (first) - result = m().mk_app(f, num, result); - else - result = m().mk_app(f, result, num); - } - return BR_DONE; -#else - // Create "tree-like circuit" - while (true) { - TRACE("bv_sharing_detail", tout << "tree-loop: num_args: " << num_args << "\n";); - unsigned j = 0; - for (unsigned i = 0; i < num_args; i += 2, j++) { - if (i == num_args - 1) { - _args[j] = _args[i]; - } - else { - s.insert(expr_pair(_args[i], _args[i+1])); - _args[j] = m().mk_app(f, _args[i], _args[i+1]); - } - } - num_args = j; - if (num_args == 1) { - if (num == nullptr) { - result = _args[0]; - } - else { - if (first) - result = m().mk_app(f, num, _args[0]); - else - result = m().mk_app(f, _args[0], num); - } - return BR_DONE; - } - } -#endif - } - - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - if (f->get_family_id() != m_util.get_family_id()) - return BR_FAILED; - switch (f->get_decl_kind()) { - case OP_BADD: - case OP_BMUL: - case OP_BOR: - case OP_BXOR: - result_pr = nullptr; - return reduce_ac_app(f, num, args, result); - default: - return BR_FAILED; - } - } - }; - - struct rw : public rewriter_tpl { - rw_cfg m_cfg; - - rw(ast_manager & m, params_ref const & p): - rewriter_tpl(m, m.proofs_enabled(), m_cfg), - m_cfg(m, p) { - } - }; - - rw m_rw; - unsigned m_num_steps = 0; - - - params_ref m_params; - public: max_bv_sharing(ast_manager & m, params_ref const & p, dependent_expr_state& fmls): dependent_expr_simplifier(m, fmls), - m_params(p), - m_rw(m, p) { + m_rewriter(m) { } - void updt_params(params_ref const & p) override { - m_params.append(p); - m_rw.cfg().updt_params(m_params); + void reset_statistics() override { + m_num_steps = 0; } - void collect_param_descrs(param_descrs & r) override { - insert_max_memory(r); - insert_max_steps(r); - r.insert("max_args", CPK_UINT, - "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); + void collect_statistics(statistics& st) const override { + st.update("max-sharing-steps", m_num_steps); } char const* name() const override { return "max-bv-sharing"; } @@ -255,15 +47,21 @@ public: void reduce() override { expr_ref new_curr(m); proof_ref new_pr(m); - for (unsigned idx = qhead(); idx < qtail() && !m_fmls.inconsistent(); idx++) { + for (unsigned idx : indices()) { auto [curr, d] = m_fmls[idx](); - m_rw(curr, new_curr, new_pr); + m_rewriter(curr, new_curr, new_pr); // Proof reconstruction: new_pr = m.mk_modus_ponens(old_pr, new_pr); - m_num_steps += m_rw.get_num_steps(); - m_fmls.update(idx, dependent_expr(m, new_curr, d)); + if (new_curr != curr) { + m_num_steps += m_rewriter.get_num_steps(); + m_fmls.update(idx, dependent_expr(m, new_curr, d)); + } } - m_rw.cfg().cleanup(); - } + } + + void push() override { dependent_expr_simplifier::push(); m_rewriter.push_scope(); } + + void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_rewriter.pop_scope(n); } + }; dependent_expr_simplifier * mk_max_bv_sharing(ast_manager & m, params_ref const & p, dependent_expr_state& fmls) { diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 0a3cfb5ee..f0d85af72 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -86,7 +86,7 @@ void propagate_values::reduce() { for (unsigned r = 0; r < m_max_rounds && m.inc() && rw != m_stats.m_num_rewrites; ++r) { rw = m_stats.m_num_rewrites; init_sub(); - for (unsigned i = qhead(); i < qtail() && m.inc() && !m_fmls.inconsistent(); ++i) + for (unsigned i : indices()) process_fml(i); init_sub(); for (unsigned i = qtail(); i-- > qhead() && m.inc() && !m_fmls.inconsistent();) From cfc8e19baf676102214ed97c71bb721ddc930a34 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Dec 2022 02:35:43 +0900 Subject: [PATCH 348/477] add more simplifiers, fix model reconstruction order for elim_unconstrained - enable sat.smt in smt_tactic that is invoked by default on first goals add flatten-clauses add push-ite have tptp5 front-end pretty print SMT2 formulas a little nicer. --- examples/tptp/tptp5.cpp | 21 +++- src/ast/simplifiers/elim_term_ite.h | 16 ++-- src/ast/simplifiers/elim_unconstrained.cpp | 20 ++-- src/ast/simplifiers/flatten_clauses.h | 95 +++++++++++++++++++ .../model_reconstruction_trail.cpp | 6 +- src/ast/simplifiers/push_ite.h | 66 +++++++++++++ src/ast/simplifiers/seq_simplifier.h | 4 +- src/math/simplex/model_based_opt.cpp | 45 +++++++-- src/sat/sat_solver/sat_smt_preprocess.cpp | 44 +++++---- src/tactic/smtlogics/smt_tactic.cpp | 8 +- 10 files changed, 271 insertions(+), 54 deletions(-) create mode 100644 src/ast/simplifiers/flatten_clauses.h create mode 100644 src/ast/simplifiers/push_ite.h diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 4f1d25aa9..04b225caf 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -2305,12 +2305,25 @@ static void display_smt2(std::ostream& out) { return; } + z3::expr_vector asms(ctx); size_t num_assumptions = fmls.m_formulas.size(); + for (size_t i = 0; i < num_assumptions; ++i) + asms.push_back(fmls.m_formulas[i]); - Z3_ast* assumptions = new Z3_ast[num_assumptions]; - for (size_t i = 0; i < num_assumptions; ++i) { - assumptions[i] = fmls.m_formulas[i]; + for (size_t i = 0; i < asms.size(); ++i) { + z3::expr fml = asms[i]; + if (fml.is_and()) { + asms.set(i, fml.arg(0)); + for (unsigned j = 1; j < fml.num_args(); ++j) + asms.push_back(fml.arg(j)); + --i; + } } + + Z3_ast* assumptions = new Z3_ast[asms.size()]; + for (size_t i = 0; i < asms.size(); ++i) + assumptions[i] = asms[i]; + Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB_FULL); Z3_string s = Z3_benchmark_to_smtlib_string( ctx, @@ -2318,7 +2331,7 @@ static void display_smt2(std::ostream& out) { 0, // no logic is set "unknown", // no status annotation "", // attributes - static_cast(num_assumptions), + static_cast(asms.size()), assumptions, ctx.bool_val(true)); diff --git a/src/ast/simplifiers/elim_term_ite.h b/src/ast/simplifiers/elim_term_ite.h index e34b0b457..6455db321 100644 --- a/src/ast/simplifiers/elim_term_ite.h +++ b/src/ast/simplifiers/elim_term_ite.h @@ -15,19 +15,21 @@ Author: #pragma once #include "ast/simplifiers/dependent_expr_state.h" -#include "ast/rewriter/elim_term_ite.h" +#include "ast/normal_forms/elim_term_ite.h"" class elim_term_ite_simplifier : public dependent_expr_simplifier { - elim_term_ite m_elim; - + defined_names m_df; + elim_term_ite_rw m_rewriter; + public: elim_term_ite_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): dependent_expr_simplifier(m, fmls), - m_elim_term_ite(m) { + m_df(m), + m_rewriter(m, m_df) { } - char const* name() const override { return "distribute-forall"; } + char const* name() const override { return "elim-term-ite"; } void reduce() override { if (!m_fmls.has_quantifiers()) @@ -42,8 +44,8 @@ public: } } - void push() override { dependent_expr_simplifier::push(); m_rewriter.push(); } + void push() override { dependent_expr_simplifier::push(); m_df.push(); m_rewriter.push(); } - void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_rewriter.pop(n); } + void pop(unsigned n) override { m_rewriter.pop(n); m_df.pop(n); dependent_expr_simplifier::pop(n); } }; diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 9d40a5f21..d9fe5d480 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -249,6 +249,16 @@ void elim_unconstrained::assert_normalized(vector& old_fmls) { void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector const& old_fmls) { auto& trail = m_fmls.model_trail(); + + for (auto const& entry : mc.entries()) { + switch (entry.m_instruction) { + case generic_model_converter::instruction::HIDE: + trail.hide(entry.m_f); + break; + case generic_model_converter::instruction::ADD: + break; + } + } scoped_ptr rp = mk_default_expr_replacer(m, false); scoped_ptr sub = alloc(expr_substitution, m, true, false); rp->set_substitution(sub.get()); @@ -265,16 +275,6 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< } } trail.push(sub.detach(), old_fmls); - - for (auto const& entry : mc.entries()) { - switch (entry.m_instruction) { - case generic_model_converter::instruction::HIDE: - trail.hide(entry.m_f); - break; - case generic_model_converter::instruction::ADD: - break; - } - } } void elim_unconstrained::reduce() { diff --git a/src/ast/simplifiers/flatten_clauses.h b/src/ast/simplifiers/flatten_clauses.h new file mode 100644 index 000000000..02444f093 --- /dev/null +++ b/src/ast/simplifiers/flatten_clauses.h @@ -0,0 +1,95 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + flatten_clauses.h + +Abstract: + + flatten clauses + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/ast_util.h" + + +class flatten_clauses : public dependent_expr_simplifier { + + unsigned m_num_flat = 0; + + bool is_literal(expr* a) { + m.is_not(a, a); + return !is_app(a) || to_app(a)->get_num_args() == 0; + } + + bool is_reducible(expr* a, expr* b) { + return b->get_ref_count() == 1 || is_literal(a); + } + +public: + flatten_clauses(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls) { + } + + char const* name() const override { return "flatten-clauses"; } + + void reset_statistics() override { m_num_flat = 0; } + + void collect_statistics(statistics& st) const override { + st.update("flatten-clauses-rewrites", m_num_flat); + } + + void reduce() override { + bool change = true; + + while (change) { + change = false; + for (unsigned idx : indices()) { + auto de = m_fmls[idx]; + expr* f = de.fml(), *a, *b, *c; + bool decomposed = false; + if (m.is_or(f, a, b) && m.is_not(b, b) && m.is_or(b) && is_reducible(a, b)) + decomposed = true; + else if (m.is_or(f, b, a) && m.is_not(b, b) && m.is_or(b) && is_reducible(a, b)) + decomposed = true; + if (decomposed) { + for (expr* arg : *to_app(b)) + m_fmls.add(dependent_expr(m, m.mk_or(a, mk_not(m, arg)), de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + change = true; + ++m_num_flat; + continue; + } + if (m.is_or(f, a, b) && m.is_and(b) && is_reducible(a, b)) + decomposed = true; + else if (m.is_or(f, b, a) && m.is_and(b) && is_reducible(a, b)) + decomposed = true; + if (decomposed) { + for (expr * arg : *to_app(b)) + m_fmls.add(dependent_expr(m, m.mk_or(a, arg), de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + change = true; + ++m_num_flat; + continue; + } + if (m.is_ite(f, a, b, c)) { + m_fmls.add(dependent_expr(m, m.mk_or(mk_not(m, a), b), de.dep())); + m_fmls.add(dependent_expr(m, m.mk_or(a, c), de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + change = true; + ++m_num_flat; + continue; + } + } + } + } +}; diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 0436822d1..7e8d3e2f1 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -151,8 +151,10 @@ std::ostream& model_reconstruction_trail::display(std::ostream& out) const { out << t->m_decl->get_name() << " <- " << mk_pp(t->m_def, m) << "\n"; else { for (auto const& [v, def] : t->m_subst->sub()) - out << mk_pp(v, m) << " <- " << mk_pp(def, m) << "\n"; + out << mk_pp(v, m) << " <- " << mk_pp(def, m) << "\n"; } + for (auto const& d : t->m_removed) + out << "rm: " << d << "\n"; } return out; -} \ No newline at end of file +} diff --git a/src/ast/simplifiers/push_ite.h b/src/ast/simplifiers/push_ite.h new file mode 100644 index 000000000..e2acdbdb0 --- /dev/null +++ b/src/ast/simplifiers/push_ite.h @@ -0,0 +1,66 @@ + +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + push_ite.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/rewriter/push_app_ite.h" + + +class push_ite_simplifier : public dependent_expr_simplifier { + push_app_ite_rw m_push; + +public: + push_ite_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls, bool c): + dependent_expr_simplifier(m, fmls), + m_push(m) { + m_push.set_conservative(c); + } + + char const* name() const override { return "push-app-ite"; } + + void reduce() override { + expr_ref r(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + m_push(d.fml(), r); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } + +}; + + +class ng_push_ite_simplifier : public dependent_expr_simplifier { + ng_push_app_ite_rw m_push; + +public: + ng_push_ite_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls, bool c): + dependent_expr_simplifier(m, fmls), + m_push(m) { + m_push.set_conservative(c); + } + + char const* name() const override { return "ng-push-app-ite"; } + + void reduce() override { + expr_ref r(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + m_push(d.fml(), r); + m_fmls.update(idx, dependent_expr(m, r, d.dep())); + } + } +}; + diff --git a/src/ast/simplifiers/seq_simplifier.h b/src/ast/simplifiers/seq_simplifier.h index 0e93f62f9..a5ef91d7c 100644 --- a/src/ast/simplifiers/seq_simplifier.h +++ b/src/ast/simplifiers/seq_simplifier.h @@ -64,7 +64,7 @@ public: } void reduce() override { - TRACE("simplifier", tout << m_fmls << "\n"); + TRACE("simplifier", tout << m_fmls); for (auto* s : m_simplifiers) { if (m_fmls.inconsistent()) break; @@ -74,7 +74,7 @@ public: collect_stats _cs(*s); s->reduce(); m_fmls.flatten_suffix(); - TRACE("simplifier", tout << s->name() << "\n" << m_fmls << "\n"); + TRACE("simplifier", tout << s->name() << "\n" << m_fmls); } } diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 9e7ac75ce..919e07b16 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1014,12 +1014,14 @@ namespace opt { return dst; } + // -x + lo <= 0 void model_based_opt::add_lower_bound(unsigned x, rational const& lo) { vector coeffs; coeffs.push_back(var(x, rational::minus_one())); add_constraint(coeffs, lo, t_le); } + // x - hi <= 0 void model_based_opt::add_upper_bound(unsigned x, rational const& hi) { vector coeffs; coeffs.push_back(var(x, rational::one())); @@ -1442,8 +1444,9 @@ namespace opt { for (unsigned ri : mod_rows) { rational a = get_coefficient(ri, x); replace_var(ri, x, rational::zero()); + rational rMod = m_rows[ri].m_mod; - // add w = b mod K + // add w = b mod rMod vector coeffs = m_rows[ri].m_vars; rational coeff = m_rows[ri].m_coeff; unsigned v = m_rows[ri].m_id; @@ -1451,16 +1454,43 @@ namespace opt { unsigned w = UINT_MAX; rational offset(0); - if (coeffs.empty() || K == 1) - offset = mod(coeff, K); + if (coeffs.empty() || rMod == 1) + offset = mod(coeff, rMod); else - w = add_mod(coeffs, coeff, K); + w = add_mod(coeffs, coeff, rMod); rational w_value = w == UINT_MAX ? offset : m_var2value[w]; - // add v = a*z + w - V, for k = (a*z_value + w_value) div K - // claim: (= (mod x K) (- x (* K (div x K)))))) is a theorem for every x, K != 0 +#if 1 + // V := (a * z_value - w_value) div rMod + // V*rMod <= a*z + w < (V+1)*rMod + // v = a*z + w - V*rMod + SASSERT(a * z_value - w_value >= 0); + rational V = div(a * z_value + w_value, rMod); + vector mod_coeffs; + SASSERT(V >= 0); + SASSERT(a * z_value + w_value >= V*rMod); + SASSERT((V+1)*rMod > a*z_value + w_value); + // -a*z - w + V*rMod <= 0 + mod_coeffs.push_back(var(z, -a)); + if (w != UINT_MAX) mod_coeffs.push_back(var(w, -rational::one())); + add_constraint(mod_coeffs, V*rMod - offset, t_le); + mod_coeffs.reset(); + // a*z + w - (V+1)*rMod + 1 <= 0 + mod_coeffs.push_back(var(z, a)); + if (w != UINT_MAX) mod_coeffs.push_back(var(w, rational::one())); + add_constraint(mod_coeffs, -(V+1)*rMod + offset + 1, t_le); + mod_coeffs.reset(); + // -v + a*z + w - V*rMod = 0 + mod_coeffs.push_back(var(v, rational::minus_one())); + mod_coeffs.push_back(var(z, a)); + if (w != UINT_MAX) mod_coeffs.push_back(var(w, rational::one())); + add_constraint(mod_coeffs, offset - V*rMod, t_eq); + +#else + // add v = a*z + w - V, for V = v_value - a * z_value - w_value + // claim: (= (mod x rMod) (- x (* rMod (div x rMod)))))) is a theorem for every x, rMod != 0 rational V = v_value - a * z_value - w_value; vector mod_coeffs; mod_coeffs.push_back(var(v, rational::minus_one())); @@ -1468,7 +1498,8 @@ namespace opt { if (w != UINT_MAX) mod_coeffs.push_back(var(w, rational::one())); add_constraint(mod_coeffs, V + offset, t_eq); add_lower_bound(v, rational::zero()); - add_upper_bound(v, K - 1); + add_upper_bound(v, rMod - 1); +#endif retire_row(ri); vs.push_back(v); diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index dfacf3fba..e3d6b3edb 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -31,27 +31,15 @@ Author: #include "ast/simplifiers/elim_bounds.h" #include "ast/simplifiers/bit2int.h" #include "ast/simplifiers/bv_elim.h" +#include "ast/simplifiers/push_ite.h" +#include "ast/simplifiers/elim_term_ite.h" +#include "ast/simplifiers/flatten_clauses.h" #include "sat/sat_params.hpp" #include "smt/params/smt_params.h" #include "sat/sat_solver/sat_smt_preprocess.h" #include "qe/lite/qe_lite.h" void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dependent_expr_state& st) { - params_ref simp1_p = p; - simp1_p.set_bool("som", true); - simp1_p.set_bool("pull_cheap_ite", true); - simp1_p.set_bool("push_ite_bv", false); - simp1_p.set_bool("local_ctx", true); - simp1_p.set_uint("local_ctx_limit", 10000000); - simp1_p.set_bool("flat", true); // required by som - simp1_p.set_bool("hoist_mul", false); // required by som - simp1_p.set_bool("elim_and", true); - simp1_p.set_bool("blast_distinct", true); - simp1_p.set_bool("flat_and_or", false); - - params_ref simp2_p = p; - simp2_p.set_bool("flat", false); - simp2_p.set_bool("flat_and_or", false); sat_params sp(p); smt_params smtp(p); @@ -70,6 +58,10 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep if (smtp.m_eliminate_bounds) s.add_simplifier(alloc(elim_bounds_simplifier, m, p, st)); if (smtp.m_simplify_bit2int) s.add_simplifier(alloc(bit2int_simplifier, m, p, st)); if (smtp.m_bb_quantifiers) s.add_simplifier(alloc(bv::elim_simplifier, m, p, st)); + if (smtp.m_eliminate_term_ite && smtp.m_lift_ite != lift_ite_kind::LI_FULL) s.add_simplifier(alloc(elim_term_ite_simplifier, m, p, st)); + if (smtp.m_lift_ite != lift_ite_kind::LI_NONE) s.add_simplifier(alloc(push_ite_simplifier, m, p, st, smtp.m_lift_ite == lift_ite_kind::LI_CONSERVATIVE)); + if (smtp.m_ng_lift_ite != lift_ite_kind::LI_NONE) s.add_simplifier(alloc(ng_push_ite_simplifier, m, p, st, smtp.m_ng_lift_ite == lift_ite_kind::LI_CONSERVATIVE)); + s.add_simplifier(alloc(flatten_clauses, m, p, st)); // // add: // euf_completion? @@ -77,17 +69,27 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep // add: make it externally programmable // #if 0 - ?? if (!invoke(m_lift_ite)) return; - m_lift_ite.m_functor.set_conservative(m_smt_params.m_lift_ite == lift_ite_kind::LI_CONSERVATIVE); - m_ng_lift_ite.m_functor.set_conservative(m_smt_params.m_ng_lift_ite == lift_ite_kind::LI_CONSERVATIVE); - ?? if (!invoke(m_ng_lift_ite)) return; - if (!invoke(m_elim_term_ite)) return; if (!invoke(m_apply_quasi_macros)) return; - if (!invoke(m_flatten_clauses)) return; #endif } else { + params_ref simp1_p = p; + simp1_p.set_bool("som", true); + simp1_p.set_bool("pull_cheap_ite", true); + simp1_p.set_bool("push_ite_bv", false); + simp1_p.set_bool("local_ctx", true); + simp1_p.set_uint("local_ctx_limit", 10000000); + simp1_p.set_bool("flat", true); // required by som + simp1_p.set_bool("hoist_mul", false); // required by som + simp1_p.set_bool("elim_and", true); + simp1_p.set_bool("blast_distinct", true); + simp1_p.set_bool("flat_and_or", false); + + params_ref simp2_p = p; + simp2_p.set_bool("flat", false); + simp2_p.set_bool("flat_and_or", false); + s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); s.add_simplifier(alloc(propagate_values, m, p, st)); s.add_simplifier(alloc(card2bv, m, p, st)); diff --git a/src/tactic/smtlogics/smt_tactic.cpp b/src/tactic/smtlogics/smt_tactic.cpp index 0b78761ca..d47650c34 100644 --- a/src/tactic/smtlogics/smt_tactic.cpp +++ b/src/tactic/smtlogics/smt_tactic.cpp @@ -18,10 +18,16 @@ Author: #include "smt/tactic/smt_tactic_core.h" #include "sat/tactic/sat_tactic.h" #include "sat/sat_params.hpp" +#include "solver/solver2tactic.h" +#include "solver/solver.h" tactic * mk_smt_tactic(ast_manager & m, params_ref const & p) { sat_params sp(p); - return sp.euf() ? mk_sat_tactic(m, p) : mk_smt_tactic_core(m, p); + if (sp.smt()) + return mk_solver2tactic(mk_smt2_solver(m, p)); + if (sp.euf()) + return mk_sat_tactic(m, p); + return mk_smt_tactic_core(m, p); } tactic * mk_smt_tactic_using(ast_manager& m, bool auto_config, params_ref const& p) { From f24ecde35c29b46706f736f5f29982d4016fb74a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Dec 2022 09:31:52 +0900 Subject: [PATCH 349/477] wip - fixes to simplifiers --- src/ast/simplifiers/elim_term_ite.h | 6 +--- src/ast/simplifiers/elim_unconstrained.cpp | 4 +++ src/ast/simplifiers/flatten_clauses.h | 36 +++++++++++++++++----- src/ast/simplifiers/push_ite.h | 1 - src/sat/sat_solver/sat_smt_solver.cpp | 2 +- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/ast/simplifiers/elim_term_ite.h b/src/ast/simplifiers/elim_term_ite.h index 6455db321..5b6ef38fa 100644 --- a/src/ast/simplifiers/elim_term_ite.h +++ b/src/ast/simplifiers/elim_term_ite.h @@ -15,7 +15,7 @@ Author: #pragma once #include "ast/simplifiers/dependent_expr_state.h" -#include "ast/normal_forms/elim_term_ite.h"" +#include "ast/normal_forms/elim_term_ite.h" class elim_term_ite_simplifier : public dependent_expr_simplifier { @@ -32,13 +32,9 @@ public: char const* name() const override { return "elim-term-ite"; } void reduce() override { - if (!m_fmls.has_quantifiers()) - return; expr_ref r(m); for (unsigned idx : indices()) { auto const& d = m_fmls[idx]; - if (!has_quantifiers(d.fml())) - continue; m_rewriter(d.fml(), r); m_fmls.update(idx, dependent_expr(m, r, d.dep())); } diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index d9fe5d480..713d7941c 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -130,6 +130,7 @@ void elim_unconstrained::init_nodes() { m_trail.append(terms); m_heap.reset(); m_root.reset(); + m_nodes.reset(); // initialize nodes for terms in the original goal init_terms(terms); @@ -159,6 +160,7 @@ void elim_unconstrained::init_terms(expr_ref_vector const& terms) { n.m_orig = e; n.m_term = e; n.m_refcount = 0; + if (is_uninterp_const(e)) m_heap.insert(root(e)); if (is_quantifier(e)) { @@ -250,6 +252,8 @@ void elim_unconstrained::assert_normalized(vector& old_fmls) { void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector const& old_fmls) { auto& trail = m_fmls.model_trail(); + // fresh declarations are added first since + // model reconstruction proceeds in reverse order of stack. for (auto const& entry : mc.entries()) { switch (entry.m_instruction) { case generic_model_converter::instruction::HIDE: diff --git a/src/ast/simplifiers/flatten_clauses.h b/src/ast/simplifiers/flatten_clauses.h index 02444f093..aa81024ef 100644 --- a/src/ast/simplifiers/flatten_clauses.h +++ b/src/ast/simplifiers/flatten_clauses.h @@ -28,7 +28,11 @@ class flatten_clauses : public dependent_expr_simplifier { bool is_literal(expr* a) { m.is_not(a, a); - return !is_app(a) || to_app(a)->get_num_args() == 0; + if (m.is_eq(a) && !m.is_iff(a)) + return true; + if (!is_app(a)) + return true; + return to_app(a)->get_family_id() != m.get_basic_family_id(); } bool is_reducible(expr* a, expr* b) { @@ -49,14 +53,14 @@ public: } void reduce() override { - bool change = true; - - while (change) { - change = false; + unsigned nf = m_num_flat + 1; + while (nf != m_num_flat) { + nf = m_num_flat; for (unsigned idx : indices()) { auto de = m_fmls[idx]; expr* f = de.fml(), *a, *b, *c; bool decomposed = false; + // (or a (not (or b_i)) => and_i (or a (not b_i)) if (m.is_or(f, a, b) && m.is_not(b, b) && m.is_or(b) && is_reducible(a, b)) decomposed = true; else if (m.is_or(f, b, a) && m.is_not(b, b) && m.is_or(b) && is_reducible(a, b)) @@ -65,10 +69,10 @@ public: for (expr* arg : *to_app(b)) m_fmls.add(dependent_expr(m, m.mk_or(a, mk_not(m, arg)), de.dep())); m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); - change = true; ++m_num_flat; continue; } + // (or a (and b_i)) => and_i (or a b_i) if (m.is_or(f, a, b) && m.is_and(b) && is_reducible(a, b)) decomposed = true; else if (m.is_or(f, b, a) && m.is_and(b) && is_reducible(a, b)) @@ -77,7 +81,24 @@ public: for (expr * arg : *to_app(b)) m_fmls.add(dependent_expr(m, m.mk_or(a, arg), de.dep())); m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); - change = true; + ++m_num_flat; + continue; + } + // not (and a (or b_i)) => and_i (not a) or (not b_i) + if (m.is_not(f, c) && m.is_and(c, a, b) && m.is_or(b) && is_reducible(a, b)) + decomposed = true; + else if (m.is_not(f, c) && m.is_and(c, b, a) && m.is_or(b) && is_reducible(a, b)) + decomposed = true; + if (decomposed) { + expr* na = mk_not(m, a); + for (expr* arg : *to_app(b)) + m_fmls.add(dependent_expr(m, m.mk_or(na, arg), de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + ++m_num_flat; + continue; + } + if (m.is_implies(f, a, b)) { + m_fmls.update(idx, dependent_expr(m, m.mk_or(mk_not(m, a), b), de.dep())); ++m_num_flat; continue; } @@ -85,7 +106,6 @@ public: m_fmls.add(dependent_expr(m, m.mk_or(mk_not(m, a), b), de.dep())); m_fmls.add(dependent_expr(m, m.mk_or(a, c), de.dep())); m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); - change = true; ++m_num_flat; continue; } diff --git a/src/ast/simplifiers/push_ite.h b/src/ast/simplifiers/push_ite.h index e2acdbdb0..e26070a7e 100644 --- a/src/ast/simplifiers/push_ite.h +++ b/src/ast/simplifiers/push_ite.h @@ -38,7 +38,6 @@ public: m_fmls.update(idx, dependent_expr(m, r, d.dep())); } } - }; diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index c544df6fa..3fd3a0080 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -63,7 +63,7 @@ class sat_smt_solver : public solver { std::ostream& display(std::ostream& out) const override { unsigned i = 0; for (auto const& d : s.m_fmls) { - if (i == qhead()) + if (i > 0 && i == qhead()) out << "---- head ---\n"; out << d << "\n"; ++i; From 30c9cda61e49c13e602daf2ecc40c73496ca4f14 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Dec 2022 10:04:33 +0900 Subject: [PATCH 350/477] increment generation for literals created during E-matching --- src/sat/smt/q_ematch.cpp | 5 +++-- src/sat/smt/q_ematch.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 9335c576b..573003305 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -383,7 +383,7 @@ namespace q { sat::literal_vector lits; lits.push_back(~j.m_clause.m_literal); for (unsigned i = 0; i < j.m_clause.size(); ++i) - lits.push_back(instantiate(j.m_clause, j.m_binding, j.m_clause[i])); + lits.push_back(instantiate(j.m_clause, j.m_generation, j.m_binding, j.m_clause[i])); m_qs.log_instantiation(lits, &j); euf::th_proof_hint* ph = nullptr; if (ctx.use_drat()) @@ -418,11 +418,12 @@ namespace q { m_qs.log_instantiation(~c.m_literal, lit); } - sat::literal ematch::instantiate(clause& c, euf::enode* const* binding, lit const& l) { + sat::literal ematch::instantiate(clause& c, unsigned generation, euf::enode* const* binding, lit const& l) { expr_ref_vector _binding(m); for (unsigned i = 0; i < c.num_decls(); ++i) _binding.push_back(binding[i]->get_expr()); var_subst subst(m); + euf::solver::scoped_generation sg(ctx, generation + 1); auto sub = [&](expr* e) { expr_ref r = subst(e, _binding); //ctx.rewrite(r); diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index c04107b3b..cbeb34679 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -103,7 +103,7 @@ namespace q { void ensure_ground_enodes(clause const& c); void instantiate(binding& b); - sat::literal instantiate(clause& c, euf::enode* const* binding, lit const& l); + sat::literal instantiate(clause& c, unsigned generation, euf::enode* const* binding, lit const& l); // register as callback into egraph. void on_merge(euf::enode* root, euf::enode* other); From 147fb0d9c16beb0a8c8dc31dc32d70c3216ccab2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 21:41:44 -0800 Subject: [PATCH 351/477] fix tptp5 build --- examples/tptp/tptp5.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 04b225caf..1355cffa8 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -2313,7 +2313,8 @@ static void display_smt2(std::ostream& out) { for (size_t i = 0; i < asms.size(); ++i) { z3::expr fml = asms[i]; if (fml.is_and()) { - asms.set(i, fml.arg(0)); + z3::expr arg0 = fml.arg(0); + asms.set(i, arg0); for (unsigned j = 1; j < fml.num_args(); ++j) asms.push_back(fml.arg(j)); --i; From 529f116be084470af275715d7691143ee04c038e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 22:29:59 -0800 Subject: [PATCH 352/477] disable new code until pre-condition gets fixed Signed-off-by: Nikolaj Bjorner --- src/ast/static_features.cpp | 6 + src/ast/static_features.h | 4 +- src/math/simplex/model_based_opt.cpp | 9 +- src/smt/params/smt_params.cpp | 228 +++++++++++++++++++++++++++ src/smt/params/smt_params.h | 44 ++++++ src/smt/smt_setup.cpp | 198 +++-------------------- 6 files changed, 311 insertions(+), 178 deletions(-) diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index ad289cf5e..c5dedb16b 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -665,3 +665,9 @@ void static_features::display(std::ostream & out) const { void static_features::get_feature_vector(vector & result) { } + +bool static_features::is_dense() const { + return + (m_num_uninterpreted_constants < 1000) && + (m_num_arith_eqs + m_num_arith_ineqs) > m_num_uninterpreted_constants * 9; +} diff --git a/src/ast/static_features.h b/src/ast/static_features.h index 92e0331fb..59c6154ef 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -188,7 +188,9 @@ struct static_features { void get_feature_vector(vector & result); bool has_uf() const; unsigned num_theories() const; - unsigned num_non_uf_theories() const; + unsigned num_non_uf_theories() const; + + bool is_dense() const; }; diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 919e07b16..8df04327d 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1462,11 +1462,14 @@ namespace opt { rational w_value = w == UINT_MAX ? offset : m_var2value[w]; -#if 1 - // V := (a * z_value - w_value) div rMod +#if 0 + // V := (a * z_value + w_value) div rMod // V*rMod <= a*z + w < (V+1)*rMod // v = a*z + w - V*rMod - SASSERT(a * z_value - w_value >= 0); + SASSERT(a > 0); + SASSERT(z_value >= 0); + SASSERT(w_value >= 0); + SASSERT(a * z_value + w_value >= 0); rational V = div(a * z_value + w_value, rMod); vector mod_coeffs; SASSERT(V >= 0); diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 8143bc31b..2636d29f3 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -188,3 +188,231 @@ void smt_params::validate_string_solver(symbol const& s) const { return; throw default_exception("Invalid string solver value. Legal values are z3str3, seq, empty, auto, none"); } + +void smt_params::setup_QF_UF() { + m_relevancy_lvl = 0; + m_nnf_cnf = false; + m_restart_strategy = RS_LUBY; + m_phase_selection = PS_CACHING_CONSERVATIVE2; + m_random_initial_activity = IA_RANDOM; +} + +void smt_params::setup_QF_RDL() { + m_relevancy_lvl = 0; + m_arith_eq2ineq = true; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_RDL(static_features & st) { + +} + +void smt_params::setup_QF_IDL() { + m_relevancy_lvl = 0; + m_arith_eq2ineq = true; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_arith_small_lemma_size = 30; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_IDL(static_features & st) { + +} + +void smt_params::setup_QF_LRA() { + m_relevancy_lvl = 0; + m_arith_eq2ineq = true; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_eliminate_term_ite = true; + m_nnf_cnf = false; + m_phase_selection = PS_THEORY; +} + +void smt_params::setup_QF_LRA(static_features const& st) { + m_relevancy_lvl = 0; + m_arith_eq2ineq = true; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_eliminate_term_ite = true; + m_nnf_cnf = false; + if (numerator(st.m_arith_k_sum) > rational(2000000) && denominator(st.m_arith_k_sum) > rational(500)) { + m_relevancy_lvl = 2; + m_relevancy_lemma = false; + } + m_phase_selection = PS_THEORY; + if (!st.m_cnf) { + m_restart_strategy = RS_GEOMETRIC; + m_arith_stronger_lemmas = false; + m_restart_adaptive = false; + } + m_arith_small_lemma_size = 32; +} + +void smt_params::setup_QF_LIA() { + m_relevancy_lvl = 0; + m_arith_eq2ineq = true; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_LIA(static_features const& st) { + m_relevancy_lvl = 0; + m_arith_eq2ineq = true; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_nnf_cnf = false; + if (st.m_max_ite_tree_depth > 50) { + m_arith_eq2ineq = false; + m_pull_cheap_ite = true; + m_arith_propagate_eqs = true; + m_relevancy_lvl = 2; + m_relevancy_lemma = false; + } + else if (st.m_num_clauses == st.m_num_units) { + m_arith_gcd_test = false; + m_arith_branch_cut_ratio = 4; + m_relevancy_lvl = 2; + m_arith_eq2ineq = true; + m_eliminate_term_ite = true; + } + else { + m_eliminate_term_ite = true; + m_restart_adaptive = false; + m_restart_strategy = RS_GEOMETRIC; + m_restart_factor = 1.5; + } + if (st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses && st.m_cnf && st.m_arith_k_sum > rational(100000)) { + m_arith_bound_prop = bound_prop_mode::BP_NONE; + m_arith_stronger_lemmas = false; + } +} + +void smt_params::setup_QF_UFLIA() { + m_relevancy_lvl = 0; + m_arith_reflect = false; + m_nnf_cnf = false; + m_arith_propagation_threshold = 1000; +} + + +void smt_params::setup_QF_UFLRA() { + m_relevancy_lvl = 0; + m_arith_reflect = false; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_BV() { + m_relevancy_lvl = 0; + m_arith_reflect = false; + m_bv_cc = false; + m_bb_ext_gates = true; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_AUFBV() { + m_array_mode = AR_SIMPLE; + m_relevancy_lvl = 0; + m_bv_cc = false; + m_bb_ext_gates = true; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_AX() { + m_array_mode = AR_SIMPLE; + m_nnf_cnf = false; +} + +void smt_params::setup_QF_AX(static_features const& st) { + m_array_mode = st.m_has_ext_arrays ? AR_FULL : AR_SIMPLE; + m_nnf_cnf = false; + if (st.m_num_clauses == st.m_num_units) { + m_relevancy_lvl = 0; + m_phase_selection = PS_ALWAYS_FALSE; + } + else + m_relevancy_lvl = 2; +} + +void smt_params::setup_QF_AUFLIA() { + m_array_mode = AR_SIMPLE; + m_nnf_cnf = false; + m_relevancy_lvl = 2; + m_restart_strategy = RS_GEOMETRIC; + m_restart_factor = 1.5; + m_phase_selection = PS_CACHING_CONSERVATIVE2; +} + +void smt_params::setup_QF_AUFLIA(static_features const& st) { + m_array_mode = st.m_has_ext_arrays ? AR_FULL : AR_SIMPLE; + if (st.m_has_real) + throw default_exception("Benchmark has real variables but it is marked as QF_AUFLIA (arrays, uninterpreted functions and linear integer arithmetic)."); + m_nnf_cnf = false; + if (st.m_num_clauses == st.m_num_units) { + TRACE("QF_AUFLIA", tout << "using relevancy: 0\n";); + m_relevancy_lvl = 0; + m_phase_selection = PS_ALWAYS_FALSE; + } + else { + m_relevancy_lvl = 0; // it was 2, for some reason 2 doesn't work anymore TODO: investigate + m_restart_strategy = RS_GEOMETRIC; + m_restart_factor = 1.5; + m_phase_selection = PS_CACHING_CONSERVATIVE2; + m_random_initial_activity = IA_ZERO; + } +} + +void smt_params::setup_AUFLIA(bool simple_array) { + m_array_mode = simple_array ? AR_SIMPLE : AR_FULL; + m_pi_use_database = true; + m_phase_selection = PS_ALWAYS_FALSE; + m_restart_strategy = RS_GEOMETRIC; + m_restart_factor = 1.5; + m_eliminate_bounds = true; + m_qi_quick_checker = MC_UNSAT; + m_qi_lazy_threshold = 20; + m_mbqi = true; // enabling MBQI and MACRO_FINDER by default :-) + + // MACRO_FINDER is a horrible for AUFLIA and UFNIA benchmarks (boogie benchmarks in general) + // It destroys the existing patterns. + // m_macro_finder = true; + + if (m_ng_lift_ite == lift_ite_kind::LI_NONE) + m_ng_lift_ite = lift_ite_kind::LI_CONSERVATIVE; +} + +void smt_params::setup_AUFLIA(static_features const & st) { + m_qi_eager_threshold = st.m_num_quantifiers_with_patterns == 0 ? 5 : 7; +} + +void smt_params::setup_AUFLIRA(bool simple_array) { + m_array_mode = simple_array ? AR_SIMPLE : AR_FULL; + m_phase_selection = PS_ALWAYS_FALSE; + m_eliminate_bounds = true; + m_qi_quick_checker = MC_UNSAT; + m_qi_eager_threshold = 5; + // Added for MBQI release + m_qi_lazy_threshold = 20; + // + m_macro_finder = true; + if (m_ng_lift_ite == lift_ite_kind::LI_NONE) + m_ng_lift_ite = lift_ite_kind::LI_CONSERVATIVE; + m_pi_max_multi_patterns = 10; //<< it was used for SMT-COMP + m_array_lazy_ieq = true; + m_array_lazy_ieq_delay = 4; + // + m_mbqi = true; // enabling MBQI by default :-) + // +} + +void smt_params::setup_LRA() { + m_relevancy_lvl = 0; + m_arith_reflect = false; + m_arith_propagate_eqs = false; + m_eliminate_term_ite = true; +} + diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 73f556eb8..96e8c9ceb 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -18,6 +18,7 @@ Revision History: --*/ #pragma once +#include "ast/static_features.h" #include "smt/params/dyn_ack_params.h" #include "smt/params/qi_params.h" #include "smt/params/theory_arith_params.h" @@ -254,6 +255,49 @@ struct smt_params : public preprocessor_params, void display(std::ostream & out) const; void validate_string_solver(symbol const& s) const; + + void setup_QF_UF(); + + void setup_QF_RDL(); + + void setup_QF_RDL(static_features & st); + + void setup_QF_IDL(); + + void setup_QF_IDL(static_features & st); + + void setup_QF_LRA(); + + void setup_QF_LRA(static_features const& st); + + void setup_QF_LIA(); + + void setup_QF_LIA(static_features const& st); + + void setup_QF_UFLIA(); + + void setup_QF_UFLRA(); + + void setup_QF_BV(); + + void setup_QF_AUFBV(); + + void setup_QF_AX(); + + void setup_QF_AX(static_features const& st); + + void setup_QF_AUFLIA(); + + void setup_QF_AUFLIA(static_features const& st); + + void setup_AUFLIA(bool simple_array); + + void setup_AUFLIA(static_features const & st); + + void setup_AUFLIRA(bool simple_array); + + void setup_LRA(); + }; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 2d131c6ab..ef5f5493c 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -212,11 +212,7 @@ namespace smt { } void setup::setup_QF_UF() { - m_params.m_relevancy_lvl = 0; - m_params.m_nnf_cnf = false; - m_params.m_restart_strategy = RS_LUBY; - m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; - m_params.m_random_initial_activity = IA_RANDOM; + m_params.setup_QF_UF(); } void setup::setup_QF_DT() { @@ -240,20 +236,10 @@ namespace smt { } void setup::setup_QF_RDL() { - m_params.m_relevancy_lvl = 0; - m_params.m_arith_eq2ineq = true; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_nnf_cnf = false; + m_params.setup_QF_RDL(); setup_mi_arith(); } - static bool is_dense(static_features const & st) { - return - st.m_num_uninterpreted_constants < 1000 && - (st.m_num_arith_eqs + st.m_num_arith_ineqs) > st.m_num_uninterpreted_constants * 9; - } - static bool is_in_diff_logic(static_features const & st) { return st.m_num_arith_eqs == st.m_num_diff_eqs && @@ -285,7 +271,7 @@ namespace smt { m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; - if (is_dense(st)) { + if (st.is_dense()) { m_params.m_restart_strategy = RS_GEOMETRIC; m_params.m_restart_adaptive = false; m_params.m_phase_selection = PS_CACHING; @@ -327,12 +313,7 @@ namespace smt { void setup::setup_QF_IDL() { TRACE("setup", tout << "setup_QF_IDL()\n";); - m_params.m_relevancy_lvl = 0; - m_params.m_arith_eq2ineq = true; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_arith_small_lemma_size = 30; - m_params.m_nnf_cnf = false; + m_params.setup_QF_IDL(); setup_lra_arith(); } @@ -353,11 +334,11 @@ namespace smt { m_params.m_nnf_cnf = false; if (st.m_num_uninterpreted_constants > 5000) m_params.m_relevancy_lvl = 2; - else if (st.m_cnf && !is_dense(st)) + else if (st.m_cnf && !st.is_dense()) m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; else m_params.m_phase_selection = PS_CACHING; - if (is_dense(st) && st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses) { + if (st.is_dense() && st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses) { m_params.m_restart_adaptive = false; m_params.m_restart_strategy = RS_GEOMETRIC; } @@ -373,7 +354,7 @@ namespace smt { if (m_manager.proofs_enabled()) { m_context.register_plugin(alloc(smt::theory_mi_arith, m_context)); } - else if (!m_params.m_arith_auto_config_simplex && is_dense(st)) { + else if (!m_params.m_arith_auto_config_simplex && st.is_dense()) { TRACE("setup", tout << "using dense diff logic...\n";); m_params.m_phase_selection = PS_CACHING_CONSERVATIVE; if (st.arith_k_sum_is_small()) @@ -418,7 +399,7 @@ namespace smt { if (st.m_num_uninterpreted_functions == 0) { m_params.m_arith_eq2ineq = true; m_params.m_arith_propagate_eqs = false; - if (is_dense(st)) { + if (st.is_dense()) { m_params.m_arith_small_lemma_size = 128; m_params.m_lemma_gc_half = true; m_params.m_restart_strategy = RS_GEOMETRIC; @@ -449,35 +430,13 @@ namespace smt { void setup::setup_QF_LRA() { TRACE("setup", tout << "setup_QF_LRA()\n";); - m_params.m_relevancy_lvl = 0; - m_params.m_arith_eq2ineq = true; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_eliminate_term_ite = true; - m_params.m_nnf_cnf = false; - m_params.m_phase_selection = PS_THEORY; + m_params.setup_QF_LRA(); setup_lra_arith(); } void setup::setup_QF_LRA(static_features const & st) { check_no_uninterpreted_functions(st, "QF_LRA"); - m_params.m_relevancy_lvl = 0; - m_params.m_arith_eq2ineq = true; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_eliminate_term_ite = true; - m_params.m_nnf_cnf = false; - if (numerator(st.m_arith_k_sum) > rational(2000000) && denominator(st.m_arith_k_sum) > rational(500)) { - m_params.m_relevancy_lvl = 2; - m_params.m_relevancy_lemma = false; - } - m_params.m_phase_selection = PS_THEORY; - if (!st.m_cnf) { - m_params.m_restart_strategy = RS_GEOMETRIC; - m_params.m_arith_stronger_lemmas = false; - m_params.m_restart_adaptive = false; - } - m_params.m_arith_small_lemma_size = 32; + m_params.setup_QF_LRA(st); setup_lra_arith(); } @@ -487,56 +446,20 @@ namespace smt { void setup::setup_QF_LIA() { TRACE("setup", tout << "setup_QF_LIA(st)\n";); - m_params.m_relevancy_lvl = 0; - m_params.m_arith_eq2ineq = true; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_nnf_cnf = false; + m_params.setup_QF_LIA(); setup_lra_arith(); } void setup::setup_QF_LIA(static_features const & st) { check_no_uninterpreted_functions(st, "QF_LIA"); TRACE("setup", tout << "QF_LIA setup\n";); - - m_params.m_relevancy_lvl = 0; - m_params.m_arith_eq2ineq = true; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_nnf_cnf = false; - if (st.m_max_ite_tree_depth > 50) { - m_params.m_arith_eq2ineq = false; - m_params.m_pull_cheap_ite = true; - m_params.m_arith_propagate_eqs = true; - m_params.m_relevancy_lvl = 2; - m_params.m_relevancy_lemma = false; - } - else if (st.m_num_clauses == st.m_num_units) { - m_params.m_arith_gcd_test = false; - m_params.m_arith_branch_cut_ratio = 4; - m_params.m_relevancy_lvl = 2; - m_params.m_arith_eq2ineq = true; - m_params.m_eliminate_term_ite = true; - } - else { - m_params.m_eliminate_term_ite = true; - m_params.m_restart_adaptive = false; - m_params.m_restart_strategy = RS_GEOMETRIC; - m_params.m_restart_factor = 1.5; - } - if (st.m_num_bin_clauses + st.m_num_units == st.m_num_clauses && st.m_cnf && st.m_arith_k_sum > rational(100000)) { - m_params.m_arith_bound_prop = bound_prop_mode::BP_NONE; - m_params.m_arith_stronger_lemmas = false; - } + m_params.setup_QF_LIA(st); setup_lra_arith(); } void setup::setup_QF_UFLIA() { - m_params.m_relevancy_lvl = 0; - m_params.m_arith_reflect = false; - m_params.m_nnf_cnf = false; - m_params.m_arith_propagation_threshold = 1000; setup_lra_arith(); + m_params.setup_QF_UFLIA(); } void setup::setup_QF_UFLIA(static_features & st) { @@ -548,103 +471,49 @@ namespace smt { } void setup::setup_QF_UFLRA() { - m_params.m_relevancy_lvl = 0; - m_params.m_arith_reflect = false; - m_params.m_nnf_cnf = false; + m_params.setup_QF_UFLRA(); setup_lra_arith(); } void setup::setup_QF_BV() { TRACE("setup", tout << "qf-bv\n";); - m_params.m_relevancy_lvl = 0; - m_params.m_arith_reflect = false; - m_params.m_bv_cc = false; - m_params.m_bb_ext_gates = true; - m_params.m_nnf_cnf = false; + m_params.setup_QF_BV(); m_context.register_plugin(alloc(smt::theory_bv, m_context)); } void setup::setup_QF_AUFBV() { - m_params.m_array_mode = AR_SIMPLE; - m_params.m_relevancy_lvl = 0; - m_params.m_bv_cc = false; - m_params.m_bb_ext_gates = true; - m_params.m_nnf_cnf = false; + m_params.setup_QF_AUFBV(); m_context.register_plugin(alloc(smt::theory_bv, m_context)); setup_arrays(); } void setup::setup_QF_AX() { TRACE("setup", tout << "QF_AX\n";); - m_params.m_array_mode = AR_SIMPLE; - m_params.m_nnf_cnf = false; + m_params.setup_QF_AX(); setup_arrays(); } void setup::setup_QF_AX(static_features const & st) { - m_params.m_array_mode = st.m_has_ext_arrays ? AR_FULL : AR_SIMPLE; - m_params.m_nnf_cnf = false; - if (st.m_num_clauses == st.m_num_units) { - m_params.m_relevancy_lvl = 0; - m_params.m_phase_selection = PS_ALWAYS_FALSE; - } - else { - m_params.m_relevancy_lvl = 2; - } + m_params.setup_QF_AX(st); setup_arrays(); } void setup::setup_QF_AUFLIA() { TRACE("QF_AUFLIA", tout << "no static features\n";); - m_params.m_array_mode = AR_SIMPLE; - m_params.m_nnf_cnf = false; - m_params.m_relevancy_lvl = 2; - m_params.m_restart_strategy = RS_GEOMETRIC; - m_params.m_restart_factor = 1.5; - m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; + m_params.setup_QF_AUFLIA(); setup_i_arith(); setup_arrays(); } void setup::setup_QF_AUFLIA(static_features const & st) { - m_params.m_array_mode = st.m_has_ext_arrays ? AR_FULL : AR_SIMPLE; - if (st.m_has_real) - throw default_exception("Benchmark has real variables but it is marked as QF_AUFLIA (arrays, uninterpreted functions and linear integer arithmetic)."); - m_params.m_nnf_cnf = false; - if (st.m_num_clauses == st.m_num_units) { - TRACE("QF_AUFLIA", tout << "using relevancy: 0\n";); - m_params.m_relevancy_lvl = 0; - m_params.m_phase_selection = PS_ALWAYS_FALSE; - } - else { - m_params.m_relevancy_lvl = 0; // it was 2, for some reason 2 doesn't work anymore TODO: investigate - m_params.m_restart_strategy = RS_GEOMETRIC; - m_params.m_restart_factor = 1.5; - m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; - m_params.m_random_initial_activity = IA_ZERO; - } + m_params.setup_QF_AUFLIA(st); setup_i_arith(); setup_arrays(); } void setup::setup_AUFLIA(bool simple_array) { TRACE("setup", tout << "AUFLIA\n";); - m_params.m_array_mode = simple_array ? AR_SIMPLE : AR_FULL; - m_params.m_pi_use_database = true; - m_params.m_phase_selection = PS_ALWAYS_FALSE; - m_params.m_restart_strategy = RS_GEOMETRIC; - m_params.m_restart_factor = 1.5; - m_params.m_eliminate_bounds = true; - m_params.m_qi_quick_checker = MC_UNSAT; - m_params.m_qi_lazy_threshold = 20; - m_params.m_mbqi = true; // enabling MBQI and MACRO_FINDER by default :-) - - // MACRO_FINDER is a horrible for AUFLIA and UFNIA benchmarks (boogie benchmarks in general) - // It destroys the existing patterns. - // m_params.m_macro_finder = true; - - if (m_params.m_ng_lift_ite == lift_ite_kind::LI_NONE) - m_params.m_ng_lift_ite = lift_ite_kind::LI_CONSERVATIVE; + m_params.setup_AUFLIA(simple_array); TRACE("setup", tout << "max_eager_multipatterns: " << m_params.m_qi_max_eager_multipatterns << "\n";); m_context.register_plugin(alloc(smt::theory_i_arith, m_context)); setup_arrays(); @@ -653,29 +522,13 @@ namespace smt { void setup::setup_AUFLIA(static_features const & st) { if (st.m_has_real) throw default_exception("Benchmark has real variables but it is marked as AUFLIA (arrays, uninterpreted functions and linear integer arithmetic)."); - m_params.m_qi_eager_threshold = st.m_num_quantifiers_with_patterns == 0 ? 5 : 7; + m_params.setup_AUFLIA(st); setup_AUFLIA(); } void setup::setup_AUFLIRA(bool simple_array) { TRACE("setup", tout << "AUFLIRA\n";); - m_params.m_array_mode = simple_array ? AR_SIMPLE : AR_FULL; - m_params.m_phase_selection = PS_ALWAYS_FALSE; - m_params.m_eliminate_bounds = true; - m_params.m_qi_quick_checker = MC_UNSAT; - m_params.m_qi_eager_threshold = 5; - // Added for MBQI release - m_params.m_qi_lazy_threshold = 20; - // - m_params.m_macro_finder = true; - if (m_params.m_ng_lift_ite == lift_ite_kind::LI_NONE) - m_params.m_ng_lift_ite = lift_ite_kind::LI_CONSERVATIVE; - m_params.m_pi_max_multi_patterns = 10; //<< it was used for SMT-COMP - m_params.m_array_lazy_ieq = true; - m_params.m_array_lazy_ieq_delay = 4; - // - m_params.m_mbqi = true; // enabling MBQI by default :-) - // + m_params.setup_AUFLIRA(simple_array); setup_mi_arith(); setup_arrays(); } @@ -697,10 +550,7 @@ namespace smt { } void setup::setup_LRA() { - m_params.m_relevancy_lvl = 0; - m_params.m_arith_reflect = false; - m_params.m_arith_propagate_eqs = false; - m_params.m_eliminate_term_ite = true; + m_params.setup_LRA(); setup_mi_arith(); } From 847aec1d300b44dd6c28ec39179a71b96bfcfe5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 22:48:10 -0800 Subject: [PATCH 353/477] update dependencies --- scripts/mk_project.py | 2 +- src/smt/params/CMakeLists.txt | 1 + src/smt/params/smt_params.cpp | 12 ++++++++++++ src/smt/params/smt_params.h | 2 ++ src/smt/smt_setup.cpp | 12 +----------- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2da7b0f21..a979359f3 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -21,10 +21,10 @@ def init_project_def(): add_lib('hilbert', ['util'], 'math/hilbert') add_lib('automata', ['util'], 'math/automata') add_lib('params', ['util']) - add_lib('smt_params', ['params'], 'smt/params') add_lib('realclosure', ['interval'], 'math/realclosure') add_lib('subpaving', ['interval'], 'math/subpaving') add_lib('ast', ['util', 'polynomial']) + add_lib('smt_params', ['ast', 'params'], 'smt/params') add_lib('parser_util', ['ast'], 'parsers/util') add_lib('euf', ['ast'], 'ast/euf') add_lib('grobner', ['ast', 'dd', 'simplex'], 'math/grobner') diff --git a/src/smt/params/CMakeLists.txt b/src/smt/params/CMakeLists.txt index 0be62f820..d7ebb2be2 100644 --- a/src/smt/params/CMakeLists.txt +++ b/src/smt/params/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(smt_params theory_str_params.cpp COMPONENT_DEPENDENCIES params + ast PYG_FILES smt_params_helper.pyg ) diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 2636d29f3..37249fdac 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -292,6 +292,18 @@ void smt_params::setup_QF_LIA(static_features const& st) { } } +void smt_params::setup_QF_UFIDL() { + m_relevancy_lvl = 0; + m_arith_reflect = false; + m_nnf_cnf = false; + m_arith_eq_bounds = true; + m_arith_eq2ineq = true; + // m_params.m_phase_selection = PS_THEORY; + m_restart_strategy = RS_GEOMETRIC; + m_restart_factor = 1.5; + m_restart_adaptive = false; +} + void smt_params::setup_QF_UFLIA() { m_relevancy_lvl = 0; m_arith_reflect = false; diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 96e8c9ceb..07b6b6095 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -274,6 +274,8 @@ struct smt_params : public preprocessor_params, void setup_QF_LIA(static_features const& st); + void setup_QF_UFIDL(); + void setup_QF_UFLIA(); void setup_QF_UFLRA(); diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index ef5f5493c..aed515ef0 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -377,15 +377,7 @@ namespace smt { void setup::setup_QF_UFIDL() { TRACE("setup", tout << "setup_QF_UFIDL()\n";); - m_params.m_relevancy_lvl = 0; - m_params.m_arith_reflect = false; - m_params.m_nnf_cnf = false; - m_params.m_arith_eq_bounds = true; - m_params.m_arith_eq2ineq = true; - // m_params.m_phase_selection = PS_THEORY; - m_params.m_restart_strategy = RS_GEOMETRIC; - m_params.m_restart_factor = 1.5; - m_params.m_restart_adaptive = false; + m_params.setup_QF_UFIDL(); setup_lra_arith(); } @@ -624,8 +616,6 @@ namespace smt { } } - - void setup::setup_arith() { static_features st(m_manager); IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); From e3e2c21632bcc15ba2973d0208bd47c11b3a73ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 22:53:14 -0800 Subject: [PATCH 354/477] Create cnf_nnf.h --- src/ast/simplifiers/cnf_nnf.h | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/ast/simplifiers/cnf_nnf.h diff --git a/src/ast/simplifiers/cnf_nnf.h b/src/ast/simplifiers/cnf_nnf.h new file mode 100644 index 000000000..eb80387d6 --- /dev/null +++ b/src/ast/simplifiers/cnf_nnf.h @@ -0,0 +1,57 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + cnf_nnf.h + +Abstract: + + pull nested quantifiers + +Author: + + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#pragma once + +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/normal_forms/pull_quant.h" + + +class cnf_nnf_simplifier : public dependent_expr_simplifier { + + defined_names m_defined_names; + +public: + cnf_nnf_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): + dependent_expr_simplifier(m, fmls), + m_pull(m) { + } + + char const* name() const override { return "cnf-nnf"; } + + void reduce() override { + nnf apply_nnf(m, m_defined_names); + expr_ref_vector push_todo(m); + proof_ref_vector push_todo_prs(m); + proof_ref pr(m); + expr_ref r(m); + unsigned sz = qtail(); + for (unsigned i = qhead(); i < sz && m.inc(); ++i) { + auto d = m_fmls[idx]; + push_todo.reset(); + push_todo_prs.reset(); + apply_nnf(d.fml(), push_todo, push_todo_prs, r, pr); + m_fmls.update(i, dependent_expr(m, r, d.dep())); + for (expr* f : m_push_todo) { + if (!m.inc()) + break; + m_rewriter(f, r, pr); + m_fmls.add(i, depdendent_expr(m, r, d.dep())); + } + } + } +}; From e5984dd3979ece320b465e5ed65538ae644e737b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2022 23:04:38 -0800 Subject: [PATCH 355/477] add cnf/nnf simplifier --- src/ast/simplifiers/cnf_nnf.h | 17 ++++++++++++----- src/sat/sat_solver/sat_smt_preprocess.cpp | 3 +++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ast/simplifiers/cnf_nnf.h b/src/ast/simplifiers/cnf_nnf.h index eb80387d6..56cdc1367 100644 --- a/src/ast/simplifiers/cnf_nnf.h +++ b/src/ast/simplifiers/cnf_nnf.h @@ -18,17 +18,20 @@ Author: #pragma once #include "ast/simplifiers/dependent_expr_state.h" -#include "ast/normal_forms/pull_quant.h" +#include "ast/normal_forms/nnf.h" +#include "ast/rewriter/th_rewriter.h" class cnf_nnf_simplifier : public dependent_expr_simplifier { defined_names m_defined_names; + th_rewriter m_rewriter; public: cnf_nnf_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): dependent_expr_simplifier(m, fmls), - m_pull(m) { + m_defined_names(m), + m_rewriter(m, p){ } char const* name() const override { return "cnf-nnf"; } @@ -41,17 +44,21 @@ public: expr_ref r(m); unsigned sz = qtail(); for (unsigned i = qhead(); i < sz && m.inc(); ++i) { - auto d = m_fmls[idx]; + auto d = m_fmls[i]; push_todo.reset(); push_todo_prs.reset(); apply_nnf(d.fml(), push_todo, push_todo_prs, r, pr); m_fmls.update(i, dependent_expr(m, r, d.dep())); - for (expr* f : m_push_todo) { + for (expr* f : push_todo) { if (!m.inc()) break; m_rewriter(f, r, pr); - m_fmls.add(i, depdendent_expr(m, r, d.dep())); + m_fmls.add(dependent_expr(m, r, d.dep())); } } } + + void push() override { dependent_expr_simplifier::push(); m_defined_names.push(); } + + void pop(unsigned n) override { dependent_expr_simplifier::pop(n); m_defined_names.pop(n); } }; diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index e3d6b3edb..7c716c481 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -34,6 +34,7 @@ Author: #include "ast/simplifiers/push_ite.h" #include "ast/simplifiers/elim_term_ite.h" #include "ast/simplifiers/flatten_clauses.h" +#include "ast/simplifiers/cnf_nnf.h" #include "sat/sat_params.hpp" #include "smt/params/smt_params.h" #include "sat/sat_solver/sat_smt_preprocess.h" @@ -48,6 +49,7 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep s.add_simplifier(alloc(propagate_values, m, p, st)); s.add_simplifier(alloc(euf::solve_eqs, m, st)); s.add_simplifier(alloc(elim_unconstrained, m, st)); + if (smtp.m_nnf_cnf) s.add_simplifier(alloc(cnf_nnf_simplifier, m, p, st)); if (smtp.m_macro_finder || smtp.m_quasi_macros) s.add_simplifier(alloc(eliminate_predicates, m, st)); if (smtp.m_qe_lite) s.add_simplifier(mk_qe_lite_simplifer(m, p, st)); if (smtp.m_pull_nested_quantifiers) s.add_simplifier(alloc(pull_nested_quantifiers_simplifier, m, p, st)); @@ -62,6 +64,7 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep if (smtp.m_lift_ite != lift_ite_kind::LI_NONE) s.add_simplifier(alloc(push_ite_simplifier, m, p, st, smtp.m_lift_ite == lift_ite_kind::LI_CONSERVATIVE)); if (smtp.m_ng_lift_ite != lift_ite_kind::LI_NONE) s.add_simplifier(alloc(ng_push_ite_simplifier, m, p, st, smtp.m_ng_lift_ite == lift_ite_kind::LI_CONSERVATIVE)); s.add_simplifier(alloc(flatten_clauses, m, p, st)); + // // add: // euf_completion? From a96b7d243afd01a130a804570cb6b193f546dd92 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Dec 2022 00:04:08 -0800 Subject: [PATCH 356/477] remove incorrect check for quantifier --- src/ast/simplifiers/bit2int.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ast/simplifiers/bit2int.h b/src/ast/simplifiers/bit2int.h index 7d07029d2..6605c2e7e 100644 --- a/src/ast/simplifiers/bit2int.h +++ b/src/ast/simplifiers/bit2int.h @@ -34,8 +34,6 @@ public: proof_ref pr(m); for (unsigned idx : indices()) { auto const& d = m_fmls[idx]; - if (!has_quantifiers(d.fml())) - continue; m_rewriter(d.fml(), r, pr); m_fmls.update(idx, dependent_expr(m, r, d.dep())); } From 54a8d656179fc092cc62bf9652700e06821cc429 Mon Sep 17 00:00:00 2001 From: yizhou7 Date: Fri, 2 Dec 2022 16:56:53 -0500 Subject: [PATCH 357/477] move flushes in display_statistics (#6472) --- src/shell/smtlib_frontend.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index d0d0b452d..220001b40 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -44,12 +44,12 @@ static void display_statistics() { lock_guard lock(*display_stats_mux); clock_t end_time = clock(); if (g_cmd_context && g_display_statistics) { - std::cout.flush(); - std::cerr.flush(); if (g_cmd_context) { g_cmd_context->set_regular_stream("stdout"); g_cmd_context->display_statistics(true, ((static_cast(end_time) - static_cast(g_start_time)) / CLOCKS_PER_SEC)); } + std::cout.flush(); + std::cerr.flush(); } } From 5073959ae02b1ff062ffd43a4d62af219db7ce34 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Dec 2022 07:52:17 -0800 Subject: [PATCH 358/477] add macro attribute --- src/ast/recfun_decl_plugin.cpp | 1 + src/ast/recfun_decl_plugin.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 558488592..86c3fcf3b 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -408,6 +408,7 @@ namespace recfun { void promise_def::set_definition(replace& r, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { SASSERT(n_vars == d->get_arity()); + d->m_is_macro = is_macro; is_imm_pred is_i(*u); d->compute_cases(*u, r, is_i, is_macro, n_vars, vars, rhs); } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index c369e2827..bb75a854c 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -117,6 +117,7 @@ namespace recfun { func_decl_ref m_decl; //!< generic declaration expr_ref m_rhs; //!< definition family_id m_fid; + bool m_is_macro; def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort *const * domain, sort* range, bool is_generated); @@ -138,6 +139,7 @@ namespace recfun { bool is_fun_macro() const { return m_cases.size() == 1; } bool is_fun_defined() const { return !is_fun_macro(); } + bool is_macro() const { return m_is_macro; } def* copy(util& dst, ast_translation& tr); From cf7bba62880c3f9a215d20e05b757a16a5da0a23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Dec 2022 07:53:32 -0800 Subject: [PATCH 359/477] use ast_manager as an attribute --- src/ast/rewriter/arith_rewriter.cpp | 226 +++++++++---------- src/ast/rewriter/arith_rewriter.h | 24 +- src/ast/rewriter/bv_rewriter.cpp | 321 +++++++++++++-------------- src/ast/rewriter/bv_rewriter.h | 13 +- src/ast/rewriter/poly_rewriter.h | 1 - src/ast/rewriter/poly_rewriter_def.h | 42 ++-- 6 files changed, 311 insertions(+), 316 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index cdf09d7f3..c2a9b4cf4 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -24,7 +24,7 @@ Notes: seq_util& arith_rewriter_core::seq() { if (!m_seq) { - m_seq = alloc(seq_util, m()); + m_seq = alloc(seq_util, m); } return *m_seq; } @@ -93,9 +93,9 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c case OP_TANH: SASSERT(num_args == 1); st = mk_tanh_core(args[0], result); break; default: st = BR_FAILED; break; } - CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m()); - for (unsigned i = 0; i < num_args; ++i) tout << mk_pp(args[i], m()) << " "; - tout << "\n==>\n" << mk_pp(result.get(), m()) << "\n"; + CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m); + for (unsigned i = 0; i < num_args; ++i) tout << mk_pp(args[i], m) << " "; + tout << "\n==>\n" << mk_pp(result.get(), m) << "\n"; if (is_app(result)) tout << "args: " << to_app(result)->get_num_args() << "\n"; ); return st; @@ -133,7 +133,7 @@ bool arith_rewriter::div_polynomial(expr * t, numeral const & g, const_treatment SASSERT(!g.is_one()); unsigned sz; expr * const * ms = get_monomials(t, sz); - expr_ref_buffer new_args(m()); + expr_ref_buffer new_args(m); numeral a; for (unsigned i = 0; i < sz; i++) { expr * arg = ms[i]; @@ -196,10 +196,10 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref & switch (kind) { case LE: c = floor(c); break; case GE: c = ceil(c); break; - case EQ: result = m().mk_false(); return true; + case EQ: result = m.mk_false(); return true; } } - expr_ref k(m_util.mk_numeral(c, is_int), m()); + expr_ref k(m_util.mk_numeral(c, is_int), m); switch (kind) { case LE: result = m_util.mk_le(pp, k); return true; case GE: result = m_util.mk_ge(pp, k); return true; @@ -223,24 +223,24 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref & if (c.is_neg()) { switch (kind) { case EQ: - case LE: result = m().mk_false(); return true; - case GE: result = m().mk_true(); return true; + case LE: result = m.mk_false(); return true; + case GE: result = m.mk_true(); return true; } } if (c.is_zero() && kind == GE) { - result = m().mk_true(); + result = m.mk_true(); return true; } if (c.is_pos() && c >= abs(b)) { switch (kind) { - case LE: result = m().mk_true(); return true; + case LE: result = m.mk_true(); return true; case EQ: - case GE: result = m().mk_false(); return true; + case GE: result = m.mk_false(); return true; } } // mod x b <= b - 1 if (c + rational::one() == abs(b) && kind == LE) { - result = m().mk_true(); + result = m.mk_true(); return true; } } @@ -304,7 +304,7 @@ br_status arith_rewriter::is_separated(expr* arg1, expr* arg2, op_kind kind, exp if (kind != LE && kind != GE) return BR_FAILED; rational bound(0), r1, r2; - expr_ref narg(m()); + expr_ref narg(m); bool has_bound = true; if (!m_util.is_numeral(arg2, r2)) return BR_FAILED; @@ -335,47 +335,47 @@ br_status arith_rewriter::is_separated(expr* arg1, expr* arg2, op_kind kind, exp if (kind == GE && r1 > r2) return BR_FAILED; if (kind == LE && r1 > r2) { - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } if (kind == GE && r1 < r2) { - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } SASSERT(r1 == r2); - expr_ref zero(m_util.mk_numeral(rational(0), arg1->get_sort()), m()); + expr_ref zero(m_util.mk_numeral(rational(0), arg1->get_sort()), m); if (r1.is_zero() && m_util.is_mul(arg1)) { - expr_ref_buffer eqs(m()); + expr_ref_buffer eqs(m); ptr_buffer args; flat_mul(arg1, args); for (expr* arg : args) { if (m_util.is_numeral(arg)) continue; - eqs.push_back(m().mk_eq(arg, zero)); + eqs.push_back(m.mk_eq(arg, zero)); } - result = m().mk_or(eqs); + result = m.mk_or(eqs); return BR_REWRITE2; } if (kind == LE && m_util.is_add(arg1)) { - expr_ref_buffer leqs(m()); + expr_ref_buffer leqs(m); for (expr* arg : *to_app(arg1)) { if (!m_util.is_numeral(arg)) leqs.push_back(m_util.mk_le(arg, zero)); } - result = m().mk_and(leqs); + result = m.mk_and(leqs); return BR_REWRITE2; } if (kind == GE && m_util.is_add(arg1)) { - expr_ref_buffer geqs(m()); + expr_ref_buffer geqs(m); for (expr* arg : *to_app(arg1)) { if (!m_util.is_numeral(arg)) geqs.push_back(m_util.mk_ge(arg, zero)); } - result = m().mk_and(geqs); + result = m.mk_and(geqs); return BR_REWRITE2; } @@ -399,8 +399,8 @@ bool arith_rewriter::elim_to_real_var(expr * var, expr_ref & new_var) { bool arith_rewriter::elim_to_real_mon(expr * monomial, expr_ref & new_monomial) { if (m_util.is_mul(monomial)) { - expr_ref_buffer new_vars(m()); - expr_ref new_var(m()); + expr_ref_buffer new_vars(m); + expr_ref new_var(m); unsigned num = to_app(monomial)->get_num_args(); for (unsigned i = 0; i < num; i++) { if (!elim_to_real_var(to_app(monomial)->get_arg(i), new_var)) @@ -417,8 +417,8 @@ bool arith_rewriter::elim_to_real_mon(expr * monomial, expr_ref & new_monomial) bool arith_rewriter::elim_to_real_pol(expr * p, expr_ref & new_p) { if (m_util.is_add(p)) { - expr_ref_buffer new_monomials(m()); - expr_ref new_monomial(m()); + expr_ref_buffer new_monomials(m); + expr_ref new_monomial(m); for (expr* arg : *to_app(p)) { if (!elim_to_real_mon(arg, new_monomial)) return false; @@ -507,14 +507,14 @@ br_status arith_rewriter::reduce_power(expr * arg1, expr * arg2, op_kind kind, e switch (kind) { case LE: result = m_util.mk_le(new_arg1, new_arg2); return BR_REWRITE1; case GE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_REWRITE1; - default: result = m().mk_eq(new_arg1, new_arg2); return BR_REWRITE1; + default: result = m.mk_eq(new_arg1, new_arg2); return BR_REWRITE1; } } br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kind, expr_ref & result) { expr *orig_arg1 = arg1, *orig_arg2 = arg2; - expr_ref new_arg1(m()); - expr_ref new_arg2(m()); + expr_ref new_arg1(m); + expr_ref new_arg2(m); if ((is_zero(arg1) && is_reduce_power_target(arg2, kind == EQ)) || (is_zero(arg2) && is_reduce_power_target(arg1, kind == EQ))) return reduce_power(arg1, arg2, kind, result); @@ -524,29 +524,29 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin arg1 = new_arg1; arg2 = new_arg2; } - expr_ref new_new_arg1(m()); - expr_ref new_new_arg2(m()); + expr_ref new_new_arg1(m); + expr_ref new_new_arg2(m); if (m_elim_to_real && elim_to_real(arg1, arg2, new_new_arg1, new_new_arg2)) { arg1 = new_new_arg1; arg2 = new_new_arg2; - CTRACE("elim_to_real", m_elim_to_real, tout << "after_elim_to_real\n" << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n";); + CTRACE("elim_to_real", m_elim_to_real, tout << "after_elim_to_real\n" << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n";); if (st == BR_FAILED) st = BR_DONE; } numeral a1, a2; if (is_numeral(arg1, a1) && is_numeral(arg2, a2)) { switch (kind) { - case LE: result = a1 <= a2 ? m().mk_true() : m().mk_false(); return BR_DONE; - case GE: result = a1 >= a2 ? m().mk_true() : m().mk_false(); return BR_DONE; - default: result = a1 == a2 ? m().mk_true() : m().mk_false(); return BR_DONE; + case LE: result = a1 <= a2 ? m.mk_true() : m.mk_false(); return BR_DONE; + case GE: result = a1 >= a2 ? m.mk_true() : m.mk_false(); return BR_DONE; + default: result = a1 == a2 ? m.mk_true() : m.mk_false(); return BR_DONE; } } #define ANUM_LE_GE_EQ() { \ switch (kind) { \ - case LE: result = am.le(v1, v2) ? m().mk_true() : m().mk_false(); return BR_DONE; \ - case GE: result = am.ge(v1, v2) ? m().mk_true() : m().mk_false(); return BR_DONE; \ - default: result = am.eq(v1, v2) ? m().mk_true() : m().mk_false(); return BR_DONE; \ + case LE: result = am.le(v1, v2) ? m.mk_true() : m.mk_false(); return BR_DONE; \ + case GE: result = am.ge(v1, v2) ? m.mk_true() : m.mk_false(); return BR_DONE; \ + default: result = am.eq(v1, v2) ? m.mk_true() : m.mk_false(); return BR_DONE; \ } \ } @@ -593,12 +593,12 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin if (!first && !g.is_one() && num_consts <= 1) { bool is_sat = div_polynomial(arg1, g, (kind == LE ? CT_CEIL : (kind == GE ? CT_FLOOR : CT_FALSE)), new_arg1); if (!is_sat) { - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } is_sat = div_polynomial(arg2, g, (kind == LE ? CT_FLOOR : (kind == GE ? CT_CEIL : CT_FALSE)), new_arg2); if (!is_sat) { - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } arg1 = new_arg1.get(); @@ -607,25 +607,25 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin } } expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m().is_ite(arg1, c, t, e) && is_numeral(t, a1) && is_numeral(arg2, a2)) { + if (m.is_ite(arg1, c, t, e) && is_numeral(t, a1) && is_numeral(arg2, a2)) { switch (kind) { - case LE: result = a1 <= a2 ? m().mk_or(c, m_util.mk_le(e, arg2)) : m().mk_and(m().mk_not(c), m_util.mk_le(e, arg2)); return BR_REWRITE2; - case GE: result = a1 >= a2 ? m().mk_or(c, m_util.mk_ge(e, arg2)) : m().mk_and(m().mk_not(c), m_util.mk_ge(e, arg2)); return BR_REWRITE2; - case EQ: result = a1 == a2 ? m().mk_or(c, m().mk_eq(e, arg2)) : m().mk_and(m().mk_not(c), m_util.mk_eq(e, arg2)); return BR_REWRITE2; + case LE: result = a1 <= a2 ? m.mk_or(c, m_util.mk_le(e, arg2)) : m.mk_and(m.mk_not(c), m_util.mk_le(e, arg2)); return BR_REWRITE2; + case GE: result = a1 >= a2 ? m.mk_or(c, m_util.mk_ge(e, arg2)) : m.mk_and(m.mk_not(c), m_util.mk_ge(e, arg2)); return BR_REWRITE2; + case EQ: result = a1 == a2 ? m.mk_or(c, m.mk_eq(e, arg2)) : m.mk_and(m.mk_not(c), m_util.mk_eq(e, arg2)); return BR_REWRITE2; } } - if (m().is_ite(arg1, c, t, e) && is_numeral(e, a1) && is_numeral(arg2, a2)) { + if (m.is_ite(arg1, c, t, e) && is_numeral(e, a1) && is_numeral(arg2, a2)) { switch (kind) { - case LE: result = a1 <= a2 ? m().mk_or(m().mk_not(c), m_util.mk_le(t, arg2)) : m().mk_and(c, m_util.mk_le(t, arg2)); return BR_REWRITE2; - case GE: result = a1 >= a2 ? m().mk_or(m().mk_not(c), m_util.mk_ge(t, arg2)) : m().mk_and(c, m_util.mk_ge(t, arg2)); return BR_REWRITE2; - case EQ: result = a1 == a2 ? m().mk_or(m().mk_not(c), m().mk_eq(t, arg2)) : m().mk_and(c, m_util.mk_eq(t, arg2)); return BR_REWRITE2; + case LE: result = a1 <= a2 ? m.mk_or(m.mk_not(c), m_util.mk_le(t, arg2)) : m.mk_and(c, m_util.mk_le(t, arg2)); return BR_REWRITE2; + case GE: result = a1 >= a2 ? m.mk_or(m.mk_not(c), m_util.mk_ge(t, arg2)) : m.mk_and(c, m_util.mk_ge(t, arg2)); return BR_REWRITE2; + case EQ: result = a1 == a2 ? m.mk_or(m.mk_not(c), m.mk_eq(t, arg2)) : m.mk_and(c, m_util.mk_eq(t, arg2)); return BR_REWRITE2; } } - if (m().is_ite(arg1, c, t, e) && arg1->get_ref_count() == 1) { + if (m.is_ite(arg1, c, t, e) && arg1->get_ref_count() == 1) { switch (kind) { - case LE: result = m().mk_ite(c, m_util.mk_le(t, arg2), m_util.mk_le(e, arg2)); return BR_REWRITE2; - case GE: result = m().mk_ite(c, m_util.mk_ge(t, arg2), m_util.mk_ge(e, arg2)); return BR_REWRITE2; - case EQ: result = m().mk_ite(c, m().mk_eq(t, arg2), m().mk_eq(e, arg2)); return BR_REWRITE2; + case LE: result = m.mk_ite(c, m_util.mk_le(t, arg2), m_util.mk_le(e, arg2)); return BR_REWRITE2; + case GE: result = m.mk_ite(c, m_util.mk_ge(t, arg2), m_util.mk_ge(e, arg2)); return BR_REWRITE2; + case EQ: result = m.mk_ite(c, m.mk_eq(t, arg2), m.mk_eq(e, arg2)); return BR_REWRITE2; } } if (m_util.is_to_int(arg2) && is_numeral(arg1)) { @@ -642,7 +642,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin return BR_REWRITE1; case EQ: result = m_util.mk_ge(t, m_util.mk_numeral(a2, false)); - result = m().mk_and(m_util.mk_lt(t, m_util.mk_numeral(a2+1, false)), result); + result = m.mk_and(m_util.mk_lt(t, m_util.mk_numeral(a2+1, false)), result); return BR_REWRITE3; } } @@ -663,7 +663,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin switch (kind) { case LE: result = m_util.mk_le(arg1, arg2); return BR_DONE; case GE: result = m_util.mk_ge(arg1, arg2); return BR_DONE; - default: result = m().mk_eq(arg1, arg2); return BR_DONE; + default: result = m.mk_eq(arg1, arg2); return BR_DONE; } } return BR_FAILED; @@ -674,7 +674,7 @@ br_status arith_rewriter::mk_le_core(expr * arg1, expr * arg2, expr_ref & result } br_status arith_rewriter::mk_lt_core(expr * arg1, expr * arg2, expr_ref & result) { - result = m().mk_not(m_util.mk_le(arg2, arg1)); + result = m.mk_not(m_util.mk_le(arg2, arg1)); return BR_REWRITE2; } @@ -683,7 +683,7 @@ br_status arith_rewriter::mk_ge_core(expr * arg1, expr * arg2, expr_ref & result } br_status arith_rewriter::mk_gt_core(expr * arg1, expr * arg2, expr_ref & result) { - result = m().mk_not(m_util.mk_le(arg1, arg2)); + result = m.mk_not(m_util.mk_le(arg1, arg2)); return BR_REWRITE2; } @@ -694,7 +694,7 @@ bool arith_rewriter::is_arith_term(expr * n) const { br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { br_status st = BR_FAILED; if (m_eq2ineq) { - result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2)); + result = m.mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2)); st = BR_REWRITE2; } else if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) { @@ -724,7 +724,7 @@ br_status arith_rewriter::mk_and_core(unsigned n, expr* const* args, expr_ref& r } if (rest.size() < n - 1) { rest.push_back(arg0); - result = m().mk_and(rest); + result = m.mk_and(rest); return BR_REWRITE1; } } @@ -742,8 +742,8 @@ bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) { rational a, b; rational g = gcd(p, k, a, b); if (g == 1) { - expr_ref nb(m_util.mk_numeral(b, true), m()); - result = m().mk_eq(m_util.mk_mod(u, y), + expr_ref nb(m_util.mk_numeral(b, true), m); + result = m.mk_eq(m_util.mk_mod(u, y), m_util.mk_mod(m_util.mk_mul(nb, arg2), y)); return true; } @@ -752,7 +752,7 @@ bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) { } expr_ref arith_rewriter::neg_monomial(expr* e) const { - expr_ref_vector args(m()); + expr_ref_vector args(m); rational a1; if (m_util.is_numeral(e, a1)) args.push_back(m_util.mk_numeral(-a1, e->get_sort())); @@ -773,10 +773,10 @@ expr_ref arith_rewriter::neg_monomial(expr* e) const { args.push_back(e); } if (args.size() == 1) { - return expr_ref(args.back(), m()); + return expr_ref(args.back(), m); } else { - return expr_ref(m_util.mk_mul(args.size(), args.data()), m()); + return expr_ref(m_util.mk_mul(args.size(), args.data()), m); } } @@ -793,7 +793,7 @@ bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) const { expr * t2 = to_app(t)->get_arg(0); if (m_util.is_mul(t2) && is_numeral(to_app(t2)->get_arg(0), r) && r.is_neg()) { - expr_ref_vector args1(m()); + expr_ref_vector args1(m); for (expr* e1 : *to_app(t)) { args1.push_back(neg_monomial(e1)); } @@ -826,7 +826,7 @@ bool arith_rewriter::is_anum_simp_target(unsigned num_args, expr * const * args) br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, expr_ref & result) { if (is_anum_simp_target(num_args, args)) { - expr_ref_buffer new_args(m()); + expr_ref_buffer new_args(m); anum_manager & am = m_util.am(); scoped_anum r(am); scoped_anum arg(am); @@ -864,7 +864,7 @@ br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, ex new_args.push_back(m_util.mk_numeral(am, r, false)); br_status st = poly_rewriter::mk_add_core(new_args.size(), new_args.data(), result); if (st == BR_FAILED) { - result = m().mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data()); + result = m.mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data()); return BR_DONE; } return st; @@ -876,7 +876,7 @@ br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, ex br_status arith_rewriter::mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { if (is_anum_simp_target(num_args, args)) { - expr_ref_buffer new_args(m()); + expr_ref_buffer new_args(m); anum_manager & am = m_util.am(); scoped_anum r(am); scoped_anum arg(am); @@ -913,7 +913,7 @@ br_status arith_rewriter::mk_mul_core(unsigned num_args, expr * const * args, ex br_status st = poly_rewriter::mk_mul_core(new_args.size(), new_args.data(), result); if (st == BR_FAILED) { - result = m().mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data()); + result = m.mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data()); return BR_DONE; } return st; @@ -998,7 +998,7 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul else { numeral k(1); k /= v2; - result = m().mk_app(get_fid(), OP_MUL, + result = m.mk_app(get_fid(), OP_MUL, m_util.mk_numeral(k, false), arg1); return BR_REWRITE1; @@ -1028,8 +1028,8 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul v1 /= v2; result = m_util.mk_mul(m_util.mk_numeral(v1, false), m_util.mk_div(b, d)); - expr_ref z(m_util.mk_real(0), m()); - result = m().mk_ite(m().mk_eq(d, z), m_util.mk_div(arg1, z), result); + expr_ref z(m_util.mk_real(0), m); + result = m.mk_ite(m.mk_eq(d, z), m_util.mk_div(arg1, z), result); return BR_REWRITE2; } } @@ -1039,7 +1039,7 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul } br_status arith_rewriter::mk_idivides(unsigned k, expr * arg, expr_ref & result) { - result = m().mk_eq(m_util.mk_mod(arg, m_util.mk_int(k)), m_util.mk_int(0)); + result = m.mk_eq(m_util.mk_mod(arg, m_util.mk_int(k)), m_util.mk_int(0)); return BR_REWRITE2; } @@ -1063,12 +1063,12 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu return BR_FAILED; } if (arg1 == arg2) { - expr_ref zero(m_util.mk_int(0), m()); - result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1)); + expr_ref zero(m_util.mk_int(0), m); + result = m.mk_ite(m.mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1)); return BR_REWRITE3; } if (m_util.is_numeral(arg2, v2, is_int) && v2.is_pos() && m_util.is_add(arg1)) { - expr_ref_buffer args(m()); + expr_ref_buffer args(m); bool change = false; rational add(0); for (expr* arg : *to_app(arg1)) { @@ -1083,15 +1083,15 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu } } if (change) { - result = m_util.mk_idiv(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2); + result = m_util.mk_idiv(m.mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2); result = m_util.mk_add(m_util.mk_numeral(add, true), result); TRACE("div_bug", tout << "mk_div result: " << result << "\n";); return BR_REWRITE3; } } if (divides(arg1, arg2, result)) { - expr_ref zero(m_util.mk_int(0), m()); - result = m().mk_ite(m().mk_eq(zero, arg2), m_util.mk_idiv(arg1, zero), result); + expr_ref zero(m_util.mk_int(0), m); + result = m.mk_ite(m.mk_eq(zero, arg2), m_util.mk_idiv(arg1, zero), result); return BR_REWRITE_FULL; } return BR_FAILED; @@ -1150,17 +1150,17 @@ expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) { flat_mul(den, args2); remove_divisor(arg, args1); remove_divisor(arg, args2); - expr_ref zero(m_util.mk_int(0), m()); + expr_ref zero(m_util.mk_int(0), m); num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.data()); den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.data()); - expr_ref d(m_util.mk_idiv(num, den), m()); - expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m()); - return expr_ref(m().mk_ite(m().mk_eq(zero, arg), + expr_ref d(m_util.mk_idiv(num, den), m); + expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m); + return expr_ref(m.mk_ite(m.mk_eq(zero, arg), m_util.mk_idiv(zero, zero), - m().mk_ite(m_util.mk_ge(arg, zero), + m.mk_ite(m_util.mk_ge(arg, zero), d, nd)), - m()); + m); } void arith_rewriter::flat_mul(expr* e, ptr_buffer& args) { @@ -1208,8 +1208,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul } if (arg1 == arg2 && !m_util.is_numeral(arg2)) { - expr_ref zero(m_util.mk_int(0), m()); - result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero); + expr_ref zero(m_util.mk_int(0), m); + result = m.mk_ite(m.mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero); return BR_DONE; } @@ -1222,8 +1222,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul // propagate mod inside only if there is something to reduce. if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos() && (is_add(arg1) || is_mul(arg1))) { - TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n";); - expr_ref_buffer args(m()); + TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n";); + expr_ref_buffer args(m); bool change = false; for (expr* arg : *to_app(arg1)) { rational arg_v; @@ -1246,8 +1246,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul if (!change) { return BR_FAILED; // did not find any target for applying simplification } - result = m_util.mk_mod(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2); - TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m()) << "\n";); + result = m_util.mk_mod(m.mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2); + TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m) << "\n";); return BR_REWRITE3; } @@ -1290,10 +1290,10 @@ br_status arith_rewriter::mk_rem_core(expr * arg1, expr * arg2, expr_ref & resul } else if (m_elim_rem) { expr * mod = m_util.mk_mod(arg1, arg2); - result = m().mk_ite(m_util.mk_ge(arg2, m_util.mk_numeral(rational(0), true)), + result = m.mk_ite(m_util.mk_ge(arg2, m_util.mk_numeral(rational(0), true)), mod, m_util.mk_uminus(mod)); - TRACE("elim_rem", tout << "result: " << mk_ismt2_pp(result, m()) << "\n";); + TRACE("elim_rem", tout << "result: " << mk_ismt2_pp(result, m) << "\n";); return BR_REWRITE3; } return BR_FAILED; @@ -1322,7 +1322,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res bool is_num_y = m_util.is_numeral(arg2, y); auto ensure_real = [&](expr* e) { return m_util.is_int(e) ? m_util.mk_to_real(e) : e; }; - TRACE("arith", tout << mk_pp(arg1, m()) << " " << mk_pp(arg2, m()) << "\n";); + TRACE("arith", tout << mk_pp(arg1, m) << " " << mk_pp(arg2, m) << "\n";); if (is_num_x && x.is_one()) { result = m_util.mk_numeral(x, false); return BR_DONE; @@ -1377,7 +1377,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res if (is_num_y && y.is_minus_one()) { result = m_util.mk_div(m_util.mk_real(1), ensure_real(arg1)); - result = m().mk_ite(m().mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))), + result = m.mk_ite(m.mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))), m_util.mk_real(0), result); return BR_REWRITE2; @@ -1387,7 +1387,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res // (^ t -k) --> (^ (/ 1 t) k) result = m_util.mk_power(m_util.mk_div(m_util.mk_numeral(rational(1), false), arg1), m_util.mk_numeral(-y, false)); - result = m().mk_ite(m().mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))), + result = m.mk_ite(m.mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))), m_util.mk_real(0), result); return BR_REWRITE3; @@ -1504,7 +1504,7 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) { // Try to apply simplifications such as: // (to_int (+ 1.0 (to_real x)) y) --> (+ 1 x (to_int y)) - expr_ref_buffer int_args(m()), real_args(m()); + expr_ref_buffer int_args(m), real_args(m); for (expr* c : *to_app(arg)) { if (m_util.is_numeral(c, a) && a.is_int()) { int_args.push_back(m_util.mk_numeral(a, true)); @@ -1520,17 +1520,17 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) { return BR_FAILED; if (real_args.empty()) { - result = m().mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), int_args.size(), int_args.data()); + result = m.mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), int_args.size(), int_args.data()); return BR_REWRITE1; } if (!int_args.empty() && m_util.is_add(arg)) { decl_kind k = to_app(arg)->get_decl()->get_decl_kind(); - expr_ref t1(m().mk_app(get_fid(), k, int_args.size(), int_args.data()), m()); - expr_ref t2(m().mk_app(get_fid(), k, real_args.size(), real_args.data()), m()); + expr_ref t1(m.mk_app(get_fid(), k, int_args.size(), int_args.data()), m); + expr_ref t2(m.mk_app(get_fid(), k, real_args.size(), real_args.data()), m); int_args.reset(); int_args.push_back(t1); int_args.push_back(m_util.mk_to_int(t2)); - result = m().mk_app(get_fid(), k, int_args.size(), int_args.data()); + result = m.mk_app(get_fid(), k, int_args.size(), int_args.data()); return BR_REWRITE3; } } @@ -1550,9 +1550,9 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) { for (expr* e : *to_app(arg)) new_args.push_back(m_util.mk_to_real(e)); if (m_util.is_add(arg)) - result = m().mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data()); + result = m.mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data()); else - result = m().mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data()); + result = m.mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data()); return BR_REWRITE2; } } @@ -1562,23 +1562,23 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) { br_status arith_rewriter::mk_is_int(expr * arg, expr_ref & result) { numeral a; if (m_util.is_numeral(arg, a)) { - result = a.is_int() ? m().mk_true() : m().mk_false(); + result = a.is_int() ? m.mk_true() : m.mk_false(); return BR_DONE; } else if (m_util.is_to_real(arg)) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } else { - result = m().mk_eq(m().mk_app(get_fid(), OP_TO_REAL, - m().mk_app(get_fid(), OP_TO_INT, arg)), + result = m.mk_eq(m.mk_app(get_fid(), OP_TO_REAL, + m.mk_app(get_fid(), OP_TO_INT, arg)), arg); return BR_REWRITE3; } } br_status arith_rewriter::mk_abs_core(expr * arg, expr_ref & result) { - result = m().mk_ite(m_util.mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg))), arg, m_util.mk_uminus(arg)); + result = m.mk_ite(m_util.mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg))), arg, m_util.mk_uminus(arg)); return BR_REWRITE2; } @@ -1647,9 +1647,9 @@ bool arith_rewriter::is_pi_integer(expr * t) { a = c; b = d; } - TRACE("tan", tout << "is_pi_integer " << mk_ismt2_pp(t, m()) << "\n"; - tout << "a: " << mk_ismt2_pp(a, m()) << "\n"; - tout << "b: " << mk_ismt2_pp(b, m()) << "\n";); + TRACE("tan", tout << "is_pi_integer " << mk_ismt2_pp(t, m) << "\n"; + tout << "a: " << mk_ismt2_pp(a, m) << "\n"; + tout << "b: " << mk_ismt2_pp(b, m) << "\n";); return (m_util.is_pi(a) && m_util.is_to_real(b)) || (m_util.is_to_real(a) && m_util.is_pi(b)); @@ -1861,7 +1861,7 @@ br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) { } if (is_pi_multiple(arg, k)) { - expr_ref n(m()), d(m()); + expr_ref n(m), d(m); n = mk_sin_value(k); if (n.get() == nullptr) goto end; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index c80226d0c..3cd9d6165 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -25,13 +25,13 @@ Notes: class arith_rewriter_core { protected: typedef rational numeral; + ast_manager& m; arith_util m_util; scoped_ptr m_seq; - bool m_expand_power{ false }; - bool m_mul2power{ false }; - bool m_expand_tan{ false }; + bool m_expand_power = false; + bool m_mul2power = false; + bool m_expand_tan = false; - ast_manager & m() const { return m_util.get_manager(); } family_id get_fid() const { return m_util.get_family_id(); } seq_util& seq(); @@ -47,7 +47,7 @@ protected: app* mk_power(expr* x, rational const& r, sort* s); expr* coerce(expr* x, sort* s); public: - arith_rewriter_core(ast_manager & m):m_util(m) {} + arith_rewriter_core(ast_manager & m):m(m), m_util(m) {} bool is_zero(expr * n) const { return m_util.is_zero(n); } }; @@ -120,7 +120,7 @@ public: br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { if (mk_app_core(f, num_args, args, result) == BR_FAILED) - result = m().mk_app(f, num_args, args); + result = m.mk_app(f, num_args, args); } br_status mk_eq_core(expr * arg1, expr * arg2, expr_ref & result); @@ -159,30 +159,30 @@ public: br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result); void mk_div(expr * arg1, expr * arg2, expr_ref & result) { if (mk_div_core(arg1, arg2, result) == BR_FAILED) - result = m().mk_app(get_fid(), OP_DIV, arg1, arg2); + result = m.mk_app(get_fid(), OP_DIV, arg1, arg2); } void mk_idiv(expr * arg1, expr * arg2, expr_ref & result) { if (mk_idiv_core(arg1, arg2, result) == BR_FAILED) - result = m().mk_app(get_fid(), OP_IDIV, arg1, arg2); + result = m.mk_app(get_fid(), OP_IDIV, arg1, arg2); } void mk_mod(expr * arg1, expr * arg2, expr_ref & result) { if (mk_mod_core(arg1, arg2, result) == BR_FAILED) - result = m().mk_app(get_fid(), OP_MOD, arg1, arg2); + result = m.mk_app(get_fid(), OP_MOD, arg1, arg2); } void mk_rem(expr * arg1, expr * arg2, expr_ref & result) { if (mk_rem_core(arg1, arg2, result) == BR_FAILED) - result = m().mk_app(get_fid(), OP_REM, arg1, arg2); + result = m.mk_app(get_fid(), OP_REM, arg1, arg2); } br_status mk_to_int_core(expr * arg, expr_ref & result); br_status mk_to_real_core(expr * arg, expr_ref & result); void mk_to_int(expr * arg, expr_ref & result) { if (mk_to_int_core(arg, result) == BR_FAILED) - result = m().mk_app(get_fid(), OP_TO_INT, 1, &arg); + result = m.mk_app(get_fid(), OP_TO_INT, 1, &arg); } void mk_to_real(expr * arg, expr_ref & result) { if (mk_to_real_core(arg, result) == BR_FAILED) - result = m().mk_app(get_fid(), OP_TO_REAL, 1, &arg); + result = m.mk_app(get_fid(), OP_TO_REAL, 1, &arg); } br_status mk_is_int(expr * arg, expr_ref & result); diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 972259bd7..1557c9b3c 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -217,7 +217,7 @@ br_status bv_rewriter::mk_uge(expr * a, expr * b, expr_ref & result) { } br_status bv_rewriter::mk_ult(expr * a, expr * b, expr_ref & result) { - result = m().mk_not(m_util.mk_ule(b, a)); + result = m.mk_not(m_util.mk_ule(b, a)); return BR_REWRITE2; } @@ -234,7 +234,7 @@ br_status bv_rewriter::mk_sge(expr * a, expr * b, expr_ref & result) { } br_status bv_rewriter::mk_slt(expr * a, expr * b, expr_ref & result) { - result = m().mk_not(m_util.mk_sle(b, a)); + result = m.mk_not(m_util.mk_sle(b, a)); return BR_REWRITE2; } @@ -300,7 +300,7 @@ bool bv_rewriter::are_eq_upto_num(expr * _a, expr * _b, if (has_num_b) is_numeral(b->get_arg(0), b0_val, b0_sz); SASSERT(a0_sz == m_util.get_bv_size(a) && b0_sz == m_util.get_bv_size(a)); if (has_num_a && numa > 2) { - common = m().mk_app(m_util.get_fid(), add_decl_kind(), numa - 1, a->get_args() + 1); + common = m.mk_app(m_util.get_fid(), add_decl_kind(), numa - 1, a->get_args() + 1); } else { common = has_num_a ? a->get_arg(1) : a; @@ -311,13 +311,13 @@ bool bv_rewriter::are_eq_upto_num(expr * _a, expr * _b, // simplifies expressions as (bvuleq (X + c1) (X + c2)) for some common expression X and numerals c1, c2 br_status bv_rewriter::rw_leq_overflow(bool is_signed, expr * a, expr * b, expr_ref & result) { if (is_signed) return BR_FAILED; - expr_ref common(m()); + expr_ref common(m); numeral a0_val, b0_val; if (!are_eq_upto_num(a, b, common, a0_val, b0_val)) return BR_FAILED; SASSERT(a0_val.is_nonneg() && b0_val.is_nonneg()); const unsigned sz = m_util.get_bv_size(a); if (a0_val == b0_val) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (a0_val < b0_val) { @@ -329,14 +329,14 @@ br_status bv_rewriter::rw_leq_overflow(bool is_signed, expr * a, expr * b, expr_ const numeral lower = rational::power_of_two(sz) - a0_val; const numeral upper = rational::power_of_two(sz) - b0_val - numeral::one(); if (lower == upper) { - result = m().mk_eq(common, mk_numeral(lower, sz)); + result = m.mk_eq(common, mk_numeral(lower, sz)); } else if (b0_val.is_zero()) { result = m_util.mk_ule(mk_numeral(lower, sz), common); } else { SASSERT(lower.is_pos()); - result = m().mk_and(m_util.mk_ule(mk_numeral(lower, sz), common), + result = m.mk_and(m_util.mk_ule(mk_numeral(lower, sz), common), m_util.mk_ule(common, mk_numeral(upper, sz))); } return BR_REWRITE2; @@ -363,11 +363,11 @@ br_status bv_rewriter::rw_leq_concats(bool is_signed, expr * _a, expr * _b, expr const numeral hi_bf = m_util.norm(bf_sz > sz_min ? div(bf, rational::power_of_two(bf_sz - sz_min)) : bf, sz_min, is_signed); if (hi_af != hi_bf) { - result = hi_af < hi_bf ? m().mk_true() : m().mk_false(); + result = hi_af < hi_bf ? m.mk_true() : m.mk_false(); return BR_DONE; } - expr_ref new_a(m()); - expr_ref new_b(m()); + expr_ref new_a(m); + expr_ref new_b(m); if (af_sz > sz_min) { ptr_buffer new_args; new_args.push_back(mk_numeral(af, af_sz - sz_min)); @@ -391,11 +391,11 @@ br_status bv_rewriter::rw_leq_concats(bool is_signed, expr * _a, expr * _b, expr { // common prefix unsigned common = 0; - while (common < num_min && m().are_equal(a->get_arg(common), b->get_arg(common))) ++common; + while (common < num_min && m.are_equal(a->get_arg(common), b->get_arg(common))) ++common; SASSERT((common == numa) == (common == numb)); if (common == numa) { SASSERT(0); // shouldn't get here as both sides are equal - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (common > 0) { @@ -411,13 +411,13 @@ br_status bv_rewriter::rw_leq_concats(bool is_signed, expr * _a, expr * _b, expr while (new_numa && new_numb) { expr * const last_a = a->get_arg(new_numa - 1); expr * const last_b = b->get_arg(new_numb - 1); - if (!m().are_equal(last_a, last_b)) break; + if (!m.are_equal(last_a, last_b)) break; new_numa--; new_numb--; } if (new_numa == 0) { SASSERT(0); // shouldn't get here as both sides are equal - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (new_numa != numa) { @@ -438,7 +438,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref bool is_num2 = is_numeral(b, r2, sz); if (a == b) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } @@ -448,7 +448,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref r2 = m_util.norm(r2, sz, is_signed); if (is_num1 && is_num2) { - result = m().mk_bool_val(r1 <= r2); + result = m.mk_bool_val(r1 <= r2); return BR_DONE; } @@ -467,11 +467,11 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref if (is_num2) { if (r2 == lower) { - result = m().mk_eq(a, b); + result = m.mk_eq(a, b); return BR_REWRITE1; } if (r2 == upper) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } } @@ -479,13 +479,13 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref if (is_num1) { // 0 <= b is true if (r1 == lower) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } // 2^n-1 <= b is a = b if (r1 == upper) { - result = m().mk_eq(a, b); + result = m.mk_eq(a, b); return BR_REWRITE1; } } @@ -512,12 +512,10 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref // other cases r1 > r2, r1 < r2 are TBD if (!is_signed && is_num1 && m_util.is_bv_add(b, a1, a2) && is_numeral(a1, r2, sz)) { result = m_util.mk_ule(a2, m_util.mk_numeral(-r2 - 1, sz)); - if (r1 > r2) { - result = m().mk_and(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); - } - else if (r1 < r2) { - result = m().mk_or(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); - } + if (r1 > r2) + result = m.mk_and(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); + else if (r1 < r2) + result = m.mk_or(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); return BR_REWRITE2; } @@ -525,7 +523,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref const br_status cst = rw_leq_concats(is_signed, a, b, result); if (cst != BR_FAILED) { TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n") - << mk_ismt2_pp(a, m(), 2) << "\n" << mk_ismt2_pp(b, m(), 2) << "\n--->\n"<< mk_ismt2_pp(result, m(), 2) << "\n";); + << mk_ismt2_pp(a, m, 2) << "\n" << mk_ismt2_pp(b, m, 2) << "\n--->\n"<< mk_ismt2_pp(result, m, 2) << "\n";); return cst; } } @@ -534,7 +532,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref const br_status cst = rw_leq_overflow(is_signed, a, b, result); if (cst != BR_FAILED) { TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n") - << mk_ismt2_pp(a, m(), 2) << "\n" << mk_ismt2_pp(b, m(), 2) << "\n--->\n"<< mk_ismt2_pp(result, m(), 2) << "\n";); + << mk_ismt2_pp(a, m, 2) << "\n" << mk_ismt2_pp(b, m, 2) << "\n--->\n"<< mk_ismt2_pp(result, m, 2) << "\n";); return cst; } } @@ -548,7 +546,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref expr * b_2 = to_app(b)->get_arg(1); unsigned sz1 = get_bv_size(b_1); unsigned sz2 = get_bv_size(b_2); - result = m().mk_and(m().mk_eq(m_mk_extract(sz2+sz1-1, sz2, a), b_1), + result = m.mk_and(m.mk_eq(m_mk_extract(sz2+sz1-1, sz2, a), b_1), m_util.mk_ule(m_mk_extract(sz2-1, 0, a), b_2)); return BR_REWRITE3; } @@ -572,11 +570,11 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref if (first_non_zero == UINT_MAX) { // all bits are zero - result = m().mk_eq(a, m_util.mk_numeral(numeral(0), bv_sz)); + result = m.mk_eq(a, m_util.mk_numeral(numeral(0), bv_sz)); return BR_REWRITE1; } else if (first_non_zero < bv_sz - 1 && m_le2extract) { - result = m().mk_and(m().mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)), + result = m.mk_and(m.mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)), m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b))); return BR_REWRITE3; } @@ -673,7 +671,7 @@ unsigned bv_rewriter::propagate_extract(unsigned high, expr * arg, expr_ref & re } if (new_arg) new_args.push_back(new_arg); } - result = m().mk_app(get_fid(), a->get_decl()->get_decl_kind(), new_args.size(), new_args.data()); + result = m.mk_app(get_fid(), a->get_decl()->get_decl_kind(), new_args.size(), new_args.data()); SASSERT(m_util.is_bv(result)); return removable; } @@ -777,17 +775,17 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ expr * curr = to_app(arg)->get_arg(i); new_args.push_back(m_mk_extract(high, low, curr)); } - result = m().mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), new_args.size(), new_args.data()); + result = m.mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), new_args.size(), new_args.data()); return BR_REWRITE2; } if (m_extract_prop && (high >= low)) { - expr_ref ep_res(m()); + expr_ref ep_res(m); const unsigned ep_rm = propagate_extract(high, arg, ep_res); if (ep_rm != 0) { result = m_mk_extract(high, low, ep_res); - TRACE("extract_prop", tout << mk_ismt2_pp(arg, m()) << "\n[" << high <<"," << low << "]\n" << ep_rm << "---->\n" - << mk_ismt2_pp(result.get(), m()) << "\n";); + TRACE("extract_prop", tout << mk_ismt2_pp(arg, m) << "\n[" << high <<"," << low << "]\n" << ep_rm << "---->\n" + << mk_ismt2_pp(result.get(), m) << "\n";); return BR_REWRITE2; } } @@ -797,9 +795,9 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ // branch of ite to be expanded or if one of the expanded ite branches have a single // reference count. expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m().is_ite(arg, c, t, e) && - (t->get_ref_count() == 1 || e->get_ref_count() == 1 || !m().is_ite(t) || !m().is_ite(e))) { - result = m().mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e)); + if (m.is_ite(arg, c, t, e) && + (t->get_ref_count() == 1 || e->get_ref_count() == 1 || !m.is_ite(t) || !m.is_ite(e))) { + result = m.mk_ite(c, m_mk_extract(high, low, t), m_mk_extract(high, low, e)); return BR_REWRITE2; } @@ -855,9 +853,9 @@ br_status bv_rewriter::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { expr* x = nullptr, *y = nullptr; if (m_util.is_bv_shl(arg1, x, y)) { - expr_ref sum(m_util.mk_bv_add(y, arg2), m()); - expr_ref cond(m_util.mk_ule(y, sum), m()); - result = m().mk_ite(cond, + expr_ref sum(m_util.mk_bv_add(y, arg2), m); + expr_ref cond(m_util.mk_ule(y, sum), m); + result = m.mk_ite(cond, m_util.mk_bv_shl(x, sum), mk_numeral(0, bv_size)); return BR_REWRITE3; @@ -989,7 +987,7 @@ br_status bv_rewriter::mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result) { r1 += r2; if (r1 > numeral(bv_size)) r1 = numeral(bv_size); - result = m().mk_app(get_fid(), OP_BASHR, + result = m.mk_app(get_fid(), OP_BASHR, to_app(arg1)->get_arg(0), mk_numeral(r1, bv_size)); return BR_REWRITE1; // not really needed at this time. @@ -1029,7 +1027,7 @@ br_status bv_rewriter::mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, e } else { // The "hardware interpretation" for (bvsdiv x 0) is (ite (bvslt x #x0000) #x0001 #xffff) - result = m().mk_ite(m().mk_app(get_fid(), OP_SLT, arg1, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_app(get_fid(), OP_SLT, arg1, mk_numeral(0, bv_size)), mk_numeral(1, bv_size), mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size)); return BR_REWRITE2; @@ -1057,7 +1055,7 @@ br_status bv_rewriter::mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m().mk_ite(m().mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), m_util.mk_bv_sdiv0(arg1), m_util.mk_bv_sdiv_i(arg1, arg2)); return BR_REWRITE2; @@ -1097,7 +1095,7 @@ br_status bv_rewriter::mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, e unsigned shift; if (r2.is_power_of_two(shift)) { - result = m().mk_app(get_fid(), OP_BLSHR, arg1, mk_numeral(shift, bv_size)); + result = m.mk_app(get_fid(), OP_BLSHR, arg1, mk_numeral(shift, bv_size)); return BR_REWRITE1; } @@ -1112,11 +1110,11 @@ br_status bv_rewriter::mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m().mk_ite(m().mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), m_util.mk_bv_udiv0(arg1), m_util.mk_bv_udiv_i(arg1, arg2)); - TRACE("bv_udiv", tout << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n---->\n" << mk_ismt2_pp(result, m()) << "\n";); + TRACE("bv_udiv", tout << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n---->\n" << mk_ismt2_pp(result, m) << "\n";); return BR_REWRITE2; } @@ -1128,7 +1126,7 @@ br_status bv_rewriter::mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, e r2 = m_util.norm(r2, bv_size, true); if (r2.is_zero()) { if (!hi_div0) { - result = m().mk_app(get_fid(), OP_BSREM0, arg1); + result = m.mk_app(get_fid(), OP_BSREM0, arg1); return BR_REWRITE1; } else { @@ -1149,19 +1147,19 @@ br_status bv_rewriter::mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, e return BR_DONE; } - result = m().mk_app(get_fid(), OP_BSREM_I, arg1, arg2); + result = m.mk_app(get_fid(), OP_BSREM_I, arg1, arg2); return BR_DONE; } if (hi_div0) { - result = m().mk_app(get_fid(), OP_BSREM_I, arg1, arg2); + result = m.mk_app(get_fid(), OP_BSREM_I, arg1, arg2); return BR_DONE; } bv_size = get_bv_size(arg2); - result = m().mk_ite(m().mk_eq(arg2, mk_numeral(0, bv_size)), - m().mk_app(get_fid(), OP_BSREM0, arg1), - m().mk_app(get_fid(), OP_BSREM_I, arg1, arg2)); + result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + m.mk_app(get_fid(), OP_BSREM0, arg1), + m.mk_app(get_fid(), OP_BSREM_I, arg1, arg2)); return BR_REWRITE2; } @@ -1253,7 +1251,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e // urem(0, x) ==> ite(x = 0, urem0(x), 0) if (is_num1 && r1.is_zero()) { expr * zero = arg1; - result = m().mk_ite(m().mk_eq(arg2, zero), + result = m.mk_ite(m.mk_eq(arg2, zero), m_util.mk_bv_urem0(zero), zero); return BR_REWRITE2; @@ -1265,7 +1263,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e bv_size = get_bv_size(arg1); expr * x_minus_1 = arg1; expr * minus_one = mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size); - result = m().mk_ite(m().mk_eq(x, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(x, mk_numeral(0, bv_size)), m_util.mk_bv_urem0(minus_one), x_minus_1); return BR_REWRITE2; @@ -1295,7 +1293,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m().mk_ite(m().mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), m_util.mk_bv_urem0(arg1), m_util.mk_bv_urem_i(arg1, arg2)); return BR_REWRITE2; @@ -1357,8 +1355,8 @@ br_status bv_rewriter::mk_bv_smod_core(expr * arg1, expr * arg2, bool hi_div0, e !m_util.is_concat(a) && !m_util.is_concat(b)) { unsigned nb = r2.get_num_bits(); - expr_ref a1(m_util.mk_bv_smod(a, arg2), m()); - expr_ref a2(m_util.mk_bv_smod(b, arg2), m()); + expr_ref a1(m_util.mk_bv_smod(a, arg2), m); + expr_ref a2(m_util.mk_bv_smod(b, arg2), m); a1 = m_util.mk_concat( mk_numeral(0, bv_size - nb), m_mk_extract(nb-1,0,a1)); a2 = m_util.mk_concat( mk_numeral(0, bv_size - nb), m_mk_extract(nb-1,0,a2)); result = m_util.mk_bv_mul(a1, a2); @@ -1371,14 +1369,14 @@ br_status bv_rewriter::mk_bv_smod_core(expr * arg1, expr * arg2, bool hi_div0, e } if (hi_div0) { - result = m().mk_app(get_fid(), OP_BSMOD_I, arg1, arg2); + result = m.mk_app(get_fid(), OP_BSMOD_I, arg1, arg2); return BR_DONE; } bv_size = get_bv_size(arg2); - result = m().mk_ite(m().mk_eq(arg2, mk_numeral(0, bv_size)), - m().mk_app(get_fid(), OP_BSMOD0, arg1), - m().mk_app(get_fid(), OP_BSMOD_I, arg1, arg2)); + result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + m.mk_app(get_fid(), OP_BSMOD0, arg1), + m.mk_app(get_fid(), OP_BSMOD_I, arg1, arg2)); return BR_REWRITE2; } @@ -1413,7 +1411,7 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) { result = m_autil.mk_int(0); return BR_DONE; } - expr_ref_vector args(m()); + expr_ref_vector args(m); unsigned num_args = to_app(arg)->get_num_args(); for (expr* x : *to_app(arg)) { @@ -1421,7 +1419,7 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) { } unsigned sz = get_bv_size(to_app(arg)->get_arg(num_args-1)); for (unsigned i = num_args - 1; i > 0; ) { - expr_ref tmp(m()); + expr_ref tmp(m); --i; tmp = args[i].get(); tmp = m_autil.mk_mul(m_autil.mk_numeral(power(numeral(2), sz), true), tmp); @@ -1432,13 +1430,13 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) { return BR_REWRITE2; } if (is_mul_no_overflow(arg)) { - expr_ref_vector args(m()); + expr_ref_vector args(m); for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x)); result = m_autil.mk_mul(args.size(), args.data()); return BR_REWRITE2; } if (is_add_no_overflow(arg)) { - expr_ref_vector args(m()); + expr_ref_vector args(m); for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x)); result = m_autil.mk_add(args.size(), args.data()); return BR_REWRITE2; @@ -1507,7 +1505,7 @@ unsigned bv_rewriter::num_leading_zero_bits(expr* e) { br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) { - expr_ref_buffer new_args(m()); + expr_ref_buffer new_args(m); numeral v1; numeral v2; unsigned sz1, sz2; @@ -1554,11 +1552,11 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re if (!fused_numeral && !expanded && !fused_extract) { expr* x, *y, *z; if (eq_args) { - if (m().is_ite(new_args.back(), x, y, z)) { + if (m.is_ite(new_args.back(), x, y, z)) { ptr_buffer args1, args2; for (expr* arg : new_args) args1.push_back(y), args2.push_back(z); - result = m().mk_ite(x, m_util.mk_concat(args1), m_util.mk_concat(args2)); + result = m.mk_ite(x, m_util.mk_concat(args1), m_util.mk_concat(args2)); return BR_REWRITE2; } } @@ -1776,8 +1774,8 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re std::reverse(exs.begin(), exs.end()); result = m_util.mk_concat(exs.size(), exs.data()); TRACE("mask_bug", - tout << "(assert (distinct (bvor (_ bv" << old_v1 << " " << sz << ")\n" << mk_ismt2_pp(t, m()) << ")\n"; - tout << mk_ismt2_pp(result, m()) << "))\n";); + tout << "(assert (distinct (bvor (_ bv" << old_v1 << " " << sz << ")\n" << mk_ismt2_pp(t, m) << ")\n"; + tout << mk_ismt2_pp(result, m) << "))\n";); return BR_REWRITE2; } @@ -1896,8 +1894,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r } SASSERT(t != 0); numeral two(2); - expr_ref_buffer exs(m()); - expr_ref not_t(m()); + expr_ref_buffer exs(m); + expr_ref not_t(m); not_t = m_util.mk_bv_not(t); unsigned low = 0; unsigned i = 0; @@ -1936,7 +1934,7 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r } ptr_buffer new_args; - expr_ref c(m()); // may not be used + expr_ref c(m); // may not be used if (!v1.is_zero()) { c = mk_numeral(v1, sz); new_args.push_back(c); @@ -1990,13 +1988,13 @@ bool bv_rewriter::distribute_concat(decl_kind k, unsigned n, expr* const* args, expr* e = to_app(arg)->get_arg(0); unsigned sz1 = get_bv_size(e); unsigned sz2 = get_bv_size(arg); - expr_ref_vector args1(m()), args2(m()); + expr_ref_vector args1(m), args2(m); for (unsigned j = 0; j < n; ++j) { args1.push_back(m_mk_extract(sz2 - 1, sz2 - sz1, args[j])); args2.push_back(m_mk_extract(sz2 - sz1 - 1, 0, args[j])); } - expr* arg1 = m().mk_app(get_fid(), k, args1.size(), args1.data()); - expr* arg2 = m().mk_app(get_fid(), k, args2.size(), args2.data()); + expr* arg1 = m.mk_app(get_fid(), k, args1.size(), args1.data()); + expr* arg2 = m.mk_app(get_fid(), k, args2.size(), args2.data()); result = m_util.mk_concat(arg1, arg2); return true; } @@ -2028,15 +2026,15 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) { } expr* x, *y, *z; - if (m().is_ite(arg, x, y, z) && m_util.is_numeral(y, val, bv_size)) { + if (m.is_ite(arg, x, y, z) && m_util.is_numeral(y, val, bv_size)) { val = bitwise_not(bv_size, val); - result = m().mk_ite(x, m_util.mk_numeral(val, bv_size), m_util.mk_bv_not(z)); + result = m.mk_ite(x, m_util.mk_numeral(val, bv_size), m_util.mk_bv_not(z)); return BR_REWRITE2; } - if (m().is_ite(arg, x, y, z) && m_util.is_numeral(z, val, bv_size)) { + if (m.is_ite(arg, x, y, z) && m_util.is_numeral(z, val, bv_size)) { val = bitwise_not(bv_size, val); - result = m().mk_ite(x, m_util.mk_bv_not(y), m_util.mk_numeral(val, bv_size)); + result = m.mk_ite(x, m_util.mk_bv_not(y), m_util.mk_numeral(val, bv_size)); return BR_REWRITE2; } @@ -2051,13 +2049,13 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) { } } if (m_util.is_bv_add(arg, s, t)) { - expr_ref ns(m()); - expr_ref nt(m()); + expr_ref ns(m); + expr_ref nt(m); // ~(x + y) --> (~x + ~y + 1) when x and y are easy to negate if (is_negatable(t, nt) && is_negatable(s, ns)) { bv_size = m_util.get_bv_size(s); expr * nargs[3] = { m_util.mk_numeral(rational::one(), bv_size), ns.get(), nt.get() }; - result = m().mk_app(m_util.get_fid(), OP_BADD, 3, nargs); + result = m.mk_app(m_util.get_fid(), OP_BADD, 3, nargs); return BR_REWRITE1; } } @@ -2092,7 +2090,7 @@ br_status bv_rewriter::mk_bv_nor(unsigned num_args, expr * const * args, expr_re br_status bv_rewriter::mk_bv_xnor(unsigned num_args, expr * const * args, expr_ref & result) { switch (num_args) { - case 0: result = m().mk_true(); break; + case 0: result = m.mk_true(); break; case 1: result = m_util.mk_bv_not(args[0]); break; case 2: result = m_util.mk_bv_not(m_util.mk_bv_xor(num_args, args)); break; default: @@ -2176,7 +2174,7 @@ br_status bv_rewriter::mk_bv_comp(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } - result = m().mk_ite(m().mk_eq(arg1, arg2), + result = m.mk_ite(m.mk_eq(arg1, arg2), mk_numeral(1, 1), mk_numeral(0, 1)); return BR_REWRITE2; @@ -2214,7 +2212,7 @@ br_status bv_rewriter::mk_bv_add(unsigned num_args, expr * const * args, expr_re return st; } - result = m().mk_app(get_fid(), OP_BOR, x, y); + result = m.mk_app(get_fid(), OP_BOR, x, y); return BR_REWRITE1; #else unsigned _num_args; @@ -2244,7 +2242,7 @@ br_status bv_rewriter::mk_bv_add(unsigned num_args, expr * const * args, expr_re } } } - result = m().mk_app(get_fid(), OP_BOR, _num_args, _args); + result = m.mk_app(get_fid(), OP_BOR, _num_args, _args); return BR_REWRITE1; #endif } @@ -2253,21 +2251,17 @@ bool bv_rewriter::is_zero_bit(expr * x, unsigned idx) { numeral val; unsigned bv_size; loop: - if (is_numeral(x, val, bv_size)) { - if (val.is_zero()) - return true; - div(val, rational::power_of_two(idx), val); - return (val % numeral(2)).is_zero(); - } + if (is_numeral(x, val, bv_size)) + return val.is_zero() || !val.get_bit(idx); + if (m_util.is_concat(x)) { unsigned i = to_app(x)->get_num_args(); while (i > 0) { --i; expr * y = to_app(x)->get_arg(i); bv_size = get_bv_size(y); - if (bv_size <= idx) { + if (bv_size <= idx) idx -= bv_size; - } else { x = y; goto loop; @@ -2363,7 +2357,7 @@ br_status bv_rewriter::mk_bit2bool(expr * n, int idx, expr_ref & result) { return BR_FAILED; div(v, rational::power_of_two(idx), bit); mod(bit, rational(2), bit); - result = m().mk_bool_val(bit.is_one()); + result = m.mk_bool_val(bit.is_one()); return BR_DONE; } @@ -2381,61 +2375,62 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) { if (is_numeral(lhs)) { SASSERT(is_numeral(rhs)); - result = m().mk_bool_val(lhs == rhs); + result = m.mk_bool_val(lhs == rhs); return BR_DONE; } expr* a = nullptr, *b = nullptr, *c = nullptr; - if (m().is_ite(lhs, a, b, c)) { - bool_rewriter rw(m()); - expr_ref e1(rw.mk_eq(b, rhs), m()); - expr_ref e2(rw.mk_eq(c, rhs), m()); + if (m.is_ite(lhs, a, b, c)) { + bool_rewriter rw(m); + expr_ref e1(rw.mk_eq(b, rhs), m); + expr_ref e2(rw.mk_eq(c, rhs), m); result = rw.mk_ite(a, e1, e2); return BR_REWRITE2; } if (m_util.is_bv_not(lhs, a)) { SASSERT(v.is_one() || v.is_zero()); - result = m().mk_eq(a, mk_numeral(numeral(1) - v, 1)); + result = m.mk_eq(a, mk_numeral(numeral(1) - v, 1)); return BR_REWRITE1; } bool is_one = v.is_one(); - expr_ref bit1(m()); - bit1 = is_one ? rhs : mk_numeral(numeral(1), 1); - + if (m_util.is_bv_or(lhs)) { + if (!m_bit1) + m_bit1 = is_one ? rhs : mk_numeral(numeral(1), 1); ptr_buffer new_args; for (expr* arg : *to_app(lhs)) - new_args.push_back(m().mk_eq(arg, bit1)); - result = m().mk_or(new_args); + new_args.push_back(m.mk_eq(arg, m_bit1)); + result = m.mk_or(new_args); if (is_one) { return BR_REWRITE2; } else { - result = m().mk_not(result); + result = m.mk_not(result); return BR_REWRITE3; } } if (m_util.is_bv_xor(lhs)) { + if (!m_bit1) + m_bit1 = is_one ? rhs : mk_numeral(numeral(1), 1); ptr_buffer new_args; for (expr* arg : *to_app(lhs)) - new_args.push_back(m().mk_eq(arg, bit1)); + new_args.push_back(m.mk_eq(arg, m_bit1)); // TODO: bool xor is not flat_assoc... must fix that. - result = m().mk_xor(new_args); + result = m.mk_xor(new_args); if (is_one) { return BR_REWRITE2; } else { - result = m().mk_not(result); + result = m.mk_not(result); return BR_REWRITE3; } } - return BR_FAILED; } @@ -2443,7 +2438,7 @@ br_status bv_rewriter::mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & resu unsigned sz = get_bv_size(lhs); if (sz == 1) return BR_FAILED; - TRACE("blast_eq_value", tout << "sz: " << sz << "\n" << mk_ismt2_pp(lhs, m()) << "\n";); + TRACE("blast_eq_value", tout << "sz: " << sz << "\n" << mk_ismt2_pp(lhs, m) << "\n";); if (is_numeral(lhs)) std::swap(lhs, rhs); @@ -2458,11 +2453,11 @@ br_status bv_rewriter::mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & resu ptr_buffer new_args; for (unsigned i = 0; i < sz; i++) { bool bit0 = (v % two).is_zero(); - new_args.push_back(m().mk_eq(m_mk_extract(i,i, lhs), + new_args.push_back(m.mk_eq(m_mk_extract(i,i, lhs), mk_numeral(bit0 ? 0 : 1, 1))); div(v, two, v); } - result = m().mk_and(new_args); + result = m.mk_and(new_args); return BR_REWRITE3; } @@ -2503,7 +2498,7 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { unsigned rsz1 = sz1 - low1; unsigned rsz2 = sz2 - low2; if (rsz1 == rsz2) { - new_eqs.push_back(m().mk_eq(m_mk_extract(sz1 - 1, low1, arg1), + new_eqs.push_back(m.mk_eq(m_mk_extract(sz1 - 1, low1, arg1), m_mk_extract(sz2 - 1, low2, arg2))); low1 = 0; low2 = 0; @@ -2512,14 +2507,14 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { continue; } else if (rsz1 < rsz2) { - new_eqs.push_back(m().mk_eq(m_mk_extract(sz1 - 1, low1, arg1), + new_eqs.push_back(m.mk_eq(m_mk_extract(sz1 - 1, low1, arg1), m_mk_extract(rsz1 + low2 - 1, low2, arg2))); low1 = 0; low2 += rsz1; --i1; } else { - new_eqs.push_back(m().mk_eq(m_mk_extract(rsz2 + low1 - 1, low1, arg1), + new_eqs.push_back(m.mk_eq(m_mk_extract(rsz2 + low1 - 1, low1, arg1), m_mk_extract(sz2 - 1, low2, arg2))); low1 += rsz2; low2 = 0; @@ -2528,7 +2523,7 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { } SASSERT(i1 == 0 && i2 == 0); SASSERT(new_eqs.size() >= 1); - result = m().mk_and(new_eqs); + result = m.mk_and(new_eqs); return BR_REWRITE3; } @@ -2548,9 +2543,9 @@ bool bv_rewriter::is_minus_one_times_t(expr * arg) { void bv_rewriter::mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result) { SASSERT(is_numeral(c)); if (is_minus_one_times_t(t1)) - result = m().mk_eq(t2, m_util.mk_bv_sub(c, t1)); + result = m.mk_eq(t2, m_util.mk_bv_sub(c, t1)); else - result = m().mk_eq(t1, m_util.mk_bv_sub(c, t2)); + result = m.mk_eq(t1, m_util.mk_bv_sub(c, t2)); } #include "ast/ast_pp.h" @@ -2564,9 +2559,9 @@ bool bv_rewriter::isolate_term(expr* lhs, expr* rhs, expr_ref& result) { } unsigned sz = to_app(rhs)->get_num_args(); expr * t1 = to_app(rhs)->get_arg(0); - expr_ref t2(m()); + expr_ref t2(m); if (sz > 2) { - t2 = m().mk_app(get_fid(), OP_BADD, sz-1, to_app(rhs)->get_args()+1); + t2 = m.mk_app(get_fid(), OP_BADD, sz-1, to_app(rhs)->get_args()+1); } else { SASSERT(sz == 2); @@ -2623,7 +2618,7 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { // c * x = a if (m_util.is_numeral(rhs, rhs_val, sz)) { // x = c_inv * a - result = m().mk_eq(x, m_util.mk_numeral(c_inv_val * rhs_val, sz)); + result = m.mk_eq(x, m_util.mk_numeral(c_inv_val * rhs_val, sz)); return BR_REWRITE1; } @@ -2634,9 +2629,9 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { // x = c_inv * c2 * x2 numeral new_c2 = m_util.norm(c_inv_val * c2_val, sz); if (new_c2.is_one()) - result = m().mk_eq(x, x2); + result = m.mk_eq(x, x2); else - result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val * c2_val, sz), x2)); + result = m.mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val * c2_val, sz), x2)); return BR_REWRITE1; } @@ -2644,7 +2639,7 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { // and t_i's have non-unary coefficients (this condition is used to make sure we are actually reducing the number of multipliers). if (is_add_mul_const(rhs)) { // Potential problem: this simplification may increase the number of adders by reducing the amount of sharing. - result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs)); + result = m.mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs)); return BR_REWRITE2; } } @@ -2662,7 +2657,7 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { } } if (found) { - result = m().mk_eq(m_util.mk_numeral(c2_inv_val*c_val, sz), + result = m.mk_eq(m_util.mk_numeral(c2_inv_val*c_val, sz), m_util.mk_bv_mul(m_util.mk_numeral(c2_inv_val, sz), rhs)); return BR_REWRITE3; } @@ -2682,12 +2677,12 @@ bool bv_rewriter::is_urem_any(expr * e, expr * & dividend, expr * & divisor) { br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (lhs == rhs) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (is_numeral(lhs) && is_numeral(rhs)) { - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } @@ -2699,7 +2694,7 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { #if 0 if (!gcd_test(lhs, rhs)) { - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } #endif @@ -2713,13 +2708,13 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { st = mk_mul_eq(lhs, rhs, result); if (st != BR_FAILED) { - TRACE("mk_mul_eq", tout << mk_ismt2_pp(lhs, m()) << "\n=\n" << mk_ismt2_pp(rhs, m()) << "\n----->\n" << mk_ismt2_pp(result,m()) << "\n";); + TRACE("mk_mul_eq", tout << mk_ismt2_pp(lhs, m) << "\n=\n" << mk_ismt2_pp(rhs, m) << "\n----->\n" << mk_ismt2_pp(result,m) << "\n";); return st; } st = mk_mul_eq(rhs, lhs, result); if (st != BR_FAILED) { - TRACE("mk_mul_eq", tout << mk_ismt2_pp(lhs, m()) << "\n=\n" << mk_ismt2_pp(rhs, m()) << "\n----->\n" << mk_ismt2_pp(result,m()) << "\n";); + TRACE("mk_mul_eq", tout << mk_ismt2_pp(lhs, m) << "\n=\n" << mk_ismt2_pp(rhs, m) << "\n----->\n" << mk_ismt2_pp(result,m) << "\n";); return st; } @@ -2738,24 +2733,24 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { && is_numeral(rhs, rhs_val, rhs_sz) && is_numeral(divisor, divisor_val, divisor_sz)) { if (!divisor_val.is_zero() && rhs_val >= divisor_val) {//(= (bvurem x c1) c2) where c2 >= c1 - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } if ((divisor_val + rhs_val) >= rational::power_of_two(divisor_sz)) {//(= (bvurem x c1) c2) where c1+c2 >= 2^width - result = m().mk_eq(dividend, rhs); + result = m.mk_eq(dividend, rhs); return BR_REWRITE2; } } } - expr_ref new_lhs(m()); - expr_ref new_rhs(m()); + expr_ref new_lhs(m); + expr_ref new_rhs(m); if (m_util.is_bv_add(lhs) || m_util.is_bv_mul(lhs) || m_util.is_bv_add(rhs) || m_util.is_bv_mul(rhs)) { st = cancel_monomials(lhs, rhs, false, new_lhs, new_rhs); if (st != BR_FAILED) { if (is_numeral(new_lhs) && is_numeral(new_rhs)) { - result = m().mk_bool_val(new_lhs == new_rhs); + result = m.mk_bool_val(new_lhs == new_rhs); return BR_DONE; } lhs = new_lhs; @@ -2772,7 +2767,7 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { } if (st != BR_FAILED) { - result = m().mk_eq(lhs, rhs); + result = m.mk_eq(lhs, rhs); return BR_DONE; } } @@ -2782,7 +2777,7 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { } if (swapped) { - result = m().mk_eq(lhs, rhs); + result = m.mk_eq(lhs, rhs); return BR_DONE; } @@ -2794,7 +2789,7 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res if (m_mkbv2num) { unsigned i; for (i = 0; i < num; i++) - if (!m().is_true(args[i]) && !m().is_false(args[i])) + if (!m.is_true(args[i]) && !m.is_false(args[i])) return BR_FAILED; numeral val; numeral two(2); @@ -2802,7 +2797,7 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res while (i > 0) { --i; val *= two; - if (m().is_true(args[i])) + if (m.is_true(args[i])) val++; } result = mk_numeral(val, num); @@ -2812,18 +2807,18 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res } br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) { - TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_ismt2_pp(c, m()) << "?\n" - << mk_ismt2_pp(t, m()) << "\n:" << mk_ismt2_pp(e, m()) << "\n";); - if (m().are_equal(t, e)) { + TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_ismt2_pp(c, m) << "?\n" + << mk_ismt2_pp(t, m) << "\n:" << mk_ismt2_pp(e, m) << "\n";); + if (m.are_equal(t, e)) { result = e; return BR_REWRITE1; } - if (m().is_not(c)) { - result = m().mk_ite(to_app(c)->get_arg(0), e, t); + if (m.is_not(c)) { + result = m.mk_ite(to_app(c)->get_arg(0), e, t); return BR_REWRITE1; } - if (m_ite2id && m().is_eq(c) && is_bv(t) && is_bv(e)) { + if (m_ite2id && m.is_eq(c) && is_bv(t) && is_bv(e)) { // detect when ite is actually some simple function based on the pattern (lhs=rhs) ? t : e expr * lhs = to_app(c)->get_arg(0); expr * rhs = to_app(c)->get_arg(1); @@ -2832,8 +2827,8 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu if (is_numeral(lhs)) std::swap(lhs, rhs); - if ( (m().are_equal(lhs, t) && m().are_equal(rhs, e)) - || (m().are_equal(lhs, e) && m().are_equal(rhs, t))) { + if ( (m.are_equal(lhs, t) && m.are_equal(rhs, e)) + || (m.are_equal(lhs, e) && m.are_equal(rhs, t))) { // (a = b ? a : b) is b. (a = b ? b : a) is a result = e; return BR_REWRITE1; @@ -2846,8 +2841,8 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu && is_numeral(t, t_n, t_sz) && is_numeral(e, e_n, e_sz)) { if (t_sz == 1) { SASSERT(rhs_sz == sz && e_sz == sz && t_sz == sz); - SASSERT(!m().are_equal(t, e)); - result = m().are_equal(rhs, t) ? lhs : m_util.mk_bv_not(lhs); + SASSERT(!m.are_equal(t, e)); + result = m.are_equal(rhs, t) ? lhs : m_util.mk_bv_not(lhs); return BR_REWRITE1; } if (rhs_n.is_one() && t_n.is_one() && e_n.is_zero()) { @@ -2873,7 +2868,7 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) { if (num_args <= 1) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } unsigned sz = get_bv_size(args[0]); @@ -2882,7 +2877,7 @@ br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_ return BR_FAILED; if (num_args <= 1u << sz) return BR_FAILED; - result = m().mk_false(); + result = m.mk_false(); return BR_DONE; } @@ -2895,11 +2890,11 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_num2 = is_numeral(args[1], a1_val, bv_sz); if (is_num1 && (a0_val.is_zero() || (bv_sz != 1 && a0_val.is_one()))) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (is_num2 && (a1_val.is_zero() || (bv_sz != 1 && a1_val.is_one()))) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } @@ -2913,9 +2908,9 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, rational lim = rational::power_of_two(bv_sz-1); rational r = a0_val * a1_val; if (is_overflow) - result = m().mk_bool_val(sign0 != sign1 || r < lim); + result = m.mk_bool_val(sign0 != sign1 || r < lim); else - result = m().mk_bool_val(sign0 == sign1 || r <= lim); + result = m.mk_bool_val(sign0 == sign1 || r <= lim); return BR_DONE; } @@ -2927,18 +2922,18 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args, bool is_num1 = is_numeral(args[0], a0_val, bv_sz); bool is_num2 = is_numeral(args[1], a1_val, bv_sz); if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) { - result = m().mk_true(); + result = m.mk_true(); return BR_DONE; } if (is_num1 && is_num2) { rational mr = a0_val * a1_val; rational lim = rational::power_of_two(bv_sz); - result = m().mk_bool_val(mr < lim); + result = m.mk_bool_val(mr < lim); return BR_DONE; } diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 703e668b6..b22a11947 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -25,10 +25,11 @@ Notes: class bv_rewriter_core { protected: + ast_manager& m; typedef rational numeral; bv_util m_util; - ast_manager & m() const { return m_util.get_manager(); } family_id get_fid() const { return m_util.get_family_id(); } + expr_ref m_bit1; bool is_numeral(expr * n) const { return m_util.is_numeral(n); } bool is_numeral(expr * n, numeral & r) const { unsigned sz; return m_util.is_numeral(n, r, sz); } @@ -44,7 +45,7 @@ protected: decl_kind power_decl_kind() const { UNREACHABLE(); return static_cast(UINT_MAX); } public: - bv_rewriter_core(ast_manager & m):m_util(m) {} + bv_rewriter_core(ast_manager & m):m(m), m_util(m), m_bit1(m) {} }; class bv_rewriter : public poly_rewriter { @@ -176,7 +177,7 @@ public: br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { if (mk_app_core(f, num_args, args, result) == BR_FAILED) - result = m().mk_app(f, num_args, args); + result = m.mk_app(f, num_args, args); } bool is_urem_any(expr * e, expr * & dividend, expr * & divisor); @@ -190,14 +191,14 @@ public: #define MK_BV_BINARY(OP) \ expr_ref OP(expr* a, expr* b) { \ - expr_ref result(m()); \ + expr_ref result(m); \ if (BR_FAILED == OP(a, b, result)) \ result = m_util.OP(a, b); \ return result; \ } \ expr_ref mk_zero_extend(unsigned n, expr * arg) { - expr_ref result(m()); + expr_ref result(m); if (BR_FAILED == mk_zero_extend(n, arg, result)) result = m_util.mk_zero_extend(n, arg); return result; @@ -211,7 +212,7 @@ public: expr_ref mk_bv2int(expr* a) { - expr_ref result(m()); + expr_ref result(m); if (BR_FAILED == mk_bv2int(a, result)) result = m_util.mk_bv2int(a); return result; diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index c505103bb..c9253b0e4 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -106,7 +106,6 @@ public: SASSERT(!m_som || !m_hoist_mul); // som is mutually exclusive with hoisting multiplication. } - ast_manager & m() const { return Config::m(); } family_id get_fid() const { return Config::get_fid(); } void updt_params(params_ref const & p); diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 0a17fc375..f9ae333b4 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -51,7 +51,7 @@ expr * poly_rewriter::mk_add_app(unsigned num_args, expr * const * args) switch (num_args) { case 0: return mk_numeral(numeral(0)); case 1: return args[0]; - default: return m().mk_app(get_fid(), add_decl_kind(), num_args, args); + default: return m.mk_app(get_fid(), add_decl_kind(), num_args, args); } } @@ -119,7 +119,7 @@ expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) if (new_args.size() > 2 && is_numeral(new_args.get(0), a)) { return mk_mul_app(a, mk_mul_app(new_args.size() - 1, new_args.data() + 1)); } - return m().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.data()); + return m.mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.data()); } } else { @@ -127,7 +127,7 @@ expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) if (num_args > 2 && is_numeral(args[0], a)) { return mk_mul_app(a, mk_mul_app(num_args - 1, args + 1)); } - return m().mk_app(get_fid(), mul_decl_kind(), num_args, args); + return m.mk_app(get_fid(), mul_decl_kind(), num_args, args); } } } @@ -189,9 +189,9 @@ br_status poly_rewriter::mk_flat_mul_core(unsigned num_args, expr * cons br_status st = mk_nflat_mul_core(flat_args.size(), flat_args.data(), result); TRACE("poly_rewriter", tout << "flat mul:\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m()) << "\n"; + for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m) << "\n"; tout << "---->\n"; - for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m()) << "\n"; + for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m) << "\n"; tout << st << "\n"; ); if (st == BR_FAILED) { @@ -292,7 +292,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con new_add_args.push_back(mk_mul_app(c, to_app(var)->get_arg(i))); } result = mk_add_app(new_add_args.size(), new_add_args.data()); - TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m(),5) << "\n";); + TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m,5) << "\n";); return BR_REWRITE2; } } @@ -328,7 +328,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con for (unsigned i = 0; i < new_args.size(); i++) { if (i > 0) tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); - tout << mk_ismt2_pp(new_args[i], m()); + tout << mk_ismt2_pp(new_args[i], m); } tout << "\nordered: " << ordered << "\n";); if (ordered && num_coeffs == 0 && !use_power()) @@ -340,7 +340,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con for (unsigned i = 0; i < new_args.size(); i++) { if (i > 0) tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); - tout << mk_ismt2_pp(new_args[i], m()); + tout << mk_ismt2_pp(new_args[i], m); } tout << "\n";); } @@ -349,8 +349,8 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con result = mk_mul_app(c, result); TRACE("poly_rewriter", for (unsigned i = 0; i < num_args; ++i) - tout << mk_ismt2_pp(args[i], m()) << " "; - tout << "\nmk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m()) << "\n";); + tout << mk_ismt2_pp(args[i], m) << " "; + tout << "\nmk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m) << "\n";); return BR_DONE; } @@ -373,7 +373,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con } } unsigned orig_size = sums.size(); - expr_ref_buffer sum(m()); // must be ref_buffer because we may throw an exception + expr_ref_buffer sum(m); // must be ref_buffer because we may throw an exception ptr_buffer m_args; TRACE("som", tout << "starting som...\n";); do { @@ -566,7 +566,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con SASSERT(m_sort_sums || ordered); TRACE("rewriter", tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";); + for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m) << "\n";); if (has_multiple) { // expensive case @@ -589,7 +589,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con coeffs.push_back(a); } } - expr_ref_buffer new_args(m()); + expr_ref_buffer new_args(m); if (!c.is_zero()) { new_args.push_back(mk_numeral(c)); } @@ -639,7 +639,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con if (num_coeffs == 1 && is_numeral(args[0], a) && !a.is_zero()) return BR_FAILED; } - expr_ref_buffer new_args(m()); + expr_ref_buffer new_args(m); if (!c.is_zero()) new_args.push_back(mk_numeral(c)); for (unsigned i = 0; i < num_args; i++) { @@ -690,8 +690,8 @@ br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, return BR_DONE; } set_curr_sort(args[0]->get_sort()); - expr_ref minus_one(mk_numeral(numeral(-1)), m()); - expr_ref_buffer new_args(m()); + expr_ref minus_one(mk_numeral(numeral(-1)), m); + expr_ref_buffer new_args(m); new_args.push_back(args[0]); for (unsigned i = 1; i < num_args; i++) { if (is_zero(args[i])) continue; @@ -984,11 +984,11 @@ bool poly_rewriter::hoist_ite(expr_ref& e) { return false; obj_hashtable shared; ptr_buffer adds; - expr_ref_vector bs(m()), pinned(m()); + expr_ref_vector bs(m), pinned(m); TO_BUFFER(is_add, adds, e); unsigned i = 0; for (expr* a : adds) { - if (m().is_ite(a)) { + if (m.is_ite(a)) { shared.reset(); numeral g(0); if (hoist_ite(a, shared, g) && (is_nontrivial_gcd(g) || !shared.empty())) { @@ -1026,7 +1026,7 @@ bool poly_rewriter::hoist_ite(expr_ref& e) { template bool poly_rewriter::hoist_ite(expr* a, obj_hashtable& shared, numeral& g) { expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m().is_ite(a, c, t, e)) { + if (m.is_ite(a, c, t, e)) { return hoist_ite(t, shared, g) && hoist_ite(e, shared, g); } rational k, g1; @@ -1064,8 +1064,8 @@ bool poly_rewriter::hoist_ite(expr* a, obj_hashtable& shared, nume template expr* poly_rewriter::apply_hoist(expr* a, numeral const& g, obj_hashtable const& shared) { expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m().is_ite(a, c, t, e)) { - return m().mk_ite(c, apply_hoist(t, g, shared), apply_hoist(e, g, shared)); + if (m.is_ite(a, c, t, e)) { + return m.mk_ite(c, apply_hoist(t, g, shared), apply_hoist(e, g, shared)); } rational k; if (is_nontrivial_gcd(g) && is_int_numeral(a, k)) { From 758c3b2c3ba02d8c6fb0d26180018fb9007549e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Dec 2022 07:53:53 -0800 Subject: [PATCH 360/477] fix filtering for recursive functions --- src/ast/simplifiers/dependent_expr_state.cpp | 18 +++++++++++++----- src/ast/simplifiers/dependent_expr_state.h | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr_state.cpp b/src/ast/simplifiers/dependent_expr_state.cpp index 40528fe99..8e9ecf190 100644 --- a/src/ast/simplifiers/dependent_expr_state.cpp +++ b/src/ast/simplifiers/dependent_expr_state.cpp @@ -65,14 +65,22 @@ void dependent_expr_state::freeze_terms(expr* e, bool only_as_array, ast_mark& v */ void dependent_expr_state::freeze_recfun() { - if (m_recfun_frozen) - return; - m_recfun_frozen = true; auto& m = m_frozen_trail.get_manager(); recfun::util rec(m); + if (!rec.has_rec_defs()) + return; + unsigned sz = rec.get_rec_funs().size(); + if (m_num_recfun >= sz) + return; + ast_mark visited; - for (func_decl* f : rec.get_rec_funs()) - freeze_terms(rec.get_def(f).get_rhs(), false, visited); + for (func_decl* f : rec.get_rec_funs()) { + auto& d = rec.get_def(f); + if (!d.is_macro()) + freeze_terms(d.get_rhs(), false, visited); + } + m_trail.push(value_trail(m_num_recfun)); + m_num_recfun = sz; } /** diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 9f27a336c..d7aa1d6eb 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -43,7 +43,7 @@ Author: class dependent_expr_state { unsigned m_qhead = 0; bool m_suffix_frozen = false; - bool m_recfun_frozen = false; + unsigned m_num_recfun = 0; lbool m_has_quantifiers = l_undef; ast_mark m_frozen; func_decl_ref_vector m_frozen_trail; From 3ebbb8472a4f57672528f69dc22850312dd9ba2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Dec 2022 07:54:14 -0800 Subject: [PATCH 361/477] fix perf bugs in new value propagation --- src/ast/simplifiers/propagate_values.cpp | 74 +++++++++++++----------- src/ast/simplifiers/propagate_values.h | 6 ++ 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index f0d85af72..7d698faa3 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -22,44 +22,19 @@ Notes: #include "params/tactic_params.hpp" #include "ast/ast_pp.h" #include "ast/ast_util.h" -#include "ast/shared_occs.h" #include "ast/simplifiers/propagate_values.h" propagate_values::propagate_values(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): dependent_expr_simplifier(m, fmls), - m_rewriter(m) { - m_rewriter.set_order_eq(true); + m_rewriter(m), + m_shared(m, true), + m_subst(m, true, false) { m_rewriter.set_flat_and_or(false); updt_params(p); } -void propagate_values::reduce() { - shared_occs shared(m, true); - expr_substitution subst(m, true, false); - expr* x, * y; - - auto add_shared = [&]() { - shared_occs_mark visited; - shared.reset(); - for (unsigned i = 0; i < qtail(); ++i) - shared(m_fmls[i].fml(), visited); - }; - - auto add_sub = [&](dependent_expr const& de) { - auto const& [f, dep] = de(); - if (m.is_not(f, x) && shared.is_shared(x)) - subst.insert(x, m.mk_false(), dep); - else if (shared.is_shared(f)) - subst.insert(f, m.mk_true(), dep); - if (m.is_eq(f, x, y)) { - if (m.is_value(x) && shared.is_shared(y)) - subst.insert(y, x, dep); - else if (m.is_value(y) && shared.is_shared(x)) - subst.insert(x, y, dep); - } - }; - - auto process_fml = [&](unsigned i) { +void propagate_values::process_fml(unsigned i) { + if (!m_subst.empty()) { auto [f, dep] = m_fmls[i](); expr_ref fml(m); proof_ref pr(m); @@ -70,14 +45,41 @@ void propagate_values::reduce() { ++m_stats.m_num_rewrites; } m_rewriter.reset_used_dependencies(); - add_sub(m_fmls[i]); - }; + } + add_sub(m_fmls[i]); +} +void propagate_values::add_sub(dependent_expr const& de) { + expr* x, * y; + auto const& [f, dep] = de(); + if (m.is_not(f, x) && m_shared.is_shared(x)) + m_subst.insert(x, m.mk_false(), dep); + if (m_shared.is_shared(f)) + m_subst.insert(f, m.mk_true(), dep); + if (m.is_eq(f, x, y)) { + if (m.is_value(x) && m_shared.is_shared(y)) + m_subst.insert(y, x, dep); + else if (m.is_value(y) && m_shared.is_shared(x)) + m_subst.insert(x, y, dep); + } +}; + +void propagate_values::reduce() { + m_shared.reset(); + m_subst.reset(); + + auto add_shared = [&]() { + shared_occs_mark visited; + m_shared.reset(); + for (unsigned i = 0; i < qtail(); ++i) + m_shared(m_fmls[i].fml(), visited); + }; + auto init_sub = [&]() { add_shared(); - subst.reset(); + m_subst.reset(); m_rewriter.reset(); - m_rewriter.set_substitution(&subst); + m_rewriter.set_substitution(&m_subst); for (unsigned i = 0; i < qhead(); ++i) add_sub(m_fmls[i]); }; @@ -91,12 +93,14 @@ void propagate_values::reduce() { init_sub(); for (unsigned i = qtail(); i-- > qhead() && m.inc() && !m_fmls.inconsistent();) process_fml(i); - if (subst.empty()) + if (m_subst.empty()) break; } m_rewriter.set_substitution(nullptr); m_rewriter.reset(); + m_subst.reset(); + m_shared.reset(); } void propagate_values::collect_statistics(statistics& st) const { diff --git a/src/ast/simplifiers/propagate_values.h b/src/ast/simplifiers/propagate_values.h index 9ad59d1b3..8b4e9fdd0 100644 --- a/src/ast/simplifiers/propagate_values.h +++ b/src/ast/simplifiers/propagate_values.h @@ -22,6 +22,7 @@ Notes: #include "ast/simplifiers/dependent_expr_state.h" #include "ast/rewriter/th_rewriter.h" +#include "ast/shared_occs.h" class propagate_values : public dependent_expr_simplifier { @@ -34,6 +35,11 @@ class propagate_values : public dependent_expr_simplifier { th_rewriter m_rewriter; stats m_stats; unsigned m_max_rounds = 4; + shared_occs m_shared; + expr_substitution m_subst; + + void process_fml(unsigned i); + void add_sub(dependent_expr const& de); public: propagate_values(ast_manager& m, params_ref const& p, dependent_expr_state& fmls); From 59fa8964cad87215cc8f6e24661224cc8566e2c3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Dec 2022 07:54:32 -0800 Subject: [PATCH 362/477] minor code cleanup --- src/tactic/arith/bound_propagator.cpp | 5 ++--- src/tactic/arith/propagate_ineqs_tactic.cpp | 4 +--- src/tactic/smtlogics/qfauflia_tactic.cpp | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/tactic/arith/bound_propagator.cpp b/src/tactic/arith/bound_propagator.cpp index 3c4844462..ba58b6160 100644 --- a/src/tactic/arith/bound_propagator.cpp +++ b/src/tactic/arith/bound_propagator.cpp @@ -840,9 +840,8 @@ void bound_propagator::explain(var x, bound * b, unsigned ts, assumption_vector break; } } - unsigned sz = todo.size(); - for (unsigned i = 0; i < sz; i++) - todo[i].second->m_mark = false; + for (var_bound& vb : todo) + vb.second->m_mark = false; todo.reset(); } diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index 0f62b45f4..871a9ac3b 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -135,9 +135,7 @@ struct propagate_ineqs_tactic::imp { mpq c_mpq_val; if (m_util.is_add(t)) { rational c_val; - unsigned num = to_app(t)->get_num_args(); - for (unsigned i = 0; i < num; i++) { - expr * mon = to_app(t)->get_arg(i); + for (expr* mon : *to_app(t)) { expr * c, * x; if (m_util.is_mul(mon, c, x) && m_util.is_numeral(c, c_val)) { nm.set(c_mpq_val, c_val.to_mpq()); diff --git a/src/tactic/smtlogics/qfauflia_tactic.cpp b/src/tactic/smtlogics/qfauflia_tactic.cpp index 2f1879d58..5c2a92ef6 100644 --- a/src/tactic/smtlogics/qfauflia_tactic.cpp +++ b/src/tactic/smtlogics/qfauflia_tactic.cpp @@ -19,7 +19,6 @@ Notes: #include "tactic/tactical.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" -#include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/smtlogics/smt_tactic.h" From 79e6d4e32dc329b4be35d413feaa299ea5da3c4a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Dec 2022 20:23:46 -0800 Subject: [PATCH 363/477] tune and debug elim-unconstrained (v2 - for simplifiers infrastructure) --- src/ast/bv_decl_plugin.h | 5 ++ src/ast/converters/expr_inverter.cpp | 54 ++++++++++--- src/ast/rewriter/bv_rewriter.cpp | 89 +++++++++++----------- src/ast/rewriter/bv_rewriter.h | 4 + src/ast/simplifiers/elim_unconstrained.cpp | 42 ++++++++-- src/ast/simplifiers/elim_unconstrained.h | 2 + 6 files changed, 132 insertions(+), 64 deletions(-) diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index ee618b42c..fc7e35245 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -411,6 +411,11 @@ public: app * mk_numeral(rational const & val, sort* s) const; app * mk_numeral(rational const & val, unsigned bv_size) const; app * mk_numeral(uint64_t u, unsigned bv_size) const { return mk_numeral(rational(u, rational::ui64()), bv_size); } + app * mk_zero(sort* s) const { return mk_numeral(rational::zero(), s); } + app * mk_zero(unsigned bv_size) const { return mk_numeral(rational::zero(), bv_size); } + app * mk_one(sort* s) const { return mk_numeral(rational::one(), s); } + app * mk_one(unsigned bv_size) const { return mk_numeral(rational::one(), bv_size); } + sort * mk_sort(unsigned bv_size); unsigned get_bv_size(sort const * s) const { diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 2874abd68..5553420ad 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -300,7 +300,7 @@ class bv_expr_inverter : public iexpr_inverter { sort* s = args[0]->get_sort(); mk_fresh_uncnstr_var_for(f, r); if (m_mc) - add_defs(num, args, r, bv.mk_numeral(rational(1), s)); + add_defs(num, args, r, bv.mk_one(s)); return true; } // c * v (c is odd) case @@ -335,7 +335,7 @@ class bv_expr_inverter : public iexpr_inverter { } mk_fresh_uncnstr_var_for(f, r); if (sh > 0) - r = bv.mk_concat(bv.mk_extract(sz - sh - 1, 0, r), bv.mk_numeral(0, sh)); + r = bv.mk_concat(bv.mk_extract(sz - sh - 1, 0, r), bv.mk_zero(sh)); if (m_mc) { rational inv_r; @@ -376,10 +376,10 @@ class bv_expr_inverter : public iexpr_inverter { else { ptr_buffer args; if (high < bv_size - 1) - args.push_back(bv.mk_numeral(rational(0), bv_size - high - 1)); + args.push_back(bv.mk_zero(bv_size - high - 1)); args.push_back(r); if (low > 0) - args.push_back(bv.mk_numeral(rational(0), low)); + args.push_back(bv.mk_zero(low)); add_def(arg, bv.mk_concat(args.size(), args.data())); } return true; @@ -391,7 +391,7 @@ class bv_expr_inverter : public iexpr_inverter { mk_fresh_uncnstr_var_for(f, r); if (m_mc) { add_def(arg1, r); - add_def(arg2, bv.mk_numeral(rational(1), s)); + add_def(arg2, bv.mk_one(s)); } return true; } @@ -419,13 +419,22 @@ class bv_expr_inverter : public iexpr_inverter { } bool process_bv_le(func_decl* f, expr* arg1, expr* arg2, bool is_signed, expr_ref& r) { + unsigned bv_sz = bv.get_bv_size(arg1); + if (uncnstr(arg1) && uncnstr(arg2)) { + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) { + add_def(arg1, m.mk_ite(r, bv.mk_zero(bv_sz), bv.mk_one(bv_sz))); + add_def(arg2, bv.mk_zero(bv_sz)); + } + return true; + } if (uncnstr(arg1)) { // v <= t expr* v = arg1; expr* t = arg2; // v <= t ---> (u or t == MAX) u is fresh // add definition v = ite(u or t == MAX, t, t+1) - unsigned bv_sz = bv.get_bv_size(arg1); + rational MAX; if (is_signed) MAX = rational::power_of_two(bv_sz - 1) - rational(1); @@ -434,7 +443,7 @@ class bv_expr_inverter : public iexpr_inverter { mk_fresh_uncnstr_var_for(f, r); r = m.mk_or(r, m.mk_eq(t, bv.mk_numeral(MAX, bv_sz))); if (m_mc) - add_def(v, m.mk_ite(r, t, bv.mk_bv_add(t, bv.mk_numeral(rational(1), bv_sz)))); + add_def(v, m.mk_ite(r, t, bv.mk_bv_add(t, bv.mk_one(bv_sz)))); return true; } if (uncnstr(arg2)) { @@ -443,7 +452,6 @@ class bv_expr_inverter : public iexpr_inverter { expr* t = arg1; // v >= t ---> (u ot t == MIN) u is fresh // add definition v = ite(u or t == MIN, t, t-1) - unsigned bv_sz = bv.get_bv_size(arg1); rational MIN; if (is_signed) MIN = -rational::power_of_two(bv_sz - 1); @@ -452,7 +460,7 @@ class bv_expr_inverter : public iexpr_inverter { mk_fresh_uncnstr_var_for(f, r); r = m.mk_or(r, m.mk_eq(t, bv.mk_numeral(MIN, bv_sz))); if (m_mc) - add_def(v, m.mk_ite(r, t, bv.mk_bv_sub(t, bv.mk_numeral(rational(1), bv_sz)))); + add_def(v, m.mk_ite(r, t, bv.mk_bv_sub(t, bv.mk_one(bv_sz)))); return true; } return false; @@ -467,6 +475,18 @@ class bv_expr_inverter : public iexpr_inverter { return true; } + bool process_shift(func_decl* f, expr* arg1, expr* arg2, expr_ref& r) { + if (uncnstr(arg1) && uncnstr(arg2)) { + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) { + add_def(arg1, r); + add_def(arg2, bv.mk_zero(arg2->get_sort())); + } + return true; + } + return false; + } + public: bv_expr_inverter(ast_manager& m) : iexpr_inverter(m), bv(m) {} @@ -543,10 +563,23 @@ class bv_expr_inverter : public iexpr_inverter { sort* s = args[0]->get_sort(); mk_fresh_uncnstr_var_for(f, r); if (m_mc) - add_defs(num, args, r, bv.mk_numeral(rational(0), s)); + add_defs(num, args, r, bv.mk_zero(s)); return true; } return false; + case OP_BAND: + if (num > 0 && uncnstr(num, args)) { + sort* s = args[0]->get_sort(); + mk_fresh_uncnstr_var_for(f, r); + if (m_mc) + add_defs(num, args, r, bv.mk_numeral(rational::power_of_two(bv.get_bv_size(s)) - 1, s)); + return true; + } + return false; + case OP_BSHL: + case OP_BASHR: + case OP_BLSHR: + return process_shift(f, args[0], args[1], r); default: return false; } @@ -599,6 +632,7 @@ public: } return true; } + return false; default: return false; } diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 1557c9b3c..34d2f6508 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -55,8 +55,8 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons SASSERT(f->get_family_id() == get_fid()); switch(f->get_decl_kind()) { - case OP_BIT0: SASSERT(num_args == 0); result = m_util.mk_numeral(0, 1); return BR_DONE; - case OP_BIT1: SASSERT(num_args == 0); result = m_util.mk_numeral(1, 1); return BR_DONE; + case OP_BIT0: SASSERT(num_args == 0); result = mk_zero(1); return BR_DONE; + case OP_BIT1: SASSERT(num_args == 0); result = mk_one(1); return BR_DONE; case OP_ULEQ: SASSERT(num_args == 2); return mk_ule(args[0], args[1], result); @@ -570,11 +570,11 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref if (first_non_zero == UINT_MAX) { // all bits are zero - result = m.mk_eq(a, m_util.mk_numeral(numeral(0), bv_sz)); + result = m.mk_eq(a, mk_zero(bv_sz)); return BR_REWRITE1; } else if (first_non_zero < bv_sz - 1 && m_le2extract) { - result = m.mk_and(m.mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)), + result = m.mk_and(m.mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), mk_zero(bv_sz - first_non_zero - 1)), m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b))); return BR_REWRITE3; } @@ -817,7 +817,7 @@ br_status bv_rewriter::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { } if (r2 >= numeral(bv_size)) { - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_DONE; } @@ -846,7 +846,7 @@ br_status bv_rewriter::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { // (bvshl x k) -> (concat (extract [n-1-k:0] x) bv0:k) unsigned k = r2.get_unsigned(); expr * new_args[2] = { m_mk_extract(bv_size - k - 1, 0, arg1), - mk_numeral(0, k) }; + mk_zero(k) }; result = m_util.mk_concat(2, new_args); return BR_REWRITE2; } @@ -857,7 +857,7 @@ br_status bv_rewriter::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { expr_ref cond(m_util.mk_ule(y, sum), m); result = m.mk_ite(cond, m_util.mk_bv_shl(x, sum), - mk_numeral(0, bv_size)); + mk_zero(bv_size)); return BR_REWRITE3; } @@ -877,7 +877,7 @@ br_status bv_rewriter::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) { } if (r2 >= numeral(bv_size)) { - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_DONE; } @@ -904,14 +904,14 @@ br_status bv_rewriter::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) { // (bvlshr x k) -> (concat bv0:k (extract [n-1:k] x)) SASSERT(r2.is_unsigned()); unsigned k = r2.get_unsigned(); - expr * new_args[2] = { mk_numeral(0, k), + expr * new_args[2] = { mk_zero(k), m_mk_extract(bv_size - 1, k, arg1) }; result = m_util.mk_concat(2, new_args); return BR_REWRITE2; } if (arg1 == arg2) { - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_DONE; } @@ -960,7 +960,7 @@ br_status bv_rewriter::mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result) { if (m_util.has_sign_bit(r1, bv_size)) result = mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size); else - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_DONE; } @@ -1027,8 +1027,8 @@ br_status bv_rewriter::mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, e } else { // The "hardware interpretation" for (bvsdiv x 0) is (ite (bvslt x #x0000) #x0001 #xffff) - result = m.mk_ite(m.mk_app(get_fid(), OP_SLT, arg1, mk_numeral(0, bv_size)), - mk_numeral(1, bv_size), + result = m.mk_ite(m.mk_app(get_fid(), OP_SLT, arg1, mk_zero(bv_size)), + mk_one(bv_size), mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size)); return BR_REWRITE2; } @@ -1055,7 +1055,7 @@ br_status bv_rewriter::mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_zero(bv_size)), m_util.mk_bv_sdiv0(arg1), m_util.mk_bv_sdiv_i(arg1, arg2)); return BR_REWRITE2; @@ -1110,7 +1110,7 @@ br_status bv_rewriter::mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_zero(bv_size)), m_util.mk_bv_udiv0(arg1), m_util.mk_bv_udiv_i(arg1, arg2)); @@ -1137,7 +1137,7 @@ br_status bv_rewriter::mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, e } if (r2.is_one()) { - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_DONE; } @@ -1157,7 +1157,7 @@ br_status bv_rewriter::mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_zero(bv_size)), m.mk_app(get_fid(), OP_BSREM0, arg1), m.mk_app(get_fid(), OP_BSREM_I, arg1, arg2)); return BR_REWRITE2; @@ -1222,7 +1222,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e } if (r2.is_one()) { - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_DONE; } @@ -1236,7 +1236,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e unsigned shift; if (r2.is_power_of_two(shift)) { expr * args[2] = { - mk_numeral(0, bv_size - shift), + mk_zero(bv_size - shift), m_mk_extract(shift-1, 0, arg1) }; result = m_util.mk_concat(2, args); @@ -1263,7 +1263,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e bv_size = get_bv_size(arg1); expr * x_minus_1 = arg1; expr * minus_one = mk_numeral(rational::power_of_two(bv_size) - numeral(1), bv_size); - result = m.mk_ite(m.mk_eq(x, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(x, mk_zero(bv_size)), m_util.mk_bv_urem0(minus_one), x_minus_1); return BR_REWRITE2; @@ -1293,7 +1293,7 @@ br_status bv_rewriter::mk_bv_urem_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_zero(bv_size)), m_util.mk_bv_urem0(arg1), m_util.mk_bv_urem_i(arg1, arg2)); return BR_REWRITE2; @@ -1343,7 +1343,7 @@ br_status bv_rewriter::mk_bv_smod_core(expr * arg1, expr * arg2, bool hi_div0, e if (r2.is_one()) { // (bvsmod x 1) --> 0 - result = mk_numeral(0, bv_size); + result = mk_zero(bv_size); return BR_REWRITE2; } @@ -1357,8 +1357,8 @@ br_status bv_rewriter::mk_bv_smod_core(expr * arg1, expr * arg2, bool hi_div0, e unsigned nb = r2.get_num_bits(); expr_ref a1(m_util.mk_bv_smod(a, arg2), m); expr_ref a2(m_util.mk_bv_smod(b, arg2), m); - a1 = m_util.mk_concat( mk_numeral(0, bv_size - nb), m_mk_extract(nb-1,0,a1)); - a2 = m_util.mk_concat( mk_numeral(0, bv_size - nb), m_mk_extract(nb-1,0,a2)); + a1 = m_util.mk_concat( mk_zero(bv_size - nb), m_mk_extract(nb-1,0,a1)); + a2 = m_util.mk_concat( mk_zero(bv_size - nb), m_mk_extract(nb-1,0,a2)); result = m_util.mk_bv_mul(a1, a2); std::cout << result << "\n"; result = m_util.mk_bv_smod(result, arg2); @@ -1374,7 +1374,7 @@ br_status bv_rewriter::mk_bv_smod_core(expr * arg1, expr * arg2, bool hi_div0, e } bv_size = get_bv_size(arg2); - result = m.mk_ite(m.mk_eq(arg2, mk_numeral(0, bv_size)), + result = m.mk_ite(m.mk_eq(arg2, mk_zero(bv_size)), m.mk_app(get_fid(), OP_BSMOD0, arg1), m.mk_app(get_fid(), OP_BSMOD_I, arg1, arg2)); return BR_REWRITE2; @@ -1585,7 +1585,7 @@ br_status bv_rewriter::mk_zero_extend(unsigned n, expr * arg, expr_ref & result) return BR_DONE; } else { - expr * args[2] = { mk_numeral(0, n), arg }; + expr * args[2] = { mk_zero(n), arg }; result = m_util.mk_concat(2, args); return BR_REWRITE1; } @@ -1789,7 +1789,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re switch (new_args.size()) { case 0: - result = mk_numeral(0, sz); + result = mk_zero(sz); return BR_DONE; case 1: result = new_args[0]; @@ -1959,7 +1959,7 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r switch (new_args.size()) { case 0: - result = mk_numeral(0, sz); + result = mk_zero(sz); return BR_DONE; case 1: result = new_args[0]; @@ -2054,7 +2054,7 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) { // ~(x + y) --> (~x + ~y + 1) when x and y are easy to negate if (is_negatable(t, nt) && is_negatable(s, ns)) { bv_size = m_util.get_bv_size(s); - expr * nargs[3] = { m_util.mk_numeral(rational::one(), bv_size), ns.get(), nt.get() }; + expr * nargs[3] = { mk_one(bv_size), ns.get(), nt.get() }; result = m.mk_app(m_util.get_fid(), OP_BADD, 3, nargs); return BR_REWRITE1; } @@ -2146,7 +2146,7 @@ br_status bv_rewriter::mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref br_status bv_rewriter::mk_bv_redor(expr * arg, expr_ref & result) { if (is_numeral(arg)) { - result = m_util.is_zero(arg) ? mk_numeral(0, 1) : mk_numeral(1, 1); + result = m_util.is_zero(arg) ? mk_zero(1) : mk_one(1); return BR_DONE; } return BR_FAILED; @@ -2156,7 +2156,7 @@ br_status bv_rewriter::mk_bv_redand(expr * arg, expr_ref & result) { numeral r; unsigned bv_size; if (is_numeral(arg, r, bv_size)) { - result = (r == rational::power_of_two(bv_size) - numeral(1)) ? mk_numeral(1, 1) : mk_numeral(0, 1); + result = (r == rational::power_of_two(bv_size) - numeral(1)) ? mk_one(1) : mk_zero(1); return BR_DONE; } return BR_FAILED; @@ -2164,19 +2164,19 @@ br_status bv_rewriter::mk_bv_redand(expr * arg, expr_ref & result) { br_status bv_rewriter::mk_bv_comp(expr * arg1, expr * arg2, expr_ref & result) { if (arg1 == arg2) { - result = mk_numeral(1,1); + result = mk_one(1); return BR_DONE; } if (is_numeral(arg1) && is_numeral(arg2)) { SASSERT(arg1 != arg2); - result = mk_numeral(0, 1); + result = mk_zero(1); return BR_DONE; } result = m.mk_ite(m.mk_eq(arg1, arg2), - mk_numeral(1, 1), - mk_numeral(0, 1)); + mk_one(1), + mk_zero(1)); return BR_REWRITE2; } @@ -2334,7 +2334,7 @@ br_status bv_rewriter::mk_bv_mul(unsigned num_args, expr * const * args, expr_re SASSERT(shift >= 1); expr * args[2] = { m_mk_extract(bv_size-shift-1, 0, y), - mk_numeral(0, shift) + mk_zero(shift) }; result = m_util.mk_concat(2, args); return BR_REWRITE2; @@ -2399,7 +2399,7 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) { if (m_util.is_bv_or(lhs)) { if (!m_bit1) - m_bit1 = is_one ? rhs : mk_numeral(numeral(1), 1); + m_bit1 = is_one ? rhs : mk_one(1); ptr_buffer new_args; for (expr* arg : *to_app(lhs)) new_args.push_back(m.mk_eq(arg, m_bit1)); @@ -2416,7 +2416,7 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) { if (m_util.is_bv_xor(lhs)) { if (!m_bit1) - m_bit1 = is_one ? rhs : mk_numeral(numeral(1), 1); + m_bit1 = is_one ? rhs : mk_one(1); ptr_buffer new_args; for (expr* arg : *to_app(lhs)) new_args.push_back(m.mk_eq(arg, m_bit1)); @@ -2499,7 +2499,7 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { unsigned rsz2 = sz2 - low2; if (rsz1 == rsz2) { new_eqs.push_back(m.mk_eq(m_mk_extract(sz1 - 1, low1, arg1), - m_mk_extract(sz2 - 1, low2, arg2))); + m_mk_extract(sz2 - 1, low2, arg2))); low1 = 0; low2 = 0; --i1; @@ -2508,14 +2508,14 @@ br_status bv_rewriter::mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result) { } else if (rsz1 < rsz2) { new_eqs.push_back(m.mk_eq(m_mk_extract(sz1 - 1, low1, arg1), - m_mk_extract(rsz1 + low2 - 1, low2, arg2))); + m_mk_extract(rsz1 + low2 - 1, low2, arg2))); low1 = 0; low2 += rsz1; --i1; } else { new_eqs.push_back(m.mk_eq(m_mk_extract(rsz2 + low1 - 1, low1, arg1), - m_mk_extract(sz2 - 1, low2, arg2))); + m_mk_extract(sz2 - 1, low2, arg2))); low1 += rsz2; low2 = 0; --i2; @@ -2572,12 +2572,9 @@ bool bv_rewriter::isolate_term(expr* lhs, expr* rhs, expr_ref& result) { } bool bv_rewriter::is_add_mul_const(expr* e) const { - if (!m_util.is_bv_add(e)) { + if (!m_util.is_bv_add(e)) return false; - } - unsigned num = to_app(e)->get_num_args(); - for (unsigned i = 0; i < num; i++) { - expr * arg = to_app(e)->get_arg(i); + for (expr * arg : *to_app(e)) { expr * c2, * x2; if (m_util.is_numeral(arg)) continue; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index b22a11947..ca999c793 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -173,6 +173,10 @@ public: bool is_bv(expr * t) const { return m_util.is_bv(t); } expr * mk_numeral(numeral const & v, unsigned sz) { return m_util.mk_numeral(v, sz); } expr * mk_numeral(unsigned v, unsigned sz) { return m_util.mk_numeral(numeral(v), sz); } + app * mk_zero(sort* s) { return m_util.mk_zero(s); } + app * mk_one(sort* s) { return m_util.mk_one(s); } + app * mk_zero(unsigned sz) { return m_util.mk_zero(sz); } + app * mk_one(unsigned sz) { return m_util.mk_one(sz); } br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 713d7941c..7404382a3 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -96,14 +96,17 @@ void elim_unconstrained::eliminate() { m_trail.push_back(r); SASSERT(r); gc(e); + init_children(e, r); m_root.setx(r->get_id(), e->get_id(), UINT_MAX); get_node(e).m_term = r; get_node(e).m_refcount++; IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(e, m) << "\n"); SASSERT(!m_heap.contains(root(e))); - if (is_uninterp_const(r)) - m_heap.insert(root(e)); + if (is_uninterp_const(r)) + m_heap.insert(root(e)); + else + m_created_compound = true; IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(n.m_orig, m) << " " << mk_bounded_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n";); @@ -177,6 +180,24 @@ void elim_unconstrained::init_terms(expr_ref_vector const& terms) { } } +void elim_unconstrained::init_children(expr* e, expr* r) { + expr_ref_vector children(m); + SASSERT(e != r); + if (is_quantifier(r)) + children.push_back(to_quantifier(r)->get_expr()); + else if (is_app(r)) + children.append(to_app(r)->get_num_args(), to_app(r)->get_args()); + else + return; + if (children.empty()) + return; + init_terms(children); + for (expr* arg : children) { + get_node(arg).m_parents.push_back(e); + inc_ref(arg); + } +} + void elim_unconstrained::gc(expr* t) { ptr_vector todo; todo.push_back(t); @@ -284,10 +305,15 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< void elim_unconstrained::reduce() { generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); m_inverter.set_model_converter(mc.get()); - init_nodes(); - eliminate(); - reconstruct_terms(); - vector old_fmls; - assert_normalized(old_fmls); - update_model_trail(*mc, old_fmls); + m_created_compound = true; + for (unsigned rounds = 0; m_created_compound && rounds < 3; ++rounds) { + m_created_compound = false; + init_nodes(); + eliminate(); + reconstruct_terms(); + vector old_fmls; + assert_normalized(old_fmls); + update_model_trail(*mc, old_fmls); + } + } diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 9da0f3fc2..1eb5d732b 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -47,6 +47,7 @@ class elim_unconstrained : public dependent_expr_simplifier { ptr_vector m_args; stats m_stats; unsigned_vector m_root; + bool m_created_compound = false; bool is_var_lt(int v1, int v2) const; node& get_node(unsigned n) { return m_nodes[n]; } @@ -58,6 +59,7 @@ class elim_unconstrained : public dependent_expr_simplifier { void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(root(t)); } void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(root(t)); } void gc(expr* t); + void init_children(expr* e, expr* r); expr* get_parent(unsigned n) const; void init_terms(expr_ref_vector const& terms); void init_nodes(); From e455897178b9bd64dcd01316df998b91c2948af9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 04:36:06 -0800 Subject: [PATCH 364/477] fix #6476 --- src/tactic/ufbv/ufbv_rewriter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index bfaf35980..a6a4e1957 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -735,6 +735,8 @@ struct match_args_aux_proc { m_subst.insert(n, 0, expr_offset(n, 1)); } } + else + throw no_match(); } void operator()(quantifier * n) { throw no_match(); } void operator()(app * n) {} From 7fe67877489f2acda6f6fddbdcf0806877fba7e1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 04:44:02 -0800 Subject: [PATCH 365/477] ufbv-rewriter is really a demodulator rewriter and does not reference ufbv so moving first the rewriter into place of other rewriters --- src/ast/rewriter/CMakeLists.txt | 1 + .../rewriter/demodulator_rewriter.cpp} | 50 +++++++++---------- .../rewriter/demodulator_rewriter.h} | 9 ++-- src/tactic/ufbv/CMakeLists.txt | 1 - src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 12 ++--- 5 files changed, 37 insertions(+), 36 deletions(-) rename src/{tactic/ufbv/ufbv_rewriter.cpp => ast/rewriter/demodulator_rewriter.cpp} (93%) rename src/{tactic/ufbv/ufbv_rewriter.h => ast/rewriter/demodulator_rewriter.h} (97%) diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index c785804c1..9eef651c8 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -11,6 +11,7 @@ z3_add_component(rewriter cached_var_subst.cpp char_rewriter.cpp datatype_rewriter.cpp + demodulator_rewriter.cpp der.cpp distribute_forall.cpp dl_rewriter.cpp diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/ast/rewriter/demodulator_rewriter.cpp similarity index 93% rename from src/tactic/ufbv/ufbv_rewriter.cpp rename to src/ast/rewriter/demodulator_rewriter.cpp index a6a4e1957..8a6911925 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/ast/rewriter/demodulator_rewriter.cpp @@ -24,9 +24,9 @@ Revision History: #include "ast/ast_pp.h" #include "ast/for_each_expr.h" #include "ast/rewriter/var_subst.h" -#include "tactic/ufbv/ufbv_rewriter.h" +#include "ast/rewriter/demodulator_rewriter.h" -ufbv_rewriter::ufbv_rewriter(ast_manager & m): +demodulator_rewriter::demodulator_rewriter(ast_manager & m): m(m), m_match_subst(m), m_bsimp(m), @@ -41,7 +41,7 @@ ufbv_rewriter::ufbv_rewriter(ast_manager & m): m_bsimp.updt_params(p); } -ufbv_rewriter::~ufbv_rewriter() { +demodulator_rewriter::~demodulator_rewriter() { reset_dealloc_values(m_fwd_idx); reset_dealloc_values(m_back_idx); for (auto & kv : m_demodulator2lhs_rhs) { @@ -51,7 +51,7 @@ ufbv_rewriter::~ufbv_rewriter() { } } -bool ufbv_rewriter::is_demodulator(expr * e, app_ref & large, expr_ref & small) const { +bool demodulator_rewriter::is_demodulator(expr * e, app_ref & large, expr_ref & small) const { if (!is_forall(e)) { return false; } @@ -117,7 +117,7 @@ public: void operator()(app * n) {} }; -int ufbv_rewriter::is_subset(expr * e1, expr * e2) const { +int demodulator_rewriter::is_subset(expr * e1, expr * e2) const { uint_set ev1, ev2; if (m.is_value(e1)) @@ -134,7 +134,7 @@ int ufbv_rewriter::is_subset(expr * e1, expr * e2) const { 0 ; } -int ufbv_rewriter::is_smaller(expr * e1, expr * e2) const { +int demodulator_rewriter::is_smaller(expr * e1, expr * e2) const { unsigned sz1 = 0, sz2 = 0; // values are always smaller! @@ -186,14 +186,14 @@ public: unsigned get_max() { return m_max_var_id; } }; -unsigned ufbv_rewriter::max_var_id(expr * e) +unsigned demodulator_rewriter::max_var_id(expr * e) { max_var_id_proc proc; for_each_expr(proc, e); return proc.get_max(); } -void ufbv_rewriter::insert_fwd_idx(expr * large, expr * small, quantifier * demodulator) { +void demodulator_rewriter::insert_fwd_idx(expr * large, expr * small, quantifier * demodulator) { SASSERT(large->get_kind() == AST_APP); SASSERT(demodulator); SASSERT(large && small); @@ -217,7 +217,7 @@ void ufbv_rewriter::insert_fwd_idx(expr * large, expr * small, quantifier * demo m_demodulator2lhs_rhs.insert(demodulator, expr_pair(large, small)); } -void ufbv_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulator) { +void demodulator_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulator) { TRACE("demodulator_fwd", tout << "REMOVE: " << std::hex << (size_t)demodulator << std::endl; ); fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f); @@ -234,7 +234,7 @@ void ufbv_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulator) { } } -bool ufbv_rewriter::check_fwd_idx_consistency() { +bool demodulator_rewriter::check_fwd_idx_consistency() { for (auto & kv : m_fwd_idx) { quantifier_set * set = kv.m_value; SASSERT(set); @@ -247,7 +247,7 @@ bool ufbv_rewriter::check_fwd_idx_consistency() { return true; } -void ufbv_rewriter::show_fwd_idx(std::ostream & out) { +void demodulator_rewriter::show_fwd_idx(std::ostream & out) { for (auto & kv : m_fwd_idx) { quantifier_set * set = kv.m_value; SASSERT(!set); @@ -265,7 +265,7 @@ void ufbv_rewriter::show_fwd_idx(std::ostream & out) { } } -bool ufbv_rewriter::rewrite1(func_decl * f, expr_ref_vector & m_new_args, expr_ref & np) { +bool demodulator_rewriter::rewrite1(func_decl * f, expr_ref_vector & m_new_args, expr_ref & np) { fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f); if (it != m_fwd_idx.end()) { TRACE("demodulator_bug", tout << "trying to rewrite: " << f->get_name() << " args:\n"; @@ -294,7 +294,7 @@ bool ufbv_rewriter::rewrite1(func_decl * f, expr_ref_vector & m_new_args, expr_r return false; } -bool ufbv_rewriter::rewrite_visit_children(app * a) { +bool demodulator_rewriter::rewrite_visit_children(app * a) { bool res=true; unsigned j = a->get_num_args(); while (j > 0) { @@ -327,11 +327,11 @@ bool ufbv_rewriter::rewrite_visit_children(app * a) { return res; } -void ufbv_rewriter::rewrite_cache(expr * e, expr * new_e, bool done) { +void demodulator_rewriter::rewrite_cache(expr * e, expr * new_e, bool done) { m_rewrite_cache.insert(e, expr_bool_pair(new_e, done)); } -expr * ufbv_rewriter::rewrite(expr * n) { +expr * demodulator_rewriter::rewrite(expr * n) { if (m_fwd_idx.empty()) return n; @@ -441,7 +441,7 @@ expr * ufbv_rewriter::rewrite(expr * n) { return r; } -class ufbv_rewriter::add_back_idx_proc { +class demodulator_rewriter::add_back_idx_proc { back_idx_map & m_back_idx; expr * m_expr; public: @@ -467,7 +467,7 @@ public: } }; -class ufbv_rewriter::remove_back_idx_proc { +class demodulator_rewriter::remove_back_idx_proc { back_idx_map & m_back_idx; expr * m_expr; public: @@ -488,7 +488,7 @@ public: } }; -void ufbv_rewriter::reschedule_processed(func_decl * f) { +void demodulator_rewriter::reschedule_processed(func_decl * f) { //use m_back_idx to find all formulas p in m_processed that contains f { back_idx_map::iterator it = m_back_idx.find_iterator(f); if (it != m_back_idx.end()) { @@ -511,7 +511,7 @@ void ufbv_rewriter::reschedule_processed(func_decl * f) { } } -bool ufbv_rewriter::can_rewrite(expr * n, expr * lhs) { +bool demodulator_rewriter::can_rewrite(expr * n, expr * lhs) { // this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'. // we cannot use the trick used for m_processed, since the main loop would not terminate. @@ -568,7 +568,7 @@ bool ufbv_rewriter::can_rewrite(expr * n, expr * lhs) { return false; } -void ufbv_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { +void demodulator_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { // use m_back_idx to find all demodulators d in m_fwd_idx that contains f { //ptr_vector to_remove; @@ -616,7 +616,7 @@ void ufbv_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { } } -void ufbv_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * prs, +void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { if (m.proofs_enabled()) { TRACE("tactic", tout << "PRE_DEMODULATOR=true is not supported when proofs are enabled.";); @@ -710,7 +710,7 @@ void ufbv_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * } -ufbv_rewriter::match_subst::match_subst(ast_manager & m): +demodulator_rewriter::match_subst::match_subst(ast_manager & m): m(m), m_subst(m) { } @@ -742,7 +742,7 @@ struct match_args_aux_proc { void operator()(app * n) {} }; -bool ufbv_rewriter::match_subst::match_args(app * lhs, expr * const * args) { +bool demodulator_rewriter::match_subst::match_args(app * lhs, expr * const * args) { m_cache.reset(); m_todo.reset(); @@ -858,7 +858,7 @@ bool ufbv_rewriter::match_subst::match_args(app * lhs, expr * const * args) { } -bool ufbv_rewriter::match_subst::operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs) { +bool demodulator_rewriter::match_subst::operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs) { if (match_args(lhs, args)) { if (m_all_args_eq) { @@ -873,7 +873,7 @@ bool ufbv_rewriter::match_subst::operator()(app * lhs, expr * rhs, expr * const return false; } -bool ufbv_rewriter::match_subst::operator()(expr * t, expr * i) { +bool demodulator_rewriter::match_subst::operator()(expr * t, expr * i) { m_cache.reset(); m_todo.reset(); if (is_var(t)) diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/ast/rewriter/demodulator_rewriter.h similarity index 97% rename from src/tactic/ufbv/ufbv_rewriter.h rename to src/ast/rewriter/demodulator_rewriter.h index d855047a0..a60debabf 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/ast/rewriter/demodulator_rewriter.h @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - demodulator.h + demodulator_rewriter.h Abstract: @@ -16,6 +16,7 @@ Author: Revision History: Christoph M. Wintersteiger (cwinter) 2012-10-24: Moved from demodulator.h to ufbv_rewriter.h + Nikolaj Bjorner (nbjorner) 2022-12-4: Moved to rewriter and renamed to demodulator_rewriter.h --*/ #pragma once @@ -91,7 +92,7 @@ The code in spc_rewriter.* does something like that. We cannot reuse this code d for the superposion engine in Z3, but we can adapt it for our needs in the preprocessor. */ -class ufbv_rewriter final { +class demodulator_rewriter final { class rewrite_proc; class add_back_idx_proc; class remove_back_idx_proc; @@ -193,8 +194,8 @@ class ufbv_rewriter final { int is_subset(expr * e1, expr * e2) const; public: - ufbv_rewriter(ast_manager & m); - ~ufbv_rewriter(); + demodulator_rewriter(ast_manager & m); + ~demodulator_rewriter(); void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); diff --git a/src/tactic/ufbv/CMakeLists.txt b/src/tactic/ufbv/CMakeLists.txt index 511dc2b2d..2c2567b91 100644 --- a/src/tactic/ufbv/CMakeLists.txt +++ b/src/tactic/ufbv/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(ufbv_tactic SOURCES macro_finder_tactic.cpp quasi_macros_tactic.cpp - ufbv_rewriter.cpp ufbv_rewriter_tactic.cpp ufbv_tactic.cpp COMPONENT_DEPENDENCIES diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index e254523c0..46958982a 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -17,21 +17,21 @@ Notes: --*/ #include "tactic/tactical.h" -#include "tactic/ufbv/ufbv_rewriter.h" +#include "ast/rewriter/demodulator_rewriter.h" #include "tactic/ufbv/ufbv_rewriter_tactic.h" -class ufbv_rewriter_tactic : public tactic { +class demodulator_rewriter_tactic : public tactic { ast_manager & m_manager; params_ref m_params; public: - ufbv_rewriter_tactic(ast_manager & m, params_ref const & p): + demodulator_rewriter_tactic(ast_manager & m, params_ref const & p): m_manager(m), m_params(p) {} char const* name() const override { return "ufbv"; } tactic * translate(ast_manager & m) override { - return alloc(ufbv_rewriter_tactic, m, m_params); + return alloc(demodulator_rewriter_tactic, m, m_params); } void updt_params(params_ref const & p) override { @@ -50,7 +50,7 @@ public: bool produce_proofs = g->proofs_enabled(); - ufbv_rewriter dem(m_manager); + demodulator_rewriter dem(m_manager); expr_ref_vector forms(m_manager), new_forms(m_manager); proof_ref_vector proofs(m_manager), new_proofs(m_manager); @@ -79,5 +79,5 @@ public: }; tactic * mk_ufbv_rewriter_tactic(ast_manager & m, params_ref const & p) { - return alloc(ufbv_rewriter_tactic, m, p); + return alloc(demodulator_rewriter_tactic, m, p); } From d218083145db789b709c57d583b8b48f17267ab6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 04:48:48 -0800 Subject: [PATCH 366/477] The demodulator doesn't produce proofs so remove code path that depends it does. --- src/ast/rewriter/demodulator_rewriter.cpp | 11 ++--------- src/ast/rewriter/demodulator_rewriter.h | 2 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 10 ++++++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/ast/rewriter/demodulator_rewriter.cpp b/src/ast/rewriter/demodulator_rewriter.cpp index 8a6911925..56be99529 100644 --- a/src/ast/rewriter/demodulator_rewriter.cpp +++ b/src/ast/rewriter/demodulator_rewriter.cpp @@ -616,15 +616,8 @@ void demodulator_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { } } -void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * prs, - expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { - if (m.proofs_enabled()) { - TRACE("tactic", tout << "PRE_DEMODULATOR=true is not supported when proofs are enabled.";); - // Let us not waste time with proof production - new_exprs.append(n, exprs); - new_prs.append(n, prs); - return; - } +void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, + expr_ref_vector & new_exprs) { TRACE("demodulator", tout << "before demodulator:\n"; for ( unsigned i = 0 ; i < n ; i++ ) diff --git a/src/ast/rewriter/demodulator_rewriter.h b/src/ast/rewriter/demodulator_rewriter.h index a60debabf..90d15bcec 100644 --- a/src/ast/rewriter/demodulator_rewriter.h +++ b/src/ast/rewriter/demodulator_rewriter.h @@ -197,7 +197,7 @@ public: demodulator_rewriter(ast_manager & m); ~demodulator_rewriter(); - void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + void operator()(unsigned n, expr * const * exprs, expr_ref_vector & new_exprs); /** Given a demodulator (aka rewrite rule) of the form diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index 46958982a..f8f3153c5 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -41,14 +41,16 @@ public: void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_produce_models(r); - insert_produce_proofs(r); } void operator()(goal_ref const & g, goal_ref_buffer & result) override { tactic_report report("ufbv-rewriter", *g); fail_if_unsat_core_generation("ufbv-rewriter", g); - bool produce_proofs = g->proofs_enabled(); + if (g->proofs_enabled()) { + result.push_back(g.get()); + return; + } demodulator_rewriter dem(m_manager); @@ -61,11 +63,11 @@ public: proofs.push_back(g->pr(i)); } - dem(forms.size(), forms.data(), proofs.data(), new_forms, new_proofs); + dem(forms.size(), forms.data(), new_forms); g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) - g->assert_expr(new_forms.get(i), produce_proofs ? new_proofs.get(i) : nullptr, nullptr); + g->assert_expr(new_forms.get(i), nullptr, nullptr); // CMW: Remark: The demodulator could potentially // remove all references to a variable. From 3d7bd40a87cee19d8b1135b3352a86b91f006a98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 06:07:45 -0800 Subject: [PATCH 367/477] a round of cleanup --- src/ast/rewriter/demodulator_rewriter.cpp | 319 ++++++++++------------ src/ast/rewriter/demodulator_rewriter.h | 13 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 7 +- 3 files changed, 150 insertions(+), 189 deletions(-) diff --git a/src/ast/rewriter/demodulator_rewriter.cpp b/src/ast/rewriter/demodulator_rewriter.cpp index 56be99529..f1fc6f969 100644 --- a/src/ast/rewriter/demodulator_rewriter.cpp +++ b/src/ast/rewriter/demodulator_rewriter.cpp @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - demodulator.cpp + demodulator_rewriter.cpp Abstract: @@ -17,6 +17,7 @@ Revision History: Christoph M. Wintersteiger (cwinter) 2010-04-21: Implementation Christoph M. Wintersteiger (cwinter) 2012-10-24: Moved from demodulator.h to ufbv_rewriter.h + Nikolaj Bjorner (nbjorner) 2022-12-4: Moved to demodulator_rewriter.h --*/ @@ -186,48 +187,45 @@ public: unsigned get_max() { return m_max_var_id; } }; -unsigned demodulator_rewriter::max_var_id(expr * e) -{ +unsigned demodulator_rewriter::max_var_id(expr_ref_vector const& es) { max_var_id_proc proc; - for_each_expr(proc, e); + for (expr* e : es) + for_each_expr(proc, e); return proc.get_max(); } -void demodulator_rewriter::insert_fwd_idx(expr * large, expr * small, quantifier * demodulator) { - SASSERT(large->get_kind() == AST_APP); +void demodulator_rewriter::insert_fwd_idx(app * large, expr * small, quantifier * demodulator) { SASSERT(demodulator); SASSERT(large && small); TRACE("demodulator_fwd", tout << "INSERT: " << mk_pp(demodulator, m) << std::endl; ); func_decl * fd = to_app(large)->get_decl(); - fwd_idx_map::iterator it = m_fwd_idx.find_iterator(fd); - if (it == m_fwd_idx.end()) { - quantifier_set * qs = alloc(quantifier_set, 1); + quantifier_set * qs; + if (!m_fwd_idx.find(fd, qs)) { + qs = alloc(quantifier_set, 1); m_fwd_idx.insert(fd, qs); - it = m_fwd_idx.find_iterator(fd); } - SASSERT(it->m_value); - it->m_value->insert(demodulator); + SASSERT(qs); + qs->insert(demodulator); m.inc_ref(demodulator); m.inc_ref(large); m.inc_ref(small); - m_demodulator2lhs_rhs.insert(demodulator, expr_pair(large, small)); + m_demodulator2lhs_rhs.insert(demodulator, app_expr_pair(large, small)); } void demodulator_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulator) { TRACE("demodulator_fwd", tout << "REMOVE: " << std::hex << (size_t)demodulator << std::endl; ); - fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f); - if (it != m_fwd_idx.end()) { - demodulator2lhs_rhs::iterator fit = m_demodulator2lhs_rhs.find_iterator(demodulator); - expr_pair p = fit->m_value; + quantifier_set* qs; + if (m_fwd_idx.find(f, qs)) { + auto [lhs, rhs] = m_demodulator2lhs_rhs[demodulator]; m_demodulator2lhs_rhs.erase(demodulator); - it->m_value->erase(demodulator); - m.dec_ref(p.first); - m.dec_ref(p.second); + qs->erase(demodulator); + m.dec_ref(lhs); + m.dec_ref(rhs); m.dec_ref(demodulator); } else { SASSERT(m_demodulator2lhs_rhs.contains(demodulator)); @@ -235,59 +233,50 @@ void demodulator_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulato } bool demodulator_rewriter::check_fwd_idx_consistency() { - for (auto & kv : m_fwd_idx) { - quantifier_set * set = kv.m_value; + for (auto & [k, set] : m_fwd_idx) { SASSERT(set); - for (auto e : *set) { + for (auto e : *set) if (!m_demodulator2lhs_rhs.contains(e)) return false; - } } - return true; } void demodulator_rewriter::show_fwd_idx(std::ostream & out) { - for (auto & kv : m_fwd_idx) { - quantifier_set * set = kv.m_value; - SASSERT(!set); - - out << kv.m_key->get_name() << ": " << std::endl; - - for (auto e : *set) { - out << std::hex << (size_t)e << std::endl; - } + for (auto & [k, set] : m_fwd_idx) { + out << k->get_name() << ": " << std::endl; + if (set) + for (auto e : *set) + out << std::hex << (size_t)e << std::endl; } out << "D2LR: " << std::endl; - for (auto & kv : m_demodulator2lhs_rhs) { - out << (size_t) kv.m_key << std::endl; + for (auto & [k, v] : m_demodulator2lhs_rhs) { + out << (size_t) k << std::endl; } } -bool demodulator_rewriter::rewrite1(func_decl * f, expr_ref_vector & m_new_args, expr_ref & np) { - fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f); - if (it != m_fwd_idx.end()) { - TRACE("demodulator_bug", tout << "trying to rewrite: " << f->get_name() << " args:\n"; - tout << m_new_args << "\n";); - for (quantifier* d : *it->m_value) { +bool demodulator_rewriter::rewrite1(func_decl * f, expr_ref_vector const & args, expr_ref & np) { + quantifier_set* set; + if (!m_fwd_idx.find(f, set)) + return false; + TRACE("demodulator_bug", tout << "trying to rewrite: " << f->get_name() << " args:\n"; + tout << m_new_args << "\n";); - SASSERT(m_demodulator2lhs_rhs.contains(d)); - expr_pair l_s; - m_demodulator2lhs_rhs.find(d, l_s); - app * large = to_app(l_s.first); + for (quantifier* d : *set) { - if (large->get_num_args() != m_new_args.size()) - continue; - - TRACE("demodulator_bug", tout << "Matching with demodulator: " << mk_pp(d, m) << std::endl; ); - - SASSERT(large->get_decl() == f); - - if (m_match_subst(large, l_s.second, m_new_args.data(), np)) { - TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(l_s.second, m) << "\n===>\n" << mk_pp(np, m) << "\n";); - return true; - } + auto const& [large, rhs] = m_demodulator2lhs_rhs[d]; + + if (large->get_num_args() != args.size()) + continue; + + TRACE("demodulator_bug", tout << "Matching with demodulator: " << mk_pp(d, m) << std::endl; ); + + SASSERT(large->get_decl() == f); + + if (m_match_subst(large, rhs, args.data(), np)) { + TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << mk_pp(np, m) << "\n";); + return true; } } @@ -449,21 +438,19 @@ public: void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app * n) { - // We track only uninterpreted and constant functions. - if (n->get_num_args()==0) return; + // We track only uninterpreted functions. + if (n->get_num_args() == 0) + return; SASSERT(m_expr && m_expr != (expr*) 0x00000003); - func_decl * d=n->get_decl(); - if (d->get_family_id() == null_family_id) { - back_idx_map::iterator it = m_back_idx.find_iterator(d); - if (it != m_back_idx.end()) { - SASSERT(it->m_value); - it->m_value->insert(m_expr); - } else { - expr_set * e = alloc(expr_set); - e->insert(m_expr); - m_back_idx.insert(d, e); - } + func_decl * d = n->get_decl(); + if (d->get_family_id() != null_family_id) + return; + expr_set* set = nullptr; + if (!m_back_idx.find(d, set)) { + set = alloc(expr_set); + m_back_idx.insert(d, set); } + set->insert(m_expr); } }; @@ -475,39 +462,48 @@ public: void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app * n) { - // We track only uninterpreted and constant functions. - if (n->get_num_args()==0) return; - func_decl * d=n->get_decl(); - if (d->get_family_id() == null_family_id) { - back_idx_map::iterator it = m_back_idx.find_iterator(d); - if (it != m_back_idx.end()) { - SASSERT(it->m_value); - it->m_value->remove(m_expr); - } - } + // We track only uninterpreted functions. + if (n->get_num_args() == 0) + return; + func_decl * d = n->get_decl(); + if (d->get_family_id() != null_family_id) + return; + expr_set* set = nullptr; + if (m_back_idx.find(d, set)) + set->remove(m_expr); } }; + +void demodulator_rewriter::insert_bwd_idx(expr* e) { + add_back_idx_proc proc(m_back_idx, e); + for_each_expr(proc, e); +} + +void demodulator_rewriter::remove_bwd_idx(expr* e) { + remove_back_idx_proc proc(m_back_idx, e); + for_each_expr(proc, e); +} + void demodulator_rewriter::reschedule_processed(func_decl * f) { //use m_back_idx to find all formulas p in m_processed that contains f { - back_idx_map::iterator it = m_back_idx.find_iterator(f); - if (it != m_back_idx.end()) { - SASSERT(it->m_value); - expr_set temp; + expr_set* set = nullptr; + if (!m_back_idx.find(f, set)) + return; + SASSERT(set); + expr_set temp; - for (expr* p : *it->m_value) { - if (m_processed.contains(p)) + for (expr* p : *set) + if (m_processed.contains(p)) temp.insert(p); - } - for (expr * p : temp) { - // remove p from m_processed and m_back_idx - m_processed.remove(p); - remove_back_idx_proc proc(m_back_idx, p); // this could change it->m_value, thus we need the `temp' set. - for_each_expr(proc, p); - // insert p into m_todo - m_todo.push_back(p); - } + for (expr * p : temp) { + // remove p from m_processed and m_back_idx + m_processed.remove(p); + // this could change `set', thus we need the `temp' set. + remove_bwd_idx(p); + // insert p into m_todo + m_todo.push_back(p); } } @@ -545,20 +541,10 @@ bool demodulator_rewriter::can_rewrite(expr * n, expr * lhs) { break; case AST_QUANTIFIER: - if (!for_each_expr_args(stack, visited, to_quantifier(curr)->get_num_patterns(), - to_quantifier(curr)->get_patterns())) { - break; - } - if (!for_each_expr_args(stack, visited, to_quantifier(curr)->get_num_no_patterns(), - to_quantifier(curr)->get_no_patterns())) { - break; - } - if (!visited.is_marked(to_quantifier(curr)->get_expr())) { + if (visited.is_marked(to_quantifier(curr)->get_expr())) + stack.pop_back(); + else stack.push_back(to_quantifier(curr)->get_expr()); - break; - } - - stack.pop_back(); break; default: UNREACHABLE(); @@ -571,66 +557,55 @@ bool demodulator_rewriter::can_rewrite(expr * n, expr * lhs) { void demodulator_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { // use m_back_idx to find all demodulators d in m_fwd_idx that contains f { - //ptr_vector to_remove; - back_idx_map::iterator it = m_back_idx.find_iterator(f); - if (it != m_back_idx.end()) { - SASSERT(it->m_value); - expr_set all_occurrences; - expr_ref l(m); + expr_set* set = nullptr; + if (!m_back_idx.find(f, set)) + return; + SASSERT(set); + expr_set all_occurrences; + app_ref l(m); - for (auto s : *it->m_value) - all_occurrences.insert(s); + for (auto s : *set) + all_occurrences.insert(s); + + // Run over all f-demodulators + for (expr* occ : all_occurrences) { + + if (!is_quantifier(occ)) + continue; + quantifier* qe = to_quantifier(occ); + + // Use the fwd idx to find out whether this is a demodulator. + app_expr_pair p; + if (!m_demodulator2lhs_rhs.find(qe, p)) + continue; - // Run over all f-demodulators - for (expr* occ : all_occurrences) { + l = p.first; + quantifier_ref d(qe, m); + func_decl_ref df(l->get_decl(), m); + + // Now we know there is an occurrence of f in d + if (!can_rewrite(d, lhs)) + continue; - if (!is_quantifier(occ)) - continue; + TRACE("demodulator", tout << "Rescheduling: " << std::endl << mk_pp(d, m) << std::endl); - // Use the fwd idx to find out whether this is a demodulator. - demodulator2lhs_rhs::iterator d2lr_it = m_demodulator2lhs_rhs.find_iterator(to_quantifier(occ)); - if (d2lr_it != m_demodulator2lhs_rhs.end()) { - l = d2lr_it->m_value.first; - quantifier_ref d(m); - func_decl_ref df(m); - d = to_quantifier(occ); - df = to_app(l)->get_decl(); - - // Now we know there is an occurrence of f in d - // if n' can rewrite d { - if (can_rewrite(d, lhs)) { - TRACE("demodulator", tout << "Rescheduling: " << std::endl << mk_pp(d, m) << std::endl; ); - // remove d from m_fwd_idx - remove_fwd_idx(df, d); - // remove d from m_back_idx - // just remember it here, because otherwise it and/or esit might become invalid? - // to_remove.insert(d); - remove_back_idx_proc proc(m_back_idx, d); - for_each_expr(proc, d); - // insert d into m_todo - m_todo.push_back(d); - } - } - } + remove_fwd_idx(df, d); + remove_bwd_idx(d); + m_todo.push_back(d); } } -void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, - expr_ref_vector & new_exprs) { +void demodulator_rewriter::operator()(expr_ref_vector const& exprs, + expr_ref_vector & new_exprs) { - TRACE("demodulator", tout << "before demodulator:\n"; - for ( unsigned i = 0 ; i < n ; i++ ) - tout << mk_pp(exprs[i], m) << std::endl; ); + TRACE("demodulator", tout << "before demodulator:\n" << exprs); // Initially, m_todo contains all formulas. That is, it contains the argument exprs. m_fwd_idx, m_processed, m_back_idx are empty. - unsigned max_vid = 0; - for ( unsigned i = 0 ; i < n ; i++ ) { - m_todo.push_back(exprs[i]); - max_vid = std::max(max_vid, max_var_id(exprs[i])); - } + for (expr* e : exprs) + m_todo.push_back(e); - m_match_subst.reserve(max_vid); + m_match_subst.reserve(max_var_id(exprs)); while (!m_todo.empty()) { // let n be the next formula in m_todo. @@ -644,7 +619,6 @@ void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, // unless there is a demodulator cycle // SASSERT(rewrite(np)==np); - // if (n' is not a demodulator) { app_ref large(m); expr_ref small(m); if (!is_demodulator(np, large, small)) { @@ -652,22 +626,11 @@ void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, m_processed.insert(np); m_in_processed.push_back(np); // update m_back_idx (traverse n' and for each uninterpreted function declaration f in n' add the entry f->n' to m_back_idx) - add_back_idx_proc proc(m_back_idx, np); - for_each_expr(proc, np); - } else { + insert_bwd_idx(np); + } + else { // np is a demodulator that allows us to replace 'large' with 'small'. - TRACE("demodulator", tout << "Found demodulator: " << std::endl; - tout << mk_pp(large.get(), m) << std::endl << " ---> " << - std::endl << mk_pp(small.get(), m) << std::endl; ); - - TRACE("demodulator_s", tout << "Found demodulator: " << std::endl; - tout << to_app(large)->get_decl()->get_name() << - "[" << to_app(large)->get_depth() << "]" << " ---> "; - if (is_app(small)) - tout << to_app(small)->get_decl()->get_name() << - "[" << to_app(small)->get_depth() << "]" << std::endl; - else - tout << mk_pp(small.get(), m) << std::endl; ); + TRACE("demodulator", tout << "Found demodulator:\n" << large << "\n ---> " << small << "\n"); // let f be the top symbol of n' func_decl * f = large->get_decl(); @@ -679,8 +642,7 @@ void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, insert_fwd_idx(large, small, to_quantifier(np)); // update m_back_idx - add_back_idx_proc proc(m_back_idx, np); - for_each_expr(proc, np); + insert_bwd_idx(np); } } @@ -690,12 +652,11 @@ void demodulator_rewriter::operator()(unsigned n, expr * const * exprs, TRACE("demodulator", tout << mk_pp(e, m) << std::endl; ); } - for (auto const& kv : m_fwd_idx) { - if (kv.m_value) { - for (expr* e : *kv.m_value) { + for (auto const& [k, set] : m_fwd_idx) { + if (set) { + for (expr* e : *set) new_exprs.push_back(e); - TRACE("demodulator", tout << mk_pp(e, m) << std::endl; ); - } + TRACE("demodulator", for (expr* e : *set) tout << mk_pp(e, m) << std::endl; ); } } diff --git a/src/ast/rewriter/demodulator_rewriter.h b/src/ast/rewriter/demodulator_rewriter.h index 90d15bcec..2152520ce 100644 --- a/src/ast/rewriter/demodulator_rewriter.h +++ b/src/ast/rewriter/demodulator_rewriter.h @@ -111,11 +111,12 @@ class demodulator_rewriter final { typedef array_map expr_map; typedef std::pair expr_pair; + typedef std::pair app_expr_pair; typedef obj_hashtable expr_set; typedef obj_map back_idx_map; typedef obj_hashtable quantifier_set; typedef obj_map fwd_idx_map; - typedef obj_map demodulator2lhs_rhs; + typedef obj_map demodulator2lhs_rhs; typedef expr_map rewrite_cache_map; /** @@ -172,20 +173,22 @@ class demodulator_rewriter final { rewrite_cache_map m_rewrite_cache; expr_ref_buffer m_new_exprs; - void insert_fwd_idx(expr * large, expr * small, quantifier * demodulator); + void insert_fwd_idx(app * large, expr * small, quantifier * demodulator); void remove_fwd_idx(func_decl * f, quantifier * demodulator); + void insert_bwd_idx(expr* q); + void remove_bwd_idx(expr* q); bool check_fwd_idx_consistency(); void show_fwd_idx(std::ostream & out); bool is_demodulator(expr * e, app_ref & large, expr_ref & small) const; bool can_rewrite(expr * n, expr * lhs); expr * rewrite(expr * n); - bool rewrite1(func_decl * f, expr_ref_vector & m_new_args, expr_ref & np); + bool rewrite1(func_decl * f, expr_ref_vector const & args, expr_ref & np); bool rewrite_visit_children(app * a); void rewrite_cache(expr * e, expr * new_e, bool done); void reschedule_processed(func_decl * f); void reschedule_demodulators(func_decl * f, expr * np); - unsigned max_var_id(expr * e); + unsigned max_var_id(expr_ref_vector const& es); // is_smaller returns -1 for e1e2. int is_smaller(expr * e1, expr * e2) const; @@ -197,7 +200,7 @@ public: demodulator_rewriter(ast_manager & m); ~demodulator_rewriter(); - void operator()(unsigned n, expr * const * exprs, expr_ref_vector & new_exprs); + void operator()(expr_ref_vector const& exprs, expr_ref_vector & new_exprs); /** Given a demodulator (aka rewrite rule) of the form diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index f8f3153c5..f374ea114 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -55,15 +55,12 @@ public: demodulator_rewriter dem(m_manager); expr_ref_vector forms(m_manager), new_forms(m_manager); - proof_ref_vector proofs(m_manager), new_proofs(m_manager); unsigned size = g->size(); - for (unsigned i = 0; i < size; i++) { + for (unsigned i = 0; i < size; i++) forms.push_back(g->form(i)); - proofs.push_back(g->pr(i)); - } - dem(forms.size(), forms.data(), new_forms); + dem(forms, new_forms); g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) From 9acbfa392361e785365498cfe18e3276d8fa10fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 06:23:32 -0800 Subject: [PATCH 368/477] move it into substitution to handle dependencies --- src/ast/rewriter/CMakeLists.txt | 1 - src/ast/substitution/CMakeLists.txt | 1 + .../demodulator_rewriter.cpp | 51 +++++++++---------- .../demodulator_rewriter.h | 0 src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 8 +-- 5 files changed, 29 insertions(+), 32 deletions(-) rename src/ast/{rewriter => substitution}/demodulator_rewriter.cpp (95%) rename src/ast/{rewriter => substitution}/demodulator_rewriter.h (100%) diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 9eef651c8..c785804c1 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -11,7 +11,6 @@ z3_add_component(rewriter cached_var_subst.cpp char_rewriter.cpp datatype_rewriter.cpp - demodulator_rewriter.cpp der.cpp distribute_forall.cpp dl_rewriter.cpp diff --git a/src/ast/substitution/CMakeLists.txt b/src/ast/substitution/CMakeLists.txt index 80e12c995..8dbf2c9e3 100644 --- a/src/ast/substitution/CMakeLists.txt +++ b/src/ast/substitution/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(substitution SOURCES + demodulator_rewriter.cpp matcher.cpp substitution.cpp substitution_tree.cpp diff --git a/src/ast/rewriter/demodulator_rewriter.cpp b/src/ast/substitution/demodulator_rewriter.cpp similarity index 95% rename from src/ast/rewriter/demodulator_rewriter.cpp rename to src/ast/substitution/demodulator_rewriter.cpp index f1fc6f969..6e79242e0 100644 --- a/src/ast/rewriter/demodulator_rewriter.cpp +++ b/src/ast/substitution/demodulator_rewriter.cpp @@ -25,7 +25,7 @@ Revision History: #include "ast/ast_pp.h" #include "ast/for_each_expr.h" #include "ast/rewriter/var_subst.h" -#include "ast/rewriter/demodulator_rewriter.h" +#include "ast/substitution/demodulator_rewriter.h" demodulator_rewriter::demodulator_rewriter(ast_manager & m): m(m), @@ -284,34 +284,31 @@ bool demodulator_rewriter::rewrite1(func_decl * f, expr_ref_vector const & args, } bool demodulator_rewriter::rewrite_visit_children(app * a) { - bool res=true; - unsigned j = a->get_num_args(); - while (j > 0) { - expr * e = a->get_arg(--j); - if (!m_rewrite_cache.contains(e) || !m_rewrite_cache.get(e).second) { - bool recursive = false; - unsigned sz = m_rewrite_todo.size(); - expr * v = e; - if (m_rewrite_cache.contains(e)) { - expr_bool_pair const & ebp = m_rewrite_cache.get(e); - if (ebp.second) { - v = ebp.first; - } - } - for (unsigned i = sz; i-- > 0;) { - if (m_rewrite_todo[i] == v) { - recursive = true; - TRACE("demodulator", tout << "Detected demodulator cycle: " << - mk_pp(a, m) << " --> " << mk_pp(v, m) << std::endl;); - rewrite_cache(e, v, true); - break; - } - } - if (!recursive) { - m_rewrite_todo.push_back(e); - res = false; + bool res = true; + for (expr* e : *a) { + if (m_rewrite_cache.contains(e) && m_rewrite_cache.get(e).second) + continue; + bool recursive = false; + unsigned sz = m_rewrite_todo.size(); + expr * v = e; + if (m_rewrite_cache.contains(e)) { + expr_bool_pair const & ebp = m_rewrite_cache.get(e); + if (ebp.second) + v = ebp.first; + } + for (unsigned i = sz; i-- > 0;) { + if (m_rewrite_todo[i] == v) { + recursive = true; + TRACE("demodulator", tout << "Detected demodulator cycle: " << + mk_pp(a, m) << " --> " << mk_pp(v, m) << std::endl;); + rewrite_cache(e, v, true); + break; } } + if (!recursive) { + m_rewrite_todo.push_back(e); + res = false; + } } return res; } diff --git a/src/ast/rewriter/demodulator_rewriter.h b/src/ast/substitution/demodulator_rewriter.h similarity index 100% rename from src/ast/rewriter/demodulator_rewriter.h rename to src/ast/substitution/demodulator_rewriter.h diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index f374ea114..66d377491 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -17,7 +17,7 @@ Notes: --*/ #include "tactic/tactical.h" -#include "ast/rewriter/demodulator_rewriter.h" +#include "ast/substitution/demodulator_rewriter.h" #include "tactic/ufbv/ufbv_rewriter_tactic.h" class demodulator_rewriter_tactic : public tactic { @@ -28,7 +28,7 @@ public: demodulator_rewriter_tactic(ast_manager & m, params_ref const & p): m_manager(m), m_params(p) {} - char const* name() const override { return "ufbv"; } + char const* name() const override { return "ufbv-rewriter"; } tactic * translate(ast_manager & m) override { return alloc(demodulator_rewriter_tactic, m, m_params); @@ -63,8 +63,8 @@ public: dem(forms, new_forms); g->reset(); - for (unsigned i = 0; i < new_forms.size(); i++) - g->assert_expr(new_forms.get(i), nullptr, nullptr); + for (expr* fml : new_forms) + g->assert_expr(fml, nullptr, nullptr); // CMW: Remark: The demodulator could potentially // remove all references to a variable. From 1974c224ab74fb7957afba04fc3f13649a8929e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 09:39:28 -0800 Subject: [PATCH 369/477] add demodulator simplifier refactor demodulator-rewriter a bit to separate reusable features. --- scripts/mk_project.py | 2 +- src/CMakeLists.txt | 2 +- src/ast/rewriter/th_rewriter.h | 1 + src/ast/simplifiers/CMakeLists.txt | 2 + .../simplifiers/demodulator_simplifier.cpp | 199 +++++++++ src/ast/simplifiers/demodulator_simplifier.h | 60 +++ src/ast/substitution/demodulator_rewriter.cpp | 377 +++++++++++++----- src/ast/substitution/demodulator_rewriter.h | 136 ++++--- 8 files changed, 624 insertions(+), 155 deletions(-) create mode 100644 src/ast/simplifiers/demodulator_simplifier.cpp create mode 100644 src/ast/simplifiers/demodulator_simplifier.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index a979359f3..a16913317 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -39,7 +39,7 @@ def init_project_def(): add_lib('macros', ['rewriter'], 'ast/macros') add_lib('model', ['macros']) add_lib('converters', ['model'], 'ast/converters') - add_lib('simplifiers', ['euf', 'normal_forms', 'bit_blaster', 'converters'], 'ast/simplifiers') + add_lib('simplifiers', ['euf', 'normal_forms', 'bit_blaster', 'converters', 'substitution'], 'ast/simplifiers') add_lib('tactic', ['simplifiers']) add_lib('solver', ['params', 'model', 'tactic', 'proofs']) add_lib('cmd_context', ['solver', 'rewriter', 'params']) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dadd70bba..652aef4ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,9 +52,9 @@ add_subdirectory(ast/macros) add_subdirectory(model) add_subdirectory(ast/euf) add_subdirectory(ast/converters) +add_subdirectory(ast/substitution) add_subdirectory(ast/simplifiers) add_subdirectory(tactic) -add_subdirectory(ast/substitution) add_subdirectory(smt/params) add_subdirectory(parsers/util) add_subdirectory(math/grobner) diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index a3f003799..71c39b18e 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -52,6 +52,7 @@ public: expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args); expr_ref mk_app(func_decl* f, ptr_vector const& args) { return mk_app(f, args.size(), args.data()); } + expr_ref mk_app(func_decl* f, expr_ref_vector const& args) { return mk_app(f, args.size(), args.data()); } expr_ref mk_eq(expr* a, expr* b); bool reduce_quantifier(quantifier * old_q, diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index c6a8469ee..df44427cf 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(simplifiers bit_blaster.cpp bv_slice.cpp card2bv.cpp + demodulator_simplifier.cpp dependent_expr_state.cpp elim_unconstrained.cpp eliminate_predicates.cpp @@ -18,4 +19,5 @@ z3_add_component(simplifiers rewriter bit_blaster normal_forms + substitution ) diff --git a/src/ast/simplifiers/demodulator_simplifier.cpp b/src/ast/simplifiers/demodulator_simplifier.cpp new file mode 100644 index 000000000..eb3585606 --- /dev/null +++ b/src/ast/simplifiers/demodulator_simplifier.cpp @@ -0,0 +1,199 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + demodulator_simplifier.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2022-12-4 + +--*/ + +#include "ast/simplifiers/demodulator_simplifier.h" + +demodulator_index::~demodulator_index() { + reset(); +} + +void demodulator_index::reset() { + for (auto& [k, v] : m_fwd_index) + dealloc(v); + for (auto& [k, v] : m_bwd_index) + dealloc(v); + m_fwd_index.reset(); + m_bwd_index.reset(); +} + +void demodulator_index::add(func_decl* f, unsigned i, obj_map& map) { + uint_set* s; + if (!map.find(f, s)) { + s = alloc(uint_set); + map.insert(f, s); + } + s->insert(i); +} + +void demodulator_index::del(func_decl* f, unsigned i, obj_map& map) { + uint_set* s; + if (map.find(f, s)) + s->remove(i); +} + +void demodulator_index::insert_bwd(expr* e, unsigned i) { + struct proc { + unsigned i; + demodulator_index& idx; + proc(unsigned i, demodulator_index& idx) :i(i), idx(idx) {} + void operator()(app* a) { + if (a->get_num_args() > 0 && is_uninterp(a)) + idx.add(a->get_decl(), i, idx.m_bwd_index); + } + void operator()(expr* e) {} + }; + proc p(i, *this); + for_each_expr(p, e); +} + +void demodulator_index::remove_bwd(expr* e, unsigned i) { + struct proc { + unsigned i; + demodulator_index& idx; + proc(unsigned i, demodulator_index& idx) :i(i), idx(idx) {} + void operator()(app* a) { + if (a->get_num_args() > 0 && is_uninterp(a)) + idx.del(a->get_decl(), i, idx.m_bwd_index); + } + void operator()(expr* e) {} + }; + proc p(i, *this); + for_each_expr(p, e); +} + +demodulator_simplifier::demodulator_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& st): + dependent_expr_simplifier(m, st), + m_util(m), + m_match_subst(m), + m_rewriter(m), + m_pinned(m) +{ + std::function rw = [&](func_decl* f, expr_ref_vector const& args, expr_ref& r) { + return rewrite1(f, args, r); + }; + m_rewriter.set_rewrite1(rw); +} + +void demodulator_simplifier::rewrite(unsigned i) { + if (m_index.empty()) + return; + + m_dependencies.reset(); + expr* f = fml(i); + expr_ref r = m_rewriter.rewrite(f); + if (r == f) + return; + expr_dependency_ref d(dep(i), m); + for (unsigned j : m_dependencies) + d = m.mk_join(d, dep(j)); + m_fmls.update(i, dependent_expr(m, r, d)); +} + +bool demodulator_simplifier::rewrite1(func_decl* f, expr_ref_vector const& args, expr_ref& np) { + uint_set* set; + if (!m_index.find_fwd(f, set)) + return false; + + TRACE("demodulator", tout << "trying to rewrite: " << f->get_name() << " args:\n" << m_new_args << "\n";); + + for (unsigned i : *set) { + + auto const& [lhs, rhs] = m_rewrites[i]; + + if (lhs->get_num_args() != args.size()) + continue; + + SASSERT(lhs->get_decl() == f); + + TRACE("demodulator", tout << "Matching with demodulator: " << mk_pp(d, m) << std::endl; ); + + if (m_match_subst(lhs, rhs, args.data(), np)) { + TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << np << "\n";); + m_dependencies.insert(i); + return true; + } + } + + return false; +} + +void demodulator_simplifier::reschedule_processed(func_decl* f) { + uint_set* set = nullptr; + if (!m_index.find_bwd(f, set)) + return; + uint_set tmp; + for (auto i : *set) + if (m_processed.contains(i)) + tmp.insert(i); + for (auto i : tmp) { + m_processed.remove(i); + m_index.remove_fwd(f, i); + m_index.remove_bwd(fml(i), i); + m_todo.push_back(i); + } +} + +void demodulator_simplifier::reschedule_demodulators(func_decl* f, expr* lhs) { + uint_set* set; + if (!m_index.find_bwd(f, set)) + return; + uint_set all_occurrences(*set); + for (unsigned i : all_occurrences) { + app_expr_pair p; + if (!m_rewrites.find(i, p)) + continue; + if (!m_match_subst.can_rewrite(fml(i), lhs)) + continue; + func_decl* f = p.first->get_decl(); + m_index.remove_fwd(f, i); + m_index.remove_bwd(fml(i), i); + m_todo.push_back(i); + } +} + +void demodulator_simplifier::reset() { + m_pinned.reset(); + m_index.reset(); + m_processed.reset(); + m_todo.reset(); + unsigned max_vid = 1; + for (unsigned i : indices()) + max_vid = std::max(max_vid, m_util.max_var_id(fml(i))); + m_match_subst.reserve(max_vid); +} + +void demodulator_simplifier::reduce() { + reset(); + for (unsigned i : indices()) + m_todo.push_back(i); + + app_ref large(m); + expr_ref small(m); + while (!m_todo.empty()) { + unsigned i = m_todo.back(); + m_todo.pop_back(); + rewrite(i); + if (m_util.is_demodulator(fml(i), large, small)) { + func_decl* f = large->get_decl(); + reschedule_processed(f); + reschedule_demodulators(f, large); + m_index.insert_fwd(f, i); + m_rewrites.insert(i, app_expr_pair(large, small)); + m_pinned.push_back(large); + m_pinned.push_back(small); + } + else + m_processed.insert(i); + m_index.insert_bwd(fml(i), i); + } +} diff --git a/src/ast/simplifiers/demodulator_simplifier.h b/src/ast/simplifiers/demodulator_simplifier.h new file mode 100644 index 000000000..e104c056b --- /dev/null +++ b/src/ast/simplifiers/demodulator_simplifier.h @@ -0,0 +1,60 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + demodulator_simplifier.h + +Author: + + Nikolaj Bjorner (nbjorner) 2022-12-4 + +--*/ + +#pragma once + +#include "ast/substitution/demodulator_rewriter.h" +#include "ast/simplifiers/dependent_expr_state.h" +#include "util/uint_set.h" + +class demodulator_index { + obj_map m_fwd_index, m_bwd_index; + void add(func_decl* f, unsigned i, obj_map& map); + void del(func_decl* f, unsigned i, obj_map& map); + public: + ~demodulator_index(); + void reset(); + void insert_fwd(func_decl* f, unsigned i) { add(f, i, m_fwd_index); } + void remove_fwd(func_decl* f, unsigned i) { del(f, i, m_fwd_index); } + void insert_bwd(expr* e, unsigned i); + void remove_bwd(expr* e, unsigned i); + bool find_fwd(func_decl* f, uint_set*& s) { return m_bwd_index.find(f, s); } + bool find_bwd(func_decl* f, uint_set*& s) { return m_fwd_index.find(f, s); } + bool empty() const { return m_fwd_index.empty(); } +}; + +class demodulator_simplifier : public dependent_expr_simplifier { + typedef std::pair app_expr_pair; + demodulator_index m_index; + demodulator_util m_util; + demodulator_match_subst m_match_subst; + demodulator_rewriter_util m_rewriter; + u_map m_rewrites; + uint_set m_processed, m_dependencies; + unsigned_vector m_todo; + expr_ref_vector m_pinned; + + void rewrite(unsigned i); + bool rewrite1(func_decl* f, expr_ref_vector const& args, expr_ref& np); + expr* fml(unsigned i) { return m_fmls[i].fml(); } + expr_dependency* dep(unsigned i) { return m_fmls[i].dep(); } + void reschedule_processed(func_decl* f); + void reschedule_demodulators(func_decl* f, expr* lhs); + void reset(); + + public: + demodulator_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& st); + void reduce() override; + + +}; diff --git a/src/ast/substitution/demodulator_rewriter.cpp b/src/ast/substitution/demodulator_rewriter.cpp index 6e79242e0..0b37308c9 100644 --- a/src/ast/substitution/demodulator_rewriter.cpp +++ b/src/ast/substitution/demodulator_rewriter.cpp @@ -27,32 +27,73 @@ Revision History: #include "ast/rewriter/var_subst.h" #include "ast/substitution/demodulator_rewriter.h" -demodulator_rewriter::demodulator_rewriter(ast_manager & m): - m(m), - m_match_subst(m), - m_bsimp(m), - m_todo(m), - m_in_processed(m), - m_new_args(m), - m_rewrite_todo(m), - m_rewrite_cache(m), - m_new_exprs(m) { - params_ref p; - p.set_bool("elim_and", true); - m_bsimp.updt_params(p); + +class var_set_proc { + uint_set & m_set; +public: + var_set_proc(uint_set &s):m_set(s) {} + void operator()(var * n) { m_set.insert(n->get_idx()); } + void operator()(quantifier * n) {} + void operator()(app * n) {} +}; + +int demodulator_util::is_subset(expr * e1, expr * e2) const { + uint_set ev1, ev2; + + if (m.is_value(e1)) + return 1; // values are always a subset! + + var_set_proc proc1(ev1); + for_each_expr(proc1, e1); + var_set_proc proc2(ev2); + for_each_expr(proc2, e2); + + return (ev1==ev2 ) ? +2 : // We return +2 if the sets are equal. + (ev1.subset_of(ev2)) ? +1 : + (ev2.subset_of(ev1)) ? -1 : + 0 ; } -demodulator_rewriter::~demodulator_rewriter() { - reset_dealloc_values(m_fwd_idx); - reset_dealloc_values(m_back_idx); - for (auto & kv : m_demodulator2lhs_rhs) { - m.dec_ref(kv.m_key); - m.dec_ref(kv.m_value.first); - m.dec_ref(kv.m_value.second); +int demodulator_util::is_smaller(expr * e1, expr * e2) const { + unsigned sz1 = 0, sz2 = 0; + + // values are always smaller! + if (m.is_value(e1)) + return +1; + else if (m.is_value(e2)) + return -1; + + // interpreted stuff is always better than uninterpreted. + if (!is_uninterp(e1) && is_uninterp(e2)) + return +1; + else if (is_uninterp(e1) && !is_uninterp(e2)) + return -1; + + // two uninterpreted functions are ordered first by the number of + // arguments, then by their id. + if (is_uninterp(e1) && is_uninterp(e2)) { + if (to_app(e1)->get_num_args() < to_app(e2)->get_num_args()) + return +1; + else if (to_app(e1)->get_num_args() > to_app(e2)->get_num_args()) + return -1; + else { + unsigned a = to_app(e1)->get_decl()->get_id(); + unsigned b = to_app(e2)->get_decl()->get_id(); + if (a < b) + return +1; + else if (a > b) + return -1; + } } + sz1 = get_depth(e1); + sz2 = get_depth(e2); + + return (sz1 == sz2) ? 0 : + (sz1 < sz2) ? +1 : + -1 ; } -bool demodulator_rewriter::is_demodulator(expr * e, app_ref & large, expr_ref & small) const { +bool demodulator_util::is_demodulator(expr * e, app_ref & large, expr_ref & small) const { if (!is_forall(e)) { return false; } @@ -109,71 +150,6 @@ bool demodulator_rewriter::is_demodulator(expr * e, app_ref & large, expr_ref & return false; } -class var_set_proc { - uint_set & m_set; -public: - var_set_proc(uint_set &s):m_set(s) {} - void operator()(var * n) { m_set.insert(n->get_idx()); } - void operator()(quantifier * n) {} - void operator()(app * n) {} -}; - -int demodulator_rewriter::is_subset(expr * e1, expr * e2) const { - uint_set ev1, ev2; - - if (m.is_value(e1)) - return 1; // values are always a subset! - - var_set_proc proc1(ev1); - for_each_expr(proc1, e1); - var_set_proc proc2(ev2); - for_each_expr(proc2, e2); - - return (ev1==ev2 ) ? +2 : // We return +2 if the sets are equal. - (ev1.subset_of(ev2)) ? +1 : - (ev2.subset_of(ev1)) ? -1 : - 0 ; -} - -int demodulator_rewriter::is_smaller(expr * e1, expr * e2) const { - unsigned sz1 = 0, sz2 = 0; - - // values are always smaller! - if (m.is_value(e1)) - return +1; - else if (m.is_value(e2)) - return -1; - - // interpreted stuff is always better than uninterpreted. - if (!is_uninterp(e1) && is_uninterp(e2)) - return +1; - else if (is_uninterp(e1) && !is_uninterp(e2)) - return -1; - - // two uninterpreted functions are ordered first by the number of - // arguments, then by their id. - if (is_uninterp(e1) && is_uninterp(e2)) { - if (to_app(e1)->get_num_args() < to_app(e2)->get_num_args()) - return +1; - else if (to_app(e1)->get_num_args() > to_app(e2)->get_num_args()) - return -1; - else { - unsigned a = to_app(e1)->get_decl()->get_id(); - unsigned b = to_app(e2)->get_decl()->get_id(); - if (a < b) - return +1; - else if (a > b) - return -1; - } - } - sz1 = get_depth(e1); - sz2 = get_depth(e2); - - return (sz1 == sz2) ? 0 : - (sz1 < sz2) ? +1 : - -1 ; -} - class max_var_id_proc { unsigned m_max_var_id; public: @@ -187,13 +163,202 @@ public: unsigned get_max() { return m_max_var_id; } }; -unsigned demodulator_rewriter::max_var_id(expr_ref_vector const& es) { +unsigned demodulator_util::max_var_id(expr* e) { + max_var_id_proc proc; + for_each_expr(proc, e); + return proc.get_max(); +} + +unsigned demodulator_util::max_var_id(expr_ref_vector const& es) { max_var_id_proc proc; for (expr* e : es) for_each_expr(proc, e); return proc.get_max(); } + +// ------------------ + +demodulator_rewriter_util::demodulator_rewriter_util(ast_manager& m): + m(m), + m_th_rewriter(m), + m_rewrite_todo(m), + m_rewrite_cache(m), + m_new_exprs(m), + m_new_args(m) +{} + +expr_ref demodulator_rewriter_util::rewrite(expr * n) { + + TRACE("demodulator", tout << "rewrite: " << mk_pp(n, m) << std::endl; ); + app * a; + + SASSERT(m_rewrite_todo.empty()); + m_new_exprs.reset(); + m_rewrite_cache.reset(); + + m_rewrite_todo.push_back(n); + while (!m_rewrite_todo.empty()) { + TRACE("demodulator_stack", tout << "STACK: " << std::endl; + for (unsigned i = 0; i < m_rewrite_todo.size(); i++) + tout << std::dec << i << ": " << std::hex << (size_t)m_rewrite_todo[i] << + " = " << mk_pp(m_rewrite_todo[i], m) << std::endl; + ); + + expr * e = m_rewrite_todo.back(); + expr_ref actual(e, m); + + if (m_rewrite_cache.contains(e)) { + const expr_bool_pair &ebp = m_rewrite_cache.get(e); + if (ebp.second) { + m_rewrite_todo.pop_back(); + continue; + } + else { + actual = ebp.first; + } + } + + switch (actual->get_kind()) { + case AST_VAR: + rewrite_cache(e, actual, true); + m_rewrite_todo.pop_back(); + break; + case AST_APP: + a = to_app(actual); + if (rewrite_visit_children(a)) { + func_decl * f = a->get_decl(); + m_new_args.reset(); + bool all_untouched = true; + for (expr* o_child : *a) { + expr * n_child; + SASSERT(m_rewrite_cache.contains(o_child) && m_rewrite_cache.get(o_child).second); + expr_bool_pair const & ebp = m_rewrite_cache.get(o_child); + n_child = ebp.first; + if (n_child != o_child) + all_untouched = false; + m_new_args.push_back(n_child); + } + expr_ref np(m); + if (m_rewrite1(f, m_new_args, np)) { + rewrite_cache(e, np, false); + // No pop. + } + else { + if (all_untouched) { + rewrite_cache(e, actual, true); + } + else { + expr_ref na(m); + na = m_th_rewriter.mk_app(f, m_new_args); + TRACE("demodulator_bug", tout << "e:\n" << mk_pp(e, m) << "\nnew_args: \n"; + tout << m_new_args << "\n"; + tout << "=====>\n"; + tout << "na:\n " << na << "\n";); + rewrite_cache(e, na, true); + } + m_rewrite_todo.pop_back(); + } + } + break; + case AST_QUANTIFIER: { + expr * body = to_quantifier(actual)->get_expr(); + if (m_rewrite_cache.contains(body)) { + const expr_bool_pair ebp = m_rewrite_cache.get(body); + SASSERT(ebp.second); + expr * new_body = ebp.first; + quantifier_ref q(m); + q = m.update_quantifier(to_quantifier(actual), new_body); + m_new_exprs.push_back(q); + expr_ref new_q = elim_unused_vars(m, q, params_ref()); + m_new_exprs.push_back(new_q); + rewrite_cache(e, new_q, true); + m_rewrite_todo.pop_back(); + } else { + m_rewrite_todo.push_back(body); + } + break; + } + default: + UNREACHABLE(); + } + } + + SASSERT(m_rewrite_cache.contains(n)); + const expr_bool_pair & ebp = m_rewrite_cache.get(n); + SASSERT(ebp.second); + expr * r = ebp.first; + + TRACE("demodulator", tout << "rewrite result: " << mk_pp(r, m) << std::endl; ); + + return expr_ref(r, m); +} + +bool demodulator_rewriter_util::rewrite_visit_children(app * a) { + bool res = true; + for (expr* e : *a) { + if (m_rewrite_cache.contains(e) && m_rewrite_cache.get(e).second) + continue; + bool recursive = false; + expr * v = e; + if (m_rewrite_cache.contains(e)) { + auto const & [t, marked] = m_rewrite_cache.get(e); + if (marked) + v = t; + } + for (expr* t : m_rewrite_todo) { + if (t == v) { + recursive = true; + TRACE("demodulator", tout << "Detected demodulator cycle: " << + mk_pp(a, m) << " --> " << mk_pp(v, m) << std::endl;); + rewrite_cache(e, v, true); + break; + } + } + if (!recursive) { + m_rewrite_todo.push_back(e); + res = false; + } + } + return res; +} + +void demodulator_rewriter_util::rewrite_cache(expr * e, expr * new_e, bool done) { + m_rewrite_cache.insert(e, expr_bool_pair(new_e, done)); +} + + + +// ------------------ + +demodulator_rewriter::demodulator_rewriter(ast_manager & m): + m(m), + m_match_subst(m), + m_util(m), + m_bsimp(m), + m_todo(m), + m_in_processed(m), + m_new_args(m), + m_rewrite_todo(m), + m_rewrite_cache(m), + m_new_exprs(m) { + params_ref p; + p.set_bool("elim_and", true); + m_bsimp.updt_params(p); +} + +demodulator_rewriter::~demodulator_rewriter() { + reset_dealloc_values(m_fwd_idx); + reset_dealloc_values(m_back_idx); + for (auto & kv : m_demodulator2lhs_rhs) { + m.dec_ref(kv.m_key); + m.dec_ref(kv.m_value.first); + m.dec_ref(kv.m_value.second); + } +} + + + void demodulator_rewriter::insert_fwd_idx(app * large, expr * small, quantifier * demodulator) { SASSERT(demodulator); SASSERT(large && small); @@ -265,17 +430,18 @@ bool demodulator_rewriter::rewrite1(func_decl * f, expr_ref_vector const & args, for (quantifier* d : *set) { - auto const& [large, rhs] = m_demodulator2lhs_rhs[d]; + auto const& [lhs, rhs] = m_demodulator2lhs_rhs[d]; - if (large->get_num_args() != args.size()) + if (lhs->get_num_args() != args.size()) continue; TRACE("demodulator_bug", tout << "Matching with demodulator: " << mk_pp(d, m) << std::endl; ); - SASSERT(large->get_decl() == f); + SASSERT(lhs->get_decl() == f); - if (m_match_subst(large, rhs, args.data(), np)) { + if (m_match_subst(lhs, rhs, args.data(), np)) { TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << mk_pp(np, m) << "\n";); + m_new_exprs.push_back(np); return true; } } @@ -289,15 +455,14 @@ bool demodulator_rewriter::rewrite_visit_children(app * a) { if (m_rewrite_cache.contains(e) && m_rewrite_cache.get(e).second) continue; bool recursive = false; - unsigned sz = m_rewrite_todo.size(); expr * v = e; if (m_rewrite_cache.contains(e)) { - expr_bool_pair const & ebp = m_rewrite_cache.get(e); - if (ebp.second) - v = ebp.first; + auto const & [t, marked] = m_rewrite_cache.get(e); + if (marked) + v = t; } - for (unsigned i = sz; i-- > 0;) { - if (m_rewrite_todo[i] == v) { + for (expr* t : m_rewrite_todo) { + if (t == v) { recursive = true; TRACE("demodulator", tout << "Detected demodulator cycle: " << mk_pp(a, m) << " --> " << mk_pp(v, m) << std::endl;); @@ -504,7 +669,7 @@ void demodulator_rewriter::reschedule_processed(func_decl * f) { } } -bool demodulator_rewriter::can_rewrite(expr * n, expr * lhs) { +bool demodulator_match_subst::can_rewrite(expr * n, expr * lhs) { // this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'. // we cannot use the trick used for m_processed, since the main loop would not terminate. @@ -530,7 +695,7 @@ bool demodulator_rewriter::can_rewrite(expr * n, expr * lhs) { case AST_APP: if (for_each_expr_args(stack, visited, to_app(curr)->get_num_args(), to_app(curr)->get_args())) { - if (m_match_subst(lhs, curr)) + if ((*this)(lhs, curr)) return true; visited.mark(curr, true); stack.pop_back(); @@ -582,7 +747,7 @@ void demodulator_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { func_decl_ref df(l->get_decl(), m); // Now we know there is an occurrence of f in d - if (!can_rewrite(d, lhs)) + if (!m_match_subst.can_rewrite(d, lhs)) continue; TRACE("demodulator", tout << "Rescheduling: " << std::endl << mk_pp(d, m) << std::endl); @@ -602,7 +767,7 @@ void demodulator_rewriter::operator()(expr_ref_vector const& exprs, for (expr* e : exprs) m_todo.push_back(e); - m_match_subst.reserve(max_var_id(exprs)); + m_match_subst.reserve(m_util.max_var_id(exprs)); while (!m_todo.empty()) { // let n be the next formula in m_todo. @@ -618,7 +783,7 @@ void demodulator_rewriter::operator()(expr_ref_vector const& exprs, app_ref large(m); expr_ref small(m); - if (!is_demodulator(np, large, small)) { + if (!m_util.is_demodulator(np, large, small)) { // insert n' into m_processed m_processed.insert(np); m_in_processed.push_back(np); @@ -661,7 +826,7 @@ void demodulator_rewriter::operator()(expr_ref_vector const& exprs, } -demodulator_rewriter::match_subst::match_subst(ast_manager & m): +demodulator_match_subst::demodulator_match_subst(ast_manager & m): m(m), m_subst(m) { } @@ -693,7 +858,7 @@ struct match_args_aux_proc { void operator()(app * n) {} }; -bool demodulator_rewriter::match_subst::match_args(app * lhs, expr * const * args) { +bool demodulator_match_subst::match_args(app * lhs, expr * const * args) { m_cache.reset(); m_todo.reset(); @@ -809,7 +974,7 @@ bool demodulator_rewriter::match_subst::match_args(app * lhs, expr * const * arg } -bool demodulator_rewriter::match_subst::operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs) { +bool demodulator_match_subst::operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs) { if (match_args(lhs, args)) { if (m_all_args_eq) { @@ -824,7 +989,7 @@ bool demodulator_rewriter::match_subst::operator()(app * lhs, expr * rhs, expr * return false; } -bool demodulator_rewriter::match_subst::operator()(expr * t, expr * i) { +bool demodulator_match_subst::operator()(expr * t, expr * i) { m_cache.reset(); m_todo.reset(); if (is_var(t)) diff --git a/src/ast/substitution/demodulator_rewriter.h b/src/ast/substitution/demodulator_rewriter.h index 2152520ce..18befc198 100644 --- a/src/ast/substitution/demodulator_rewriter.h +++ b/src/ast/substitution/demodulator_rewriter.h @@ -24,6 +24,7 @@ Revision History: #include "ast/ast.h" #include "ast/substitution/substitution.h" #include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" #include "util/obj_hashtable.h" #include "util/obj_pair_hashtable.h" #include "util/array_map.h" @@ -92,6 +93,92 @@ The code in spc_rewriter.* does something like that. We cannot reuse this code d for the superposion engine in Z3, but we can adapt it for our needs in the preprocessor. */ +class demodulator_util { + ast_manager& m; + int is_subset(expr*, expr*) const; + int is_smaller(expr*, expr*) const; + public: + demodulator_util(ast_manager& m):m(m) {} + bool is_demodulator(expr* e, app_ref& large, expr_ref & small) const; + unsigned max_var_id(expr* e); + unsigned max_var_id(expr_ref_vector const& e); +}; + +/** + \brief Custom matcher & substitution application +*/ +class demodulator_match_subst { + typedef std::pair expr_pair; + typedef obj_pair_hashtable cache; + + void reset(); + + ast_manager & m; + substitution m_subst; + cache m_cache; + svector m_todo; + bool m_all_args_eq; + + bool match_args(app * t, expr * const * args); + +public: + demodulator_match_subst(ast_manager & m); + + void reserve(unsigned max_vid) { m_subst.reserve(2, max_vid+1); } + /** + \brief Let f be the top symbol of lhs. If (f args) is an + instance of lhs, that is, there is a substitution s + s.t. s[lhs] = (f args), then return true and store s[rhs] + into new_rhs. Where s[t] represents the application of the + substitution s into t. + + Assumptions, the variables in lhs and (f args) are assumed to be distinct. + So, (f x y) matches (f y x). + Moreover, the result should be in terms of the variables in (f args). + */ + bool operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs); + + /** + \brief Return true if \c i is an instance of \c t. + */ + bool operator()(expr * t, expr * i); + + bool can_rewrite(expr* n, expr* lhs); +}; + +class demodulator_rewriter_util { + ast_manager& m; + std::function m_rewrite1; + + typedef std::pair expr_bool_pair; + + class plugin { + ast_manager& m; + public: + plugin(ast_manager& m): m(m) { } + void ins_eh(expr* k, expr_bool_pair v) { m.inc_ref(k); m.inc_ref(v.first); } + void del_eh(expr* k, expr_bool_pair v) { m.dec_ref(k); m.dec_ref(v.first); } + static unsigned to_int(expr const * k) { return k->get_id(); } + }; + typedef array_map expr_map; + + typedef expr_map rewrite_cache_map; + + th_rewriter m_th_rewriter; + expr_ref_buffer m_rewrite_todo; + rewrite_cache_map m_rewrite_cache; + expr_ref_buffer m_new_exprs; + expr_ref_vector m_new_args; + + bool rewrite_visit_children(app * a); + void rewrite_cache(expr * e, expr * new_e, bool done); + +public: + demodulator_rewriter_util(ast_manager& m); + void set_rewrite1(std::function& fn) { m_rewrite1 = fn; } + expr_ref rewrite(expr * n); +}; + class demodulator_rewriter final { class rewrite_proc; class add_back_idx_proc; @@ -119,47 +206,10 @@ class demodulator_rewriter final { typedef obj_map demodulator2lhs_rhs; typedef expr_map rewrite_cache_map; - /** - \brief Custom matcher & substitution application - */ - class match_subst { - typedef std::pair expr_pair; - typedef obj_pair_hashtable cache; - - void reset(); - - ast_manager & m; - substitution m_subst; - cache m_cache; - svector m_todo; - bool m_all_args_eq; - - bool match_args(app * t, expr * const * args); - - public: - match_subst(ast_manager & m); - void reserve(unsigned max_vid) { m_subst.reserve(2, max_vid+1); } - /** - \brief Let f be the top symbol of lhs. If (f args) is an - instance of lhs, that is, there is a substitution s - s.t. s[lhs] = (f args), then return true and store s[rhs] - into new_rhs. Where s[t] represents the application of the - substitution s into t. - - Assumptions, the variables in lhs and (f args) are assumed to be distinct. - So, (f x y) matches (f y x). - Moreover, the result should be in terms of the variables in (f args). - */ - bool operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs); - - /** - \brief Return true if \c i is an instance of \c t. - */ - bool operator()(expr * t, expr * i); - }; ast_manager & m; - match_subst m_match_subst; + demodulator_match_subst m_match_subst; + demodulator_util m_util; bool_rewriter m_bsimp; fwd_idx_map m_fwd_idx; back_idx_map m_back_idx; @@ -179,7 +229,6 @@ class demodulator_rewriter final { void remove_bwd_idx(expr* q); bool check_fwd_idx_consistency(); void show_fwd_idx(std::ostream & out); - bool is_demodulator(expr * e, app_ref & large, expr_ref & small) const; bool can_rewrite(expr * n, expr * lhs); expr * rewrite(expr * n); @@ -188,13 +237,6 @@ class demodulator_rewriter final { void rewrite_cache(expr * e, expr * new_e, bool done); void reschedule_processed(func_decl * f); void reschedule_demodulators(func_decl * f, expr * np); - unsigned max_var_id(expr_ref_vector const& es); - - // is_smaller returns -1 for e1e2. - int is_smaller(expr * e1, expr * e2) const; - - // is_subset returns -1 for e1 subset e2, +1 for e2 subset e1, 0 else. - int is_subset(expr * e1, expr * e2) const; public: demodulator_rewriter(ast_manager & m); From 0f7bebcbed8fe33c6d5c3f9c653be57eb7e9adb8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 09:49:32 -0800 Subject: [PATCH 370/477] try big M for linux build --- src/ast/rewriter/poly_rewriter.h | 1 + src/ast/rewriter/poly_rewriter_def.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index c9253b0e4..6880f7e23 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -36,6 +36,7 @@ protected: bool m_hoist_mul; bool m_ast_order; bool m_hoist_ite; + ast_manager& M() { return Config::m; } bool is_numeral(expr * n) const { return Config::is_numeral(n); } bool is_numeral(expr * n, numeral & r) const { return Config::is_numeral(n, r); } diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index f9ae333b4..33f1b510a 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -51,7 +51,7 @@ expr * poly_rewriter::mk_add_app(unsigned num_args, expr * const * args) switch (num_args) { case 0: return mk_numeral(numeral(0)); case 1: return args[0]; - default: return m.mk_app(get_fid(), add_decl_kind(), num_args, args); + default: return M().mk_app(get_fid(), add_decl_kind(), num_args, args); } } From 9b58135876826b569e7967aedade05e9430f9b52 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 09:55:31 -0800 Subject: [PATCH 371/477] try to fix linux builds --- src/ast/rewriter/poly_rewriter_def.h | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 33f1b510a..6550089c9 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -119,7 +119,7 @@ expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) if (new_args.size() > 2 && is_numeral(new_args.get(0), a)) { return mk_mul_app(a, mk_mul_app(new_args.size() - 1, new_args.data() + 1)); } - return m.mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.data()); + return M().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.data()); } } else { @@ -127,7 +127,7 @@ expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) if (num_args > 2 && is_numeral(args[0], a)) { return mk_mul_app(a, mk_mul_app(num_args - 1, args + 1)); } - return m.mk_app(get_fid(), mul_decl_kind(), num_args, args); + return M().mk_app(get_fid(), mul_decl_kind(), num_args, args); } } } @@ -189,9 +189,9 @@ br_status poly_rewriter::mk_flat_mul_core(unsigned num_args, expr * cons br_status st = mk_nflat_mul_core(flat_args.size(), flat_args.data(), result); TRACE("poly_rewriter", tout << "flat mul:\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m) << "\n"; + for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], M()) << "\n"; tout << "---->\n"; - for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m) << "\n"; + for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], M()) << "\n"; tout << st << "\n"; ); if (st == BR_FAILED) { @@ -328,7 +328,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con for (unsigned i = 0; i < new_args.size(); i++) { if (i > 0) tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); - tout << mk_ismt2_pp(new_args[i], m); + tout << mk_ismt2_pp(new_args[i], M()); } tout << "\nordered: " << ordered << "\n";); if (ordered && num_coeffs == 0 && !use_power()) @@ -340,7 +340,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con for (unsigned i = 0; i < new_args.size(); i++) { if (i > 0) tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); - tout << mk_ismt2_pp(new_args[i], m); + tout << mk_ismt2_pp(new_args[i], M()); } tout << "\n";); } @@ -349,8 +349,8 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con result = mk_mul_app(c, result); TRACE("poly_rewriter", for (unsigned i = 0; i < num_args; ++i) - tout << mk_ismt2_pp(args[i], m) << " "; - tout << "\nmk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m) << "\n";); + tout << mk_ismt2_pp(args[i], M()) << " "; + tout << "\nmk_nflat_mul_core result:\n" << mk_ismt2_pp(result, M()) << "\n";); return BR_DONE; } @@ -373,9 +373,9 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con } } unsigned orig_size = sums.size(); - expr_ref_buffer sum(m); // must be ref_buffer because we may throw an exception + expr_ref_buffer sum(M()); // must be ref_buffer because we may throw an exception ptr_buffer m_args; - TRACE("som", tout << "starting som...\n";); + TRACE("som", tout << "starting soM()...\n";); do { TRACE("som", for (unsigned i = 0; i < it.size(); i++) tout << it[i] << " "; tout << "\n";); @@ -566,7 +566,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con SASSERT(m_sort_sums || ordered); TRACE("rewriter", tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m) << "\n";); + for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], M()) << "\n";); if (has_multiple) { // expensive case @@ -589,7 +589,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con coeffs.push_back(a); } } - expr_ref_buffer new_args(m); + expr_ref_buffer new_args(M()); if (!c.is_zero()) { new_args.push_back(mk_numeral(c)); } @@ -639,7 +639,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con if (num_coeffs == 1 && is_numeral(args[0], a) && !a.is_zero()) return BR_FAILED; } - expr_ref_buffer new_args(m); + expr_ref_buffer new_args(M()); if (!c.is_zero()) new_args.push_back(mk_numeral(c)); for (unsigned i = 0; i < num_args; i++) { @@ -690,8 +690,8 @@ br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, return BR_DONE; } set_curr_sort(args[0]->get_sort()); - expr_ref minus_one(mk_numeral(numeral(-1)), m); - expr_ref_buffer new_args(m); + expr_ref minus_one(mk_numeral(numeral(-1)), M()); + expr_ref_buffer new_args(M()); new_args.push_back(args[0]); for (unsigned i = 1; i < num_args; i++) { if (is_zero(args[i])) continue; @@ -984,11 +984,11 @@ bool poly_rewriter::hoist_ite(expr_ref& e) { return false; obj_hashtable shared; ptr_buffer adds; - expr_ref_vector bs(m), pinned(m); + expr_ref_vector bs(M()), pinned(M()); TO_BUFFER(is_add, adds, e); unsigned i = 0; for (expr* a : adds) { - if (m.is_ite(a)) { + if (M().is_ite(a)) { shared.reset(); numeral g(0); if (hoist_ite(a, shared, g) && (is_nontrivial_gcd(g) || !shared.empty())) { @@ -1026,7 +1026,7 @@ bool poly_rewriter::hoist_ite(expr_ref& e) { template bool poly_rewriter::hoist_ite(expr* a, obj_hashtable& shared, numeral& g) { expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m.is_ite(a, c, t, e)) { + if (M().is_ite(a, c, t, e)) { return hoist_ite(t, shared, g) && hoist_ite(e, shared, g); } rational k, g1; @@ -1064,8 +1064,8 @@ bool poly_rewriter::hoist_ite(expr* a, obj_hashtable& shared, nume template expr* poly_rewriter::apply_hoist(expr* a, numeral const& g, obj_hashtable const& shared) { expr* c = nullptr, *t = nullptr, *e = nullptr; - if (m.is_ite(a, c, t, e)) { - return m.mk_ite(c, apply_hoist(t, g, shared), apply_hoist(e, g, shared)); + if (M().is_ite(a, c, t, e)) { + return M().mk_ite(c, apply_hoist(t, g, shared), apply_hoist(e, g, shared)); } rational k; if (is_nontrivial_gcd(g) && is_int_numeral(a, k)) { From b76ed6a47fc00d184fbceb518eeb5b18ea8ae93d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 10:19:39 -0800 Subject: [PATCH 372/477] proper fix to #6476 --- src/ast/simplifiers/demodulator_simplifier.cpp | 6 +++--- src/ast/substitution/demodulator_rewriter.cpp | 7 ++----- src/ast/substitution/demodulator_rewriter.h | 3 --- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/ast/simplifiers/demodulator_simplifier.cpp b/src/ast/simplifiers/demodulator_simplifier.cpp index eb3585606..d7650717e 100644 --- a/src/ast/simplifiers/demodulator_simplifier.cpp +++ b/src/ast/simplifiers/demodulator_simplifier.cpp @@ -104,7 +104,7 @@ bool demodulator_simplifier::rewrite1(func_decl* f, expr_ref_vector const& args, if (!m_index.find_fwd(f, set)) return false; - TRACE("demodulator", tout << "trying to rewrite: " << f->get_name() << " args:\n" << m_new_args << "\n";); + TRACE("demodulator", tout << "trying to rewrite: " << f->get_name() << " args:\n" << args << "\n";); for (unsigned i : *set) { @@ -115,7 +115,7 @@ bool demodulator_simplifier::rewrite1(func_decl* f, expr_ref_vector const& args, SASSERT(lhs->get_decl() == f); - TRACE("demodulator", tout << "Matching with demodulator: " << mk_pp(d, m) << std::endl; ); + TRACE("demodulator", tout << "Matching with demodulator: " << mk_pp(lhs, m) << std::endl; ); if (m_match_subst(lhs, rhs, args.data(), np)) { TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << np << "\n";); @@ -154,7 +154,7 @@ void demodulator_simplifier::reschedule_demodulators(func_decl* f, expr* lhs) { continue; if (!m_match_subst.can_rewrite(fml(i), lhs)) continue; - func_decl* f = p.first->get_decl(); + SASSERT(f == p.first->get_decl()); m_index.remove_fwd(f, i); m_index.remove_bwd(fml(i), i); m_todo.push_back(i); diff --git a/src/ast/substitution/demodulator_rewriter.cpp b/src/ast/substitution/demodulator_rewriter.cpp index 0b37308c9..7b06234dc 100644 --- a/src/ast/substitution/demodulator_rewriter.cpp +++ b/src/ast/substitution/demodulator_rewriter.cpp @@ -847,12 +847,9 @@ struct match_args_aux_proc { SASSERT(r.get_offset() == 1); throw no_match(); } - else { - m_subst.insert(n, 0, expr_offset(n, 1)); - } } - else - throw no_match(); + else + m_subst.insert(n, 0, expr_offset(n, 1)); } void operator()(quantifier * n) { throw no_match(); } void operator()(app * n) {} diff --git a/src/ast/substitution/demodulator_rewriter.h b/src/ast/substitution/demodulator_rewriter.h index 18befc198..3a1e442d5 100644 --- a/src/ast/substitution/demodulator_rewriter.h +++ b/src/ast/substitution/demodulator_rewriter.h @@ -111,8 +111,6 @@ class demodulator_match_subst { typedef std::pair expr_pair; typedef obj_pair_hashtable cache; - void reset(); - ast_manager & m; substitution m_subst; cache m_cache; @@ -229,7 +227,6 @@ class demodulator_rewriter final { void remove_bwd_idx(expr* q); bool check_fwd_idx_consistency(); void show_fwd_idx(std::ostream & out); - bool can_rewrite(expr * n, expr * lhs); expr * rewrite(expr * n); bool rewrite1(func_decl * f, expr_ref_vector const & args, expr_ref & np); From ead2a46a88972caa03e7013b43dd5f9e1dbb4a23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 10:38:24 -0800 Subject: [PATCH 373/477] build --- src/ast/rewriter/poly_rewriter_def.h | 2 +- .../simplifiers/demodulator_simplifier.cpp | 7 +- src/ast/simplifiers/demodulator_simplifier.h | 3 +- src/ast/substitution/demodulator_rewriter.cpp | 87 +++++++++---------- 4 files changed, 46 insertions(+), 53 deletions(-) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 6550089c9..f739579e6 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -292,7 +292,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con new_add_args.push_back(mk_mul_app(c, to_app(var)->get_arg(i))); } result = mk_add_app(new_add_args.size(), new_add_args.data()); - TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m,5) << "\n";); + TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, M(), 5) << "\n";); return BR_REWRITE2; } } diff --git a/src/ast/simplifiers/demodulator_simplifier.cpp b/src/ast/simplifiers/demodulator_simplifier.cpp index d7650717e..7c402c7b5 100644 --- a/src/ast/simplifiers/demodulator_simplifier.cpp +++ b/src/ast/simplifiers/demodulator_simplifier.cpp @@ -115,11 +115,12 @@ bool demodulator_simplifier::rewrite1(func_decl* f, expr_ref_vector const& args, SASSERT(lhs->get_decl() == f); - TRACE("demodulator", tout << "Matching with demodulator: " << mk_pp(lhs, m) << std::endl; ); + TRACE("demodulator", tout << "Matching with demodulator: " << mk_pp(lhs, m) << "\n"); if (m_match_subst(lhs, rhs, args.data(), np)) { - TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << np << "\n";); - m_dependencies.insert(i); + TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << np << "\n"); + if (dep(i)) + m_dependencies.insert(i); return true; } } diff --git a/src/ast/simplifiers/demodulator_simplifier.h b/src/ast/simplifiers/demodulator_simplifier.h index e104c056b..afb5d1a18 100644 --- a/src/ast/simplifiers/demodulator_simplifier.h +++ b/src/ast/simplifiers/demodulator_simplifier.h @@ -54,7 +54,6 @@ class demodulator_simplifier : public dependent_expr_simplifier { public: demodulator_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& st); - void reduce() override; - + void reduce() override; }; diff --git a/src/ast/substitution/demodulator_rewriter.cpp b/src/ast/substitution/demodulator_rewriter.cpp index 7b06234dc..18d6ff925 100644 --- a/src/ast/substitution/demodulator_rewriter.cpp +++ b/src/ast/substitution/demodulator_rewriter.cpp @@ -669,53 +669,6 @@ void demodulator_rewriter::reschedule_processed(func_decl * f) { } } -bool demodulator_match_subst::can_rewrite(expr * n, expr * lhs) { - // this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'. - // we cannot use the trick used for m_processed, since the main loop would not terminate. - - ptr_vector stack; - expr * curr; - expr_mark visited; - - stack.push_back(n); - - while (!stack.empty()) { - curr = stack.back(); - - if (visited.is_marked(curr)) { - stack.pop_back(); - continue; - } - - switch(curr->get_kind()) { - case AST_VAR: - visited.mark(curr, true); - stack.pop_back(); - break; - - case AST_APP: - if (for_each_expr_args(stack, visited, to_app(curr)->get_num_args(), to_app(curr)->get_args())) { - if ((*this)(lhs, curr)) - return true; - visited.mark(curr, true); - stack.pop_back(); - } - break; - - case AST_QUANTIFIER: - if (visited.is_marked(to_quantifier(curr)->get_expr())) - stack.pop_back(); - else - stack.push_back(to_quantifier(curr)->get_expr()); - break; - default: - UNREACHABLE(); - } - } - - return false; -} - void demodulator_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { // use m_back_idx to find all demodulators d in m_fwd_idx that contains f { @@ -831,6 +784,46 @@ demodulator_match_subst::demodulator_match_subst(ast_manager & m): m_subst(m) { } +bool demodulator_match_subst::can_rewrite(expr* n, expr* lhs) { + // this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'. + // we cannot use the trick used for m_processed, since the main loop would not terminate. + ptr_vector stack; + expr* curr; + expr_mark visited; + + stack.push_back(n); + while (!stack.empty()) { + curr = stack.back(); + if (visited.is_marked(curr)) { + stack.pop_back(); + continue; + } + switch (curr->get_kind()) { + case AST_VAR: + visited.mark(curr, true); + stack.pop_back(); + break; + case AST_APP: + if (for_each_expr_args(stack, visited, to_app(curr)->get_num_args(), to_app(curr)->get_args())) { + if ((*this)(lhs, curr)) + return true; + visited.mark(curr, true); + stack.pop_back(); + } + break; + case AST_QUANTIFIER: + if (visited.is_marked(to_quantifier(curr)->get_expr())) + stack.pop_back(); + else + stack.push_back(to_quantifier(curr)->get_expr()); + break; + default: + UNREACHABLE(); + } + } + return false; +} + /** \brief Auxiliary functor used to implement optimization in match_args. See comment there. */ From 87095950cb7ac8a5f5653b44d0a1bd8ac50f5636 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Dec 2022 13:02:45 -0800 Subject: [PATCH 374/477] fix #6477 --- src/ast/rewriter/bv_rewriter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 34d2f6508..179113241 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -1988,6 +1988,10 @@ bool bv_rewriter::distribute_concat(decl_kind k, unsigned n, expr* const* args, expr* e = to_app(arg)->get_arg(0); unsigned sz1 = get_bv_size(e); unsigned sz2 = get_bv_size(arg); + if (sz1 == sz2) { + result = m.mk_app(get_fid(), k, n, args); + return true; + } expr_ref_vector args1(m), args2(m); for (unsigned j = 0; j < n; ++j) { args1.push_back(m_mk_extract(sz2 - 1, sz2 - sz1, args[j])); From de916f50d62b18b85194949fc213f7f7bb86ece5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Dec 2022 03:20:46 -0800 Subject: [PATCH 375/477] add demodulator tactic based on demodulator-simplifier - some handling for commutative operators - fix bug in demodulator_index where fwd and bwd are swapped --- .../simplifiers/demodulator_simplifier.cpp | 18 +++- src/ast/simplifiers/demodulator_simplifier.h | 9 +- src/ast/substitution/demodulator_rewriter.cpp | 92 ++++++++++++------- src/tactic/core/CMakeLists.txt | 1 + src/tactic/core/demodulator_tactic.h | 40 ++++++++ 5 files changed, 123 insertions(+), 37 deletions(-) create mode 100644 src/tactic/core/demodulator_tactic.h diff --git a/src/ast/simplifiers/demodulator_simplifier.cpp b/src/ast/simplifiers/demodulator_simplifier.cpp index 7c402c7b5..afd57b425 100644 --- a/src/ast/simplifiers/demodulator_simplifier.cpp +++ b/src/ast/simplifiers/demodulator_simplifier.cpp @@ -71,8 +71,20 @@ void demodulator_index::remove_bwd(expr* e, unsigned i) { for_each_expr(p, e); } +std::ostream& demodulator_index::display(std::ostream& out) const { + out << "forward\n"; + for (auto& [k, v] : m_fwd_index) + out << mk_pp(k, m) << " : " << *v << "\n"; + out << "backward\n"; + for (auto& [k, v] : m_bwd_index) + out << mk_pp(k, m) << " : " << *v << "\n"; + return out; +} + + demodulator_simplifier::demodulator_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& st): dependent_expr_simplifier(m, st), + m_index(m), m_util(m), m_match_subst(m), m_rewriter(m), @@ -104,18 +116,19 @@ bool demodulator_simplifier::rewrite1(func_decl* f, expr_ref_vector const& args, if (!m_index.find_fwd(f, set)) return false; - TRACE("demodulator", tout << "trying to rewrite: " << f->get_name() << " args:\n" << args << "\n";); + TRACE("demodulator", tout << "trying to rewrite: " << f->get_name() << " args:" << args << "\n"; m_index.display(tout)); for (unsigned i : *set) { auto const& [lhs, rhs] = m_rewrites[i]; + TRACE("demodulator", tout << "Matching with demodulator: " << i << " " << mk_pp(lhs, m) << "\n"); + if (lhs->get_num_args() != args.size()) continue; SASSERT(lhs->get_decl() == f); - TRACE("demodulator", tout << "Matching with demodulator: " << mk_pp(lhs, m) << "\n"); if (m_match_subst(lhs, rhs, args.data(), np)) { TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(rhs, m) << "\n===>\n" << np << "\n"); @@ -186,6 +199,7 @@ void demodulator_simplifier::reduce() { rewrite(i); if (m_util.is_demodulator(fml(i), large, small)) { func_decl* f = large->get_decl(); + TRACE("demodulator", tout << i << " " << mk_pp(fml(i), m) << ": " << large << " ==> " << small << "\n"); reschedule_processed(f); reschedule_demodulators(f, large); m_index.insert_fwd(f, i); diff --git a/src/ast/simplifiers/demodulator_simplifier.h b/src/ast/simplifiers/demodulator_simplifier.h index afb5d1a18..9dff42f19 100644 --- a/src/ast/simplifiers/demodulator_simplifier.h +++ b/src/ast/simplifiers/demodulator_simplifier.h @@ -18,19 +18,22 @@ Author: #include "util/uint_set.h" class demodulator_index { + ast_manager& m; obj_map m_fwd_index, m_bwd_index; void add(func_decl* f, unsigned i, obj_map& map); void del(func_decl* f, unsigned i, obj_map& map); public: + demodulator_index(ast_manager& m): m(m) {} ~demodulator_index(); void reset(); void insert_fwd(func_decl* f, unsigned i) { add(f, i, m_fwd_index); } void remove_fwd(func_decl* f, unsigned i) { del(f, i, m_fwd_index); } void insert_bwd(expr* e, unsigned i); void remove_bwd(expr* e, unsigned i); - bool find_fwd(func_decl* f, uint_set*& s) { return m_bwd_index.find(f, s); } - bool find_bwd(func_decl* f, uint_set*& s) { return m_fwd_index.find(f, s); } + bool find_fwd(func_decl* f, uint_set*& s) { return m_fwd_index.find(f, s); } + bool find_bwd(func_decl* f, uint_set*& s) { return m_bwd_index.find(f, s); } bool empty() const { return m_fwd_index.empty(); } + std::ostream& display(std::ostream& out) const; }; class demodulator_simplifier : public dependent_expr_simplifier { @@ -56,4 +59,6 @@ class demodulator_simplifier : public dependent_expr_simplifier { demodulator_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& st); void reduce() override; + + char const* name() const override { return "demodulator"; } }; diff --git a/src/ast/substitution/demodulator_rewriter.cpp b/src/ast/substitution/demodulator_rewriter.cpp index 18d6ff925..c25647c01 100644 --- a/src/ast/substitution/demodulator_rewriter.cpp +++ b/src/ast/substitution/demodulator_rewriter.cpp @@ -852,19 +852,45 @@ bool demodulator_match_subst::match_args(app * lhs, expr * const * args) { m_cache.reset(); m_todo.reset(); + auto fill_commutative = [&](app* lhs, expr * const* args) { + if (!lhs->get_decl()->is_commutative()) + return false; + if (lhs->get_num_args() != 2) + return false; + expr* l1 = lhs->get_arg(0); + expr* l2 = lhs->get_arg(1); + expr* r1 = args[0]; + expr* r2 = args[1]; + + if (is_app(l1) && is_app(r1) && to_app(l1)->get_decl() != to_app(r1)->get_decl()) { + m_all_args_eq = false; + m_todo.push_back(expr_pair(l1, r2)); + m_todo.push_back(expr_pair(l2, r1)); + return true; + } + if (is_app(l2) && is_app(r2) && to_app(l2)->get_decl() != to_app(r2)->get_decl()) { + m_all_args_eq = false; + m_todo.push_back(expr_pair(l1, r2)); + m_todo.push_back(expr_pair(l2, r1)); + return true; + } + return false; + }; // fill todo-list, and perform quick success/failure tests m_all_args_eq = true; unsigned num_args = lhs->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * t_arg = lhs->get_arg(i); - expr * i_arg = args[i]; - if (t_arg != i_arg) - m_all_args_eq = false; - if (is_app(t_arg) && is_app(i_arg) && to_app(t_arg)->get_decl() != to_app(i_arg)->get_decl()) { - // quick failure... - return false; + if (!fill_commutative(lhs, args)) { + for (unsigned i = 0; i < num_args; i++) { + expr * t_arg = lhs->get_arg(i); + expr * i_arg = args[i]; + if (t_arg != i_arg) + m_all_args_eq = false; + if (is_app(t_arg) && is_app(i_arg) && to_app(t_arg)->get_decl() != to_app(i_arg)->get_decl()) { + // quick failure... + return false; + } + m_todo.push_back(expr_pair(t_arg, i_arg)); } - m_todo.push_back(expr_pair(t_arg, i_arg)); } if (m_all_args_eq) { @@ -875,48 +901,47 @@ bool demodulator_match_subst::match_args(app * lhs, expr * const * args) { m_subst.reset(); while (!m_todo.empty()) { - expr_pair const & p = m_todo.back(); + auto const & [a, b] = m_todo.back(); - if (is_var(p.first)) { + if (is_var(a)) { expr_offset r; - if (m_subst.find(to_var(p.first), 0, r)) { - if (r.get_expr() != p.second) + if (m_subst.find(to_var(a), 0, r)) { + if (r.get_expr() != b) return false; } else { - m_subst.insert(to_var(p.first), 0, expr_offset(p.second, 1)); + m_subst.insert(to_var(a), 0, expr_offset(b, 1)); } m_todo.pop_back(); continue; } - if (is_var(p.second)) + if (is_var(b)) return false; // we may have nested quantifiers. - if (is_quantifier(p.first) || is_quantifier(p.second)) + if (is_quantifier(a) || is_quantifier(b)) return false; - SASSERT(is_app(p.first) && is_app(p.second)); + SASSERT(is_app(a) && is_app(b)); - if (to_app(p.first)->is_ground() && !to_app(p.second)->is_ground()) + if (to_app(a)->is_ground() && !to_app(b)->is_ground()) return false; - if (p.first == p.second && to_app(p.first)->is_ground()) { - SASSERT(to_app(p.second)->is_ground()); + if (a == b && to_app(a)->is_ground()) { m_todo.pop_back(); continue; } - if (m_cache.contains(p)) { + if (m_cache.contains(expr_pair(a, b))) { m_todo.pop_back(); continue; } - if (p.first == p.second) { - // p.first and p.second is not ground... + if (a == b) { + // a and b is not ground... - // Traverse p.first and check whether every variable X:0 in p.first + // Traverse a and check whether every variable X:0 in a // 1) is unbounded (then we bind X:0 -> X:1) // 2) or, is already bounded to X:1 // If that is, the case, we execute: @@ -927,10 +952,10 @@ bool demodulator_match_subst::match_args(app * lhs, expr * const * args) { // return false; match_args_aux_proc proc(m_subst); try { - for_each_expr(proc, p.first); + for_each_expr(proc, a); // succeeded m_todo.pop_back(); - m_cache.insert(p); + m_cache.insert(expr_pair(a, b)); continue; } catch (const match_args_aux_proc::no_match &) { @@ -938,8 +963,8 @@ bool demodulator_match_subst::match_args(app * lhs, expr * const * args) { } } - app * n1 = to_app(p.first); - app * n2 = to_app(p.second); + app * n1 = to_app(a); + app * n2 = to_app(b); if (n1->get_decl() != n2->get_decl()) return false; @@ -953,12 +978,13 @@ bool demodulator_match_subst::match_args(app * lhs, expr * const * args) { if (num_args1 == 0) continue; - m_cache.insert(p); - unsigned j = num_args1; - while (j > 0) { - --j; + m_cache.insert(expr_pair(a, b)); + + if (fill_commutative(n1, n2->get_args())) + continue; + + for (unsigned j = num_args1; j-- > 0; ) m_todo.push_back(expr_pair(n1->get_arg(j), n2->get_arg(j))); - } } return true; } diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index bc8c4ab71..8a86e9a0b 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -32,6 +32,7 @@ z3_add_component(core_tactics cofactor_term_ite_tactic.h collect_statistics_tactic.h ctx_simplify_tactic.h + demodulator_tactic.h der_tactic.h distribute_forall_tactic.h dom_simplify_tactic.h diff --git a/src/tactic/core/demodulator_tactic.h b/src/tactic/core/demodulator_tactic.h new file mode 100644 index 000000000..2583e902e --- /dev/null +++ b/src/tactic/core/demodulator_tactic.h @@ -0,0 +1,40 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + demodulator_tactic.h + +Abstract: + + Tactic for solving variables + +Author: + + Nikolaj Bjorner (nbjorner) 2022-10-30 + +--*/ +#pragma once + +#include "util/params.h" +#include "tactic/tactic.h" +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/demodulator_simplifier.h" + + +class demodulator_tactic_factory : public dependent_expr_simplifier_factory { +public: + dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { + return alloc(demodulator_simplifier, m, p, s); + } +}; + +inline tactic * mk_demodulator_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, alloc(demodulator_tactic_factory)); +} + +/* + ADD_TACTIC("demodulator", "solve for variables.", "mk_demodulator_tactic(m, p)") +*/ + + From eb8c53c16431ddb6f3f07b5f102eab2a1a50769b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 5 Dec 2022 14:07:57 +0000 Subject: [PATCH 376/477] simplify factory of dependent_expr_state_tactic And as a side-effect, remove heap allocations for factories --- src/ast/simplifiers/dependent_expr_state.h | 18 ------------------ src/qe/lite/qe_lite.cpp | 10 ++-------- src/tactic/arith/card2bv_tactic.h | 13 ++----------- src/tactic/bv/bv_slice_tactic.cpp | 11 ++--------- src/tactic/bv/max_bv_sharing_tactic.h | 9 +-------- src/tactic/core/demodulator_tactic.h | 13 ++----------- src/tactic/core/elim_uncnstr2_tactic.h | 13 ++----------- src/tactic/core/eliminate_predicates_tactic.h | 13 ++----------- src/tactic/core/euf_completion_tactic.cpp | 10 ++-------- src/tactic/core/propagate_values2_tactic.h | 14 ++------------ src/tactic/core/solve_eqs_tactic.h | 13 ++----------- src/tactic/dependent_expr_state_tactic.h | 12 +++++++----- 12 files changed, 26 insertions(+), 123 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index d7aa1d6eb..212bc99a4 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -149,21 +149,3 @@ public: ast_manager& get_manager() { return m; } dependent_expr_state& get_fmls() { return m_fmls; } }; - -/** - Factory interface for creating simplifiers. - The use of a factory allows delaying the creation of the dependent_expr_state - argument until the point where the expression simplifier is created. - This is used in tactics where the dependent_expr_state is a reference to the - new tactic. - - Alternatively have a clone method on dependent_expr_simplifier. - */ -class dependent_expr_simplifier_factory { - unsigned m_ref = 0; -public: - virtual dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) = 0; - virtual ~dependent_expr_simplifier_factory() {} - void inc_ref() { ++m_ref; } - void dec_ref() { if (--m_ref == 0) dealloc(this); } -}; diff --git a/src/qe/lite/qe_lite.cpp b/src/qe/lite/qe_lite.cpp index 2ea11b6b9..d3d45bd4b 100644 --- a/src/qe/lite/qe_lite.cpp +++ b/src/qe/lite/qe_lite.cpp @@ -2440,17 +2440,11 @@ namespace { } } }; - - class qe_lite_tactic_factory : public dependent_expr_simplifier_factory { - public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(qe_lite_simplifier, m, p, s); - } - }; } tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p) { - return alloc(dependent_expr_state_tactic, m, p, alloc(qe_lite_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(qe_lite_simplifier, m, p, s); }); } dependent_expr_simplifier* mk_qe_lite_simplifer(ast_manager& m, params_ref const& p, dependent_expr_state& st) { diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 63cb021d7..d7ad76e7d 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -16,25 +16,16 @@ Author: --*/ #pragma once - #include "util/params.h" #include "tactic/tactic.h" #include "tactic/dependent_expr_state_tactic.h" #include "ast/simplifiers/card2bv.h" -class card2bv_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(card2bv, m, p, s); - } -}; - inline tactic* mk_card2bv_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(card2bv_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(card2bv, m, p, s); }); } /* ADD_TACTIC("card2bv", "convert pseudo-boolean constraints to bit-vectors.", "mk_card2bv_tactic(m, p)") */ - - diff --git a/src/tactic/bv/bv_slice_tactic.cpp b/src/tactic/bv/bv_slice_tactic.cpp index 17d69c7b1..d470f6e72 100644 --- a/src/tactic/bv/bv_slice_tactic.cpp +++ b/src/tactic/bv/bv_slice_tactic.cpp @@ -20,14 +20,7 @@ Author: #include "tactic/dependent_expr_state_tactic.h" #include "tactic/bv/bv_slice_tactic.h" - -class bv_slice_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(bv::slice, m, s); - } -}; - tactic* mk_bv_slice_tactic(ast_manager& m, params_ref const& p) { - return alloc(dependent_expr_state_tactic, m, p, alloc(bv_slice_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(bv::slice, m, s); }); } diff --git a/src/tactic/bv/max_bv_sharing_tactic.h b/src/tactic/bv/max_bv_sharing_tactic.h index 3521b4a04..bf14e9f14 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.h +++ b/src/tactic/bv/max_bv_sharing_tactic.h @@ -24,15 +24,8 @@ Revision History: #include "ast/simplifiers/max_bv_sharing.h" #include "tactic/dependent_expr_state_tactic.h" -class max_bv_sharing_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return mk_max_bv_sharing(m, p, s); - } -}; - inline tactic* mk_max_bv_sharing_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(max_bv_sharing_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, mk_max_bv_sharing); } /* diff --git a/src/tactic/core/demodulator_tactic.h b/src/tactic/core/demodulator_tactic.h index 2583e902e..b278392c9 100644 --- a/src/tactic/core/demodulator_tactic.h +++ b/src/tactic/core/demodulator_tactic.h @@ -21,20 +21,11 @@ Author: #include "tactic/dependent_expr_state_tactic.h" #include "ast/simplifiers/demodulator_simplifier.h" - -class demodulator_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(demodulator_simplifier, m, p, s); - } -}; - inline tactic * mk_demodulator_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(demodulator_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(demodulator_simplifier, m, p, s); }); } /* ADD_TACTIC("demodulator", "solve for variables.", "mk_demodulator_tactic(m, p)") */ - - diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h index e7226a8f0..61e3bbb5a 100644 --- a/src/tactic/core/elim_uncnstr2_tactic.h +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -21,20 +21,11 @@ Author: #include "tactic/dependent_expr_state_tactic.h" #include "ast/simplifiers/elim_unconstrained.h" -class elim_uncnstr2_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(elim_unconstrained, m, s); - } -}; - inline tactic * mk_elim_uncnstr2_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(elim_uncnstr2_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(elim_unconstrained, m, s); }); } - /* ADD_TACTIC("elim-uncnstr2", "eliminate unconstrained variables.", "mk_elim_uncnstr2_tactic(m, p)") */ - - diff --git a/src/tactic/core/eliminate_predicates_tactic.h b/src/tactic/core/eliminate_predicates_tactic.h index de2291260..d89f369dc 100644 --- a/src/tactic/core/eliminate_predicates_tactic.h +++ b/src/tactic/core/eliminate_predicates_tactic.h @@ -21,20 +21,11 @@ Author: #include "tactic/tactic.h" #include "tactic/dependent_expr_state_tactic.h" - -class eliminate_predicates_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(eliminate_predicates, m, s); - } -}; - inline tactic * mk_eliminate_predicates_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(eliminate_predicates_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(eliminate_predicates, m, s); }); } /* ADD_TACTIC("elim-predicates", "eliminate predicates.", "mk_eliminate_predicates_tactic(m, p)") */ - - diff --git a/src/tactic/core/euf_completion_tactic.cpp b/src/tactic/core/euf_completion_tactic.cpp index d229df62f..ec4408782 100644 --- a/src/tactic/core/euf_completion_tactic.cpp +++ b/src/tactic/core/euf_completion_tactic.cpp @@ -20,13 +20,7 @@ Author: #include "ast/simplifiers/euf_completion.h" #include "tactic/core/euf_completion_tactic.h" -class euf_completion_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(euf::completion, m, s); - } -}; - tactic * mk_euf_completion_tactic(ast_manager& m, params_ref const& p) { - return alloc(dependent_expr_state_tactic, m, p, alloc(euf_completion_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(euf::completion, m, s); }); } diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h index 834e8bebd..4c89fae97 100644 --- a/src/tactic/core/propagate_values2_tactic.h +++ b/src/tactic/core/propagate_values2_tactic.h @@ -14,8 +14,6 @@ Author: Nikolaj Bjorner (nbjorner) 2022-11-24 --*/ - -#include "util/params.h" #pragma once #include "util/params.h" @@ -23,19 +21,11 @@ Author: #include "tactic/dependent_expr_state_tactic.h" #include "ast/simplifiers/propagate_values.h" -class propagate_values2_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(propagate_values, m, p, s); - } -}; - inline tactic * mk_propagate_values2_tactic(ast_manager & m, params_ref const & p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(propagate_values2_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(propagate_values, m, p, s); }); } - /* ADD_TACTIC("propagate-values2", "propagate constants.", "mk_propagate_values2_tactic(m, p)") */ - diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 76a738660..a0fd3b63b 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -21,20 +21,11 @@ Author: #include "tactic/dependent_expr_state_tactic.h" #include "ast/simplifiers/solve_eqs.h" - -class solve_eqs_tactic_factory : public dependent_expr_simplifier_factory { -public: - dependent_expr_simplifier* mk(ast_manager& m, params_ref const& p, dependent_expr_state& s) override { - return alloc(euf::solve_eqs, m, s); - } -}; - inline tactic * mk_solve_eqs_tactic(ast_manager& m, params_ref const& p = params_ref()) { - return alloc(dependent_expr_state_tactic, m, p, alloc(solve_eqs_tactic_factory)); + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(euf::solve_eqs, m, s); }); } /* ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs_tactic(m, p)") */ - - diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 3afc0fc9f..f2d532368 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -20,19 +20,22 @@ Author: #include "ast/simplifiers/dependent_expr_state.h" class dependent_expr_state_tactic : public tactic, public dependent_expr_state { +public: + using factoryTy = dependent_expr_simplifier(*(*)(ast_manager& m, params_ref const& p, dependent_expr_state& s)); +private: ast_manager& m; params_ref m_params; trail_stack m_trail; goal_ref m_goal; dependent_expr m_dep; statistics m_st; - ref m_factory; + factoryTy m_factory; scoped_ptr m_simp; scoped_ptr m_model_trail; void init() { if (!m_simp) { - m_simp = m_factory->mk(m, m_params, *this); + m_simp = m_factory(m, m_params, *this); m_st.reset(); } if (!m_model_trail) @@ -41,12 +44,11 @@ class dependent_expr_state_tactic : public tactic, public dependent_expr_state { public: - dependent_expr_state_tactic(ast_manager& m, params_ref const& p, dependent_expr_simplifier_factory* f): + dependent_expr_state_tactic(ast_manager& m, params_ref const& p, factoryTy f): dependent_expr_state(m), m(m), m_params(p), m_factory(f), - m_simp(nullptr), m_dep(m, m.mk_true(), nullptr) {} @@ -96,7 +98,7 @@ public: } tactic * translate(ast_manager & m) override { - return alloc(dependent_expr_state_tactic, m, m_params, m_factory.get()); + return alloc(dependent_expr_state_tactic, m, m_params, m_factory); } void operator()(goal_ref const & in, From a2f5a5b50b47f64ee02db964058da05ce00a4656 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 5 Dec 2022 14:29:14 +0000 Subject: [PATCH 377/477] remove memory alloc from statistics_report --- src/tactic/core/elim_uncnstr_tactic.cpp | 3 +-- src/tactic/tactic.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index ed54b6768..b8b4334f4 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -867,8 +867,7 @@ class elim_uncnstr_tactic : public tactic { void run(goal_ref const & g, goal_ref_buffer & result) { bool produce_proofs = g->proofs_enabled(); TRACE("goal", g->display(tout);); - std::function coll = [&](statistics& st) { collect_statistics(st); }; - statistics_report sreport(coll); + statistics_report sreport([&](statistics& st) { collect_statistics(st); }); tactic_report report("elim-uncnstr", *g); m_vars.reset(); collect_occs p; diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index c43120943..ddd187337 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -120,7 +120,7 @@ class statistics_report { std::function m_collector; public: statistics_report(tactic& t):m_tactic(&t) {} - statistics_report(std::function& coll): m_collector(coll) {} + statistics_report(std::function&& coll): m_collector(std::move(coll)) {} ~statistics_report(); }; From f1a65d964224cff059ac1aabfa8a47a90c594107 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Dec 2022 03:34:14 -0800 Subject: [PATCH 378/477] add documentation notes --- src/tactic/core/demodulator_tactic.h | 67 +++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/tactic/core/demodulator_tactic.h b/src/tactic/core/demodulator_tactic.h index b278392c9..c591f9089 100644 --- a/src/tactic/core/demodulator_tactic.h +++ b/src/tactic/core/demodulator_tactic.h @@ -7,12 +7,75 @@ Module Name: Abstract: - Tactic for solving variables + Tactic for rewriting goals using quantified equalities Author: Nikolaj Bjorner (nbjorner) 2022-10-30 +Documentation Notes: + +Name: demodulator + +Short Description: + extracts equalities from quantifiers and applies them for simplification + +Long Description: + In first-order theorem proving (FOTP), a demodulator is a universally quantified formula of the form: + + Forall X1, ..., Xn. L[X1, ..., Xn] = R[X1, ..., Xn] + Where L[X1, ..., Xn] contains all variables in R[X1, ..., Xn], and + L[X1, ..., Xn] is "bigger" than R[X1, ...,Xn]. + + The idea is to replace something big L[X1, ..., Xn] with something smaller R[X1, ..., Xn]. + + After selecting the demodulators, we traverse the rest of the formula looking for instances of L[X1, ..., Xn]. + Whenever we find an instance, we replace it with the associated instance of R[X1, ..., Xn]. + + For example, suppose we have + + ``` + Forall x, y. f(x+y, y) = y + and + f(g(b) + h(c), h(c)) <= 0 + ``` + + The term `f(g(b) + h(c), h(c))` is an instance of `f(x+y, y)` if we replace `x <- g(b)` and `y <- h(c)`. + So, we can replace it with `y` which is bound to `h(c)` in this example. So, the result of the transformation is: + + ``` + Forall x, y. f(x+y, y) = y + and + h(c) <= 0 + ``` + + +Usage: + (declare-sort S 0) + (declare-sort S1 0) + (declare-sort S2 0) + (declare-fun f () S) + (declare-fun f1 () S) + (declare-fun f2 (S1 S) S) + (declare-fun f3 (S2 S) S1) + (declare-fun f4 () S) + (declare-fun f5 () S2) + (assert (not (= f1 (f2 (f3 f5 f4) f)))) + (assert (forall ((q S) (v S)) (or (= q v) (= f1 (f2 (f3 f5 q) v)) (= (f2 (f3 f5 v) q) f1)))) + (assert (forall ((q S) (x S)) (not (= (f2 (f3 f5 q) x) f1)))) + (apply demodulator) + + (goals + (goal + (forall ((q S) (v S)) (= q v)) + (forall ((q S) (x S)) (not (= (f2 (f3 f5 q) x) f1))) + :precision precise :depth 1) + ) + +Supports: unsat cores + +Does not support: proofs + --*/ #pragma once @@ -27,5 +90,5 @@ inline tactic * mk_demodulator_tactic(ast_manager& m, params_ref const& p = para } /* - ADD_TACTIC("demodulator", "solve for variables.", "mk_demodulator_tactic(m, p)") + ADD_TACTIC("demodulator", "extracts equalities from quantifiers and applies them to simplify.", "mk_demodulator_tactic(m, p)") */ From 5a5758baaa54eef5a65b58414d4cb082515a37fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Dec 2022 20:04:58 -0800 Subject: [PATCH 379/477] add documentation to initial selection of tactics --- doc/mk_tactic_doc.py | 47 ++++++++++++ src/ast/simplifiers/solve_context_eqs.cpp | 2 +- src/tactic/core/demodulator_tactic.h | 67 +++++++++-------- src/tactic/core/elim_uncnstr2_tactic.h | 90 +++++++++++++++++++++++ src/tactic/core/solve_eqs_tactic.h | 55 +++++++++++++- 5 files changed, 229 insertions(+), 32 deletions(-) create mode 100644 doc/mk_tactic_doc.py diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py new file mode 100644 index 000000000..49d2a177a --- /dev/null +++ b/doc/mk_tactic_doc.py @@ -0,0 +1,47 @@ +# Copyright (c) Microsoft Corporation 2015 +""" +Tactic documentation generator script +""" + +import os +import re + +SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) +OUTPUT_DIRECTORY = os.path.join(os.getcwd(), 'api') + +def doc_path(path): + return os.path.join(SCRIPT_DIR, path) + +is_doc = re.compile("Tactic Documentation") +is_doc_end = re.compile("\-\-\*\/") + +def generate_tactic_doc(ous, f, ins): + for line in ins: + if is_doc_end.search(line): + break + ous.write(line) + +def extract_tactic_doc(ous, f): + with open(f) as ins: + for line in ins: + if is_doc.search(line): + generate_tactic_doc(ous, f, ins) + +def help(ous): + ous.write("---\n") + ous.write("title: Tactics Summary\n") + ous.write("sidebar_position: 5\n") + ous.write("---\n") + for root, dirs, files in os.walk(doc_path("../src")): + for f in files: + if f.endswith("tactic.h"): + extract_tactic_doc(ous, os.path.join(root, f)) + +def mk_dir(d): + if not os.path.exists(d): + os.makedirs(d) + +mk_dir(os.path.join(OUTPUT_DIRECTORY, 'md')) + +with open(OUTPUT_DIRECTORY + "/md/tactics-summary.md",'w') as ous: + help(ous) diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index e87381825..6cb38e4a6 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -279,7 +279,7 @@ namespace euf { } else if (m.is_not(f, f)) todo.push_back({ !s, depth, f }); - else if (!s && 1 == depth % 2) { + else if (!s && 1 <= depth) { for (extract_eq* ex : m_solve_eqs.m_extract_plugins) { ex->set_allow_booleans(false); ex->get_eqs(dependent_expr(m, f, df.dep()), eqs); diff --git a/src/tactic/core/demodulator_tactic.h b/src/tactic/core/demodulator_tactic.h index c591f9089..9ffaa6ca9 100644 --- a/src/tactic/core/demodulator_tactic.h +++ b/src/tactic/core/demodulator_tactic.h @@ -13,44 +13,47 @@ Author: Nikolaj Bjorner (nbjorner) 2022-10-30 -Documentation Notes: +Tactic Documentation: -Name: demodulator +## Tactic demodulator -Short Description: - extracts equalities from quantifiers and applies them for simplification +### Short Description: -Long Description: - In first-order theorem proving (FOTP), a demodulator is a universally quantified formula of the form: +Extracts equalities from quantifiers and applies them for simplification - Forall X1, ..., Xn. L[X1, ..., Xn] = R[X1, ..., Xn] - Where L[X1, ..., Xn] contains all variables in R[X1, ..., Xn], and - L[X1, ..., Xn] is "bigger" than R[X1, ...,Xn]. +### Long Description - The idea is to replace something big L[X1, ..., Xn] with something smaller R[X1, ..., Xn]. +In first-order theorem proving (FOTP), a demodulator is a universally quantified formula of the form: - After selecting the demodulators, we traverse the rest of the formula looking for instances of L[X1, ..., Xn]. - Whenever we find an instance, we replace it with the associated instance of R[X1, ..., Xn]. +`Forall X1, ..., Xn. L[X1, ..., Xn] = R[X1, ..., Xn]` +Where `L[X1, ..., Xn]` contains all variables in `R[X1, ..., Xn]`, and +`L[X1, ..., Xn]` is "bigger" than `R[X1, ...,Xn]`. - For example, suppose we have +The idea is to replace something big `L[X1, ..., Xn]` with something smaller `R[X1, ..., Xn]`. - ``` - Forall x, y. f(x+y, y) = y - and - f(g(b) + h(c), h(c)) <= 0 - ``` +After selecting the demodulators, we traverse the rest of the formula looking for instances of `L[X1, ..., Xn]`. +Whenever we find an instance, we replace it with the associated instance of `R[X1, ..., Xn]`. - The term `f(g(b) + h(c), h(c))` is an instance of `f(x+y, y)` if we replace `x <- g(b)` and `y <- h(c)`. - So, we can replace it with `y` which is bound to `h(c)` in this example. So, the result of the transformation is: +For example, suppose we have - ``` - Forall x, y. f(x+y, y) = y - and - h(c) <= 0 - ``` +``` +Forall x, y. f(x+y, y) = y +and +f(g(b) + h(c), h(c)) <= 0 +``` +The term `f(g(b) + h(c), h(c))` is an instance of `f(x+y, y)` if we replace `x <- g(b)` and `y <- h(c)`. +So, we can replace it with `y` which is bound to `h(c)` in this example. So, the result of the transformation is: -Usage: +``` +Forall x, y. f(x+y, y) = y +and +h(c) <= 0 +``` + +### Example + +``` (declare-sort S 0) (declare-sort S1 0) (declare-sort S2 0) @@ -64,17 +67,23 @@ Usage: (assert (forall ((q S) (v S)) (or (= q v) (= f1 (f2 (f3 f5 q) v)) (= (f2 (f3 f5 v) q) f1)))) (assert (forall ((q S) (x S)) (not (= (f2 (f3 f5 q) x) f1)))) (apply demodulator) - +``` + +It generates + +``` (goals (goal (forall ((q S) (v S)) (= q v)) (forall ((q S) (x S)) (not (= (f2 (f3 f5 q) x) f1))) :precision precise :depth 1) ) +``` -Supports: unsat cores +### Notes -Does not support: proofs +* supports unsat cores +* does not support fine-grained proofs --*/ #pragma once diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h index 61e3bbb5a..f1c9b9bd7 100644 --- a/src/tactic/core/elim_uncnstr2_tactic.h +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -13,6 +13,96 @@ Author: Nikolaj Bjorner (nbjorner) 2022-10-30 +Tactic Documentation: + +## Tactic elim-uncnstr + +### Short Description + +Eliminate Unconstrained uninterpreted constants + +### Long Description + +The tactic eliminates uninterpreted constants that occur only once in a goal and such that the immediate context +where they occur can be replaced by a fresh constant. We call these occurrences invertible. +It relies on a series of theory specific invertibility transformations. +In the following assume `x` and `x'` occur in a unique subterm and `y` is a fresh uninterpreted constant. + +#### Boolean Connectives + +| Original Context | New Term | Updated solution | +|------------------|----------|------------------------ | +`(if c x x')` | `y` | `x = x' = y` | +`(if x x' e)` | `y` | `x = true, x' = y` | +`(if x t x')` | `y` | `x = false, x' = y` | +`(not x)` | `y` | `x = (not y)` | +`(and x x')` | `y` | `x = y, x' = true` | +`(or x x')` | `y` | `x = y, x' = false` | +`(= x t)` | `y` | `x = (if y t (diff t))` | + +where diff is a diagnonalization function available in domains of size `>` 1. + +#### Arithmetic + +| Original Context | New Term | Updated solution | +|------------------|----------|------------------------ | +`(+ x t)` | `y` | `x = y - t` | +`(* x x')` | `y` | `x = y, x' = 1` | +`(* -1 x)` | `y` | `x = -y` | +`(<= x t)` | `y` | `x = (if y t (+ t 1))` | +`(<= t x)` | `y` | `x = (if y t (- t 1))` | + +#### Bit-vectors + +| Original Context | New Term | Updated solution | +|------------------|----------|--------------------------| +`(bvadd x t)` | `y` | `x = y - t` | +`(bvmul x x')` | `y` | `x = y, x' = 1` | +`(bvmul odd x)` | `y` | `x = inv(odd)*y` | +`((extract sz-1 0) x)` | `y` | `x = y` | +`((extract hi lo) x)` | `y` | `x = (concat y1 y y2)` | +`(udiv x x')` | `y` | `x = y, x' = 1` | +`(concat x x')` | `y` | `x = (extract hi1 lo1 y)` | +`(bvule x t)` | `(or y (= t MAX))` | `x = (if y t (bvadd t 1))` | +`(bvule t x)` | `(or y (= t MIN))` | `x = (if y t (bvsub t 1))` | +`(bvnot x)` | `y` | `x = (bvnot y)` | +`(bvand x x')` | `y` | `x = y, x' = MAX` | + +In addition there are conversions for shift and bit-wise or and signed comparison. + +#### Arrays + +| Original Context | New Term | Updated solution | +|------------------|----------|--------------------------| +`(select x t)` | `y` | `x = (const y)` | +`(store x x1 x2)` | `y` | `x2 = (select x x1), x = y, x1 = arb` | + +#### Algebraic Datatypes + +| Original Context | New Term | Updated solution | +|------------------|----------|--------------------------| +`(head x)` | `y` | `x = (cons y arb)` | + + + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-fun p (Int) Bool) +(assert (>= (+ y (+ x y)) y)) +(assert (p y)) +(apply elim-uncnstr) +(assert (p (+ x y))) +(apply elim-uncnstr) +``` + +### Notes + +* supports unsat cores +* does not support fine-grained proofs + --*/ #pragma once diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index a0fd3b63b..1207f3de9 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -13,9 +13,60 @@ Author: Nikolaj Bjorner (nbjorner) 2022-10-30 ---*/ -#pragma once +Tactic Documentation: +## Tactic solve-eqs + +### Short Description + +Solve for variables + +### Long Description + +The tactic eliminates variables that can be brought into solved form. +For example, the assertion `x = f(y + z)` can be solved for `x`, replacing `x` +everywhere by `f(x + y)`. It depends on a set of theory specific equality solvers + +* Basic equations + * equations between uninterpreted constants and terms. + * equations written as `(if p (= x t) (= x s))` are solved as `(= x (if p t s))`. + * asserting `p` or `(not p)` where `p` is uninterpreted, causes `p` to be replaced by `true` (or `false`). + +* Arithmetic equations + * It solves `x mod k = s` to `x = k * m' + s`, where m'` is a fresh constant. + * It finds variables with unit coefficients in integer linear equations. + * It solves for `x * Y = Z$ under the side-condition `Y != 0` as `x = Z/Y`. + +It also allows solving for uninterpreted constants that only appear in a single disjuction. For example, +`(or (= x (+ 5 y)) (= y (+ u z)))` allows solving for `x`. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(declare-const u Int) +(assert (or (and (= x (+ 5 y)) (> u z)) (= y (+ u z)))) +(apply solve-eqs) +``` + +It produces the goal +``` +(goal + (or (not (<= u z)) (= y (+ u z))) + :precision precise :depth 1) +``` +where `x` was solved as `(+ 5 y)`. + +### Notes + +* supports unsat cores +* does not support fine-grained proofs + +--*/ + +#pragma once #include "util/params.h" #include "tactic/tactic.h" #include "tactic/dependent_expr_state_tactic.h" From 90ba225ae3bd82aa9be438303f02d6a9e650a993 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 05:39:05 -0800 Subject: [PATCH 380/477] add more doc Signed-off-by: Nikolaj Bjorner --- src/tactic/core/propagate_values2_tactic.h | 35 +++++++++++++++++++--- src/tactic/core/simplify_tactic.h | 32 +++++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h index 4c89fae97..e380ce7d3 100644 --- a/src/tactic/core/propagate_values2_tactic.h +++ b/src/tactic/core/propagate_values2_tactic.h @@ -5,14 +5,41 @@ Module Name: propagate_values2_tactic.h -Abstract: - - Tactic for propagating equalities (= t v) where v is a value - Author: Nikolaj Bjorner (nbjorner) 2022-11-24 +Tactic Documentation: + +## Tactic propagate-values + +### Short Description: + +Tactic for propagating equalities `(= t v)` where `v` is a value + +### Long Description + +In a context where terms are equated to constants it is invariably beneficial to +replace terms, that can be compound, with the constants and then simplify the resulting formulas. +The propagate-values tactic accomplishes the task of replacing such terms. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-fun f (Int) Int) +(assert (= 1 (f (+ x y)))) +(assert (= 2 x)) +(assert (> (f (+ 2 y)) y)) +(apply propagate-values) +``` + +### Notes + +* supports unsat cores + + --*/ #pragma once diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index fc262f998..39e3e9bde 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -13,7 +13,37 @@ Author: Leonardo (leonardo) 2011-11-20 -Notes: +Tactic Documentation: + +## Tactic simplify + +### Short Description: + +The tactic performs algebraic simplifcations on formulas + +### Long Description + +The simplify tactic invokes z3's main rewriting engine. +The rewriting engine contains support for theory specific simplifications. +The set of simplifications invoked is open ended. Useful algebraic simplifications +are added to the rewrite engine as they are discovered to be useful. + +Note that the simplifier does not ensure that equivalent formulas are simplified to the same form. +In other words it does not guarantee canonicity. This contrasts with BDD packages where BDDs constructed +from two equivalent formulas are guaranteed to be equal. + +### Example + +```z3 + (declare-const x Int) + (declare-const y Int) + (assert (> x (+ x y))) + (apply simplify) +``` + +### Notes + +* supports unsat cores, proof terms --*/ #pragma once From 7df4e04a2c881479d661a2c9d3edea2913548118 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 05:46:52 -0800 Subject: [PATCH 381/477] add der description Signed-off-by: Nikolaj Bjorner --- src/tactic/core/der_tactic.h | 33 ++++++++++++++++++++++++++++++ src/tactic/core/solve_eqs_tactic.h | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/tactic/core/der_tactic.h b/src/tactic/core/der_tactic.h index 01417c08d..555d3108d 100644 --- a/src/tactic/core/der_tactic.h +++ b/src/tactic/core/der_tactic.h @@ -13,6 +13,39 @@ Author: Leonardo de Moura (leonardo) 2012-10-20 +Tactic Documentation: + +## Tactic der + +### Short Description: + +The tactic performs _destructive equality resolution_. + +### Long Description + +Destructive equality resolution replaces bound variables that are +_solved_ by their solutions in formulas. In short, the destructive +equality resolution rule takes the form: + +``` + (forall (X Y) (or X /= s C[X])) --> (forall (Y) C[Y]) +``` + + +### Example + +```z3 + (declare-fun f (Int) Int) + (declare-fun p (Int Int) Bool) + (assert (forall ((x Int) (y Int)) (or (not (= x (f y))) (p x y)))) + (apply der) +``` + +### Notes + +* supports unsat cores, proof terms + + --*/ #pragma once diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 1207f3de9..604bcf426 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -42,7 +42,7 @@ It also allows solving for uninterpreted constants that only appear in a single ### Example -```z3 +``` (declare-const x Int) (declare-const y Int) (declare-const z Int) From 1e06c7414acf11bd4ad85f777d4ed1f6d49e1c3e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 15:44:21 -0800 Subject: [PATCH 382/477] add doc --- doc/mk_tactic_doc.py | 23 ++++++++++ src/tactic/core/nnf_tactic.h | 42 ++++++++++++++++- src/tactic/core/reduce_args_tactic.h | 67 +++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index 49d2a177a..b49811fb9 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -5,7 +5,10 @@ Tactic documentation generator script import os import re +import sys +import subprocess +BUILD_DIR='../build' SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) OUTPUT_DIRECTORY = os.path.join(os.getcwd(), 'api') @@ -14,10 +17,30 @@ def doc_path(path): is_doc = re.compile("Tactic Documentation") is_doc_end = re.compile("\-\-\*\/") +is_tac_name = re.compile("## Tactic (.*)") +def extract_params(ous, tac): + z3_exe = BUILD_DIR + "/z3" + out = subprocess.Popen([z3_exe, f"-tactics:{tac}"], stdout=subprocess.PIPE).communicate()[0] + if not out: + return + out = out.decode(sys.stdout.encoding) + ous.write("#### Parameters\n") + ous.write("```\n") + for line in out: + ous.write(line.replace("\r","")) + ous.write("\n") + ous.write("```\n") + def generate_tactic_doc(ous, f, ins): + tac_name = None for line in ins: + m = is_tac_name.search(line) + if m: + tac_name = m.group(1) if is_doc_end.search(line): + if tac_name: + extract_params(ous, tac_name) break ous.write(line) diff --git a/src/tactic/core/nnf_tactic.h b/src/tactic/core/nnf_tactic.h index a821f56d0..fa724f2b8 100644 --- a/src/tactic/core/nnf_tactic.h +++ b/src/tactic/core/nnf_tactic.h @@ -13,7 +13,47 @@ Author: Leonardo de Moura (leonardo) 2011-12-28. -Revision History: +Note: + + tactic documentation below co-created using gptchat (with some corrections) :-) + +Tactic Documentation: + +## Tactic nnf + +### Short Description: + +The tactic converts formulas to negation normal form (NNF) + +### Long Description + +In NNF, negations only appear in front of atomic formulas. + +Standard rules for conversion into negation normal form are: +- `(not (and p q))` is converted to `(or (not p) (not q))` +- `(not (or p q))` is converted to `(and (not p) (not q))` +- `(not (not p))` is converted to `p` +- `(not (exists x. p))` is converted to `(forall x. (not p))` +- `(not (forall x. p))` is converted to `(exists x. (not p))` + + +Once all negations are pushed inside, the resulting formula is in NNF. + +### Example + +```z3 + (declare-const x Int) + (assert (not (or (> x 0) (< x 0)))) + (apply nnf) +``` + +This would convert the formula (not (or (> x 0) (< x 0))) to (and (<= x 0) (>= x 0)), which is in NNF. + +### Notes + +* supports unsat cores, proof terms + + --*/ #pragma once diff --git a/src/tactic/core/reduce_args_tactic.h b/src/tactic/core/reduce_args_tactic.h index ed4dc3fb3..5fa1f74cd 100644 --- a/src/tactic/core/reduce_args_tactic.h +++ b/src/tactic/core/reduce_args_tactic.h @@ -13,7 +13,72 @@ Author: Leonardo (leonardo) 2012-02-19 -Notes: +Tactic Documentation: + +## Tactic reduce-args + +### Short Description: + +Reduce the number of arguments of function applications, when for all occurrences of a function f the i-th is a value. + +### Long Description + +Example, suppose we have a function `f` with `2` arguments. +There are 1000 applications of this function, but the first argument is always "a", "b" or "c". +Thus, we replace the `f(t1, t2)` with + +* `f_a(t2)` if `t1 = a` +* `f_b(t2)` if `t2 = b` +* `f_c(t2)` if `t2 = c` + +Since `f_a`, `f_b`, `f_c` are new symbols, satisfiability is preserved. + +This transformation is very similar in spirit to the Ackermman's reduction. + +This transformation should work in the following way: + +``` + 1- Create a mapping decl2arg_map from declarations to tuples of booleans, an entry [f -> (true, false, true)] + means that f is a declaration with 3 arguments where the first and third arguments are always values. + 2- Traverse the formula and populate the mapping. + For each function application f(t1, ..., tn) do + a) Create a boolean tuple (is_value(t1), ..., is_value(tn)) and do + the logical-and with the tuple that is already in the mapping. If there is no such tuple + in the mapping, we just add a new entry. + + If all entries are false-tuples, then there is nothing to be done. The transformation is not applicable. + + Now, we create a mapping decl2new_decl from (decl, val_1, ..., val_n) to decls. Note that, n may be different for each entry, + but it is the same for the same declaration. + For example, suppose we have [f -> (true, false, true)] in decl2arg_map, + and applications f(1, a, 2), f(1, b, 2), f(1, b, 3), f(2, b, 3), f(2, c, 3) in the formula. + Then, decl2arg_map would contain + (f, 1, 2) -> f_1_2 + (f, 1, 3) -> f_1_3 + (f, 2, 3) -> f_2_3 + where f_1_2, f_1_3 and f_2_3 are new function symbols. + Using the new map, we can replace the occurrences of f. +``` + +### Example + +```z3 +(declare-fun f (Int Int) Bool) +(declare-const x Int) +(assert (f 1 2)) +(assert (f 1 3)) +(assert (f 2 4)) +(assert (f 2 5)) +(assert (f 1 6)) +(assert (f 1 7)) +(assert (f 1 x)) +(apply reduce-args) +``` + +### Notes + +* supports unsat cores +* does not support proof terms --*/ #pragma once From d125d87aed403edaf2e971f4038e573eaba708c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 15:51:38 -0800 Subject: [PATCH 383/477] typo Signed-off-by: Nikolaj Bjorner --- src/tactic/core/solve_eqs_tactic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 604bcf426..fec46bf04 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -35,7 +35,7 @@ everywhere by `f(x + y)`. It depends on a set of theory specific equality solver * Arithmetic equations * It solves `x mod k = s` to `x = k * m' + s`, where m'` is a fresh constant. * It finds variables with unit coefficients in integer linear equations. - * It solves for `x * Y = Z$ under the side-condition `Y != 0` as `x = Z/Y`. + * It solves for `x * Y = Z` under the side-condition `Y != 0` as `x = Z/Y`. It also allows solving for uninterpreted constants that only appear in a single disjuction. For example, `(or (= x (+ 5 y)) (= y (+ u z)))` allows solving for `x`. From aaabbfb594fcfed4240c580e31db51cc3483e6ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 15:53:55 -0800 Subject: [PATCH 384/477] remove comment that does not align with result Signed-off-by: Nikolaj Bjorner --- src/tactic/core/nnf_tactic.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/core/nnf_tactic.h b/src/tactic/core/nnf_tactic.h index fa724f2b8..083380be8 100644 --- a/src/tactic/core/nnf_tactic.h +++ b/src/tactic/core/nnf_tactic.h @@ -47,7 +47,6 @@ Once all negations are pushed inside, the resulting formula is in NNF. (apply nnf) ``` -This would convert the formula (not (or (> x 0) (< x 0))) to (and (<= x 0) (>= x 0)), which is in NNF. ### Notes From 80033e874499d18f9b650235dbd4e75c568aa447 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 17:02:04 -0800 Subject: [PATCH 385/477] cave in to supporting proofs (partially) in simplifiers, updated doc --- doc/mk_tactic_doc.py | 6 ++-- src/ast/simplifiers/bit2int.h | 4 ++- src/ast/simplifiers/bit_blaster.cpp | 4 +-- src/ast/simplifiers/bv_elim.h | 2 +- src/ast/simplifiers/bv_slice.cpp | 6 ++-- src/ast/simplifiers/card2bv.cpp | 6 ++-- src/ast/simplifiers/cnf_nnf.h | 5 ++-- .../simplifiers/demodulator_simplifier.cpp | 2 +- src/ast/simplifiers/dependent_expr.h | 24 ++++++++++++++-- src/ast/simplifiers/dependent_expr_state.h | 3 ++ src/ast/simplifiers/distribute_forall.h | 2 +- src/ast/simplifiers/elim_bounds.h | 2 +- src/ast/simplifiers/elim_term_ite.h | 8 ++++-- src/ast/simplifiers/elim_unconstrained.cpp | 4 +-- src/ast/simplifiers/eliminate_predicates.cpp | 10 +++---- src/ast/simplifiers/euf_completion.cpp | 8 +++--- src/ast/simplifiers/extract_eqs.cpp | 4 +-- src/ast/simplifiers/flatten_clauses.h | 20 ++++++------- src/ast/simplifiers/max_bv_sharing.cpp | 5 ++-- .../model_reconstruction_trail.cpp | 11 ++++---- src/ast/simplifiers/propagate_values.cpp | 6 ++-- src/ast/simplifiers/pull_nested_quantifiers.h | 4 ++- src/ast/simplifiers/push_ite.h | 5 ++-- src/ast/simplifiers/refine_inj_axiom.h | 2 +- src/ast/simplifiers/rewriter_simplifier.h | 3 +- src/ast/simplifiers/solve_context_eqs.cpp | 2 +- src/ast/simplifiers/solve_eqs.cpp | 7 +++-- src/qe/lite/qe_lite.cpp | 5 ++-- src/sat/sat_solver/sat_smt_solver.cpp | 8 +++--- src/shell/main.cpp | 7 +++-- src/shell/smtlib_frontend.cpp | 7 +++-- src/shell/smtlib_frontend.h | 2 +- src/tactic/core/injectivity_tactic.cpp | 15 +--------- src/tactic/core/injectivity_tactic.h | 28 ++++++++++++++++++- src/tactic/core/reduce_args_tactic.h | 14 +++++----- src/tactic/dependent_expr_state_tactic.h | 14 +++++----- 36 files changed, 157 insertions(+), 108 deletions(-) diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index b49811fb9..85dfcb4c3 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -21,16 +21,14 @@ is_tac_name = re.compile("## Tactic (.*)") def extract_params(ous, tac): z3_exe = BUILD_DIR + "/z3" - out = subprocess.Popen([z3_exe, f"-tactics:{tac}"], stdout=subprocess.PIPE).communicate()[0] + out = subprocess.Popen([z3_exe, f"-tacticsmd:{tac}"], stdout=subprocess.PIPE).communicate()[0] if not out: return out = out.decode(sys.stdout.encoding) - ous.write("#### Parameters\n") - ous.write("```\n") + ous.write("### Parameters\n\n") for line in out: ous.write(line.replace("\r","")) ous.write("\n") - ous.write("```\n") def generate_tactic_doc(ous, f, ins): tac_name = None diff --git a/src/ast/simplifiers/bit2int.h b/src/ast/simplifiers/bit2int.h index 6605c2e7e..64c7f3ecf 100644 --- a/src/ast/simplifiers/bit2int.h +++ b/src/ast/simplifiers/bit2int.h @@ -35,8 +35,10 @@ public: for (unsigned idx : indices()) { auto const& d = m_fmls[idx]; m_rewriter(d.fml(), r, pr); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + m_fmls.update(idx, dependent_expr(m, r, mp(d.pr(), pr), d.dep())); } } + + bool supports_proofs() const override { return true; } }; diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp index a1988a930..c66cef826 100644 --- a/src/ast/simplifiers/bit_blaster.cpp +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -38,13 +38,13 @@ void bit_blaster::reduce() { proof_ref new_pr(m); bool change = false; for (unsigned idx : indices()) { - auto [curr, d] = m_fmls[idx](); + auto [curr, p, d] = m_fmls[idx](); m_rewriter(curr, new_curr, new_pr); if (curr != new_curr) { m_num_steps += m_rewriter.get_num_steps(); change = true; TRACE("bit_blaster", tout << mk_pp(curr, m) << " -> " << new_curr << "\n";); - m_fmls.update(idx, dependent_expr(m, new_curr, d)); + m_fmls.update(idx, dependent_expr(m, new_curr, mp(p, new_pr), d)); } } diff --git a/src/ast/simplifiers/bv_elim.h b/src/ast/simplifiers/bv_elim.h index 6f045fc54..344a9df82 100644 --- a/src/ast/simplifiers/bv_elim.h +++ b/src/ast/simplifiers/bv_elim.h @@ -36,7 +36,7 @@ public: if (!has_quantifiers(d.fml())) continue; m_rewriter(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + m_fmls.update(idx, dependent_expr(m, r, nullptr, d.dep())); } } }; diff --git a/src/ast/simplifiers/bv_slice.cpp b/src/ast/simplifiers/bv_slice.cpp index 7ffa56a29..45db268b3 100644 --- a/src/ast/simplifiers/bv_slice.cpp +++ b/src/ast/simplifiers/bv_slice.cpp @@ -28,7 +28,7 @@ namespace bv { void slice::process_eqs() { for (unsigned i : indices()) { - auto const [f, d] = m_fmls[i](); + auto const [f, p, d] = m_fmls[i](); process_eq(f); } } @@ -137,7 +137,7 @@ namespace bv { ptr_vector todo, args; expr* c; for (unsigned i : indices()) { - auto const [f, d] = m_fmls[i](); + auto const [f, p, d] = m_fmls[i](); todo.push_back(f); pin.push_back(f); while (!todo.empty()) { @@ -191,7 +191,7 @@ namespace bv { } c = cache.get(f->get_id()); if (c != f) - m_fmls.update(i, dependent_expr(m, c, d)); + m_fmls.update(i, dependent_expr(m, c, nullptr, d)); } } diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index 58774e1c6..b2fece21e 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -30,12 +30,12 @@ void card2bv::reduce() { expr_ref new_f1(m), new_f2(m); proof_ref new_pr(m); for (unsigned idx : indices()) { - auto [f, d] = m_fmls[idx](); + auto [f, p, d] = m_fmls[idx](); rw1(f, new_f1); rw2(false, new_f1, new_f2, new_pr); if (new_f2 != f) { TRACE("card2bv", tout << "Rewriting " << new_f1 << "\n" << new_f2 << "\n"); - m_fmls.update(idx, dependent_expr(m, new_f2, d)); + m_fmls.update(idx, dependent_expr(m, new_f2, mp(p, new_pr), d)); ++m_stats.m_num_rewrites; } } @@ -43,7 +43,7 @@ void card2bv::reduce() { expr_ref_vector fmls(m); rw2.flush_side_constraints(fmls); for (expr* e : fmls) - m_fmls.add(dependent_expr(m, e, nullptr)); + m_fmls.add(dependent_expr(m, e, nullptr, nullptr)); func_decl_ref_vector const& fns = rw2.fresh_constants(); for (func_decl* f : fns) diff --git a/src/ast/simplifiers/cnf_nnf.h b/src/ast/simplifiers/cnf_nnf.h index 56cdc1367..6cb1c346e 100644 --- a/src/ast/simplifiers/cnf_nnf.h +++ b/src/ast/simplifiers/cnf_nnf.h @@ -48,12 +48,13 @@ public: push_todo.reset(); push_todo_prs.reset(); apply_nnf(d.fml(), push_todo, push_todo_prs, r, pr); - m_fmls.update(i, dependent_expr(m, r, d.dep())); + m_fmls.update(i, dependent_expr(m, r, mp(d.pr(), pr), d.dep())); for (expr* f : push_todo) { if (!m.inc()) break; m_rewriter(f, r, pr); - m_fmls.add(dependent_expr(m, r, d.dep())); + if (f != r) + m_fmls.add(dependent_expr(m, r, pr, d.dep())); } } } diff --git a/src/ast/simplifiers/demodulator_simplifier.cpp b/src/ast/simplifiers/demodulator_simplifier.cpp index afd57b425..0e42e3481 100644 --- a/src/ast/simplifiers/demodulator_simplifier.cpp +++ b/src/ast/simplifiers/demodulator_simplifier.cpp @@ -108,7 +108,7 @@ void demodulator_simplifier::rewrite(unsigned i) { expr_dependency_ref d(dep(i), m); for (unsigned j : m_dependencies) d = m.mk_join(d, dep(j)); - m_fmls.update(i, dependent_expr(m, r, d)); + m_fmls.update(i, dependent_expr(m, r, nullptr, d)); } bool demodulator_simplifier::rewrite1(func_decl* f, expr_ref_vector const& args, expr_ref& np) { diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index ddf119070..55f8d8f46 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -24,21 +24,26 @@ Author: class dependent_expr { ast_manager& m; expr* m_fml; + proof* m_proof; expr_dependency* m_dep; public: - dependent_expr(ast_manager& m, expr* fml, expr_dependency* d): + dependent_expr(ast_manager& m, expr* fml, proof* p, expr_dependency* d): m(m), m_fml(fml), + m_proof(p), m_dep(d) { SASSERT(fml); m.inc_ref(fml); m.inc_ref(d); + m.inc_ref(p); } dependent_expr(ast_translation& tr, dependent_expr const& src) : m(tr.to()) { m_fml = tr(src.fml()); m.inc_ref(m_fml); + m_proof = tr(src.pr()); + m.inc_ref(m_proof); expr_dependency_translation dtr(tr); m_dep = dtr(src.dep()); m.inc_ref(m_dep); @@ -49,10 +54,13 @@ public: if (this != &other) { m.inc_ref(other.m_fml); m.inc_ref(other.m_dep); + m.inc_ref(other.m_proof); m.dec_ref(m_fml); m.dec_ref(m_dep); + m.dec_ref(m_proof); m_fml = other.m_fml; m_dep = other.m_dep; + m_proof = other.m_proof; } return *this; } @@ -60,24 +68,30 @@ public: dependent_expr(dependent_expr const& other): m(other.m), m_fml(other.m_fml), + m_proof(other.m_proof), m_dep(other.m_dep) { m.inc_ref(m_fml); + m.inc_ref(m_proof); m.inc_ref(m_dep); } dependent_expr(dependent_expr && other) noexcept : m(other.m), m_fml(nullptr), + m_proof(nullptr), m_dep(nullptr) { std::swap(m_fml, other.m_fml); + std::swap(m_proof, other.m_proof); std::swap(m_dep, other.m_dep); } ~dependent_expr() { m.dec_ref(m_fml); m.dec_ref(m_dep); + m.dec_ref(m_proof); m_fml = nullptr; m_dep = nullptr; + m_proof = nullptr; } ast_manager& get_manager() const { return m; } @@ -85,9 +99,11 @@ public: expr* fml() const { return m_fml; } expr_dependency* dep() const { return m_dep; } + + proof* pr() const { return m_proof; } - std::tuple operator()() const { - return { m_fml, m_dep }; + std::tuple operator()() const { + return { m_fml, m_proof, m_dep }; } std::ostream& display(std::ostream& out) const { @@ -99,6 +115,8 @@ public: for (expr* arg : deps) out << mk_pp(arg, m) << " "; } + if (m_proof) + out << "\n:- " << mk_pp(m_proof, m); return out; } }; diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 212bc99a4..85b6352ad 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -135,6 +135,8 @@ protected: index_set indices() { return index_set(*this); } + proof* mp(proof* a, proof* b) { return (a && b) ? m.mk_modus_ponens(a, b) : nullptr; } + public: dependent_expr_simplifier(ast_manager& m, dependent_expr_state& s) : m(m), m_fmls(s), m_trail(s.m_trail) {} virtual ~dependent_expr_simplifier() {} @@ -146,6 +148,7 @@ public: virtual void reset_statistics() {} virtual void updt_params(params_ref const& p) {} virtual void collect_param_descrs(param_descrs& r) {} + virtual bool supports_proofs() const { return false; } ast_manager& get_manager() { return m; } dependent_expr_state& get_fmls() { return m_fmls; } }; diff --git a/src/ast/simplifiers/distribute_forall.h b/src/ast/simplifiers/distribute_forall.h index 82709d29f..3127a4ec8 100644 --- a/src/ast/simplifiers/distribute_forall.h +++ b/src/ast/simplifiers/distribute_forall.h @@ -38,7 +38,7 @@ public: if (!has_quantifiers(d.fml())) continue; m_dist(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + m_fmls.update(idx, dependent_expr(m, r, nullptr, d.dep())); } } }; diff --git a/src/ast/simplifiers/elim_bounds.h b/src/ast/simplifiers/elim_bounds.h index d6631adfd..ed93faeba 100644 --- a/src/ast/simplifiers/elim_bounds.h +++ b/src/ast/simplifiers/elim_bounds.h @@ -38,7 +38,7 @@ public: if (!has_quantifiers(d.fml())) continue; m_rewriter(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + m_fmls.update(idx, dependent_expr(m, r, nullptr, d.dep())); } } }; diff --git a/src/ast/simplifiers/elim_term_ite.h b/src/ast/simplifiers/elim_term_ite.h index 5b6ef38fa..1b8f58f9e 100644 --- a/src/ast/simplifiers/elim_term_ite.h +++ b/src/ast/simplifiers/elim_term_ite.h @@ -33,13 +33,17 @@ public: void reduce() override { expr_ref r(m); + proof_ref pr(m); for (unsigned idx : indices()) { auto const& d = m_fmls[idx]; - m_rewriter(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + m_rewriter(d.fml(), r, pr); + if (d.fml() != r) + m_fmls.update(idx, dependent_expr(m, r, mp(d.pr(), pr), d.dep())); } } + bool supports_proofs() const override { return true; } + void push() override { dependent_expr_simplifier::push(); m_df.push(); m_rewriter.push(); } void pop(unsigned n) override { m_rewriter.pop(n); m_df.pop(n); dependent_expr_simplifier::pop(n); } diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 7404382a3..032c46a92 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -258,13 +258,13 @@ void elim_unconstrained::reconstruct_terms() { void elim_unconstrained::assert_normalized(vector& old_fmls) { for (unsigned i : indices()) { - auto [f, d] = m_fmls[i](); + auto [f, p, d] = m_fmls[i](); node& n = get_node(f); expr* g = n.m_term; if (f == g) continue; old_fmls.push_back(m_fmls[i]); - m_fmls.update(i, dependent_expr(m, g, d)); + m_fmls.update(i, dependent_expr(m, g, nullptr, d)); IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); TRACE("elim_unconstrained", tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); } diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 700f96ce3..118edf04d 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -536,7 +536,7 @@ void eliminate_predicates::reduce_definitions() { macro_expander.insert(v->m_head, v->m_def, v->m_dep); for (unsigned i : indices()) { - auto [f, d] = m_fmls[i](); + auto [f, p, d] = m_fmls[i](); expr_ref fml(f, m), new_fml(m); expr_dependency_ref dep(d, m); while (true) { @@ -546,7 +546,7 @@ void eliminate_predicates::reduce_definitions() { rewrite(new_fml); fml = new_fml; } - m_fmls.update(i, dependent_expr(m, fml, dep)); + m_fmls.update(i, dependent_expr(m, fml, nullptr, dep)); } reset(); init_clauses(); @@ -770,7 +770,7 @@ void eliminate_predicates::process_to_exclude(ast_mark& exclude_set) { eliminate_predicates::clause* eliminate_predicates::init_clause(unsigned i) { - auto [f, d] = m_fmls[i](); + auto [f, p, d] = m_fmls[i](); return init_clause(f, d, i); } @@ -821,12 +821,12 @@ void eliminate_predicates::decompile() { if (cl->m_fml_index != UINT_MAX) { if (cl->m_alive) continue; - dependent_expr de(m, m.mk_true(), nullptr); + dependent_expr de(m, m.mk_true(), nullptr, nullptr); m_fmls.update(cl->m_fml_index, de); } else if (cl->m_alive) { expr_ref new_cl = cl->m_fml; - dependent_expr de(m, new_cl, cl->m_dep); + dependent_expr de(m, new_cl, nullptr, cl->m_dep); m_fmls.add(de); } } diff --git a/src/ast/simplifiers/euf_completion.cpp b/src/ast/simplifiers/euf_completion.cpp index 78be41c1a..3ede7024e 100644 --- a/src/ast/simplifiers/euf_completion.cpp +++ b/src/ast/simplifiers/euf_completion.cpp @@ -82,7 +82,7 @@ namespace euf { for (unsigned i = qhead(); i < sz; ++i) { expr* x, * y; - auto [f, d] = m_fmls[i](); + auto [f, p, d] = m_fmls[i](); if (m.is_eq(f, x, y)) { enode* a = mk_enode(x); enode* b = mk_enode(y); @@ -108,19 +108,19 @@ namespace euf { if (m_egraph.inconsistent()) { auto* d = explain_conflict(); - dependent_expr de(m, m.mk_false(), d); + dependent_expr de(m, m.mk_false(), nullptr, d); m_fmls.update(0, de); return; } unsigned sz = qtail(); for (unsigned i = qhead(); i < sz; ++i) { - auto [f, d] = m_fmls[i](); + auto [f, p, d] = m_fmls[i](); expr_dependency_ref dep(d, m); expr_ref g = canonize_fml(f, dep); if (g != f) { - m_fmls.update(i, dependent_expr(m, g, dep)); + m_fmls.update(i, dependent_expr(m, g, nullptr, dep)); m_stats.m_num_rewrites++; IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); update_has_new_eq(g); diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index fdb889ee3..b2e264b1f 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -39,7 +39,7 @@ namespace euf { } void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { - auto [f, d] = e(); + auto [f, p, d] = e(); expr* x, * y; if (m.is_eq(f, x, y)) { if (x == y) @@ -246,7 +246,7 @@ namespace euf { void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { if (!m_enabled) return; - auto [f, d] = e(); + auto [f, p, d] = e(); expr* x, * y; if (m.is_eq(f, x, y) && a.is_int_real(x)) { solve_eq(f, x, y, d, eqs); diff --git a/src/ast/simplifiers/flatten_clauses.h b/src/ast/simplifiers/flatten_clauses.h index aa81024ef..e2da2d182 100644 --- a/src/ast/simplifiers/flatten_clauses.h +++ b/src/ast/simplifiers/flatten_clauses.h @@ -67,8 +67,8 @@ public: decomposed = true; if (decomposed) { for (expr* arg : *to_app(b)) - m_fmls.add(dependent_expr(m, m.mk_or(a, mk_not(m, arg)), de.dep())); - m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + m_fmls.add(dependent_expr(m, nullptr, m.mk_or(a, mk_not(m, arg)), de.dep())); + m_fmls.update(idx, dependent_expr(m, nullptr, m.mk_true(), nullptr)); ++m_num_flat; continue; } @@ -79,8 +79,8 @@ public: decomposed = true; if (decomposed) { for (expr * arg : *to_app(b)) - m_fmls.add(dependent_expr(m, m.mk_or(a, arg), de.dep())); - m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + m_fmls.add(dependent_expr(m, nullptr, m.mk_or(a, arg), de.dep())); + m_fmls.update(idx, dependent_expr(m, nullptr, m.mk_true(), nullptr)); ++m_num_flat; continue; } @@ -92,20 +92,20 @@ public: if (decomposed) { expr* na = mk_not(m, a); for (expr* arg : *to_app(b)) - m_fmls.add(dependent_expr(m, m.mk_or(na, arg), de.dep())); - m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + m_fmls.add(dependent_expr(m, m.mk_or(na, arg), nullptr, de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr, nullptr)); ++m_num_flat; continue; } if (m.is_implies(f, a, b)) { - m_fmls.update(idx, dependent_expr(m, m.mk_or(mk_not(m, a), b), de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_or(mk_not(m, a), b), nullptr, de.dep())); ++m_num_flat; continue; } if (m.is_ite(f, a, b, c)) { - m_fmls.add(dependent_expr(m, m.mk_or(mk_not(m, a), b), de.dep())); - m_fmls.add(dependent_expr(m, m.mk_or(a, c), de.dep())); - m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr)); + m_fmls.add(dependent_expr(m, m.mk_or(mk_not(m, a), b), nullptr, de.dep())); + m_fmls.add(dependent_expr(m, m.mk_or(a, c), nullptr, de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr, nullptr)); ++m_num_flat; continue; } diff --git a/src/ast/simplifiers/max_bv_sharing.cpp b/src/ast/simplifiers/max_bv_sharing.cpp index c12fa4410..f708f9dce 100644 --- a/src/ast/simplifiers/max_bv_sharing.cpp +++ b/src/ast/simplifiers/max_bv_sharing.cpp @@ -48,12 +48,11 @@ public: expr_ref new_curr(m); proof_ref new_pr(m); for (unsigned idx : indices()) { - auto [curr, d] = m_fmls[idx](); + auto [curr, p, d] = m_fmls[idx](); m_rewriter(curr, new_curr, new_pr); - // Proof reconstruction: new_pr = m.mk_modus_ponens(old_pr, new_pr); if (new_curr != curr) { m_num_steps += m_rewriter.get_num_steps(); - m_fmls.update(idx, dependent_expr(m, new_curr, d)); + m_fmls.update(idx, dependent_expr(m, new_curr, mp(p, new_pr), d)); } } } diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 7e8d3e2f1..567546e67 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -61,16 +61,17 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st args.push_back(m.mk_var(i, d->get_domain(i))); head = m.mk_app(d, args); mrp.insert(head, t->m_def, t->m_dep); - dependent_expr de(m, t->m_def, t->m_dep); + dependent_expr de(m, t->m_def, nullptr, t->m_dep); add_vars(de, free_vars); for (unsigned i = qhead; i < st.qtail(); ++i) { - auto [f, dep1] = st[i](); + auto [f, p, dep1] = st[i](); expr_ref g(m); expr_dependency_ref dep2(m); mrp(f, dep1, g, dep2); CTRACE("simplifier", f != g, tout << "updated " << mk_pp(g, m) << "\n"); - st.update(i, dependent_expr(m, g, dep2)); + if (f != g) + st.update(i, dependent_expr(m, g, nullptr, dep2)); } continue; } @@ -81,7 +82,7 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st ptr_vector dep_exprs; expr_ref_vector trail(m); for (unsigned i = qhead; i < st.qtail(); ++i) { - auto [f, dep1] = st[i](); + auto [f, p, dep1] = st[i](); auto [g, dep2] = rp->replace_with_dep(f); if (dep1) { dep_exprs.reset(); @@ -98,7 +99,7 @@ void model_reconstruction_trail::replay(unsigned qhead, dependent_expr_state& st if (!trail.empty()) dep1 = m.mk_join(dep_exprs.size(), dep_exprs.data()); } - dependent_expr d(m, g, m.mk_join(dep1, dep2)); + dependent_expr d(m, g, nullptr, m.mk_join(dep1, dep2)); CTRACE("simplifier", f != g, tout << "updated " << mk_pp(g, m) << "\n"); add_vars(d, free_vars); st.update(i, d); diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 7d698faa3..1083cc36d 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -35,13 +35,13 @@ propagate_values::propagate_values(ast_manager& m, params_ref const& p, dependen void propagate_values::process_fml(unsigned i) { if (!m_subst.empty()) { - auto [f, dep] = m_fmls[i](); + auto [f, p, dep] = m_fmls[i](); expr_ref fml(m); proof_ref pr(m); m_rewriter(f, fml, pr); if (fml != f) { dep = m.mk_join(dep, m_rewriter.get_used_dependencies()); - m_fmls.update(i, dependent_expr(m, fml, dep)); + m_fmls.update(i, dependent_expr(m, fml, mp(p, pr), dep)); ++m_stats.m_num_rewrites; } m_rewriter.reset_used_dependencies(); @@ -51,7 +51,7 @@ void propagate_values::process_fml(unsigned i) { void propagate_values::add_sub(dependent_expr const& de) { expr* x, * y; - auto const& [f, dep] = de(); + auto const& [f, p, dep] = de(); if (m.is_not(f, x) && m_shared.is_shared(x)) m_subst.insert(x, m.mk_false(), dep); if (m_shared.is_shared(f)) diff --git a/src/ast/simplifiers/pull_nested_quantifiers.h b/src/ast/simplifiers/pull_nested_quantifiers.h index a113c36c2..fac605d49 100644 --- a/src/ast/simplifiers/pull_nested_quantifiers.h +++ b/src/ast/simplifiers/pull_nested_quantifiers.h @@ -40,7 +40,9 @@ public: for (unsigned idx : indices()) { auto d = m_fmls[idx]; m_pull(d.fml(), new_curr, new_pr); - m_fmls.update(idx, dependent_expr(m, new_curr, d.dep())); + m_fmls.update(idx, dependent_expr(m, new_curr, mp(d.pr(), new_pr), d.dep())); } } + + bool supports_proofs() const override { return true; } }; diff --git a/src/ast/simplifiers/push_ite.h b/src/ast/simplifiers/push_ite.h index e26070a7e..8e508bf53 100644 --- a/src/ast/simplifiers/push_ite.h +++ b/src/ast/simplifiers/push_ite.h @@ -35,7 +35,8 @@ public: for (unsigned idx : indices()) { auto const& d = m_fmls[idx]; m_push(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + if (r != d.fml()) + m_fmls.update(idx, dependent_expr(m, r, nullptr, d.dep())); } } }; @@ -58,7 +59,7 @@ public: for (unsigned idx : indices()) { auto const& d = m_fmls[idx]; m_push(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, d.dep())); + m_fmls.update(idx, dependent_expr(m, r, nullptr, d.dep())); } } }; diff --git a/src/ast/simplifiers/refine_inj_axiom.h b/src/ast/simplifiers/refine_inj_axiom.h index 2333ba690..53c960812 100644 --- a/src/ast/simplifiers/refine_inj_axiom.h +++ b/src/ast/simplifiers/refine_inj_axiom.h @@ -38,7 +38,7 @@ public: for (unsigned idx : indices()) { expr* f = m_fmls[idx].fml(); if (is_quantifier(f) && simplify_inj_axiom(m, to_quantifier(f), r)) - m_fmls.update(idx, dependent_expr(m, r, m_fmls[idx].dep())); + m_fmls.update(idx, dependent_expr(m, r, nullptr, m_fmls[idx].dep())); } } }; diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h index be54ca005..f3dc91a51 100644 --- a/src/ast/simplifiers/rewriter_simplifier.h +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -44,9 +44,10 @@ public: auto d = m_fmls[idx]; m_rewriter(d.fml(), new_curr, new_pr); m_num_steps += m_rewriter.get_num_steps(); - m_fmls.update(idx, dependent_expr(m, new_curr, d.dep())); + m_fmls.update(idx, dependent_expr(m, new_curr, mp(d.pr(), new_pr), d.dep())); } } + bool supports_proofs() const override { return true; } void collect_statistics(statistics& st) const override { st.update("simplifier-steps", m_num_steps); } void reset_statistics() override { m_num_steps = 0; } void updt_params(params_ref const& p) override { m_params.append(p); m_rewriter.updt_params(m_params); } diff --git a/src/ast/simplifiers/solve_context_eqs.cpp b/src/ast/simplifiers/solve_context_eqs.cpp index 6cb38e4a6..b56802caf 100644 --- a/src/ast/simplifiers/solve_context_eqs.cpp +++ b/src/ast/simplifiers/solve_context_eqs.cpp @@ -282,7 +282,7 @@ namespace euf { else if (!s && 1 <= depth) { for (extract_eq* ex : m_solve_eqs.m_extract_plugins) { ex->set_allow_booleans(false); - ex->get_eqs(dependent_expr(m, f, df.dep()), eqs); + ex->get_eqs(dependent_expr(m, f, nullptr, df.dep()), eqs); ex->set_allow_booleans(true); } } diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 94b089c80..e481dad8d 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -191,14 +191,15 @@ namespace euf { rp->set_substitution(m_subst.get()); for (unsigned i : indices()) { - auto [f, d] = m_fmls[i](); + auto [f, p, d] = m_fmls[i](); auto [new_f, new_dep] = rp->replace_with_dep(f); - m_rewriter(new_f); + proof_ref new_pr(m); + m_rewriter(new_f, new_f, new_pr); if (new_f == f) continue; new_dep = m.mk_join(d, new_dep); old_fmls.push_back(m_fmls[i]); - m_fmls.update(i, dependent_expr(m, new_f, new_dep)); + m_fmls.update(i, dependent_expr(m, new_f, mp(p, new_pr), new_dep)); } } diff --git a/src/qe/lite/qe_lite.cpp b/src/qe/lite/qe_lite.cpp index d3d45bd4b..a052ae944 100644 --- a/src/qe/lite/qe_lite.cpp +++ b/src/qe/lite/qe_lite.cpp @@ -2431,12 +2431,13 @@ namespace { proof_ref new_pr(m); expr_ref new_f(m); for (unsigned i : indices()) { - expr* f = m_fmls[i].fml(); + auto [f, p, d] = m_fmls[i](); if (!has_quantifiers(f)) continue; new_f = f; m_qe(new_f, new_pr); - m_fmls.update(i, dependent_expr(m, new_f, m_fmls[i].dep())); + if (f != new_f) + m_fmls.update(i, dependent_expr(m, new_f, mp(p, new_pr), d)); } } }; diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index 3fd3a0080..e37d513a0 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -86,7 +86,7 @@ class sat_smt_solver : public solver { if (s.m.is_and(f)) { auto* d = s.m_fmls[i].dep(); for (expr* arg : *to_app(f)) - s.m_fmls.push_back(dependent_expr(s.m, arg, d)); + s.m_fmls.push_back(dependent_expr(s.m, arg, nullptr, d)); continue; } if (i != j) @@ -349,18 +349,18 @@ public: return a; expr* new_dep = m.mk_fresh_const("dep", m.mk_bool_sort()); expr* fml = m.mk_iff(new_dep, a); - m_fmls.push_back(dependent_expr(m, fml, nullptr)); + m_fmls.push_back(dependent_expr(m, fml, nullptr, nullptr)); m_dep.insert(a, new_dep); return new_dep; } void assert_expr_core2(expr * t, expr * a) override { a = ensure_literal(a); - m_fmls.push_back(dependent_expr(m, t, m.mk_leaf(a))); + m_fmls.push_back(dependent_expr(m, t, nullptr, m.mk_leaf(a))); } void assert_expr_core(expr * t) override { - m_fmls.push_back(dependent_expr(m, t, nullptr)); + m_fmls.push_back(dependent_expr(m, t, nullptr, nullptr)); } ast_manager& get_manager() const override { return m; } diff --git a/src/shell/main.cpp b/src/shell/main.cpp index af3b22db0..2fdd95d79 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -293,11 +293,12 @@ static void parse_cmd_line_args(std::string& input_file, int argc, char ** argv) if (!opt_arg) help_tactics(); else - help_tactic(opt_arg); + help_tactic(opt_arg, false); } - else if (strcmp(opt_name, "probes") == 0) { + else if (strcmp(opt_name, "tacticsmd") == 0 && opt_arg) + help_tactic(opt_arg, true); + else if (strcmp(opt_name, "probes") == 0) help_probes(); - } else { std::cerr << "Error: invalid command line option: " << arg << "\n"; std::cerr << "For usage information: z3 -h\n"; diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 220001b40..698f0f239 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -88,14 +88,17 @@ void help_tactics() { std::cout << "- " << cmd->get_name() << " " << cmd->get_descr() << "\n"; } -void help_tactic(char const* name) { +void help_tactic(char const* name, bool markdown) { cmd_context ctx; for (auto cmd : ctx.tactics()) { if (cmd->get_name() == name) { tactic_ref t = cmd->mk(ctx.m()); param_descrs descrs; t->collect_param_descrs(descrs); - descrs.display(std::cout, 4); + if (markdown) + descrs.display_markdown(std::cout); + else + descrs.display(std::cout, 4); } } } diff --git a/src/shell/smtlib_frontend.h b/src/shell/smtlib_frontend.h index 04f35c5c8..9769472f2 100644 --- a/src/shell/smtlib_frontend.h +++ b/src/shell/smtlib_frontend.h @@ -22,6 +22,6 @@ unsigned read_smtlib_file(char const * benchmark_file); unsigned read_smtlib2_commands(char const * command_file); void help_tactics(); void help_probes(); -void help_tactic(char const* name); +void help_tactic(char const* name, bool markdown); diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index dfcb152a2..e4071628c 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -5,19 +5,11 @@ Module Name: injectivity_tactic.cpp -Abstract: - - Injectivity tactics - - Discover axioms of the form `forall x. (= (g (f x)) x` - Mark `f` as injective - - Rewrite (sub)terms of the form `(= (f x) (f y))` to `(= x y)` whenever `f` is injective. Author: Nicolas Braud-Santoni (t-nibrau) 2017-08-10 -Notes: - --*/ #include #include @@ -164,8 +156,6 @@ class injectivity_tactic : public tactic { struct rewriter_eq_cfg : public default_rewriter_cfg { ast_manager & m_manager; InjHelper & inj_map; -// expr_ref_vector m_out; -// sort_ref_vector m_bindings; ast_manager & m() const { return m_manager; } @@ -176,14 +166,13 @@ class injectivity_tactic : public tactic { } void cleanup_buffers() { -// m_out.finalize(); } void reset() { } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - if(num != 2) + if (num != 2) return BR_FAILED; if (!m().is_eq(f)) @@ -230,8 +219,6 @@ class injectivity_tactic : public tactic { finder * m_finder; rewriter_eq * m_eq; InjHelper * m_map; -// rewriter_inverse * m_inverse; - params_ref m_params; ast_manager & m_manager; diff --git a/src/tactic/core/injectivity_tactic.h b/src/tactic/core/injectivity_tactic.h index e23f82163..78310909a 100644 --- a/src/tactic/core/injectivity_tactic.h +++ b/src/tactic/core/injectivity_tactic.h @@ -13,7 +13,33 @@ Author: Nicolas Braud-Santoni (t-nibrau) 2017-08-10 -Notes: + +Tactic Documentation: + +## Tactic injectivity + +### Short Description: + +- Discover axioms of the form `forall x. (= (g (f x)) x` + Mark `f` as injective + +- Rewrite (sub)terms of the form `(= (f x) (f y))` to `(= x y)` whenever `f` is injective. + +### Example + +```z3 + (declare-fun f (Int) Int) + (declare-fun g (Int) Int) + (declare-const x Int) + (declare-const y Int) + (assert (forall ((x Int)) (= (g (f x)) x))) + (assert (not (= (f x) (f (f y))))) + (apply injectivity) +``` + +### Notes + +* does not support cores nor proofs --*/ #pragma once diff --git a/src/tactic/core/reduce_args_tactic.h b/src/tactic/core/reduce_args_tactic.h index 5fa1f74cd..615b4d70f 100644 --- a/src/tactic/core/reduce_args_tactic.h +++ b/src/tactic/core/reduce_args_tactic.h @@ -23,15 +23,15 @@ Reduce the number of arguments of function applications, when for all occurrence ### Long Description -Example, suppose we have a function `f` with `2` arguments. -There are 1000 applications of this function, but the first argument is always "a", "b" or "c". -Thus, we replace the `f(t1, t2)` with +Example, suppose we have a function $f$ with 2 arguments. +There are 1000 applications of this function, but the first argument is always $a$, $b$ or $c$. +Thus, we replace the $f(t_1, t_2)$ with -* `f_a(t2)` if `t1 = a` -* `f_b(t2)` if `t2 = b` -* `f_c(t2)` if `t2 = c` +* $f_a(t_2)$ if $t_1 = a$ +* $f_b(t_2)$ if $t_2 = b$ +* $f_c(t_2)$ if $t_2 = c$ -Since `f_a`, `f_b`, `f_c` are new symbols, satisfiability is preserved. +Since $f_a$, $f_b$, $f_c$ are new symbols, satisfiability is preserved. This transformation is very similar in spirit to the Ackermman's reduction. diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index f2d532368..9da9c1965 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -49,7 +49,7 @@ public: m(m), m_params(p), m_factory(f), - m_dep(m, m.mk_true(), nullptr) + m_dep(m, m.mk_true(), nullptr, nullptr) {} /** @@ -58,22 +58,22 @@ public: unsigned qtail() const override { return m_goal->size(); } dependent_expr const& operator[](unsigned i) override { - m_dep = dependent_expr(m, m_goal->form(i), m_goal->dep(i)); + m_dep = dependent_expr(m, m_goal->form(i), m_goal->pr(i), m_goal->dep(i)); return m_dep; } void update(unsigned i, dependent_expr const& j) override { if (inconsistent()) return; - auto [f, d] = j(); - m_goal->update(i, f, nullptr, d); + auto [f, p, d] = j(); + m_goal->update(i, f, p, d); } void add(dependent_expr const& j) override { if (inconsistent()) return; - auto [f, d] = j(); - m_goal->assert_expr(f, nullptr, d); + auto [f, p, d] = j(); + m_goal->assert_expr(f, p, d); } bool inconsistent() override { @@ -108,7 +108,7 @@ public: tactic_report report(name(), *in); m_goal = in.get(); try { - if (!in->proofs_enabled()) + if (!in->proofs_enabled() || m_simp->supports_proofs()) m_simp->reduce(); if (m.inc()) advance_qhead(); From c33e58ee1a4e482319de25a06c651dde75ed3ac6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 17:59:33 -0800 Subject: [PATCH 386/477] update distribute forall Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/CMakeLists.txt | 1 + src/ast/simplifiers/distribute_forall.h | 26 ++-- src/tactic/core/CMakeLists.txt | 1 - src/tactic/core/distribute_forall_tactic.cpp | 141 ------------------- src/tactic/core/distribute_forall_tactic.h | 32 ++++- 5 files changed, 39 insertions(+), 162 deletions(-) delete mode 100644 src/tactic/core/distribute_forall_tactic.cpp diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index df44427cf..b807b00e3 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -5,6 +5,7 @@ z3_add_component(simplifiers card2bv.cpp demodulator_simplifier.cpp dependent_expr_state.cpp + distribute_forall.cpp elim_unconstrained.cpp eliminate_predicates.cpp euf_completion.cpp diff --git a/src/ast/simplifiers/distribute_forall.h b/src/ast/simplifiers/distribute_forall.h index 3127a4ec8..d5c511ab1 100644 --- a/src/ast/simplifiers/distribute_forall.h +++ b/src/ast/simplifiers/distribute_forall.h @@ -15,31 +15,23 @@ Author: #pragma once #include "ast/simplifiers/dependent_expr_state.h" -#include "ast/rewriter/distribute_forall.h" class distribute_forall_simplifier : public dependent_expr_simplifier { - distribute_forall m_dist; + + struct rw_cfg; + struct rw; public: + distribute_forall_simplifier(ast_manager& m, params_ref const& p, dependent_expr_state& fmls): - dependent_expr_simplifier(m, fmls), - m_dist(m) { + dependent_expr_simplifier(m, fmls) { } char const* name() const override { return "distribute-forall"; } - - void reduce() override { - if (!m_fmls.has_quantifiers()) - return; - expr_ref r(m); - for (unsigned idx : indices()) { - auto const& d = m_fmls[idx]; - if (!has_quantifiers(d.fml())) - continue; - m_dist(d.fml(), r); - m_fmls.update(idx, dependent_expr(m, r, nullptr, d.dep())); - } - } + + bool supports_proofs() const override { return true; } + + void reduce() override; }; diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 8a86e9a0b..d4a115dcc 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -6,7 +6,6 @@ z3_add_component(core_tactics collect_statistics_tactic.cpp ctx_simplify_tactic.cpp der_tactic.cpp - distribute_forall_tactic.cpp dom_simplify_tactic.cpp elim_term_ite_tactic.cpp elim_uncnstr_tactic.cpp diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp deleted file mode 100644 index 1d171aae3..000000000 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - distribute_forall_tactic.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2012-02-18. - ---*/ -#include "tactic/tactical.h" -#include "ast/ast_util.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/rewriter/var_subst.h" - -class distribute_forall_tactic : public tactic { - - struct rw_cfg : public default_rewriter_cfg { - ast_manager & m; - - rw_cfg(ast_manager & _m):m(_m) {} - bool reduce_quantifier(quantifier * old_q, - expr * new_body, - expr * const * new_patterns, - expr * const * new_no_patterns, - expr_ref & result, - proof_ref & result_pr) { - - if (!is_forall(old_q)) { - return false; - } - - if (m.is_not(new_body) && m.is_or(to_app(new_body)->get_arg(0))) { - // (forall X (not (or F1 ... Fn))) - // --> - // (and (forall X (not F1)) - // ... - // (forall X (not Fn))) - app * or_e = to_app(to_app(new_body)->get_arg(0)); - unsigned num_args = or_e->get_num_args(); - expr_ref_buffer new_args(m); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = or_e->get_arg(i); - expr * not_arg = mk_not(m, arg); - quantifier_ref tmp_q(m); - tmp_q = m.update_quantifier(old_q, not_arg); - new_args.push_back(elim_unused_vars(m, tmp_q, params_ref())); - } - result = m.mk_and(new_args.size(), new_args.data()); - if (m.proofs_enabled()) { - result_pr = m.mk_push_quant(old_q, result); - } - return true; - } - - if (m.is_and(new_body)) { - // (forall X (and F1 ... Fn)) - // --> - // (and (forall X F1) - // ... - // (forall X Fn) - unsigned num_args = to_app(new_body)->get_num_args(); - expr_ref_buffer new_args(m); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(new_body)->get_arg(i); - quantifier_ref tmp_q(m); - tmp_q = m.update_quantifier(old_q, arg); - new_args.push_back(elim_unused_vars(m, tmp_q, params_ref())); - } - result = m.mk_and(new_args.size(), new_args.data()); - if (m.proofs_enabled()) { - result_pr = m.mk_push_quant(old_q, result); - } - return true; - } - - return false; - } - }; - - struct rw : public rewriter_tpl { - rw_cfg m_cfg; - - rw(ast_manager & m, bool proofs_enabled): - rewriter_tpl(m, proofs_enabled, m_cfg), - m_cfg(m) { - } - }; - - rw * m_rw; - -public: - distribute_forall_tactic():m_rw(nullptr) {} - - tactic * translate(ast_manager & m) override { - return alloc(distribute_forall_tactic); - } - - char const* name() const override { return "distribute_forall"; } - - void operator()(goal_ref const & g, - goal_ref_buffer & result) override { - ast_manager & m = g->m(); - bool produce_proofs = g->proofs_enabled(); - rw r(m, produce_proofs); - m_rw = &r; - result.reset(); - tactic_report report("distribute-forall", *g); - - expr_ref new_curr(m); - proof_ref new_pr(m); - unsigned size = g->size(); - for (unsigned idx = 0; idx < size; idx++) { - if (g->inconsistent()) - break; - expr * curr = g->form(idx); - r(curr, new_curr, new_pr); - if (g->proofs_enabled()) { - proof * pr = g->pr(idx); - new_pr = m.mk_modus_ponens(pr, new_pr); - } - g->update(idx, new_curr, new_pr, g->dep(idx)); - } - - g->inc_depth(); - result.push_back(g.get()); - m_rw = nullptr; - } - - void cleanup() override {} -}; - -tactic * mk_distribute_forall_tactic(ast_manager & m, params_ref const & p) { - return alloc(distribute_forall_tactic); -} diff --git a/src/tactic/core/distribute_forall_tactic.h b/src/tactic/core/distribute_forall_tactic.h index d7a030500..328a62b2f 100644 --- a/src/tactic/core/distribute_forall_tactic.h +++ b/src/tactic/core/distribute_forall_tactic.h @@ -13,14 +13,40 @@ Author: Leonardo de Moura (leonardo) 2012-02-18. +Tactic Documentation: + +## Tactic distribute-forall + +### Short Description: + +Distribute $\forall$ over conjunctions (and distribute $\exists$ over disjunctions) + +### Example + +```z3 + (declare-const x Int) + (declare-fun p (Int) Bool) + (declare-fun q (Int) Bool) + (assert (forall ((x Int)) (and (p x) (q x)))) + (apply distribute-forall) +``` + +### Notes + +* supports unsat cores, proof terms + + --*/ #pragma once #include "util/params.h" -class ast_manager; -class tactic; +#include "tactic/dependent_expr_state_tactic.h" +#include "ast/simplifiers/distribute_forall.h" -tactic * mk_distribute_forall_tactic(ast_manager & m, params_ref const & p); +inline tactic * mk_distribute_forall_tactic(ast_manager& m, params_ref const& p = params_ref()) { + return alloc(dependent_expr_state_tactic, m, p, + [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(distribute_forall_simplifier, m, p, s); }); +} /* ADD_TACTIC("distribute-forall", "distribute forall over conjunctions.", "mk_distribute_forall_tactic(m, p)") From 7e69dab8f69747680d7af1d825bfc68a634afbd8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Dec 2022 18:15:18 -0800 Subject: [PATCH 387/477] distribute forall cpp code --- doc/mk_tactic_doc.py | 5 ++ src/ast/simplifiers/distribute_forall.cpp | 105 ++++++++++++++++++++++ src/util/params.cpp | 2 + 3 files changed, 112 insertions(+) create mode 100644 src/ast/simplifiers/distribute_forall.cpp diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index 85dfcb4c3..37b77ef52 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -19,12 +19,17 @@ is_doc = re.compile("Tactic Documentation") is_doc_end = re.compile("\-\-\*\/") is_tac_name = re.compile("## Tactic (.*)") +def is_ws(s): + return all([0 for ch in s if ch != ' ' and ch != '\n']) + def extract_params(ous, tac): z3_exe = BUILD_DIR + "/z3" out = subprocess.Popen([z3_exe, f"-tacticsmd:{tac}"], stdout=subprocess.PIPE).communicate()[0] if not out: return out = out.decode(sys.stdout.encoding) + if is_ws(out): + return ous.write("### Parameters\n\n") for line in out: ous.write(line.replace("\r","")) diff --git a/src/ast/simplifiers/distribute_forall.cpp b/src/ast/simplifiers/distribute_forall.cpp new file mode 100644 index 000000000..c7cc6659a --- /dev/null +++ b/src/ast/simplifiers/distribute_forall.cpp @@ -0,0 +1,105 @@ +/*++ +Copyright (c) 2022 Microsoft Corporation + +Module Name: + + distribute_forall.cpp + +Author: + + Leonardo de Moura (leonardo) 2012-02-18. + Nikolaj Bjorner (nbjorner) 2022-11-24 + +--*/ + +#include "ast/ast_util.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/var_subst.h" +#include "ast/simplifiers/dependent_expr_state.h" +#include "ast/simplifiers/distribute_forall.h" + +struct distribute_forall_simplifier::rw_cfg : public default_rewriter_cfg { + ast_manager & m; + + rw_cfg(ast_manager & m):m(m) {} + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + + quantifier_ref tmp_q(m); + expr_ref_vector es(m); + expr* f; + if (is_forall(old_q)) { + // (forall X (and F1 ... Fn)) + // --> + // (and (forall X F1) + // ... + // (forall X Fn) + + if (!m.is_and(new_body) && !(m.is_not(new_body, f) && (m.is_implies(f) || m.is_or(f)))) + return false; + flatten_and(new_body, es); + unsigned i = 0; + for (expr* arg : es) { + tmp_q = m.update_quantifier(old_q, arg); + es[i++] = elim_unused_vars(m, tmp_q, params_ref()); + } + result = mk_and(es); + if (m.proofs_enabled()) + result_pr = m.mk_push_quant(old_q, result); + return true; + } + if (is_exists(old_q)) { + // (exists X (or F1 ... Fn)) + // --> + // (or (exists X F1) + // ... + // (exists X Fn) + + if (!m.is_or(new_body) && !m.is_implies(new_body) && !(m.is_not(new_body, f) && m.is_and(f))) + return false; + flatten_or(new_body, es); + unsigned i = 0; + for (expr* arg : es) { + tmp_q = m.update_quantifier(old_q, arg); + es[i++] = elim_unused_vars(m, tmp_q, params_ref()); + } + result = mk_or(es); + if (m.proofs_enabled()) + result_pr = m.mk_push_quant(old_q, result); + return true; + } + return false; + } +}; + +struct distribute_forall_simplifier::rw : public rewriter_tpl { + rw_cfg m_cfg; + + rw(ast_manager & m, bool proofs_enabled): + rewriter_tpl(m, proofs_enabled, m_cfg), + m_cfg(m) { + } +}; + +void distribute_forall_simplifier::reduce() { + if (!m_fmls.has_quantifiers()) + return; + rw rw(m, m.proofs_enabled()); + expr_ref r(m); + proof_ref pr(m); + for (unsigned idx : indices()) { + auto const& d = m_fmls[idx]; + if (!has_quantifiers(d.fml())) + continue; + rw(d.fml(), r, pr); + if (r != d.fml()) + m_fmls.update(idx, dependent_expr(m, r, mp(d.pr(), pr), d.dep())); + } +}; + diff --git a/src/util/params.cpp b/src/util/params.cpp index ee61bf47f..c801b3421 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -167,6 +167,8 @@ struct param_descrs::imp { names.push_back(kv.m_key); } std::sort(names.begin(), names.end(), symlt()); + if (names.empty()) + return; if (markdown) { out << " Parameter | Type | Description | Default\n"; out << " ----------|------|-------------|--------\n"; From c45c40e782d6c8c95771cc9ec8944600c78de760 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Dec 2022 08:51:18 -0800 Subject: [PATCH 388/477] doc Signed-off-by: Nikolaj Bjorner --- src/tactic/core/blast_term_ite_tactic.cpp | 2 - src/tactic/core/blast_term_ite_tactic.h | 38 +++++++++++++++---- src/tactic/core/ctx_simplify_tactic.h | 25 +++++++++++- src/tactic/core/elim_term_ite_tactic.h | 35 ++++++++++++++--- src/tactic/core/pb_preprocess_tactic.cpp | 32 ++++------------ src/tactic/core/pb_preprocess_tactic.h | 46 ++++++++++++++++++++++- src/tactic/core/tseitin_cnf_tactic.cpp | 39 +------------------ src/tactic/core/tseitin_cnf_tactic.h | 32 +++++++++++++++- 8 files changed, 167 insertions(+), 82 deletions(-) diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 49e43e633..987ab9f90 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -13,8 +13,6 @@ Author: Nikolaj Bjorner (nbjorner) 2013-11-4 -Notes: - --*/ #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter_def.h" diff --git a/src/tactic/core/blast_term_ite_tactic.h b/src/tactic/core/blast_term_ite_tactic.h index b5f643a1e..a322b8e11 100644 --- a/src/tactic/core/blast_term_ite_tactic.h +++ b/src/tactic/core/blast_term_ite_tactic.h @@ -4,20 +4,42 @@ Copyright (c) 2013 Microsoft Corporation Module Name: blast_term_ite_tactic.h - -Abstract: - - Blast term if-then-else by hoisting them up. - This is expensive but useful in some cases, such as - for enforcing constraints being in difference logic. - Use elim-term-ite elsewhere when possible. Author: Nikolaj Bjorner (nbjorner) 2013-11-4 -Notes: +Tactic Documentation: + +## Tactic blast-term-ite + +### Short Description: + +Blast term if-then-else by hoisting them up. +This is expensive but useful in some cases, such as +for enforcing constraints being in difference logic. +Use `elim-term-ite` elsewhere when possible. + +### Example + +```z3 +(declare-fun f (Int) Int) +(declare-fun p (Int) Bool) +(declare-const c1 Bool) +(declare-const c2 Bool) +(declare-const c3 Bool) +(declare-const e1 Int) +(declare-const e2 Int) +(declare-const e3 Int) +(declare-const e4 Int) +(assert (p (f (if c1 (if c2 e1 (if c3 e2 e3)) e4)))) +(apply blast-term-ite) +``` + +### Notes + + --*/ #pragma once diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index c8e34f33d..213f01f62 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -13,7 +13,30 @@ Author: Leonardo (leonardo) 2011-10-26 -Notes: +Tactic Documentation: + +## Tactic ctx-simplify + +### Short Description: + +The tactic performs simplifies sub-formulas using context built up by walking assertions and sub-formulas. + +### Example + +```z3 + (declare-const p Bool) + (declare-const q Bool) + (declare-const r Bool) + (declare-fun f (Bool) Bool) + (assert p) + (assert (or (f p) (and r (or (not r) q)))) + (apply ctx-simplify) +``` + +### Notes + +* supports proof terms with limited features + --*/ #pragma once diff --git a/src/tactic/core/elim_term_ite_tactic.h b/src/tactic/core/elim_term_ite_tactic.h index 8fa9f9031..ca8d3d43e 100644 --- a/src/tactic/core/elim_term_ite_tactic.h +++ b/src/tactic/core/elim_term_ite_tactic.h @@ -5,16 +5,39 @@ Module Name: elim_term_ite_tactic.h -Abstract: - - Eliminate term if-then-else by adding - new fresh auxiliary variables. - Author: Leonardo (leonardo) 2011-12-29 -Notes: +Tactic Documentation: + +## Tactic elim-term-ite + +### Short Description: + +Eliminate term if-then-else by adding +new fresh auxiliary variables. + + +### Example + +```z3 +(declare-fun f (Int) Int) +(declare-fun p (Int) Bool) +(declare-const c1 Bool) +(declare-const c2 Bool) +(declare-const c3 Bool) +(declare-const e1 Int) +(declare-const e2 Int) +(declare-const e3 Int) +(declare-const e4 Int) +(assert (p (f (if c1 (if c2 e1 (if c3 e2 e3)) e4)))) +(apply elim-term-ite) +``` + +### Notes + +* supports proof terms and unsat cores --*/ #pragma once diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 9f0717135..05ed6eee9 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -14,22 +14,6 @@ Author: Nikolaj Bjorner (nbjorner) 2013-12-23 -Notes: - - Resolution for PB constraints require the implicit - inequalities that each variable ranges over [0,1] - so not all resolvents produce smaller sets of clauses. - - We here implement subsumption resolution. - - x + y >= 1 - A~x + B~y + Cz >= k - --------------------- - Cz >= k - B - - where A <= B, x, y do not occur elsewhere. - - --*/ #include "tactic/core/pb_preprocess_tactic.h" #include "tactic/tactical.h" @@ -106,22 +90,20 @@ public: return alloc(pb_preprocess_tactic, m); } - char const* name() const override { return "pb_preprocess"; } + char const* name() const override { return "pb-preprocess"; } void operator()( goal_ref const & g, goal_ref_buffer & result) override { tactic_report report("pb-preprocess", *g); - if (g->proofs_enabled()) { - throw tactic_exception("pb-preprocess does not support proofs"); - } - - generic_model_converter* pp = alloc(generic_model_converter, m, "pb-preprocess"); - g->inc_depth(); result.push_back(g.get()); - while (simplify(g, *pp)); - g->add(pp); + + if (!g->proofs_enabled()) { + generic_model_converter* pp = alloc(generic_model_converter, m, "pb-preprocess"); + while (simplify(g, *pp)); + g->add(pp); + } // decompose(g); } diff --git a/src/tactic/core/pb_preprocess_tactic.h b/src/tactic/core/pb_preprocess_tactic.h index ec387e6e0..83e8723f6 100644 --- a/src/tactic/core/pb_preprocess_tactic.h +++ b/src/tactic/core/pb_preprocess_tactic.h @@ -14,7 +14,51 @@ Author: Nikolaj Bjorner (nbjorner) 2013-12-23 -Notes: +Documentation: + +## Tactic pb-preprocess + +### Short Description: + +The tactic eliminates variables from pseudo-Boolean inequalities and performs algebraic simplifcations on formulas + +### Long Description + +Resolution for PB constraints require the implicit +inequalities that each variable ranges over [0,1] +so not all resolvents produce smaller sets of clauses. + +We here implement subsumption resolution. + +``` + x + y >= 1 + A~x + B~y + Cz >= k + --------------------- + Cz >= k - B +``` + +where `A <= B` and `x, y` do not occur elsewhere. + + +### Example + +```z3 + (declare-const x Bool) + (declare-const y Bool) + (declare-const z Bool) + (declare-const u Bool) + (declare-const v Bool) + (assert ((_ pbge 1 1 1 2) (not x) (not y) (not z))) + (assert ((_ pbge 1 1 1 2) x u v)) + (assert (not (and y v))) + (assert (not (and z u))) + (apply pb-preprocess) +``` + +### Notes + +* supports unsat cores +* does not support proof terms --*/ #pragma once diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index e4476548a..667d53626 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -5,49 +5,14 @@ Module Name: tseitin_cnf_tactic.cpp -Abstract: - - Puts an assertion set in CNF. - Auxiliary variables are used to avoid blowup. - - Features: - - - Efficient encoding is used for commonly used patterns such as: - (iff a (iff b c)) - (or (not (or a b)) (not (or a c)) (not (or b c))) - - - Efficient encoding is used for chains of if-then-elses - - - Distributivity is applied to non-shared nodes if the blowup is acceptable. - - - The features above can be disabled/enabled using parameters. - - - The assertion-set is only modified if the resultant set of clauses - is "acceptable". - - Notes: - - - Term-if-then-else expressions are not handled by this strategy. - This kind of expression should be processed by other strategies. - - - Quantifiers are treated as "theory" atoms. They are viewed - as propositional variables by this strategy. - - - The assertion set may contain free variables. - - - This strategy assumes the assertion_set_rewriter was - used before invoking it. - In particular, it is more effective when "and" operators - were eliminated. - - TODO: add proof production - Author: Leonardo (leonardo) 2011-12-29 Notes: + TODO: add proof production + --*/ #include "ast/ast_pp.h" #include "tactic/tactical.h" diff --git a/src/tactic/core/tseitin_cnf_tactic.h b/src/tactic/core/tseitin_cnf_tactic.h index 363a1fafc..a5e116825 100644 --- a/src/tactic/core/tseitin_cnf_tactic.h +++ b/src/tactic/core/tseitin_cnf_tactic.h @@ -10,12 +10,40 @@ Abstract: Puts an assertion set in CNF. Auxiliary variables are used to avoid blowup. + Features: + + - Efficient encoding is used for commonly used patterns such as: + (iff a (iff b c)) + (or (not (or a b)) (not (or a c)) (not (or b c))) + + - Efficient encoding is used for chains of if-then-elses + + - Distributivity is applied to non-shared nodes if the blowup is acceptable. + + - The features above can be disabled/enabled using parameters. + + - The assertion-set is only modified if the resultant set of clauses + is "acceptable". + + Notes: + + - Term-if-then-else expressions are not handled by this strategy. + This kind of expression should be processed by other strategies. + + - Quantifiers are treated as "theory" atoms. They are viewed + as propositional variables by this strategy. + + - The assertion set may contain free variables. + + - This strategy assumes the assertion_set_rewriter was + used before invoking it. + In particular, it is more effective when "and" operators + were eliminated. + Author: Leonardo (leonardo) 2011-12-29 -Notes: - --*/ #pragma once From 4a451b10d8ba9f8186789048b08379e19776a4d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Dec 2022 09:07:13 -0800 Subject: [PATCH 389/477] add custom coercion for floats. fix #6482 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 05df8186e..72a3cd05f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1194,7 +1194,7 @@ def _coerce_expr_merge(s, a): else: if z3_debug(): _z3_assert(s1.ctx == s.ctx, "context mismatch") - _z3_assert(False, "sort mismatch") + _z3_assert(False, "sort mismatch") else: return s @@ -1207,6 +1207,11 @@ def _coerce_exprs(a, b, ctx=None): a = StringVal(a, b.ctx) if isinstance(b, str) and isinstance(a, SeqRef): b = StringVal(b, a.ctx) + if isinstance(a, float) and isinstance(b, ArithRef): + a = RealVal(a, b.ctx) + if isinstance(b, float) and isinstance(a, ArithRef): + b = RealVal(b, a.ctx) + s = None s = _coerce_expr_merge(s, a) s = _coerce_expr_merge(s, b) From 8981d32caf488cd4df4ed6ec7f14c390eba8ddb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Dec 2022 07:06:27 -0800 Subject: [PATCH 390/477] #6481 --- src/math/lp/stacked_vector.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/math/lp/stacked_vector.h b/src/math/lp/stacked_vector.h index 61131955a..ecd61eb10 100644 --- a/src/math/lp/stacked_vector.h +++ b/src/math/lp/stacked_vector.h @@ -55,6 +55,9 @@ public: bool operator==(B const& other) const { return m_vec.m_vector[m_i] == other; } + bool operator!=(B const& other) const { + return m_vec.m_vector[m_i] != other; + } B& operator+=(B const &delta) { // not tracking the change here! return m_vec.m_vector[m_i] += delta; From ca6fed8b25331cd6a472d3296b4b28b73c0c993b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 8 Dec 2022 18:20:46 +0000 Subject: [PATCH 391/477] minor code simplification --- src/qe/lite/qe_lite.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qe/lite/qe_lite.cpp b/src/qe/lite/qe_lite.cpp index a052ae944..75c90ee4d 100644 --- a/src/qe/lite/qe_lite.cpp +++ b/src/qe/lite/qe_lite.cpp @@ -2444,8 +2444,7 @@ namespace { } tactic * mk_qe_lite_tactic(ast_manager & m, params_ref const & p) { - return alloc(dependent_expr_state_tactic, m, p, - [](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(qe_lite_simplifier, m, p, s); }); + return alloc(dependent_expr_state_tactic, m, p, mk_qe_lite_simplifer); } dependent_expr_simplifier* mk_qe_lite_simplifer(ast_manager& m, params_ref const& p, dependent_expr_state& st) { From c6f9c09d70b7202ecb2b1492493e6d7bec392253 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 9 Dec 2022 11:34:53 +0000 Subject: [PATCH 392/477] cleanup more in dependent_expr_state_tactic to reduce mem consumption --- src/ast/simplifiers/dependent_expr.h | 1 - src/tactic/dependent_expr_state_tactic.h | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index 55f8d8f46..c1ba9dd2d 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -32,7 +32,6 @@ public: m_fml(fml), m_proof(p), m_dep(d) { - SASSERT(fml); m.inc_ref(fml); m.inc_ref(d); m.inc_ref(p); diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 9da9c1965..f635acca1 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -49,7 +49,7 @@ public: m(m), m_params(p), m_factory(f), - m_dep(m, m.mk_true(), nullptr, nullptr) + m_dep(m, nullptr, nullptr, nullptr) {} /** @@ -115,13 +115,13 @@ public: } catch (rewriter_exception& ex) { throw tactic_exception(ex.msg()); - } + } m_goal->elim_true(); m_goal->elim_redundancies(); m_goal->inc_depth(); if (in->models_enabled()) in->add(m_model_trail->get_model_converter().get()); - result.push_back(in.get()); + result.push_back(in.get()); cleanup(); } @@ -130,6 +130,8 @@ public: m_simp->collect_statistics(m_st); m_simp = nullptr; m_model_trail = nullptr; + m_goal = nullptr; + m_dep = dependent_expr(m, nullptr, nullptr, nullptr); } void collect_statistics(statistics & st) const override { From a96f5a9b425b6f5ba7e8ce1c1a75db6683c4bdc9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 9 Dec 2022 11:59:39 +0000 Subject: [PATCH 393/477] fix overflow in mpz::bitwise_not --- src/util/mpz.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 9b0da70fc..c56ab1667 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -1460,9 +1460,11 @@ void mpz_manager::bitwise_xor(mpz const & a, mpz const & b, mpz & c) { template void mpz_manager::bitwise_not(unsigned sz, mpz const & a, mpz & c) { SASSERT(is_nonneg(a)); - if (is_small(a) && sz <= 63) { - int64_t mask = (static_cast(1) << sz) - static_cast(1); - set_i64(c, (~ i64(a)) & mask); + if (is_small(a) && sz <= 64) { + uint64_t v = ~get_uint64(a); + unsigned zero_out = 64 - sz; + v = (v >> zero_out) << zero_out; + set(c, v); } else { mpz a1, a2, m, tmp; From 96a2c0402657d2b836e23428a4c95c3ff8637070 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2022 07:56:51 -0800 Subject: [PATCH 394/477] fix bug reported by Nuno qhead should not be changed after tactic execution. It should remain 0 so the same tactic can be applied repeatedly on the entire state --- src/tactic/dependent_expr_state_tactic.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index f635acca1..58507a850 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -110,8 +110,6 @@ public: try { if (!in->proofs_enabled() || m_simp->supports_proofs()) m_simp->reduce(); - if (m.inc()) - advance_qhead(); } catch (rewriter_exception& ex) { throw tactic_exception(ex.msg()); From 9ebacd87e2ee8a79adfe128021fbfd444db7857a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 9 Dec 2022 16:16:52 +0000 Subject: [PATCH 395/477] fix buggy mask (typo in my last commit..) --- src/util/mpz.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index c56ab1667..c3ba30161 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -1463,7 +1463,7 @@ void mpz_manager::bitwise_not(unsigned sz, mpz const & a, mpz & c) { if (is_small(a) && sz <= 64) { uint64_t v = ~get_uint64(a); unsigned zero_out = 64 - sz; - v = (v >> zero_out) << zero_out; + v = (v << zero_out) >> zero_out; set(c, v); } else { From 1434c7d394d36ab53627b42d85dde50f8921a1cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2022 08:50:32 -0800 Subject: [PATCH 396/477] #6059 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 21 +++++++++++++++++++++ src/api/python/z3/z3.py | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 553e71287..caf7ce07e 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1566,6 +1566,11 @@ namespace z3 { */ expr substitute(expr_vector const& dst); + /** + \brief Apply function substitution by macro definitions. + */ + expr substitute(func_decl_vector const& funs, expr_vector const& bodies); + class iterator { expr& e; @@ -4059,6 +4064,22 @@ namespace z3 { return expr(ctx(), r); } + inline expr expr::substitute(func_decl_vector const& funs, expr_vector const& dst) { + array _dst(dst.size()); + array _funs(funs.size()); + if (dst.size() != funs.size()) { + Z3_THROW(exception("length of argument lists don't align")); + return expr(ctx(), nullptr); + } + for (unsigned i = 0; i < dst.size(); ++i) { + _dst[i] = dst[i]; + _funs[i] = funs[i]; + } + Z3_ast r = Z3_substitute_funs(ctx(), m_ast, dst.size(), _funs.ptr(), _dst.ptr()); + check_error(); + return expr(ctx(), r); + } + typedef std::function on_clause_eh_t; class on_clause { diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 72a3cd05f..c97cd2124 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8837,7 +8837,7 @@ def substitute_vars(t, *m): return _to_expr_ref(Z3_substitute_vars(t.ctx.ref(), t.as_ast(), num, _to), t.ctx) def substitute_funs(t, *m): - """Apply subistitution m on t, m is a list of pairs of a function and expression (from, to) + """Apply substitution m on t, m is a list of pairs of a function and expression (from, to) Every occurrence in to of the function from is replaced with the expression to. The expression to can have free variables, that refer to the arguments of from. For examples, see From a302c2f15ee0e4d24ce9036050fffd8e827fe053 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 11 Dec 2022 15:21:23 +0000 Subject: [PATCH 397/477] fix crashes in elim-uncnstr2 This would crash before: (declare-fun x () (_ BitVec 4)) (assert (not (bvule x #x1))) (apply elim-uncnstr2) That's because the index_set iterator was querying qtail to compute the end of the iteration But the problem is that elim-uncnstr2 may add new fmls to the goal, as in this case. The bvule is replaced with an 'or', but since it's negated, it turns into 2 goals Solve the issue by freezing the qtail for the iteration loop. This is the right behavior for elim-uncnstr2, as it can't rewrite exprs that haven't been analyzed before @NikolajBjorner please check if this the right behavior for the other simplifiers. Thank you --- src/ast/simplifiers/dependent_expr_state.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 85b6352ad..f9faee549 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -116,20 +116,17 @@ protected: unsigned qtail() const { return m_fmls.qtail(); } struct iterator { dependent_expr_simplifier& s; - unsigned m_index = 0; - bool at_end = false; - unsigned index() const { return at_end ? s.qtail() : std::min(m_index, s.qtail()); } - iterator(dependent_expr_simplifier& s, unsigned i) : s(s), m_index(i), at_end(i == s.qtail()) {} - bool operator==(iterator const& other) const { return index() == other.index(); } - bool operator!=(iterator const& other) const { return !(*this == other); } - iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent()) at_end = true; else ++m_index; return *this; } + unsigned m_index, m_end; + iterator(dependent_expr_simplifier& s, unsigned i, unsigned end) : s(s), m_index(i), m_end(end) {} + bool operator!=(iterator const& other) const { return m_index != other.m_index; } + iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent()) m_index = m_end; else ++m_index; return *this; } unsigned operator*() const { return m_index; } }; struct index_set { dependent_expr_simplifier& s; - iterator begin() { return iterator(s, s.qhead()); } - iterator end() { return iterator(s, s.qtail()); } + iterator begin() { return iterator(s, s.qhead(), s.qtail()); } + iterator end() { return iterator(s, s.qtail(), s.qtail()); } index_set(dependent_expr_simplifier& s) : s(s) {} }; From 527fb18366f5b028b6144d0f84df43767cc45985 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 09:51:30 -0800 Subject: [PATCH 398/477] add doc for card2bv --- src/ast/rewriter/pb2bv_rewriter.cpp | 8 ++-- src/tactic/arith/arith_bounds_tactic.cpp | 2 +- src/tactic/arith/bound_manager.cpp | 11 +++--- src/tactic/arith/card2bv_tactic.h | 49 ++++++++++++++++++++++-- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 5e4e2aa28..d3dd8ae76 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -200,7 +200,7 @@ struct pb2bv_rewriter::imp { } if (m_pb_solver == "segmented") { - throw default_exception("segmented encoding is disabled, use a different value for pb.solver"); + throw default_exception("segmented encoding is disabled, use a different value for pb.solver"); switch (is_le) { case l_true: return mk_seg_le(k); case l_false: return mk_seg_ge(k); @@ -1077,9 +1077,9 @@ struct pb2bv_rewriter::imp { } void collect_param_descrs(param_descrs& r) const { - r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: false) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver"); - r.insert("pb.solver", CPK_SYMBOL, "(default: solver) retain pb constraints (don't bit-blast them) and use built-in pb solver"); - r.insert("cardinality.encoding", CPK_SYMBOL, "(default: none) grouped, bimander, ordered, unate, circuit"); + r.insert("keep_cardinality_constraints", CPK_BOOL, "retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver", "false"); + r.insert("pb.solver", CPK_SYMBOL, "encoding used for Pseudo-Boolean constraints: totalizer, sorting, binary_merge, bv, solver. PB constraints are retained if set to 'solver'", "solver"); + r.insert("cardinality.encoding", CPK_SYMBOL, "encoding used for cardinality constraints: grouped, bimander, ordered, unate, circuit", "none"); } unsigned get_num_steps() const { return m_rw.get_num_steps(); } diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index 87308078a..9a57b9eca 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -61,7 +61,7 @@ struct arith_bounds_tactic : public tactic { return true; } if ((!is_negated && (a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1))) || - (is_negated && (a.is_le(e, e2, e1) || a.is_ge(e, e1, e2)))) { + (is_negated && (a.is_le(e, e2, e1) || a.is_ge(e, e1, e2)))) { is_strict = true; return true; } diff --git a/src/tactic/arith/bound_manager.cpp b/src/tactic/arith/bound_manager.cpp index ef8ca3fcb..d6422abff 100644 --- a/src/tactic/arith/bound_manager.cpp +++ b/src/tactic/arith/bound_manager.cpp @@ -262,13 +262,12 @@ void bound_manager::reset() { } bool bound_manager::inconsistent() const { - for (auto const& kv : m_lowers) { - limit const& lim1 = kv.m_value; + for (auto const& [k,v] : m_lowers) { + limit const& lim1 = v; limit lim2; - if (m_uppers.find(kv.m_key, lim2)) { - if (lim1.first > lim2.first) { - return true; - } + if (m_uppers.find(k, lim2)) { + if (lim1.first > lim2.first) + return true; if (lim1.first == lim2.first && !lim1.second && lim2.second) { return true; diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index d7ad76e7d..d28326514 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -5,14 +5,55 @@ Module Name: card2bv_tactic.cpp -Abstract: - - Tactic for converting Pseudo-Boolean constraints to BV - Author: Nikolaj Bjorner (nbjorner) 2014-03-20 +Tactic Documentation: + +## Tactic car2bv + +### Short Description + +Tactic for converting Pseudo-Boolean constraints to bit-vectors. + +### Long Description + +The tactic implements a set of standard methods for converting cardinality and Pseudo-Boolean constraints into bit-vector or propositional formulas +(using basic logical connectives, conjunction, disjunction, negation). The conversions from cardinality constraints are controlled +separately from the conversions from Pseudo-Boolean constraints using different parameters. + +### Example + +```z3 +(declare-const a1 Bool) +(declare-const a2 Bool) +(declare-const a3 Bool) +(declare-const a4 Bool) +(declare-const a5 Bool) +(declare-const a6 Bool) +(push) +(assert ((_ at-most 1) a1 a2 a3 a4 a5 a6)) +(assert ((_ at-most 2) a1 a2 a3 a4 a5 a6)) +(apply (with card2bv :cardinality.encoding unate)) +(apply (with card2bv :cardinality.encoding circuit)) +(apply (with card2bv :cardinality.encoding ordered)) +(apply (with card2bv :cardinality.encoding grouped)) +(apply (with card2bv :cardinality.encoding bimander)) +(pop) +(assert ((_ pbge 5 2 3 4 4 3 5) a1 a2 a3 a4 a5 a6)) +(apply (with card2bv :pb.solver totalizer)) +(apply (with card2bv :pb.solver sorting)) +(apply (with card2bv :pb.solver binary_merge)) +(apply (with card2bv :pb.solver bv)) +(apply (with card2bv :pb.solver solver)) +``` + +### Notes + +* supports cores +* does not support proofs + --*/ #pragma once From a9f52b0069bf31d316f3485731b13897551aee43 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 10:04:01 -0800 Subject: [PATCH 399/477] doc fixes --- doc/mk_tactic_doc.py | 17 +++++++++++++---- src/ast/simplifiers/card2bv.cpp | 2 +- src/tactic/arith/card2bv_tactic.h | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index 37b77ef52..e4c71341a 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -53,15 +53,24 @@ def extract_tactic_doc(ous, f): if is_doc.search(line): generate_tactic_doc(ous, f, ins) +def presort_files(): + tac_files = [] + for root, dirs, files in os.walk(doc_path("../src")): + for f in files: + if f.endswith("tactic.h"): + tac_files += [(f, os.path.join(root, f))] + tac_files = sorted(tac_files, key = lambda x: x[0]) + return tac_files + def help(ous): + presort_files() ous.write("---\n") ous.write("title: Tactics Summary\n") ous.write("sidebar_position: 5\n") ous.write("---\n") - for root, dirs, files in os.walk(doc_path("../src")): - for f in files: - if f.endswith("tactic.h"): - extract_tactic_doc(ous, os.path.join(root, f)) + tac_files = presort_files() + for file, path in tac_files: + extract_tactic_doc(ous, path) def mk_dir(d): if not os.path.exists(d): diff --git a/src/ast/simplifiers/card2bv.cpp b/src/ast/simplifiers/card2bv.cpp index b2fece21e..d2d482aa3 100644 --- a/src/ast/simplifiers/card2bv.cpp +++ b/src/ast/simplifiers/card2bv.cpp @@ -55,7 +55,7 @@ void card2bv::collect_statistics(statistics& st) const { } void card2bv::collect_param_descrs(param_descrs& r) { - r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints for solver"); + r.insert("keep_cardinality_constraints", CPK_BOOL, "retain cardinality constraints for solver", "true"); pb2bv_rewriter rw(m, m_params); rw.collect_param_descrs(r); } diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index d28326514..f3cd4e2c8 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -11,7 +11,7 @@ Author: Tactic Documentation: -## Tactic car2bv +## Tactic card2bv ### Short Description From f7269bb60a3165d6a670f22aaa45b164b23906a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 10:16:17 -0800 Subject: [PATCH 400/477] update doc Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/propagate_values.cpp | 2 +- src/ast/simplifiers/solve_eqs.cpp | 8 ++++---- src/tactic/core/blast_term_ite_tactic.cpp | 2 +- src/tactic/core/ctx_simplify_tactic.cpp | 4 ++-- src/tactic/core/propagate_values_tactic.cpp | 2 +- src/util/params.cpp | 8 ++++---- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ast/simplifiers/propagate_values.cpp b/src/ast/simplifiers/propagate_values.cpp index 1083cc36d..efaf7f244 100644 --- a/src/ast/simplifiers/propagate_values.cpp +++ b/src/ast/simplifiers/propagate_values.cpp @@ -115,5 +115,5 @@ void propagate_values::updt_params(params_ref const& p) { void propagate_values::collect_param_descrs(param_descrs& r) { th_rewriter::get_param_descrs(r); - r.insert("max_rounds", CPK_UINT, "(default: 4) maximum number of rounds."); + r.insert("max_rounds", CPK_UINT, "maximum number of rounds.", "4"); } diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index e481dad8d..1117ad0bc 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -270,10 +270,10 @@ namespace euf { } void solve_eqs::collect_param_descrs(param_descrs& r) { - r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations."); - r.insert("theory_solver", CPK_BOOL, "(default: true) use theory solvers."); - r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); - r.insert("context_solve", CPK_BOOL, "(default: false) solve equalities under disjunctions."); + r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations.", "4294967295"); + r.insert("theory_solver", CPK_BOOL, "theory solvers.", "true"); + r.insert("ite_solver", CPK_BOOL, "use if-then-else solver.", "true"); + r.insert("context_solve", CPK_BOOL, "solve equalities under disjunctions.", "false"); } void solve_eqs::collect_statistics(statistics& st) const { diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 987ab9f90..b38f08e54 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -179,7 +179,7 @@ public: void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); - r.insert("max_inflation", CPK_UINT, "(default: infinity) multiplicative factor of initial term size."); + r.insert("max_inflation", CPK_UINT, "(default: infinity) multiplicative factor of initial term size.", "4294967295"); } void operator()(goal_ref const & in, goal_ref_buffer & result) override { diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 9ef1cf224..aa4358e9c 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -611,8 +611,8 @@ void ctx_simplify_tactic::updt_params(params_ref const & p) { void ctx_simplify_tactic::get_param_descrs(param_descrs & r) { insert_max_memory(r); insert_max_steps(r); - r.insert("max_depth", CPK_UINT, "(default: 1024) maximum term depth."); - r.insert("propagate_eq", CPK_BOOL, "(default: false) enable equality propagation from bounds."); + r.insert("max_depth", CPK_UINT, "maximum term depth.", "1024"); + r.insert("propagate_eq", CPK_BOOL, "enable equality propagation from bounds.", "false"); } void ctx_simplify_tactic::operator()(goal_ref const & in, diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 6b8395fd8..5d5bc0945 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -230,7 +230,7 @@ public: void collect_param_descrs(param_descrs & r) override { th_rewriter::get_param_descrs(r); - r.insert("max_rounds", CPK_UINT, "(default: 4) maximum number of rounds."); + r.insert("max_rounds", CPK_UINT, "maximum number of rounds.", "4"); } void operator()(goal_ref const & in, goal_ref_buffer & result) override { diff --git a/src/util/params.cpp b/src/util/params.cpp index c801b3421..d89026152 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -314,19 +314,19 @@ void param_descrs::display_markdown(std::ostream & out, bool smt2_style, bool in } void insert_max_memory(param_descrs & r) { - r.insert("max_memory", CPK_UINT, "(default: infty) maximum amount of memory in megabytes."); + r.insert("max_memory", CPK_UINT, "(default: infty) maximum amount of memory in megabytes.", "4294967295"); } void insert_max_steps(param_descrs & r) { - r.insert("max_steps", CPK_UINT, "(default: infty) maximum number of steps."); + r.insert("max_steps", CPK_UINT, "(default: infty) maximum number of steps.", "4294967295"); } void insert_produce_models(param_descrs & r) { - r.insert("produce_models", CPK_BOOL, "(default: false) model generation."); + r.insert("produce_models", CPK_BOOL, "model generation.", "false"); } void insert_produce_proofs(param_descrs & r) { - r.insert("produce_proofs", CPK_BOOL, "(default: false) proof generation."); + r.insert("produce_proofs", CPK_BOOL, "proof generation.", "false"); } void insert_timeout(param_descrs & r) { From 6a1b3f73446bc1c33bad3bd8a063c772bdac8f72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 12:51:46 -0800 Subject: [PATCH 401/477] move debug output to before state update --- src/ast/simplifiers/elim_unconstrained.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 032c46a92..fc3928a2c 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -108,7 +108,7 @@ void elim_unconstrained::eliminate() { else m_created_compound = true; - IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(n.m_orig, m) << " " << mk_bounded_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n";); + IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(get_node(v).m_orig, m) << " " << mk_bounded_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n";); SASSERT(!side_cond && "not implemented to add side conditions\n"); } @@ -264,9 +264,9 @@ void elim_unconstrained::assert_normalized(vector& old_fmls) { if (f == g) continue; old_fmls.push_back(m_fmls[i]); - m_fmls.update(i, dependent_expr(m, g, nullptr, d)); IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(f, m, 3) << " -> " << mk_bounded_pp(g, m, 3) << "\n"); TRACE("elim_unconstrained", tout << mk_bounded_pp(f, m) << " -> " << mk_bounded_pp(g, m) << "\n"); + m_fmls.update(i, dependent_expr(m, g, nullptr, d)); } } From 2d43ccc4c6a4f63c2c6da58302a02c5610f98a30 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 11 Dec 2022 21:37:25 +0000 Subject: [PATCH 402/477] Revert "fix crashes in elim-uncnstr2" This reverts commit a302c2f15ee0e4d24ce9036050fffd8e827fe053. --- src/ast/simplifiers/dependent_expr_state.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index f9faee549..85b6352ad 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -116,17 +116,20 @@ protected: unsigned qtail() const { return m_fmls.qtail(); } struct iterator { dependent_expr_simplifier& s; - unsigned m_index, m_end; - iterator(dependent_expr_simplifier& s, unsigned i, unsigned end) : s(s), m_index(i), m_end(end) {} - bool operator!=(iterator const& other) const { return m_index != other.m_index; } - iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent()) m_index = m_end; else ++m_index; return *this; } + unsigned m_index = 0; + bool at_end = false; + unsigned index() const { return at_end ? s.qtail() : std::min(m_index, s.qtail()); } + iterator(dependent_expr_simplifier& s, unsigned i) : s(s), m_index(i), at_end(i == s.qtail()) {} + bool operator==(iterator const& other) const { return index() == other.index(); } + bool operator!=(iterator const& other) const { return !(*this == other); } + iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent()) at_end = true; else ++m_index; return *this; } unsigned operator*() const { return m_index; } }; struct index_set { dependent_expr_simplifier& s; - iterator begin() { return iterator(s, s.qhead(), s.qtail()); } - iterator end() { return iterator(s, s.qtail(), s.qtail()); } + iterator begin() { return iterator(s, s.qhead()); } + iterator end() { return iterator(s, s.qtail()); } index_set(dependent_expr_simplifier& s) : s(s) {} }; From 2520dcb04ba2661cb7ed8e433833338e25559f7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 14:03:22 -0800 Subject: [PATCH 403/477] merge Signed-off-by: Nikolaj Bjorner --- .github/workflows/coverage.yml | 2 +- src/ast/simplifiers/dependent_expr_state.h | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 707db63d6..e8caa9bfb 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -58,7 +58,7 @@ jobs: - name: Run examples run: | - ${{github.workspace}}/build/examples/c_example_build_dir/c_example +# Disabled: ${{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 diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 85b6352ad..6d1f1aa77 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -116,13 +116,10 @@ protected: unsigned qtail() const { return m_fmls.qtail(); } struct iterator { dependent_expr_simplifier& s; - unsigned m_index = 0; - bool at_end = false; - unsigned index() const { return at_end ? s.qtail() : std::min(m_index, s.qtail()); } - iterator(dependent_expr_simplifier& s, unsigned i) : s(s), m_index(i), at_end(i == s.qtail()) {} - bool operator==(iterator const& other) const { return index() == other.index(); } - bool operator!=(iterator const& other) const { return !(*this == other); } - iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent()) at_end = true; else ++m_index; return *this; } + unsigned m_index, m_end; + iterator(dependent_expr_simplifier& s, unsigned i, unsigned end) : s(s), m_index(i), m_end(end) {} + bool operator!=(iterator const& other) const { return m_index != other.m_index; } + iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent() || m_index > s.qtail()) m_index = m_end; else ++m_index; return *this; } unsigned operator*() const { return m_index; } }; From 6b60a3dbed4f7ed492afb4244eb59cd2edd4cf2a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 14:06:08 -0800 Subject: [PATCH 404/477] fix syntax Signed-off-by: Nikolaj Bjorner --- .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 e8caa9bfb..366a2224e 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -56,9 +56,10 @@ jobs: ./test-z3 -a cd - +# Disabled: ${{github.workspace}}/build/examples/c_example_build_dir/c_example + - name: Run examples run: | -# Disabled: ${{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 From d308b8f5557d49da1f69290b68ec0ddc3bb19524 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 11 Dec 2022 22:09:41 +0000 Subject: [PATCH 405/477] simplify code + remove unused file --- .../converters/generic_model_converter.cpp | 5 -- src/ast/converters/generic_model_converter.h | 2 - src/smt/tactic/smt_tactic_core.h | 1 - src/tactic/filter_model_converter.h | 50 ------------------- src/tactic/goal.cpp | 4 +- 5 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 src/tactic/filter_model_converter.h diff --git a/src/ast/converters/generic_model_converter.cpp b/src/ast/converters/generic_model_converter.cpp index 50c3b071a..9adb9ee4b 100644 --- a/src/ast/converters/generic_model_converter.cpp +++ b/src/ast/converters/generic_model_converter.cpp @@ -28,11 +28,6 @@ Notes: #include "model/model_v2_pp.h" #include "model/model_evaluator.h" - -generic_model_converter::~generic_model_converter() { -} - - void generic_model_converter::add(func_decl * d, expr* e) { VERIFY(e); VERIFY(d->get_range() == e->get_sort()); diff --git a/src/ast/converters/generic_model_converter.h b/src/ast/converters/generic_model_converter.h index 0706b181f..cf551c92a 100644 --- a/src/ast/converters/generic_model_converter.h +++ b/src/ast/converters/generic_model_converter.h @@ -41,8 +41,6 @@ private: public: generic_model_converter(ast_manager & m, char const* orig) : m(m), m_orig(orig) {} - ~generic_model_converter() override; - void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); } void hide(func_decl * f) { m_entries.push_back(entry(f, nullptr, m, HIDE)); } diff --git a/src/smt/tactic/smt_tactic_core.h b/src/smt/tactic/smt_tactic_core.h index f89b3c649..7c6fa97f7 100644 --- a/src/smt/tactic/smt_tactic_core.h +++ b/src/smt/tactic/smt_tactic_core.h @@ -24,7 +24,6 @@ Notes: #include "tactic/goal.h" class tactic; -class filter_model_converter; tactic * mk_smt_tactic_core(ast_manager& m, params_ref const & p = params_ref(), symbol const& logic = symbol::null); // syntax sugar for using_params(mk_smt_tactic(), p) where p = (:auto_config, auto_config) diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h deleted file mode 100644 index 56dda91db..000000000 --- a/src/tactic/filter_model_converter.h +++ /dev/null @@ -1,50 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - filter_model_converter.h - -Abstract: - - Filter decls from a model - -Author: - - Leonardo (leonardo) 2011-05-06 - -Notes: - ---*/ -#pragma once - -#include "tactic/model_converter.h" - -class filter_model_converter : public model_converter { - func_decl_ref_vector m_decls; -public: - filter_model_converter(ast_manager & m):m_decls(m) {} - - ~filter_model_converter() override; - - ast_manager & m() const { return m_decls.get_manager(); } - - void operator()(model_ref & md, unsigned goal_idx) override; - - virtual void operator()(svector & labels, unsigned goal_idx); - - void operator()(model_ref & md) override { operator()(md, 0); } // TODO: delete - - void cancel() override {} - - void display(std::ostream & out) override; - - void insert(func_decl * d) { - m_decls.push_back(d); - } - - model_converter * translate(ast_translation & translator) override; -}; - -typedef ref filter_model_converter_ref; - diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index e489a1100..b6fe76f6a 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -159,9 +159,7 @@ void goal::quick_process(bool save_first, expr_ref& f, expr_dependency * d) { while (!todo.empty()) { if (m_inconsistent) return; - expr_pol p = todo.back(); - expr * curr = p.first; - bool pol = p.second; + auto [curr, pol] = todo.back(); todo.pop_back(); if (pol && m().is_and(curr)) { app * t = to_app(curr); From cb8603177e7624b98ae23f5c0c56a8c0c964df4b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 11 Dec 2022 22:17:11 +0000 Subject: [PATCH 406/477] fix build --- src/ast/simplifiers/dependent_expr_state.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 6d1f1aa77..e8f137e35 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -119,14 +119,14 @@ protected: unsigned m_index, m_end; iterator(dependent_expr_simplifier& s, unsigned i, unsigned end) : s(s), m_index(i), m_end(end) {} bool operator!=(iterator const& other) const { return m_index != other.m_index; } - iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent() || m_index > s.qtail()) m_index = m_end; else ++m_index; return *this; } + iterator& operator++() { if (!s.m.inc() || s.m_fmls.inconsistent() || m_index >= s.qtail()) m_index = m_end; else ++m_index; return *this; } unsigned operator*() const { return m_index; } }; struct index_set { dependent_expr_simplifier& s; - iterator begin() { return iterator(s, s.qhead()); } - iterator end() { return iterator(s, s.qtail()); } + iterator begin() { return iterator(s, s.qhead(), s.qtail()); } + iterator end() { return iterator(s, s.qtail(), s.qtail()); } index_set(dependent_expr_simplifier& s) : s(s) {} }; From 039de6a2c80f6640cdfb6bb3db3add1f8c8e68a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2022 15:05:03 -0800 Subject: [PATCH 407/477] build issues Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/extract_eqs.cpp | 6 +++--- src/ast/simplifiers/model_reconstruction_trail.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index b2e264b1f..5c2851e91 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -34,7 +34,7 @@ namespace euf { public: basic_extract_eq(ast_manager& m) : m(m) {} - virtual void set_allow_booleans(bool f) { + void set_allow_booleans(bool f) override { m_allow_bool = f; } @@ -74,7 +74,7 @@ namespace euf { eqs.push_back(dependent_eq(e.fml(), to_app(x), expr_ref(m.mk_false(), m), d)); } - void updt_params(params_ref const& p) { + void updt_params(params_ref const& p) override { tactic_params tp(p); m_ite_solver = p.get_bool("ite_solver", tp.solve_eqs_ite_solver()); } @@ -263,7 +263,7 @@ namespace euf { } - void updt_params(params_ref const& p) { + void updt_params(params_ref const& p) override { tactic_params tp(p); m_enabled = p.get_bool("theory_solver", tp.solve_eqs_ite_solver()); } diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 4ef58f790..7f8c7dc8f 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -49,7 +49,7 @@ class model_reconstruction_trail { entry(ast_manager& m, func_decl* h) : m_decl(h, m), m_def(m), m_dep(m) {} entry(ast_manager& m, func_decl* f, expr* def, expr_dependency* dep, vector const& rem) : - m_decl(f, m), m_def(def, m), m_removed(rem), m_dep(dep, m) {} + m_removed(rem), m_decl(f, m), m_def(def, m), m_dep(dep, m) {} bool is_loose() const { return !m_removed.empty(); } From a3e68856802b4d4a440b6bc178277521917f0d0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Dec 2022 09:50:44 -0800 Subject: [PATCH 408/477] fix #6488 --- src/ast/simplifiers/elim_unconstrained.cpp | 24 ++++++++++++++-------- src/ast/simplifiers/elim_unconstrained.h | 3 ++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index fc3928a2c..a6acd7260 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -96,7 +96,7 @@ void elim_unconstrained::eliminate() { m_trail.push_back(r); SASSERT(r); gc(e); - init_children(e, r); + freeze_rec(r); m_root.setx(r->get_id(), e->get_id(), UINT_MAX); get_node(e).m_term = r; @@ -180,9 +180,8 @@ void elim_unconstrained::init_terms(expr_ref_vector const& terms) { } } -void elim_unconstrained::init_children(expr* e, expr* r) { +void elim_unconstrained::freeze_rec(expr* r) { expr_ref_vector children(m); - SASSERT(e != r); if (is_quantifier(r)) children.push_back(to_quantifier(r)->get_expr()); else if (is_app(r)) @@ -191,11 +190,20 @@ void elim_unconstrained::init_children(expr* e, expr* r) { return; if (children.empty()) return; - init_terms(children); - for (expr* arg : children) { - get_node(arg).m_parents.push_back(e); - inc_ref(arg); - } + for (expr* t : subterms::all(children)) + freeze(t); +} + +void elim_unconstrained::freeze(expr* t) { + if (!is_uninterp_const(t)) + return; + if (m_nodes.size() <= t->get_id()) + return; + node& n = get_node(t); + if (!n.m_term) + return; + n.m_refcount = UINT_MAX / 2; + m_heap.increased(root(t)); } void elim_unconstrained::gc(expr* t) { diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 1eb5d732b..68ca30777 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -58,8 +58,9 @@ class elim_unconstrained : public dependent_expr_simplifier { unsigned get_refcount(expr* t) const { return get_node(t).m_refcount; } void inc_ref(expr* t) { ++get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.increased(root(t)); } void dec_ref(expr* t) { --get_node(t).m_refcount; if (is_uninterp_const(t)) m_heap.decreased(root(t)); } + void freeze(expr* t); + void freeze_rec(expr* r); void gc(expr* t); - void init_children(expr* e, expr* r); expr* get_parent(unsigned n) const; void init_terms(expr_ref_vector const& terms); void init_nodes(); From 4598af70c823f741ed12186aa1273bf6febc7a45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Dec 2022 11:04:46 -0800 Subject: [PATCH 409/477] fix #6488 Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/elim_unconstrained.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index a6acd7260..b3f833a78 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -199,6 +199,8 @@ void elim_unconstrained::freeze(expr* t) { return; if (m_nodes.size() <= t->get_id()) return; + if (m_nodes.size() <= root(t)) + return; node& n = get_node(t); if (!n.m_term) return; From aded8e5bf475b6a645488b67bc49d33fd5a7a2c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Dec 2022 11:40:59 -0800 Subject: [PATCH 410/477] fix #6488 Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/elim_unconstrained.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index b3f833a78..bb7a4fa49 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -205,7 +205,8 @@ void elim_unconstrained::freeze(expr* t) { if (!n.m_term) return; n.m_refcount = UINT_MAX / 2; - m_heap.increased(root(t)); + if (m_heap.contains(root(t))) + m_heap.increased(root(t)); } void elim_unconstrained::gc(expr* t) { From e82c8e78ae7f9825d40ffaf9935a6364b793c2db Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Mon, 12 Dec 2022 23:12:31 +0100 Subject: [PATCH 411/477] Fix a compilation error with clang-cl (VS2022) (#6489) --- src/math/polynomial/upolynomial_factorization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index fad8a85e4..310a11fd1 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -27,7 +27,7 @@ Notes: #include "math/polynomial/upolynomial_factorization_int.h" #include "util/prime_generator.h" -using namespace std; +using std::endl; namespace upolynomial { From e648e68d3608b39077dadfd252908e76c314f775 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Dec 2022 17:29:58 -0800 Subject: [PATCH 412/477] add doc Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/degree_shift_tactic.h | 35 +++++++++++++++----- src/tactic/arith/diff_neq_tactic.cpp | 2 +- src/tactic/arith/diff_neq_tactic.h | 44 ++++++++++++++++++++------ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/tactic/arith/degree_shift_tactic.h b/src/tactic/arith/degree_shift_tactic.h index 9f3f9f09d..cdc4823e2 100644 --- a/src/tactic/arith/degree_shift_tactic.h +++ b/src/tactic/arith/degree_shift_tactic.h @@ -5,18 +5,37 @@ Module Name: degree_shift_tactic.h -Abstract: - - Simple degree shift procedure. - Basic idea: if goal G contains a real variable x, x occurs with degrees - d_1, ..., d_k in G, and n = gcd(d_1, ..., d_k) > 1. - Then, replace x^n with a new fresh variable y. - Author: Leonardo de Moura (leonardo) 2011-12-30. -Revision History: +Tactic Documentation: + +## Tactic degree-shift + +### Short Description + +The procedure reduces the degrees of variables. + +### Long Description + +Basic idea: if goal $G$ contains a real variable $x$, $x$ occurs with degrees +$d_1, ..., d_k$ in $G$, and $n = \gcd(d_1, ..., d_k) > 1$. +Then, replace $x^n$ with a new fresh variable $y$. + +### Example + +```z3 +(declare-const x Real) +(declare-const y Real) +(assert (> (+ (* x x x 4) (* x x 3) 0))) +(assert (= (* x x) (* y y))) +(apply degree-shift) +``` + +### Notes + +* supports proofs and cores --*/ #pragma once diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 4269aff85..59baace10 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -365,7 +365,7 @@ public: } void collect_param_descrs(param_descrs & r) override { - r.insert("diff_neq_max_k", CPK_UINT, "(default: 1024) maximum variable upper bound for diff neq solver."); + r.insert("diff_neq_max_k", CPK_UINT, "maximum variable upper bound for diff neq solver.", "1024"); } void collect_statistics(statistics & st) const override { diff --git a/src/tactic/arith/diff_neq_tactic.h b/src/tactic/arith/diff_neq_tactic.h index 2280a5d77..02028c385 100644 --- a/src/tactic/arith/diff_neq_tactic.h +++ b/src/tactic/arith/diff_neq_tactic.h @@ -5,19 +5,45 @@ Module Name: diff_neq_tactic.h -Abstract: - - Solver for integer problems that contains literals of the form - k <= x - x <= k - x - y != k - And all variables are bounded. - Author: Leonardo de Moura (leonardo) 2012-02-07. -Revision History: +Tactic Documentation: + +## Tactic diff-neq + +### Short Description + +A specialized solver for integer problems using only constant bounds and differences to constants. + +### Long Description + +Solver for integer problems that contains literals of the form +``` + k <= x + x <= k + x - y != k +``` + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(assert (<= 0 x)) +(assert (<= x 1)) +(assert (<= 0 y)) +(assert (<= y 1)) +(assert (not (= (+ x (* -1 y)) -1))) +(assert (not (= (+ x (* -1 y)) 1))) +(assert (not (= (+ x (* -1 y)) 0))) +(apply diff-neq) +``` + +### Notes + +* The tactic works only when the lower bounds are 0 and disequalities use multiplication with -1. Use normalize-bounds to ensure all lower bounds are 0. --*/ #pragma once From 7afcaa5364370dc20ba73b05304c138eb9dd7aed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Dec 2022 18:56:21 -0800 Subject: [PATCH 413/477] update doc Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/eq2bv_tactic.h | 28 ++++++++++++++---- src/tactic/arith/factor_tactic.cpp | 2 +- src/tactic/arith/factor_tactic.h | 16 ++++++++++- src/tactic/arith/fix_dl_var_tactic.h | 29 +++++++++++++++---- src/tactic/arith/fm_tactic.cpp | 18 ++++++------ src/tactic/arith/fm_tactic.h | 43 +++++++++++++++++++++------- 6 files changed, 102 insertions(+), 34 deletions(-) diff --git a/src/tactic/arith/eq2bv_tactic.h b/src/tactic/arith/eq2bv_tactic.h index e8c29715c..81d2718a6 100644 --- a/src/tactic/arith/eq2bv_tactic.h +++ b/src/tactic/arith/eq2bv_tactic.h @@ -5,16 +5,32 @@ Module Name: eq2bv_tactic.h -Abstract: - - Extract integer variables that are used as finite domain indicators. - The integer variables can only occur in equalities. - Author: Nikolaj Bjorner (nbjorner) 2015-8-19 -Notes: +Tactic Documentation: + +## Tactic eq2bv + +### Short Description + +Extract integer variables that are used as finite domain indicators. +The integer variables can only occur in equalities. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(assert (or (= x 5) (> y 3))) +(assert (or (= x 4) (= y 2))) +(apply eq2bv) +``` + +### Notes + +* does not support proofs --*/ #pragma once diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index 6b9b226b3..565f43af9 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -303,7 +303,7 @@ public: void collect_param_descrs(param_descrs & r) override { r.insert("split_factors", CPK_BOOL, - "(default: true) apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0))."); + "apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0)).", "true"); polynomial::factor_params::get_param_descrs(r); } diff --git a/src/tactic/arith/factor_tactic.h b/src/tactic/arith/factor_tactic.h index b02f67448..7be5c5df6 100644 --- a/src/tactic/arith/factor_tactic.h +++ b/src/tactic/arith/factor_tactic.h @@ -13,7 +13,21 @@ Author: Leonardo de Moura (leonardo) 2012-02-03 -Revision History: +Tactic Documentation: + +## Tactic factor + +### Short Description + +Factor polynomials in equalities and inequalities. + +### Example +```z3 +(declare-const x Real) +(declare-const y Real) +(assert (> (* x x) (* x y))) +(apply factor) +``` --*/ #pragma once diff --git a/src/tactic/arith/fix_dl_var_tactic.h b/src/tactic/arith/fix_dl_var_tactic.h index d7a79bf4b..f8b03557f 100644 --- a/src/tactic/arith/fix_dl_var_tactic.h +++ b/src/tactic/arith/fix_dl_var_tactic.h @@ -7,18 +7,35 @@ Module Name: Abstract: - Fix a difference logic variable to 0. - If the problem is in the difference logic fragment, that is, all arithmetic terms - are of the form (x + k), and the arithmetic atoms are of the - form x - y <= k or x - y = k. Then, we can set one variable to 0. - This is useful because, many bounds can be exposed after this operation is performed. Author: Leonardo (leonardo) 2011-12-29 -Notes: +Tactic Documentation: + +## Tactic fix-dl-var + +### Short Description + +Fix a difference logic variable to `0`. +If the problem is in the difference logic fragment, that is, all arithmetic terms +are of the form `(x + k)`, and the arithmetic atoms are of the +form `x - y <= k` or `x - y = k`. Then, we can set one variable to `0`. + +This is useful because, many bounds can be exposed after this operation is performed. + +### Example + +```z3 +(declare-const x Real) +(declare-const y Real) +(declare-const z Real) +(assert (<= (+ x (* -1.0 y)) 3.0)) +(assert (<= (+ x (* -1.0 z)) 5.0)) +(apply fix-dl-var) +``` --*/ #pragma once diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index d0564139a..1d3bc2770 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -467,10 +467,8 @@ class fm_tactic : public tactic { x = t; return true; } - else if (m_util.is_to_real(t) && is_uninterp_const(to_app(t)->get_arg(0))) { - x = to_app(t)->get_arg(0); - return true; - } + else if (m_util.is_to_real(t, x) && is_uninterp_const(x)) + return true; return false; } @@ -1675,12 +1673,12 @@ public: void collect_param_descrs(param_descrs & r) override { insert_produce_models(r); insert_max_memory(r); - r.insert("fm_real_only", CPK_BOOL, "(default: true) consider only real variables for fourier-motzkin elimination."); - r.insert("fm_occ", CPK_BOOL, "(default: false) consider inequalities occurring in clauses for FM."); - r.insert("fm_limit", CPK_UINT, "(default: 5000000) maximum number of constraints, monomials, clauses visited during FM."); - r.insert("fm_cutoff1", CPK_UINT, "(default: 8) first cutoff for FM based on maximum number of lower/upper occurrences."); - r.insert("fm_cutoff2", CPK_UINT, "(default: 256) second cutoff for FM based on num_lower * num_upper occurrences."); - r.insert("fm_extra", CPK_UINT, "(default: 0) max. increase on the number of inequalities for each FM variable elimination step."); + r.insert("fm_real_only", CPK_BOOL, "consider only real variables for fourier-motzkin elimination.", "true"); + r.insert("fm_occ", CPK_BOOL, "consider inequalities occurring in clauses for FM.", "false"); + r.insert("fm_limit", CPK_UINT, "maximum number of constraints, monomials, clauses visited during FM.", "5000000"); + r.insert("fm_cutoff1", CPK_UINT, "first cutoff for FM based on maximum number of lower/upper occurrences.", "8"); + r.insert("fm_cutoff2", CPK_UINT, "second cutoff for FM based on num_lower * num_upper occurrences.", "256"); + r.insert("fm_extra", CPK_UINT, "max. increase on the number of inequalities for each FM variable elimination step.", "0"); } diff --git a/src/tactic/arith/fm_tactic.h b/src/tactic/arith/fm_tactic.h index 622007703..7021dc273 100644 --- a/src/tactic/arith/fm_tactic.h +++ b/src/tactic/arith/fm_tactic.h @@ -5,20 +5,43 @@ Module Name: fm_tactic.h -Abstract: - - Use Fourier-Motzkin to eliminate variables. - This strategy can handle conditional bounds - (i.e., clauses with at most one constraint). - - The strategy mk_occf can be used to put the - formula in OCC form. - Author: Leonardo de Moura (leonardo) 2012-02-04. -Revision History: +Tactic Documentation: + +## Tactic fm + +### Short Description + +Use Fourier-Motzkin to eliminate variables. +This strategy can handle conditional bounds +(i.e., clauses with at most one constraint). + +The strategy mk_occf can be used to put the +formula in OCC form. + +### Example + +```z3 +(declare-const x Real) +(declare-const y Real) +(declare-const z Real) +(declare-const u Real) +(declare-const v Real) +(declare-const w Real) +(declare-fun P (Real) Bool) +(assert (<= x (+ y (* 2.0 z)))) +(assert (>= x (- y z))) +(assert (>= x (- y 3 (* 3 z)))) +(assert (>= x 5)) +(assert (<= x u)) +(assert (>= x v)) +(assert (P u)) +(assert (P v)) +(apply fm) +``` --*/ #pragma once From 2d7a38e95e2c29ed32b8e75954ea6eac6535e5de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Dec 2022 16:07:41 -0800 Subject: [PATCH 414/477] fix #6488 Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/elim_unconstrained.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index bb7a4fa49..2e950868a 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -65,7 +65,6 @@ void elim_unconstrained::eliminate() { expr_ref r(m), side_cond(m); int v = m_heap.erase_min(); node& n = get_node(v); - IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(n.m_orig, m) << " @ " << n.m_refcount << "\n"); if (n.m_refcount == 0) continue; if (n.m_refcount > 1) @@ -203,10 +202,11 @@ void elim_unconstrained::freeze(expr* t) { return; node& n = get_node(t); if (!n.m_term) - return; - n.m_refcount = UINT_MAX / 2; - if (m_heap.contains(root(t))) + return; + if (m_heap.contains(root(t))) { + n.m_refcount = UINT_MAX / 2; m_heap.increased(root(t)); + } } void elim_unconstrained::gc(expr* t) { From cd3d38caf79ccc0ecbf18f28044451b135f69cb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Dec 2022 16:17:38 -0800 Subject: [PATCH 415/477] sort out terminology/add explanations, add shortcut to C++, fix #6491 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 17 +++++++++++++++++ src/api/python/z3/z3.py | 4 +++- src/api/z3_api.h | 8 ++++++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index caf7ce07e..838a34be6 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -366,8 +366,14 @@ namespace z3 { void recdef(func_decl, expr_vector const& args, expr const& body); func_decl user_propagate_function(symbol const& name, sort_vector const& domain, sort const& range); + /** + \brief create an uninterpreted constant. + */ expr constant(symbol const & name, sort const & s); expr constant(char const * name, sort const & s); + /** + \brief create uninterpreted constants of a given sort. + */ expr bool_const(char const * name); expr int_const(char const * name); expr real_const(char const * name); @@ -378,6 +384,12 @@ namespace z3 { template expr fpa_const(char const * name); + /** + \brief create a de-Bruijn variable. + */ + expr variable(unsigned index, sort const& s); + + expr fpa_rounding_mode(); expr bool_val(bool b); @@ -3580,6 +3592,11 @@ namespace z3 { return expr(*this, r); } inline expr context::constant(char const * name, sort const & s) { return constant(str_symbol(name), s); } + inline expr context::variable(unsigned idx, sort const& s) { + Z3_ast r = Z3_mk_bound(m_ctx, idx, s); + check_error(); + return expr(*this, r); + } inline expr context::bool_const(char const * name) { return constant(name, bool_sort()); } inline expr context::int_const(char const * name) { return constant(name, int_sort()); } inline expr context::real_const(char const * name) { return constant(name, real_sort()); } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index c97cd2124..e829fdafb 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1469,7 +1469,9 @@ def FreshConst(sort, prefix="c"): def Var(idx, s): """Create a Z3 free variable. Free variables are used to create quantified formulas. - + A free variable with index n is bound when it occurs within the scope of n+1 quantified + declarations. + >>> Var(0, IntSort()) Var(0) >>> eq(Var(0, IntSort()), Var(0, BoolSort())) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 1100d60dd..467f30792 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4051,7 +4051,10 @@ extern "C" { Z3_pattern Z3_API Z3_mk_pattern(Z3_context c, unsigned num_patterns, Z3_ast const terms[]); /** - \brief Create a bound variable. + \brief Create a variable. + + Variables are intended to be bound by a scope created by a quantifier. So we call them bound variables + even if they appear as free variables in the expression produced by \c Z3_mk_bound. Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain the meaning of de-Bruijn indices by indicating the compilation process from @@ -5318,8 +5321,9 @@ extern "C" { Z3_ast const to[]); /** - \brief Substitute the free variables in \c a with the expressions in \c to. + \brief Substitute the variables in \c a with the expressions in \c to. For every \c i smaller than \c num_exprs, the variable with de-Bruijn index \c i is replaced with term \ccode{to[i]}. + Note that a variable is created using the function \ref Z3_mk_bound. def_API('Z3_substitute_vars', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST))) */ From 9054e729203931be474a9cdb15d6bc16e000cf01 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Dec 2022 19:35:20 -0800 Subject: [PATCH 416/477] fix #6467 --- src/muz/base/dl_rule.cpp | 25 ++++++++------- src/muz/base/dl_rule.h | 2 +- src/muz/base/dl_util.h | 23 +++++++------- src/muz/rel/dl_base.h | 2 +- src/muz/rel/dl_finite_product_relation.cpp | 2 +- src/muz/rel/dl_mk_explanations.cpp | 37 ++++++++++++---------- src/muz/rel/dl_relation_manager.cpp | 2 +- src/muz/rel/dl_sieve_relation.cpp | 4 +-- 8 files changed, 51 insertions(+), 46 deletions(-) diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index a1864d3b9..4ef02c03c 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -1013,28 +1013,31 @@ namespace datalog { } } - void rule::display(context & ctx, std::ostream & out) const { + void rule::display(context & ctx, std::ostream & out, bool compact) const { ast_manager & m = ctx.get_manager(); - out << m_name.str () << ":\n"; + if (!compact) + out << m_name.str () << ":\n"; output_predicate(ctx, m_head, out); if (m_tail_size == 0) { - out << ".\n"; + out << "."; + if (!compact) + out << "\n"; return; } out << " :- "; for (unsigned i = 0; i < m_tail_size; i++) { if (i > 0) out << ","; - out << "\n "; + if (!compact) + out << "\n"; + out << " "; if (is_neg_tail(i)) out << "not "; app * t = get_tail(i); - if (ctx.is_predicate(t)) { + if (ctx.is_predicate(t)) output_predicate(ctx, t, out); - } - else { + else out << mk_pp(t, m); - } } out << '.'; if (ctx.output_profile()) { @@ -1042,10 +1045,10 @@ namespace datalog { output_profile(out); out << '}'; } - out << '\n'; - if (m_proof) { + if (!compact) + out << '\n'; + if (m_proof) out << mk_pp(m_proof, m) << '\n'; - } } diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 6a21a2621..60b2bbe8f 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -365,7 +365,7 @@ namespace datalog { void get_vars(ast_manager& m, ptr_vector& sorts) const; - void display(context & ctx, std::ostream & out) const; + void display(context & ctx, std::ostream & out, bool compact = false) const; /** \brief Return the name(s) associated with this rule. Plural for preprocessed (e.g. obtained by inlining) rules. diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 4688a67fd..623f287f7 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -320,32 +320,31 @@ namespace datalog { unsigned_vector & res, bool & identity); template - void permutate_by_cycle(T & container, unsigned cycle_len, const unsigned * permutation_cycle) { - if (cycle_len<2) { + void permute_by_cycle(T& container, unsigned cycle_len, const unsigned * permutation_cycle) { + if (cycle_len < 2) return; - } auto aux = container[permutation_cycle[0]]; - for (unsigned i=1; i - void permutate_by_cycle(ref_vector & container, unsigned cycle_len, const unsigned * permutation_cycle) { + void permute_by_cycle(ref_vector & container, unsigned cycle_len, const unsigned * permutation_cycle) { if (cycle_len<2) { return; } + verbose_stream() << "ptr\n"; T * aux = container.get(permutation_cycle[0]); - for (unsigned i=1; i - void permutate_by_cycle(T & container, const unsigned_vector & permutation_cycle) { - permutate_by_cycle(container, permutation_cycle.size(), permutation_cycle.data()); + void permute_by_cycle(T & container, const unsigned_vector & permutation_cycle) { + permute_by_cycle(container, permutation_cycle.size(), permutation_cycle.data()); } diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index ea317ca45..f6d031624 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -160,7 +160,7 @@ namespace datalog { SASSERT(cycle_len>=2); result=src; - permutate_by_cycle(result, cycle_len, permutation_cycle); + permute_by_cycle(result, cycle_len, permutation_cycle); } /** diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index a991c9e6c..b1cdf0553 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -674,7 +674,7 @@ namespace datalog { unsigned sig_sz = r.get_signature().size(); unsigned_vector permutation; add_sequence(0, sig_sz, permutation); - permutate_by_cycle(permutation, cycle_len, permutation_cycle); + permute_by_cycle(permutation, cycle_len, permutation_cycle); unsigned_vector table_permutation; diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 7c5691c0a..37c67e0c8 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -70,20 +70,16 @@ namespace datalog { m_union_decl(mk_explanations::get_union_decl(get_context()), get_ast_manager()) {} ~explanation_relation_plugin() override { - for (unsigned i = 0; i < m_pool.size(); ++i) { - for (unsigned j = 0; j < m_pool[i].size(); ++j) { + for (unsigned i = 0; i < m_pool.size(); ++i) + for (unsigned j = 0; j < m_pool[i].size(); ++j) dealloc(m_pool[i][j]); - } - } } bool can_handle_signature(const relation_signature & s) override { unsigned n=s.size(); - for (unsigned i=0; iget_sort()), m_data[0]); + verbose_stream() << "FORMULA " << fml << "\n"; } bool is_undefined(unsigned col_idx) const { @@ -339,6 +340,7 @@ namespace datalog { if (!r.empty()) { relation_fact proj_data = r.m_data; project_out_vector_columns(proj_data, m_removed_cols); + verbose_stream() << "project\n"; res->assign_data(proj_data); } return res; @@ -365,9 +367,9 @@ namespace datalog { explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); if (!r.empty()) { - relation_fact permutated_data = r.m_data; - permutate_by_cycle(permutated_data, m_cycle); - res->assign_data(permutated_data); + relation_fact permuted_data = r.m_data; + permute_by_cycle(dynamic_cast(permuted_data), m_cycle); + res->assign_data(permuted_data); } return res; } @@ -406,6 +408,7 @@ namespace datalog { } else { if (tgt.empty()) { + verbose_stream() << "union\n"; tgt.assign_data(src.m_data); if (delta && delta->empty()) { delta->assign_data(src.m_data); @@ -704,7 +707,7 @@ namespace datalog { symbol mk_explanations::get_rule_symbol(rule * r) { if (r->name() == symbol::null) { std::stringstream sstm; - r->display(m_context, sstm); + r->display(m_context, sstm, true); std::string res = sstm.str(); res = res.substr(0, res.find_last_not_of('\n')+1); return symbol(res.c_str()); diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 9410e2ab0..8de25c8f3 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1149,7 +1149,7 @@ namespace datalog { } void modify_fact(table_fact & f) const override { - permutate_by_cycle(f, m_cycle); + permute_by_cycle(f, m_cycle); } table_base * operator()(const table_base & t) override { diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index c7eab9549..801108999 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -413,14 +413,14 @@ namespace datalog { unsigned sig_sz = r.get_signature().size(); unsigned_vector permutation; add_sequence(0, sig_sz, permutation); - permutate_by_cycle(permutation, cycle_len, permutation_cycle); + permute_by_cycle(permutation, cycle_len, permutation_cycle); bool inner_identity; unsigned_vector inner_permutation; collect_sub_permutation(permutation, r.m_sig2inner, inner_permutation, inner_identity); bool_vector result_inner_cols = r.m_inner_cols; - permutate_by_cycle(result_inner_cols, cycle_len, permutation_cycle); + permute_by_cycle(result_inner_cols, cycle_len, permutation_cycle); relation_signature result_sig; relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, result_sig); From dbb4bbe7dc8b494c7a3aff206672a7fcab69317c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Dec 2022 19:36:55 -0800 Subject: [PATCH 417/477] remove debug out --- src/muz/rel/dl_mk_explanations.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 37c67e0c8..a4b704597 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -147,7 +147,6 @@ namespace datalog { void assign_data(const relation_fact & f) { m_empty = false; - verbose_stream() << "assign data " << f << "\n"; unsigned n = get_signature().size(); SASSERT(f.size()==n); m_data.reset(); @@ -159,7 +158,6 @@ namespace datalog { m_data.resize(get_signature().size()); } void unite_with_data(const relation_fact & f) { - verbose_stream() << "unite data " << f << "\n"; if (empty()) { assign_data(f); @@ -186,7 +184,6 @@ namespace datalog { void to_formula(expr_ref& fml) const override { ast_manager& m = fml.get_manager(); fml = m.mk_eq(m.mk_var(0, m_data[0]->get_sort()), m_data[0]); - verbose_stream() << "FORMULA " << fml << "\n"; } bool is_undefined(unsigned col_idx) const { @@ -340,7 +337,6 @@ namespace datalog { if (!r.empty()) { relation_fact proj_data = r.m_data; project_out_vector_columns(proj_data, m_removed_cols); - verbose_stream() << "project\n"; res->assign_data(proj_data); } return res; @@ -408,7 +404,6 @@ namespace datalog { } else { if (tgt.empty()) { - verbose_stream() << "union\n"; tgt.assign_data(src.m_data); if (delta && delta->empty()) { delta->assign_data(src.m_data); From c4b2acac24c1e660df99bbf4364f531826186b11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Dec 2022 09:27:43 -0800 Subject: [PATCH 418/477] add missing error checking #6492 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 838a34be6..ec7b451fa 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1919,21 +1919,21 @@ namespace z3 { inline expr operator>(expr const & a, int b) { return a > a.ctx().num_val(b, a.get_sort()); } inline expr operator>(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) > b; } - inline expr operator&(expr const & a, expr const & b) { if (a.is_bool()) return a && b; check_context(a, b); Z3_ast r = Z3_mk_bvand(a.ctx(), a, b); return expr(a.ctx(), r); } + inline expr operator&(expr const & a, expr const & b) { if (a.is_bool()) return a && b; check_context(a, b); Z3_ast r = Z3_mk_bvand(a.ctx(), a, b); a.check_error(); return expr(a.ctx(), r); } inline expr operator&(expr const & a, int b) { return a & a.ctx().num_val(b, a.get_sort()); } inline expr operator&(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) & b; } - inline expr operator^(expr const & a, expr const & b) { check_context(a, b); Z3_ast r = a.is_bool() ? Z3_mk_xor(a.ctx(), a, b) : Z3_mk_bvxor(a.ctx(), a, b); return expr(a.ctx(), r); } + inline expr operator^(expr const & a, expr const & b) { check_context(a, b); Z3_ast r = a.is_bool() ? Z3_mk_xor(a.ctx(), a, b) : Z3_mk_bvxor(a.ctx(), a, b); a.check_error(); return expr(a.ctx(), r); } inline expr operator^(expr const & a, int b) { return a ^ a.ctx().num_val(b, a.get_sort()); } inline expr operator^(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) ^ b; } - inline expr operator|(expr const & a, expr const & b) { if (a.is_bool()) return a || b; check_context(a, b); Z3_ast r = Z3_mk_bvor(a.ctx(), a, b); return expr(a.ctx(), r); } + inline expr operator|(expr const & a, expr const & b) { if (a.is_bool()) return a || b; check_context(a, b); Z3_ast r = Z3_mk_bvor(a.ctx(), a, b); a.check_error(); return expr(a.ctx(), r); } inline expr operator|(expr const & a, int b) { return a | a.ctx().num_val(b, a.get_sort()); } inline expr operator|(int a, expr const & b) { return b.ctx().num_val(a, b.get_sort()) | b; } - inline expr nand(expr const& a, expr const& b) { if (a.is_bool()) return !(a && b); check_context(a, b); Z3_ast r = Z3_mk_bvnand(a.ctx(), a, b); return expr(a.ctx(), r); } - inline expr nor(expr const& a, expr const& b) { if (a.is_bool()) return !(a || b); check_context(a, b); Z3_ast r = Z3_mk_bvnor(a.ctx(), a, b); return expr(a.ctx(), r); } - inline expr xnor(expr const& a, expr const& b) { if (a.is_bool()) return !(a ^ b); check_context(a, b); Z3_ast r = Z3_mk_bvxnor(a.ctx(), a, b); return expr(a.ctx(), r); } + inline expr nand(expr const& a, expr const& b) { if (a.is_bool()) return !(a && b); check_context(a, b); Z3_ast r = Z3_mk_bvnand(a.ctx(), a, b); a.check_error(); return expr(a.ctx(), r); } + inline expr nor(expr const& a, expr const& b) { if (a.is_bool()) return !(a || b); check_context(a, b); Z3_ast r = Z3_mk_bvnor(a.ctx(), a, b); a.check_error(); return expr(a.ctx(), r); } + inline expr xnor(expr const& a, expr const& b) { if (a.is_bool()) return !(a ^ b); check_context(a, b); Z3_ast r = Z3_mk_bvxnor(a.ctx(), a, b); a.check_error(); return expr(a.ctx(), r); } inline expr min(expr const& a, expr const& b) { check_context(a, b); Z3_ast r; @@ -1947,6 +1947,7 @@ namespace z3 { assert(a.is_fpa()); r = Z3_mk_fpa_min(a.ctx(), a, b); } + a.check_error(); return expr(a.ctx(), r); } inline expr max(expr const& a, expr const& b) { @@ -1962,6 +1963,7 @@ namespace z3 { assert(a.is_fpa()); r = Z3_mk_fpa_max(a.ctx(), a, b); } + a.check_error(); return expr(a.ctx(), r); } inline expr bvredor(expr const & a) { From d47dd159d7019c103e5a78d9ec1c291919418c9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Dec 2022 09:43:29 -0800 Subject: [PATCH 419/477] set encoding into gparams because this is the only entry point in zstring #6490 --- src/params/context_params.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/params/context_params.cpp b/src/params/context_params.cpp index 294c5cbbe..fbdd90b8c 100644 --- a/src/params/context_params.cpp +++ b/src/params/context_params.cpp @@ -109,6 +109,7 @@ void context_params::set(char const * param, char const * value) { else if (p == "encoding") { if (strcmp(value, "unicode") == 0 || strcmp(value, "bmp") == 0 || strcmp(value, "ascii") == 0) { m_encoding = value; + gparams::set("encoding", value); } else { std::stringstream strm; From aed3d76a886ea1ef0a7c2db9504df893e388e591 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Dec 2022 16:45:58 -0800 Subject: [PATCH 420/477] add doc Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/lia2card_tactic.h | 34 +++++++++-- src/tactic/arith/nla2bv_tactic.h | 24 +++++++- src/tactic/arith/normalize_bounds_tactic.h | 31 ++++++++--- src/tactic/arith/recover_01_tactic.h | 65 +++++++++++++++------- 4 files changed, 121 insertions(+), 33 deletions(-) diff --git a/src/tactic/arith/lia2card_tactic.h b/src/tactic/arith/lia2card_tactic.h index ff076aa42..5186b419b 100644 --- a/src/tactic/arith/lia2card_tactic.h +++ b/src/tactic/arith/lia2card_tactic.h @@ -5,16 +5,38 @@ Module Name: lia2card_tactic.h -Abstract: - - Extract 0-1 integer variables used in - cardinality constraints and replace them by Booleans. - Author: Nikolaj Bjorner (nbjorner) 2013-11-5 -Notes: +Tactic Documentation: + +## Tactic lia2card + +### Short Description + +Extract 0-1 integer variables used in +cardinality and pseudo-Boolean constraints and replace them by Booleans. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(assert (<= 0 x)) +(assert (<= 0 y)) +(assert (<= 0 z)) +(assert (>= 1 x)) +(assert (>= 1 y)) +(assert (>= 1 z)) +(assert (>= (+ (* 5 x) (* -2 z) (* 3 y) 1) 4)) +(apply lia2card) +``` + +### Notes + +* The tactic does not (properly) support proofs or cores. --*/ #pragma once diff --git a/src/tactic/arith/nla2bv_tactic.h b/src/tactic/arith/nla2bv_tactic.h index 80a60b30f..d1acc861a 100644 --- a/src/tactic/arith/nla2bv_tactic.h +++ b/src/tactic/arith/nla2bv_tactic.h @@ -7,7 +7,6 @@ Module Name: Abstract: - Convert quantified NIA problems to bounded bit-vector arithmetic problems. Author: @@ -16,6 +15,29 @@ Author: Notes: Ported to tactic framework on 2012-02-28 +Tactic Documentation: + +## Tactic nla2bv + +### Short Description + +Convert quantified NIA problems to bounded bit-vector arithmetic problems. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(assert (= (* x x y) (* 2 z y y))) +(apply nla2bv) +``` + +### Notes + +* The tactic creates an under-approximation (a stronger set of formulas) + + --*/ #pragma once diff --git a/src/tactic/arith/normalize_bounds_tactic.h b/src/tactic/arith/normalize_bounds_tactic.h index dec4d486e..4d456c38a 100644 --- a/src/tactic/arith/normalize_bounds_tactic.h +++ b/src/tactic/arith/normalize_bounds_tactic.h @@ -5,17 +5,34 @@ Module Name: normalize_bounds_tactic.h -Abstract: - - Replace x with x' + l, when l <= x - where x' is a fresh variable. - Note that, after the transformation 0 <= x'. - Author: Leonardo de Moura (leonardo) 2011-10-21. -Revision History: +Tactic Documentation: + +## Tactic normalize-bounds + +### Short Description + +Replace $x$ with $x' + l$, when $l \leq x$ +where $x'$ is a fresh variable. +Note that, after the transformation $0 \leq x'$. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(assert (<= 3 x)) +(assert (<= (+ x y) z)) +(apply normalize-bounds) +``` + +### Notes + +* supports proofs and cores --*/ #pragma once diff --git a/src/tactic/arith/recover_01_tactic.h b/src/tactic/arith/recover_01_tactic.h index 4e16dbf4a..cd7e47ea0 100644 --- a/src/tactic/arith/recover_01_tactic.h +++ b/src/tactic/arith/recover_01_tactic.h @@ -5,29 +5,56 @@ Module Name: recover_01_tactic.h -Abstract: - - Recover 01 variables - - Search for clauses of the form - p or q or x = 0 - ~p or q or x = k1 - p or ~q or x = k2 - ~p or ~q or x = k1+k2 - - Then, replaces - x with k1*y1 + k2*y2 - p with y1=1 - q with y2=1 - where y1 and y2 are fresh 01 variables - - The clauses are also removed. - Author: Leonardo de Moura (leonardo) 2012-02-17. -Revision History: +Tactic Documentation: + +## Tactic recover-01 + +### Short Description + +Recover 01 variables from propositional constants. + +### Long Description + +Search for clauses of the form + +``` + p or q or x = 0 + ~p or q or x = k1 + p or ~q or x = k2 + ~p or ~q or x = k1+k2 +``` + +Then, replaces + + +* `x` with `k1*y1 + k2*y2` +* `p` with `y1 = 1` +* `q` with `y2 = 1` + +where `y1` and `y2` are fresh 01 variables. + +The clauses are also removed. + +### Example + +```z3 +(declare-const p Bool) +(declare-const q Bool) +(declare-const x Int) +(assert (or p q (= x 0))) +(assert (or (not p) q (= x 3))) +(assert (or p (not q) (= x 6))) +(assert (or (not p) (not q) (= x 9))) +(apply recover-01) +``` + +### Notes + +* does not support proofs, does not support cores --*/ #pragma once From d5316e017e9c0c9f44e4aa2453f908fde7ff4324 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Dec 2022 20:38:28 -0800 Subject: [PATCH 421/477] add tactic descriptions --- src/muz/spacer/spacer_sym_mux.cpp | 4 +- src/tactic/arith/pb2bv_tactic.h | 27 ++++++++++- src/tactic/arith/propagate_ineqs_tactic.h | 57 +++++++++++++++-------- src/tactic/arith/purify_arith_tactic.h | 23 ++++++++- 4 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp index cfe0908d6..451a2b3dc 100644 --- a/src/muz/spacer/spacer_sym_mux.cpp +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -144,10 +144,12 @@ public: bool get_subst(expr * s, expr * & t, proof * & t_pr) { - if (!is_app(s)) { return false; } + if (!is_app(s)) + return false; app * a = to_app(s); func_decl * sym = a->get_decl(); if (!m_parent.has_index(sym, m_from_idx)) { + CTRACE("spacer", m_homogenous && m_parent.is_muxed(sym), tout << "not found " << mk_pp(a, m) << "\n"); SASSERT(!m_homogenous || !m_parent.is_muxed(sym)); return false; } diff --git a/src/tactic/arith/pb2bv_tactic.h b/src/tactic/arith/pb2bv_tactic.h index e23c54d83..b1c94a6ba 100644 --- a/src/tactic/arith/pb2bv_tactic.h +++ b/src/tactic/arith/pb2bv_tactic.h @@ -13,7 +13,32 @@ Author: Christoph (cwinter) 2012-02-15 -Notes: +Tactic Documentation: + +## Tactic pb2bv + +### Short Description + +Convert pseudo-boolean constraints to bit-vectors + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(declare-const u Int) +(assert (<= 0 x)) +(assert (<= 0 y)) +(assert (<= 0 z)) +(assert (<= 0 u)) +(assert (<= x 1)) +(assert (<= y 1)) +(assert (<= z 1)) +(assert (<= u 1)) +(assert (>= (+ (* 3 x) (* 2 y) (* 2 z) (* 2 u)) 4)) +(apply pb2bv) +``` --*/ #pragma once diff --git a/src/tactic/arith/propagate_ineqs_tactic.h b/src/tactic/arith/propagate_ineqs_tactic.h index 47806a341..6341bf281 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.h +++ b/src/tactic/arith/propagate_ineqs_tactic.h @@ -4,30 +4,49 @@ Copyright (c) 2012 Microsoft Corporation Module Name: propagate_ineqs_tactic.h - -Abstract: - - This tactic performs the following tasks: - - - Propagate bounds using the bound_propagator. - - Eliminate subsumed inequalities. - For example: - x - y >= 3 - can be replaced with true if we know that - x >= 3 and y <= 0 - - - Convert inequalities of the form p <= k and p >= k into p = k, - where p is a polynomial and k is a constant. - - This strategy assumes the input is in arith LHS mode. - This can be achieved by using option :arith-lhs true in the - simplifier. Author: Leonardo (leonardo) 2012-02-19 -Notes: +Tactic Documentation: + +## Tactic propagate-ineqs + +### Short Description + +Propagate ineqs/bounds, remove subsumed inequalities + +### Long Description + +This tactic performs the following tasks: + +- Propagate bounds using the bound_propagator. +- Eliminate subsumed inequalities. + - For example: + `x - y >= 3` can be replaced with true if we know that `x >= 3` and `y <= 0` + + - Convert inequalities of the form `p <= k` and `p >= k` into `p = k`, + where `p` is a polynomial and `k` is a constant. + +This strategy assumes the input is in arith LHS mode. +This can be achieved by using option :arith-lhs true in the simplifier. + +### Example +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(declare-const u Int) +(declare-const v Int) +(declare-const w Int) +(assert (>= x 3)) +(assert (<= y 0)) +(assert (>= (- x y) 3)) +(assert (>= (* u v w) 2)) +(assert (<= (* v u w) 2)) +(apply (and-then simplify propagate-ineqs)) +``` --*/ #pragma once diff --git a/src/tactic/arith/purify_arith_tactic.h b/src/tactic/arith/purify_arith_tactic.h index ef5f08b61..4f3aa847a 100644 --- a/src/tactic/arith/purify_arith_tactic.h +++ b/src/tactic/arith/purify_arith_tactic.h @@ -42,7 +42,28 @@ Author: Leonardo de Moura (leonardo) 2011-12-30. -Revision History: +Tactic Documentation: + +## Tactic purify-arith + +### Short Description + +Eliminate unnecessary operators: -, /, div, mod, rem, is-int, to-int, ^, root-objects. +These operators can be replaced by introcing fresh variables and using multiplication and addition. + +### Example +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(declare-const u Int) +(declare-const v Int) +(declare-const w Int) +(assert (= (div x 3) y)) +(assert (= (mod z 4) u)) +(assert (> (mod v w) u)) +(apply purify-arith) +``` --*/ #pragma once From 13920c4772683d179932507230755a7a19dc8b24 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Dec 2022 11:42:02 -0800 Subject: [PATCH 422/477] more doc Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/nla2bv_tactic.cpp | 6 ++-- src/tactic/arith/normalize_bounds_tactic.cpp | 2 +- src/tactic/arith/purify_arith_tactic.cpp | 6 ++-- src/tactic/arith/recover_01_tactic.cpp | 2 +- src/tactic/bv/bit_blaster_tactic.cpp | 8 +++--- src/tactic/bv/bit_blaster_tactic.h | 30 ++++++++++++++------ 6 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index bdcf57953..cd37db402 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -442,9 +442,9 @@ public: void collect_param_descrs(param_descrs & r) override { r.insert("nla2bv_max_bv_size", CPK_UINT, "(default: inf) maximum bit-vector size used by nla2bv tactic"); - r.insert("nla2bv_bv_size", CPK_UINT, "(default: 4) default bit-vector size used by nla2bv tactic."); - r.insert("nla2bv_root", CPK_UINT, "(default: 2) nla2bv tactic encodes reals into bit-vectors using expressions of the form a+b*sqrt(c), this parameter sets the value of c used in the encoding."); - r.insert("nla2bv_divisor", CPK_UINT, "(default: 2) nla2bv tactic parameter."); + r.insert("nla2bv_bv_size", CPK_UINT, "default bit-vector size used by nla2bv tactic.", "4"); + r.insert("nla2bv_root", CPK_UINT, "nla2bv tactic encodes reals into bit-vectors using expressions of the form a+b*sqrt(c), this parameter sets the value of c used in the encoding.", "2"); + r.insert("nla2bv_divisor", CPK_UINT, "nla2bv tactic parameter.", "2"); } /** diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index cba791ee1..b20eaf53a 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -161,7 +161,7 @@ public: void collect_param_descrs(param_descrs & r) override { insert_produce_models(r); - r.insert("norm_int_only", CPK_BOOL, "(default: true) normalize only the bounds of integer constants."); + r.insert("norm_int_only", CPK_BOOL, "normalize only the bounds of integer constants.", "true"); } void operator()(goal_ref const & in, diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 7c69ef12e..db1986398 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -911,11 +911,11 @@ public: void collect_param_descrs(param_descrs & r) override { r.insert("complete", CPK_BOOL, - "(default: true) add constraints to make sure that any interpretation of a underspecified arithmetic operators is a function. The result will include additional uninterpreted functions/constants: /0, div0, mod0, 0^0, neg-root"); + "add constraints to make sure that any interpretation of a underspecified arithmetic operators is a function. The result will include additional uninterpreted functions/constants: /0, div0, mod0, 0^0, neg-root", "true"); r.insert("elim_root_objects", CPK_BOOL, - "(default: true) eliminate root objects."); + "eliminate root objects.", "true"); r.insert("elim_inverses", CPK_BOOL, - "(default: true) eliminate inverse trigonometric functions (asin, acos, atan)."); + "eliminate inverse trigonometric functions (asin, acos, atan).", "true"); th_rewriter::get_param_descrs(r); } diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index d97f9b80f..623f82cf9 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -407,7 +407,7 @@ public: void collect_param_descrs(param_descrs & r) override { th_rewriter::get_param_descrs(r); - r.insert("recover_01_max_bits", CPK_UINT, "(default: 10) maximum number of bits to consider in a clause."); + r.insert("recover_01_max_bits", CPK_UINT, "maximum number of bits to consider in a clause.", "10"); } void operator()(goal_ref const & g, diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 978a0a9a6..5e35d7d9a 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -129,10 +129,10 @@ public: void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); - r.insert("blast_mul", CPK_BOOL, "(default: true) bit-blast multipliers (and dividers, remainders)."); - r.insert("blast_add", CPK_BOOL, "(default: true) bit-blast adders."); - r.insert("blast_quant", CPK_BOOL, "(default: false) bit-blast quantified variables."); - r.insert("blast_full", CPK_BOOL, "(default: false) bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms."); + r.insert("blast_mul", CPK_BOOL, "bit-blast multipliers (and dividers, remainders).", "true"); + r.insert("blast_add", CPK_BOOL, "bit-blast adders.", "true"); + r.insert("blast_quant", CPK_BOOL, "bit-blast quantified variables.", "false"); + r.insert("blast_full", CPK_BOOL, "bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms.", "false"); } void operator()(goal_ref const & g, diff --git a/src/tactic/bv/bit_blaster_tactic.h b/src/tactic/bv/bit_blaster_tactic.h index e90a675aa..07d85d9c6 100644 --- a/src/tactic/bv/bit_blaster_tactic.h +++ b/src/tactic/bv/bit_blaster_tactic.h @@ -1,21 +1,33 @@ /*++ Copyright (c) 2011 Microsoft Corporation - Module Name: +Module Name: bit_blaster_tactic.h - Abstract: +Author: - Apply bit-blasting to a given goal. - - Author: - - Leonardo (leonardo) 2011-10-25 - - Notes: + Leonardo (leonardo) 2011-10-25 +Tactic Documentation: + +## Tactic bit-blast + +### Short Description + +Apply bit-blasting to a given goal. + +### Example + +```z3 +(declare-const x (_ BitVec 8)) +(declare-const y (_ BitVec 8)) +(assert (bvule x y)) +(apply bit-blast) +``` + --*/ + #pragma once #include "util/params.h" From ecf25a4fe267cc7151a0f42ae0c7bbd8b6664b4b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Dec 2022 14:57:52 -0800 Subject: [PATCH 423/477] outline scheme Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/solve_eqs.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/ast/simplifiers/solve_eqs.cpp b/src/ast/simplifiers/solve_eqs.cpp index 1117ad0bc..ad58239c3 100644 --- a/src/ast/simplifiers/solve_eqs.cpp +++ b/src/ast/simplifiers/solve_eqs.cpp @@ -13,6 +13,24 @@ Author: Nikolaj Bjorner (nbjorner) 2022-11-2. +Notes: + +extract_subst is inefficient. +It traverses the same sub-terms many times. + +Outline of a presumably better scheme: + +1. maintain map FV: term -> bit-set where bitset reprsents set of free variables. Assume the number of variables is bounded. + FV is built from initial terms. +2. maintain parent: term -> term-list of parent occurrences. +3. repeat + pick x = t, such that x not in FV(t) + orient x -> t + for p in parent*(x): + FV(p) := FV(p) u FV(t) + if y = s is processed and x in FV(s) order y < x + if y = s is processed and x in FV(t) order x < y + --*/ From 0768a2ead15d162e0e39c5791441cd16ccd73dd0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Dec 2022 19:23:32 -0800 Subject: [PATCH 424/477] updated doc --- src/tactic/bv/bv1_blaster_tactic.h | 38 +++++++++++++++------- src/tactic/bv/bv_bound_chk_tactic.cpp | 1 - src/tactic/bv/bv_bound_chk_tactic.h | 14 ++++---- src/tactic/bv/bv_size_reduction_tactic.h | 41 ++++++++++++++++++++---- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/tactic/bv/bv1_blaster_tactic.h b/src/tactic/bv/bv1_blaster_tactic.h index c150778fd..9cc7f90d5 100644 --- a/src/tactic/bv/bv1_blaster_tactic.h +++ b/src/tactic/bv/bv1_blaster_tactic.h @@ -5,21 +5,37 @@ Module Name: bv1_blaster_tactic.h -Abstract: - - Rewriter for "blasting" bit-vectors of size n into bit-vectors of size 1. - This rewriter only supports concat and extract operators. - This transformation is useful for handling benchmarks that contain - many BV equalities. - - Remark: other operators can be mapped into concat/extract by using - the simplifiers. - Author: Leonardo (leonardo) 2011-10-25 -Notes: +Tactic Documentation: + +## Tactic bv1-blast + +### Short Description + +Reduce bit-vector expressions into bit-vectors of size 1 (notes: only equality, extract and concat are supported). + +### Long Description + +Rewriter for "blasting" bit-vectors of size n into bit-vectors of size 1. +This rewriter only supports concat and extract operators. +This transformation is useful for handling benchmarks that contain +many BV equalities. + +_Remark_: other operators can be mapped into concat/extract by using +the simplifiers. + +### Example + +```z3 +(declare-const x (_ BitVec 8)) +(declare-const y (_ BitVec 4)) +(declare-const z (_ BitVec 4)) +(assert (= (concat y z) x)) + (apply bv1-blast) +``` --*/ #pragma once diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 3a2f85831..f6db3c30e 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -48,7 +48,6 @@ struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { m_bv_ineq_consistency_test_max = p.bv_ineq_consistency_test_max(); m_max_memory = p.max_memory(); m_max_steps = p.max_steps(); - } ast_manager & m() const { return m_m; } diff --git a/src/tactic/bv/bv_bound_chk_tactic.h b/src/tactic/bv/bv_bound_chk_tactic.h index 60411e693..bafd2ec51 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.h +++ b/src/tactic/bv/bv_bound_chk_tactic.h @@ -1,18 +1,18 @@ /*++ - Copyright (c) 2016 Microsoft Corporation +Copyright (c) 2016 Microsoft Corporation - Module Name: +Module Name: - bv_bound_chk_tactic.h + bv_bound_chk_tactic.h - Abstract: +Author: + Mikolas Janota - Author: +### Notes - Mikolas Janota +* does not support proofs, does not support cores - Revision History: --*/ #pragma once diff --git a/src/tactic/bv/bv_size_reduction_tactic.h b/src/tactic/bv/bv_size_reduction_tactic.h index 1bb512f3f..a55c66e73 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.h +++ b/src/tactic/bv/bv_size_reduction_tactic.h @@ -7,12 +7,6 @@ Module Name: Abstract: - Reduce the number of bits used to encode constants, by using signed bounds. - Example: suppose x is a bit-vector of size 8, and we have - signed bounds for x such that: - -2 <= x <= 2 - Then, x can be replaced by ((sign-extend 5) k) - where k is a fresh bit-vector constant of size 3. Author: @@ -20,6 +14,41 @@ Author: Notes: +Tactic Documentation: + +## Tactic reduce-bv-size + +### Short Description + +Rry to reduce bit-vector sizes using inequalities. + +### Long Description + +Reduce the number of bits used to encode constants, by using signed bounds. +Example: suppose $x$ is a bit-vector of size 8, and we have +signed bounds for $x$ such that: + +``` + -2 <= x <= 2 +``` + +Then, $x$ can be replaced by `((sign-extend 5) k)` +where `k` is a fresh bit-vector constant of size 3. + +### Example + +```z3 +(declare-const x (_ BitVec 32)) +(assert (bvsle (bvneg (_ bv2 32)) x)) +(assert (bvsle x (_ bv2 32))) +(assert (= (bvmul x x) (_ bv9 32))) +(apply (and-then simplify reduce-bv-size)) +``` + +### Notes + +* does not support proofs, nor unsat cores + --*/ #pragma once From e423fabf6a8808c36d906cdd62dda9c90773992d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Dec 2022 20:35:36 -0800 Subject: [PATCH 425/477] tactic Signed-off-by: Nikolaj Bjorner --- doc/mk_tactic_doc.py | 10 +- src/tactic/bv/bv_bounds_tactic.cpp | 165 +++++++++++--------------- src/tactic/bv/bv_bounds_tactic.h | 27 ++++- src/tactic/bv/bvarray2uf_tactic.h | 26 ++-- src/tactic/bv/dt2bv_tactic.h | 23 +++- src/tactic/bv/elim_small_bv_tactic.h | 16 +++ src/tactic/bv/max_bv_sharing_tactic.h | 20 +++- 7 files changed, 170 insertions(+), 117 deletions(-) diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index e4c71341a..6f4837cdd 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -53,13 +53,21 @@ def extract_tactic_doc(ous, f): if is_doc.search(line): generate_tactic_doc(ous, f, ins) +def find_tactic_name(path): + with open(path) as ins: + for line in ins: + m = is_tac_name.search(line) + if m: + return m.group(1) + return "" + def presort_files(): tac_files = [] for root, dirs, files in os.walk(doc_path("../src")): for f in files: if f.endswith("tactic.h"): tac_files += [(f, os.path.join(root, f))] - tac_files = sorted(tac_files, key = lambda x: x[0]) + tac_files = sorted(tac_files, key = lambda x: find_tactic_name(x[1])) return tac_files def help(ous): diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 72f0266c1..58183287d 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -35,11 +35,12 @@ namespace { struct interval { // l < h: [l, h] // l > h: [0, h] U [l, UMAX_INT] - uint64_t l, h; - unsigned sz; - bool tight; + uint64_t l = 0, h = 0; + unsigned sz = 0; + bool tight = true; interval() {} + interval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { // canonicalize full set if (is_wrapped() && l == h + 1) { @@ -50,8 +51,7 @@ namespace { } bool invariant() const { - return l <= uMaxInt(sz) && h <= uMaxInt(sz) && - (!is_wrapped() || l != h+1); + return l <= uMaxInt(sz) && h <= uMaxInt(sz) && (!is_wrapped() || l != h+1); } bool is_full() const { return l == 0 && h == uMaxInt(sz); } @@ -67,22 +67,17 @@ namespace { bool implies(const interval& b) const { if (b.is_full()) return true; - if (is_full()) + else if (is_full()) return false; - - if (is_wrapped()) { + else if (is_wrapped()) // l >= b.l >= b.h >= h - return b.is_wrapped() && h <= b.h && l >= b.l; - } - else if (b.is_wrapped()) { + return b.is_wrapped() && h <= b.h && l >= b.l; + else if (b.is_wrapped()) // b.l > b.h >= h >= l // h >= l >= b.l > b.h - return h <= b.h || l >= b.l; - } - else { - // - return l >= b.l && h <= b.h; - } + return h <= b.h || l >= b.l; + else + return l >= b.l && h <= b.h; } /// return false if intersection is unsat @@ -98,28 +93,26 @@ namespace { if (is_wrapped()) { if (b.is_wrapped()) { - if (h >= b.l) { + if (h >= b.l) result = b; - } else if (b.h >= l) { + else if (b.h >= l) result = *this; - } else { + else result = interval(std::max(l, b.l), std::min(h, b.h), sz); - } - } else { - return b.intersect(*this, result); } + else + return b.intersect(*this, result); } else if (b.is_wrapped()) { // ... b.h ... l ... h ... b.l .. - if (h < b.l && l > b.h) { - return false; - } + if (h < b.l && l > b.h) + return false; // ... l ... b.l ... h ... - if (h >= b.l && l <= b.h) { + if (h >= b.l && l <= b.h) result = b; - } else if (h >= b.l) { + else if (h >= b.l) result = interval(b.l, h, sz); - } else { + else { // ... l .. b.h .. h .. b.l ... SASSERT(l <= b.h); result = interval(l, std::min(h, b.h), sz); @@ -136,20 +129,16 @@ namespace { /// return false if negation is empty bool negate(interval& result) const { - if (!tight) { + if (!tight) result = interval(0, uMaxInt(sz), true); - return true; - } - - if (is_full()) + else if (is_full()) return false; - if (l == 0) { + else if (l == 0) result = interval(h + 1, uMaxInt(sz), sz); - } else if (uMaxInt(sz) == h) { + else if (uMaxInt(sz) == h) result = interval(0, l - 1, sz); - } else { - result = interval(h + 1, l - 1, sz); - } + else + result = interval(h + 1, l - 1, sz); return true; } }; @@ -163,9 +152,9 @@ namespace { struct undo_bound { - expr* e { nullptr }; + expr* e = nullptr; interval b; - bool fresh { false }; + bool fresh = false; undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} }; @@ -176,7 +165,7 @@ namespace { ast_manager& m; params_ref m_params; - bool m_propagate_eq; + bool m_propagate_eq = false; bv_util m_bv; vector m_scopes; map m_bound; @@ -224,7 +213,8 @@ namespace { v = lhs; return true; } - } else if (m.is_eq(e, lhs, rhs)) { + } + else if (m.is_eq(e, lhs, rhs)) { if (is_number(lhs, n, sz)) { if (m_bv.is_numeral(rhs)) return false; @@ -252,7 +242,7 @@ namespace { } static void get_param_descrs(param_descrs& r) { - r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); + r.insert("propagate-eq", CPK_BOOL, "propagate equalities from inequalities", "false"); } ~bv_bounds_simplifier() override { @@ -546,22 +536,19 @@ namespace { } static void get_param_descrs(param_descrs& r) { - r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); + r.insert("propagate-eq", CPK_BOOL, "propagate equalities from inequalities", "false"); } ~dom_bv_bounds_simplifier() override { - for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { - dealloc(m_expr_vars[i]); - } - for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { - dealloc(m_bound_exprs[i]); - } + for (auto* e : m_expr_vars) + dealloc(e); + for (auto* b : m_bound_exprs) + dealloc(b); } bool assert_expr(expr * t, bool sign) override { - while (m.is_not(t, t)) { - sign = !sign; - } + while (m.is_not(t, t)) + sign = !sign; interval b; expr* t1; @@ -581,7 +568,8 @@ namespace { return true; m_scopes.push_back(undo_bound(t1, old, false)); old = intr; - } else { + } + else { m_bound.insert(t1, b); m_scopes.push_back(undo_bound(t1, interval(), true)); } @@ -602,9 +590,8 @@ namespace { return; bool sign = false; - while (m.is_not(t, t)) { - sign = !sign; - } + while (m.is_not(t, t)) + sign = !sign; if (!is_bound(t, t1, b)) return; @@ -619,27 +606,21 @@ namespace { interval ctx, intr; bool was_updated = true; - if (b.is_full() && b.tight) { - r = m.mk_true(); - } + if (b.is_full() && b.tight) + r = m.mk_true(); else if (m_bound.find(t1, ctx)) { - if (ctx.implies(b)) { - r = m.mk_true(); - } - else if (!b.intersect(ctx, intr)) { - r = m.mk_false(); - } - else if (m_propagate_eq && intr.is_singleton()) { + if (ctx.implies(b)) + r = m.mk_true(); + else if (!b.intersect(ctx, intr)) + r = m.mk_false(); + else if (m_propagate_eq && intr.is_singleton()) r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), - t1->get_sort())); - } - else { - was_updated = false; - } - } - else { - was_updated = false; + t1->get_sort())); + else + was_updated = false; } + else + was_updated = false; TRACE("bv", tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); if (sign && was_updated) @@ -654,18 +635,16 @@ namespace { while (!todo.empty()) { t = todo.back(); todo.pop_back(); - if (mark.is_marked(t)) { - continue; - } + if (mark.is_marked(t)) + continue; if (t == v) { todo.reset(); return true; } mark.mark(t); - if (!is_app(t)) { - continue; - } + if (!is_app(t)) + continue; app* a = to_app(t); todo.append(a->get_num_args(), a->get_args()); } @@ -680,14 +659,11 @@ namespace { while (!todo.empty()) { t = todo.back(); todo.pop_back(); - if (mark1.is_marked(t)) { - continue; - } - mark1.mark(t); - - if (!is_app(t)) { - continue; - } + if (mark1.is_marked(t)) + continue; + mark1.mark(t); + if (!is_app(t)) + continue; interval b; expr* e; if (is_bound(t, e, b)) { @@ -718,14 +694,13 @@ namespace { m_scopes.reset(); return; } - for (unsigned i = m_scopes.size()-1; i >= target; --i) { + for (unsigned i = m_scopes.size(); i-- > target; ) { undo_bound& undo = m_scopes[i]; SASSERT(m_bound.contains(undo.e)); - if (undo.fresh) { + if (undo.fresh) m_bound.erase(undo.e); - } else { - m_bound.insert(undo.e, undo.b); - } + else + m_bound.insert(undo.e, undo.b); } m_scopes.shrink(target); } diff --git a/src/tactic/bv/bv_bounds_tactic.h b/src/tactic/bv/bv_bounds_tactic.h index 58de42199..325cca89e 100644 --- a/src/tactic/bv/bv_bounds_tactic.h +++ b/src/tactic/bv/bv_bounds_tactic.h @@ -5,15 +5,34 @@ Module Name: bv_bounds_tactic.h -Abstract: - - Contextual bounds simplification tactic. - Author: Nuno Lopes (nlopes) 2016-2-12 Nikolaj Bjorner (nbjorner) +Tactic Documentation: + +## Tactic propagate-bv-bounds + +### Short Description + +Contextual bounds simplification tactic. + +### Example + +```z3 +(declare-const x (_ BitVec 32)) +(declare-const y (_ BitVec 32)) +(declare-const z (_ BitVec 32)) +(assert (bvule (_ bv4 32) x)) +(assert (bvule x (_ bv24 32))) +(assert (or (bvule x (_ bv100 32)) (bvule (_ bv32 32) x))) +(apply propagate-bv-bounds) +``` + +### Notes + +* assumes that bit-vector inequalities have been simplified to use bvule/bvsle --*/ #pragma once diff --git a/src/tactic/bv/bvarray2uf_tactic.h b/src/tactic/bv/bvarray2uf_tactic.h index a22a78f86..393ab164c 100644 --- a/src/tactic/bv/bvarray2uf_tactic.h +++ b/src/tactic/bv/bvarray2uf_tactic.h @@ -3,18 +3,30 @@ Copyright (c) 2015 Microsoft Corporation Module Name: - bvarray2ufbvarray2uf_tactic.h - -Abstract: - - Tactic that rewrites bit-vector arrays into bit-vector - (uninterpreted) functions. + bvarray2uf_tactic.h Author: Christoph (cwinter) 2015-11-04 -Notes: +Tactic Documentation: + +## Tactic bvarray2uf + +### Short Description + +Tactic that rewrites bit-vector arrays into bit-vector +(uninterpreted) functions. + +### Example + +```z3 +(declare-const a (Array (_ BitVec 32) (_ BitVec 32))) +(declare-const b (_ BitVec 32)) +(declare-const c (_ BitVec 32)) +(assert (= (select a b) c)) +(apply bvarray2uf) +``` --*/ #pragma once diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index 906386ed4..05713dfd6 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -5,15 +5,28 @@ Module Name: dt2bv_tactic.h -Abstract: - - Tactic that eliminates finite domain data-types. - Author: nbjorner 2016-07-22 -Revision History: +Tactic Documentation + +## Tactic dt2bv + +### Short Description + +Tactic that eliminates finite domain data-types. + +### Example + +```z3 +(declare-datatypes ((Color 0)) (((Red) (Blue) (Green) (DarkBlue) (MetallicBlack) (MetallicSilver) (Silver) (Black)))) +(declare-const x Color) +(declare-const y Color) +(assert (not (= x y))) +(assert (not (= x Red))) +(apply dt2bv) +``` --*/ #pragma once diff --git a/src/tactic/bv/elim_small_bv_tactic.h b/src/tactic/bv/elim_small_bv_tactic.h index e4a91f70f..46e6dca39 100644 --- a/src/tactic/bv/elim_small_bv_tactic.h +++ b/src/tactic/bv/elim_small_bv_tactic.h @@ -15,6 +15,22 @@ Author: Revision History: +Tactic Documentation + +## Tactic elim-small-bv + +### Short Description + +Eliminate small, quantified bit-vectors by expansion + +### Example + +```z3 +(declare-fun p ((_ BitVec 2)) Bool) +(assert (forall ((x (_ BitVec 2))) (p x))) +(apply elim-small-bv) +``` + --*/ #pragma once diff --git a/src/tactic/bv/max_bv_sharing_tactic.h b/src/tactic/bv/max_bv_sharing_tactic.h index bf14e9f14..2f21ee4b9 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.h +++ b/src/tactic/bv/max_bv_sharing_tactic.h @@ -7,16 +7,26 @@ Module Name: Abstract: - Rewriter for "maximing" the number of shared terms. - The idea is to rewrite AC terms to maximize sharing. - This rewriter is particularly useful for reducing - the number of Adders and Multipliers before "bit-blasting". + Author: Leonardo de Moura (leonardo) 2011-12-29. -Revision History: +Tactic Documentation + +## Tactic max-bv-sharing + +### Short Description + +Use heuristics to maximize the sharing of bit-vector expressions such as adders and multipliers + +### Long Description + +Rewriter for "maximing" the number of shared terms. +The idea is to rewrite AC terms to maximize sharing. +This rewriter is particularly useful for reducing +the number of Adders and Multipliers before "bit-blasting". --*/ #pragma once From 603597a22ebdfc90a1cdddf5ed0f41ef89bc00a8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Dec 2022 12:40:39 -0800 Subject: [PATCH 426/477] deal with cancellation in qe for #6500 Signed-off-by: Nikolaj Bjorner --- src/qe/qe.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index d859880d8..f4ebce594 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1437,13 +1437,12 @@ namespace qe { res = m_solver.check(); if (res == l_true && has_uninterpreted(m, m_fml)) res = l_undef; - if (res == l_true) { + if (res == l_true) + res = final_check(); + if (res == l_true) is_sat = true; - final_check(); - } - else { + else break; - } } if (res == l_undef) { free_vars.append(num_vars, vars); @@ -1501,30 +1500,33 @@ namespace qe { private: - void final_check() { - model_ref model; + lbool final_check() { + model_ref model; m_solver.get_model(model); + if (!model) + return l_undef; scoped_ptr model_eval = alloc(model_evaluator, *model); - while (true) { + while (m.inc()) { TRACE("qe", model_v2_pp(tout, *model);); - while (can_propagate_assignment(*model_eval)) { + while (can_propagate_assignment(*model_eval)) propagate_assignment(*model_eval); - } VERIFY(CHOOSE_VAR == update_current(*model_eval, true)); SASSERT(m_current->fml()); if (l_true != m_solver.check()) { - return; + return l_true; } m_solver.get_model(model); model_eval = alloc(model_evaluator, *model); search_tree* st = m_current; update_current(*model_eval, false); - if (st == m_current) { + if (st == m_current) break; - } - } - pop(*model_eval); + } + if (!m.inc()) + return l_undef; + pop(*model_eval); + return l_true; } ast_manager& get_manager() override { return m; } From fe8034731d3f43fa9d0f8ebe5d72d085779752fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Dec 2022 21:02:23 -0800 Subject: [PATCH 427/477] fix #6501 --- src/ast/decl_collector.cpp | 29 +++++++++++++++-------------- src/smt/smt_context.cpp | 4 ++++ src/smt/smt_context.h | 2 ++ src/smt/theory_recfun.cpp | 2 +- src/tactic/core/simplify_tactic.h | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index 5b634abbd..7786a79d4 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -32,9 +32,8 @@ void decl_collector::visit_sort(sort * n) { m_todo.push_back(cnstr); ptr_vector const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr); unsigned num_cas = cnstr_acc.size(); - for (unsigned j = 0; j < num_cas; j++) { - m_todo.push_back(cnstr_acc.get(j)); - } + for (unsigned j = 0; j < num_cas; j++) + m_todo.push_back(cnstr_acc.get(j)); } } for (unsigned i = n->get_num_parameters(); i-- > 0; ) { @@ -49,14 +48,19 @@ bool decl_collector::is_bool(sort * s) { void decl_collector::visit_func(func_decl * n) { func_decl* g; + if (!m_visited.is_marked(n)) { family_id fid = n->get_family_id(); if (fid == null_family_id) m_decls.push_back(n); else if (fid == m_rec_fid) { - m_rec_decls.push_back(n); recfun::util u(m()); - m_todo.push_back(u.get_def(n).get_rhs()); + if (u.has_def(n)) { + m_rec_decls.push_back(n); + m_todo.push_back(u.get_def(n).get_rhs()); + } + else + m_decls.push_back(n); } else if (m_ar_util.is_as_array(n, g)) m_todo.push_back(g); @@ -97,13 +101,11 @@ void decl_collector::visit(ast* n) { case AST_QUANTIFIER: { quantifier * q = to_quantifier(n); unsigned num_decls = q->get_num_decls(); - for (unsigned i = 0; i < num_decls; ++i) { - m_todo.push_back(q->get_decl_sort(i)); - } + for (unsigned i = 0; i < num_decls; ++i) + m_todo.push_back(q->get_decl_sort(i)); m_todo.push_back(q->get_expr()); - for (unsigned i = 0; i < q->get_num_patterns(); ++i) { - m_todo.push_back(q->get_pattern(i)); - } + for (unsigned i = 0; i < q->get_num_patterns(); ++i) + m_todo.push_back(q->get_pattern(i)); break; } case AST_SORT: @@ -111,9 +113,8 @@ void decl_collector::visit(ast* n) { break; case AST_FUNC_DECL: { func_decl * d = to_func_decl(n); - for (sort* srt : *d) { - m_todo.push_back(srt); - } + for (sort* srt : *d) + m_todo.push_back(srt); m_todo.push_back(d->get_range()); visit_func(d); break; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 45c469bde..d1cf2d875 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3027,6 +3027,10 @@ namespace smt { TRACE("end_assert_expr_ll", ast_mark m; m_asserted_formulas.display_ll(tout, m);); } + void context::add_asserted(expr* e) { + m_asserted_formulas.assert_expr(e); + } + void context::assert_expr(expr * e) { assert_expr(e, nullptr); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 2b3a343f7..b6bf04a20 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1618,6 +1618,8 @@ namespace smt { void register_plugin(theory * th); + void add_asserted(expr* e); + void assert_expr(expr * e); void assert_expr(expr * e, proof * pr); diff --git a/src/smt/theory_recfun.cpp b/src/smt/theory_recfun.cpp index 515a51a17..6a8f2ab60 100644 --- a/src/smt/theory_recfun.cpp +++ b/src/smt/theory_recfun.cpp @@ -249,7 +249,7 @@ namespace smt { expr_ref eq1(m.mk_eq(l, r), m); expr_ref fn(m.mk_fresh_const("rec-eq", m.mk_bool_sort()), m); expr_ref eq(m.mk_eq(fn, eq1), m); - ctx.assert_expr(eq); + ctx.add_asserted(eq); ctx.internalize_assertions(); lit = mk_literal(fn); } diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index 39e3e9bde..1594b3d37 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -41,6 +41,23 @@ from two equivalent formulas are guaranteed to be equal. (apply simplify) ``` +The simplifier is also exposed as a stand-alone command. +There are several options to control its behavior. + +```z3 +(declare-const x Int) +(declare-const y Int) +(declare-const z Int) +(declare-const u Int) +(declare-fun p (Int) Bool) +(assert (p (* (+ x y) (+ z u)))) +(apply simplify) +(apply (with simplify :som true)) + +(simplify (* (+ x y) (+ z u)) :som false) +(simplify (* (+ x y) (+ z u)) :som true) +``` + ### Notes * supports unsat cores, proof terms From 8efaaaf24982ce810b8ea85fdf74eedc3dea29ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Dec 2022 17:28:57 -0800 Subject: [PATCH 428/477] Fix #6503 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e829fdafb..ca3486ac5 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1559,13 +1559,15 @@ class BoolRef(ExprRef): def __mul__(self, other): """Create the Z3 expression `self * other`. """ - if other == 1: + if isinstance(other, int) and other == 1: return self - if other == 0: - return 0 + if isinstance(other, int) and other == 0: + return + if isinstance(other, BoolRef): + other = If(other, 1, 0) return If(self, other, 0) - + def is_bool(a): """Return `True` if `a` is a Z3 Boolean expression. From b9c4f5d4fafcace3968eb3a5c5489a4c881628a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Dec 2022 18:33:01 -0800 Subject: [PATCH 429/477] #6506 Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/elim_unconstrained.cpp | 74 ++++++++++++++++++++-- src/ast/simplifiers/elim_unconstrained.h | 4 ++ 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 2e950868a..df6f92251 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -81,20 +81,24 @@ void elim_unconstrained::eliminate() { continue; } app* t = to_app(e); - m_args.reset(); + unsigned sz = m_args.size(); for (expr* arg : *to_app(t)) - m_args.push_back(get_node(arg).m_term); - if (!m_inverter(t->get_decl(), m_args.size(), m_args.data(), r, side_cond)) { + m_args.push_back(reconstruct_term(get_node(arg))); + bool inverted = m_inverter(t->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz, r, side_cond); + n.m_refcount = 0; + m_args.shrink(sz); + if (!inverted) { IF_VERBOSE(11, verbose_stream() << "not inverted " << mk_bounded_pp(e, m) << "\n"); - n.m_refcount = 0; continue; } + + TRACE("elim_unconstrained", tout << mk_pp(t, m) << " -> " << r << "\n"); SASSERT(r->get_sort() == t->get_sort()); m_stats.m_num_eliminated++; - n.m_refcount = 0; m_trail.push_back(r); SASSERT(r); gc(e); + invalidate_parents(e); freeze_rec(r); m_root.setx(r->get_id(), e->get_id(), UINT_MAX); @@ -119,6 +123,26 @@ expr* elim_unconstrained::get_parent(unsigned n) const { return p; return nullptr; } + +void elim_unconstrained::invalidate_parents(expr* e) { + ptr_vector todo; + do { + node& n = get_node(e); + if (!n.m_dirty) { + n.m_dirty = true; + for (expr* e : n.m_parents) + todo.push_back(e); + } + e = nullptr; + if (!todo.empty()) { + e = todo.back(); + todo.pop_back(); + } + } + while (e); +} + + /** * initialize node structure */ @@ -230,6 +254,45 @@ void elim_unconstrained::gc(expr* t) { } } +expr_ref elim_unconstrained::reconstruct_term(node& n0) { + expr* t = n0.m_term; + if (!n0.m_dirty) + return expr_ref(t, m); + ptr_vector todo; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + node& n = get_node(t); + unsigned sz0 = todo.size(); + if (is_app(t)) { + for (expr* arg : *to_app(t)) + if (get_node(arg).m_dirty) + todo.push_back(arg); + if (todo.size() != sz0) + continue; + + unsigned sz = m_args.size(); + for (expr* arg : *to_app(t)) + m_args.push_back(get_node(arg).m_term); + n.m_term = m.mk_app(to_app(t)->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz); + m_args.shrink(sz); + } + else if (is_quantifier(t)) { + expr* body = to_quantifier(t)->get_expr(); + node& n2 = get_node(body); + if (n2.m_dirty) { + todo.push_back(body); + continue; + } + n.m_term = m.update_quantifier(to_quantifier(t), n2.m_term); + } + m_trail.push_back(n.m_term); + todo.pop_back(); + n.m_dirty = false; + } + return expr_ref(n0.m_term, m); +} + /** * walk nodes starting from lowest depth and reconstruct their normalized forms. */ @@ -266,6 +329,7 @@ void elim_unconstrained::reconstruct_terms() { } } + void elim_unconstrained::assert_normalized(vector& old_fmls) { for (unsigned i : indices()) { diff --git a/src/ast/simplifiers/elim_unconstrained.h b/src/ast/simplifiers/elim_unconstrained.h index 68ca30777..aae14bdcb 100644 --- a/src/ast/simplifiers/elim_unconstrained.h +++ b/src/ast/simplifiers/elim_unconstrained.h @@ -26,6 +26,7 @@ class elim_unconstrained : public dependent_expr_simplifier { unsigned m_refcount = 0; expr* m_term = nullptr; expr* m_orig = nullptr; + bool m_dirty = false; ptr_vector m_parents; }; struct var_lt { @@ -66,8 +67,11 @@ class elim_unconstrained : public dependent_expr_simplifier { void init_nodes(); void eliminate(); void reconstruct_terms(); + expr_ref reconstruct_term(node& n); void assert_normalized(vector& old_fmls); void update_model_trail(generic_model_converter& mc, vector const& old_fmls); + void invalidate_parents(expr* e); + public: From 6fab4fec230820c6c73221a3e85164d6faedcfbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Dec 2022 15:36:58 -0800 Subject: [PATCH 430/477] #6508 --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 467f30792..0cd5e119f 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3763,7 +3763,7 @@ extern "C" { If \c s does not contain \c substr, then the value is -1, def_API('Z3_mk_seq_last_index', AST, (_in(CONTEXT), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_seq_last_index(Z3_context c, Z3_ast, Z3_ast substr); + Z3_ast Z3_API Z3_mk_seq_last_index(Z3_context c, Z3_ast s, Z3_ast substr); /** \brief Convert string to integer. From 8d332cc3a17ccdd6cf39490020ea7d7eeedf56a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Dec 2022 15:42:04 -0800 Subject: [PATCH 431/477] #6508 (#6509) --- src/api/z3_api.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0cd5e119f..cdcab36d5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3893,7 +3893,7 @@ extern "C" { def_API('Z3_mk_re_power', AST, (_in(CONTEXT), _in(AST), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast, unsigned n); + Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast re, unsigned n); /** \brief Create the intersection of the regular languages. @@ -5881,7 +5881,7 @@ extern "C" { def_API('Z3_eval_smtlib2_string', STRING, (_in(CONTEXT), _in(STRING),)) */ - Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context, Z3_string str); + Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context c Z3_string str); /** @@ -7029,7 +7029,7 @@ extern "C" { def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST))) */ - void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq); + void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback cb, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq); /** \brief Check whether the assertions in a given solver are consistent or not. From bc19992543c4793ae90f286d4834c782e9b23548 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Dec 2022 12:02:08 -0800 Subject: [PATCH 432/477] add doc for ackermannize Signed-off-by: Nikolaj Bjorner --- src/ackermannization/ackermannize_bv_tactic.h | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/ackermannization/ackermannize_bv_tactic.h b/src/ackermannization/ackermannize_bv_tactic.h index 073a680bf..b99ae00e4 100644 --- a/src/ackermannization/ackermannize_bv_tactic.h +++ b/src/ackermannization/ackermannize_bv_tactic.h @@ -11,7 +11,37 @@ Author: Mikolas Janota -Revision History: +Tactic Documentation: + +## Tactic ackernannize_bv + +### Short Description + +A tactic for performing Ackermann reduction for bit-vector formulas + +### Long Description + +The Ackermann reduction replaces uninterpreted functions $f(t_1), f(t_2)$ +by fresh variables $f_1, f_2$ and addes axioms $t_1 \simeq t_2 \implies f_1 \simeq f_2$. +The reduction has the effect of eliminating uninterpreted functions. When the reduction +produces a pure bit-vector benchmark, it allows Z3 to use a specialized SAT solver. + +### Example + +```z3 +(declare-const x (_ BitVec 32)) +(declare-const y (_ BitVec 32)) +(declare-fun f ((_ BitVec 32)) (_ BitVec 8)) + +(assert (not (= (f x) (f y)))) +(apply ackermannize_bv) +``` + +### Notes + +* does not support proofs, does not support unsatisfiable cores + + --*/ #pragma once From 3e8cbb66112aaa58710e8e23719ab864b51ad0fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Dec 2022 18:07:57 -0800 Subject: [PATCH 433/477] #5884 Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index cdcab36d5..7a0b47da0 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5881,7 +5881,7 @@ extern "C" { def_API('Z3_eval_smtlib2_string', STRING, (_in(CONTEXT), _in(STRING),)) */ - Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context c Z3_string str); + Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context c, Z3_string str); /** From ec74a874232b6b23b17c741a91fff75f8d2fa6c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Dec 2022 20:19:26 -0800 Subject: [PATCH 434/477] fix #6510 Signed-off-by: Nikolaj Bjorner --- Parameters.md | 605 ---------------------------------------- src/api/python/z3/z3.py | 4 +- 2 files changed, 2 insertions(+), 607 deletions(-) delete mode 100644 Parameters.md diff --git a/Parameters.md b/Parameters.md deleted file mode 100644 index ea69becad..000000000 --- a/Parameters.md +++ /dev/null @@ -1,605 +0,0 @@ -## Module pi - -Description: pattern inference (heuristics) for universal formulas (without annotation) - Parameter | Type | Description | Default - ----------|------|-------------|-------- -arith | unsigned int | 0 - do not infer patterns with arithmetic terms, 1 - use patterns with arithmetic terms if there is no other pattern, 2 - always use patterns with arithmetic terms | 1 -arith_weight | unsigned int | default weight for quantifiers where the only available pattern has nested arithmetic terms | 5 -block_loop_patterns | bool | block looping patterns during pattern inference | true -max_multi_patterns | unsigned int | when patterns are not provided, the prover uses a heuristic to infer them, this option sets the threshold on the number of extra multi-patterns that can be created; by default, the prover creates at most one multi-pattern when there is no unary pattern | 0 -non_nested_arith_weight | unsigned int | default weight for quantifiers where the only available pattern has non nested arithmetic terms | 10 -pull_quantifiers | bool | pull nested quantifiers, if no pattern was found | true -use_database | bool | use pattern database | false -warnings | bool | enable/disable warning messages in the pattern inference module | false - -## Module tactic - -Description: tactic parameters - Parameter | Type | Description | Default - ----------|------|-------------|-------- -blast_term_ite.max_inflation | unsigned int | multiplicative factor of initial term size. | 4294967295 -blast_term_ite.max_steps | unsigned int | maximal number of steps allowed for tactic. | 4294967295 -default_tactic | symbol | overwrite default tactic in strategic solver | -propagate_values.max_rounds | unsigned int | maximal number of rounds to propagate values. | 4 -solve_eqs.context_solve | bool | solve equalities within disjunctions. | true -solve_eqs.ite_solver | bool | use if-then-else solvers. | true -solve_eqs.max_occs | unsigned int | maximum number of occurrences for considering a variable for gaussian eliminations. | 4294967295 -solve_eqs.theory_solver | bool | use theory solvers. | true - -## Module pp - -Description: pretty printer - Parameter | Type | Description | Default - ----------|------|-------------|-------- -bounded | bool | ignore characters exceeding max width | false -bv_literals | bool | use Bit-Vector literals (e.g, #x0F and #b0101) during pretty printing | true -bv_neg | bool | use bvneg when displaying Bit-Vector literals where the most significant bit is 1 | false -decimal | bool | pretty print real numbers using decimal notation (the output may be truncated). Z3 adds a ? if the value is not precise | false -decimal_precision | unsigned int | maximum number of decimal places to be used when pp.decimal=true | 10 -fixed_indent | bool | use a fixed indentation for applications | false -flat_assoc | bool | flat associative operators (when pretty printing SMT2 terms/formulas) | true -fp_real_literals | bool | use real-numbered floating point literals (e.g, +1.0p-1) during pretty printing | false -max_depth | unsigned int | max. term depth (when pretty printing SMT2 terms/formulas) | 5 -max_indent | unsigned int | max. indentation in pretty printer | 4294967295 -max_num_lines | unsigned int | max. number of lines to be displayed in pretty printer | 4294967295 -max_ribbon | unsigned int | max. ribbon (width - indentation) in pretty printer | 80 -max_width | unsigned int | max. width in pretty printer | 80 -min_alias_size | unsigned int | min. size for creating an alias for a shared term (when pretty printing SMT2 terms/formulas) | 10 -pretty_proof | bool | use slower, but prettier, printer for proofs | false -simplify_implies | bool | simplify nested implications for pretty printing | true -single_line | bool | ignore line breaks when true | false - -## Module sat - -Description: propositional SAT solver - Parameter | Type | Description | Default - ----------|------|-------------|-------- -abce | bool | eliminate blocked clauses using asymmetric literals | false -acce | bool | eliminate covered clauses using asymmetric added literals | false -anf | bool | enable ANF based simplification in-processing | false -anf.delay | unsigned int | delay ANF simplification by in-processing round | 2 -anf.exlin | bool | enable extended linear simplification | false -asymm_branch | bool | asymmetric branching | true -asymm_branch.all | bool | asymmetric branching on all literals per clause | false -asymm_branch.delay | unsigned int | number of simplification rounds to wait until invoking asymmetric branch simplification | 1 -asymm_branch.limit | unsigned int | approx. maximum number of literals visited during asymmetric branching | 100000000 -asymm_branch.rounds | unsigned int | maximal number of rounds to run asymmetric branch simplifications if progress is made | 2 -asymm_branch.sampled | bool | use sampling based asymmetric branching based on binary implication graph | true -ate | bool | asymmetric tautology elimination | true -backtrack.conflicts | unsigned int | number of conflicts before enabling chronological backtracking | 4000 -backtrack.scopes | unsigned int | number of scopes to enable chronological backtracking | 100 -bca | bool | blocked clause addition - add blocked binary clauses | false -bce | bool | eliminate blocked clauses | false -bce_at | unsigned int | eliminate blocked clauses only once at the given simplification round | 2 -bce_delay | unsigned int | delay eliminate blocked clauses until simplification round | 2 -binspr | bool | enable SPR inferences of binary propagation redundant clauses. This inprocessing step eliminates models | false -blocked_clause_limit | unsigned int | maximum number of literals visited during blocked clause elimination | 100000000 -branching.anti_exploration | bool | apply anti-exploration heuristic for branch selection | false -branching.heuristic | symbol | branching heuristic vsids, chb | vsids -burst_search | unsigned int | number of conflicts before first global simplification | 100 -cardinality.encoding | symbol | encoding used for at-most-k constraints: grouped, bimander, ordered, unate, circuit | grouped -cardinality.solver | bool | use cardinality solver | true -cce | bool | eliminate covered clauses | false -core.minimize | bool | minimize computed core | false -core.minimize_partial | bool | apply partial (cheap) core minimization | false -cut | bool | enable AIG based simplification in-processing | false -cut.aig | bool | extract aigs (and ites) from cluases for cut simplification | false -cut.delay | unsigned int | delay cut simplification by in-processing round | 2 -cut.dont_cares | bool | integrate dont cares with cuts | true -cut.force | bool | force redoing cut-enumeration until a fixed-point | false -cut.lut | bool | extract luts from clauses for cut simplification | false -cut.npn3 | bool | extract 3 input functions from clauses for cut simplification | false -cut.redundancies | bool | integrate redundancy checking of cuts | true -cut.xor | bool | extract xors from clauses for cut simplification | false -ddfw.init_clause_weight | unsigned int | initial clause weight for DDFW local search | 8 -ddfw.reinit_base | unsigned int | increment basis for geometric backoff scheme of re-initialization of weights | 10000 -ddfw.restart_base | unsigned int | number of flips used a starting point for hessitant restart backoff | 100000 -ddfw.threads | unsigned int | number of ddfw threads to run in parallel with sat solver | 0 -ddfw.use_reward_pct | unsigned int | percentage to pick highest reward variable when it has reward 0 | 15 -ddfw_search | bool | use ddfw local search instead of CDCL | false -dimacs.core | bool | extract core from DIMACS benchmarks | false -drat.activity | bool | dump variable activities | false -drat.binary | bool | use Binary DRAT output format | false -drat.check_sat | bool | build up internal trace, check satisfying model | false -drat.check_unsat | bool | build up internal proof and check | false -drat.file | symbol | file to dump DRAT proofs | -drup.trim | bool | build and trim drup proof | false -dyn_sub_res | bool | dynamic subsumption resolution for minimizing learned clauses | true -elim_vars | bool | enable variable elimination using resolution during simplification | true -elim_vars_bdd | bool | enable variable elimination using BDD recompilation during simplification | true -elim_vars_bdd_delay | unsigned int | delay elimination of variables using BDDs until after simplification round | 3 -enable_pre_simplify | bool | enable pre simplifications before the bounded search | false -euf | bool | enable euf solver (this feature is preliminary and not ready for general consumption) | false -force_cleanup | bool | force cleanup to remove tautologies and simplify clauses | false -gc | symbol | garbage collection strategy: psm, glue, glue_psm, dyn_psm | glue_psm -gc.burst | bool | perform eager garbage collection during initialization | false -gc.defrag | bool | defragment clauses when garbage collecting | true -gc.increment | unsigned int | increment to the garbage collection threshold | 500 -gc.initial | unsigned int | learned clauses garbage collection frequency | 20000 -gc.k | unsigned int | learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm) | 7 -gc.small_lbd | unsigned int | learned clauses with small LBD are never deleted (only used in dyn_psm) | 3 -inprocess.max | unsigned int | maximal number of inprocessing passes | 4294967295 -inprocess.out | symbol | file to dump result of the first inprocessing step and exit | -local_search | bool | use local search instead of CDCL | false -local_search_dbg_flips | bool | write debug information for number of flips | false -local_search_mode | symbol | local search algorithm, either default wsat or qsat | wsat -local_search_threads | unsigned int | number of local search threads to find satisfiable solution | 0 -lookahead.cube.cutoff | symbol | cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat | depth -lookahead.cube.depth | unsigned int | cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth. | 1 -lookahead.cube.fraction | double | adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat | 0.4 -lookahead.cube.freevars | double | cube free variable fraction. Used when lookahead.cube.cutoff is freevars | 0.8 -lookahead.cube.psat.clause_base | double | clause base for PSAT cutoff | 2 -lookahead.cube.psat.trigger | double | trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat | 5 -lookahead.cube.psat.var_exp | double | free variable exponent for PSAT cutoff | 1 -lookahead.delta_fraction | double | number between 0 and 1, the smaller the more literals are selected for double lookahead | 1.0 -lookahead.double | bool | enable doubld lookahead | true -lookahead.global_autarky | bool | prefer to branch on variables that occur in clauses that are reduced | false -lookahead.preselect | bool | use pre-selection of subset of variables for branching | false -lookahead.reward | symbol | select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu | march_cu -lookahead.use_learned | bool | use learned clauses when selecting lookahead literal | false -lookahead_scores | bool | extract lookahead scores. A utility that can only be used from the DIMACS front-end | false -lookahead_simplify | bool | use lookahead solver during simplification | false -lookahead_simplify.bca | bool | add learned binary clauses as part of lookahead simplification | true -max_conflicts | unsigned int | maximum number of conflicts | 4294967295 -max_memory | unsigned int | maximum amount of memory in megabytes | 4294967295 -minimize_lemmas | bool | minimize learned clauses | true -override_incremental | bool | override incremental safety gaps. Enable elimination of blocked clauses and variables even if solver is reused | false -pb.lemma_format | symbol | generate either cardinality or pb lemmas | cardinality -pb.min_arity | unsigned int | minimal arity to compile pb/cardinality constraints to CNF | 9 -pb.resolve | symbol | resolution strategy for boolean algebra solver: cardinality, rounding | cardinality -pb.solver | symbol | method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), binary_merge, segmented, solver (use native solver) | solver -phase | symbol | phase selection strategy: always_false, always_true, basic_caching, random, caching | caching -phase.sticky | bool | use sticky phase caching | true -prob_search | bool | use probsat local search instead of CDCL | false -probing | bool | apply failed literal detection during simplification | true -probing_binary | bool | probe binary clauses | true -probing_cache | bool | add binary literals as lemmas | true -probing_cache_limit | unsigned int | cache binaries unless overall memory usage exceeds cache limit | 1024 -probing_limit | unsigned int | limit to the number of probe calls | 5000000 -propagate.prefetch | bool | prefetch watch lists for assigned literals | true -random_freq | double | frequency of random case splits | 0.01 -random_seed | unsigned int | random seed | 0 -reorder.activity_scale | unsigned int | scaling factor for activity update | 100 -reorder.base | unsigned int | number of conflicts per random reorder | 4294967295 -reorder.itau | double | inverse temperature for softmax | 4.0 -rephase.base | unsigned int | number of conflicts per rephase | 1000 -resolution.cls_cutoff1 | unsigned int | limit1 - total number of problems clauses for the second cutoff of Boolean variable elimination | 100000000 -resolution.cls_cutoff2 | unsigned int | limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination | 700000000 -resolution.limit | unsigned int | approx. maximum number of literals visited during variable elimination | 500000000 -resolution.lit_cutoff_range1 | unsigned int | second cutoff (total number of literals) for Boolean variable elimination, for problems containing less than res_cls_cutoff1 clauses | 700 -resolution.lit_cutoff_range2 | unsigned int | second cutoff (total number of literals) for Boolean variable elimination, for problems containing more than res_cls_cutoff1 and less than res_cls_cutoff2 | 400 -resolution.lit_cutoff_range3 | unsigned int | second cutoff (total number of literals) for Boolean variable elimination, for problems containing more than res_cls_cutoff2 | 300 -resolution.occ_cutoff | unsigned int | first cutoff (on number of positive/negative occurrences) for Boolean variable elimination | 10 -resolution.occ_cutoff_range1 | unsigned int | second cutoff (number of positive/negative occurrences) for Boolean variable elimination, for problems containing less than res_cls_cutoff1 clauses | 8 -resolution.occ_cutoff_range2 | unsigned int | second cutoff (number of positive/negative occurrences) for Boolean variable elimination, for problems containing more than res_cls_cutoff1 and less than res_cls_cutoff2 | 5 -resolution.occ_cutoff_range3 | unsigned int | second cutoff (number of positive/negative occurrences) for Boolean variable elimination, for problems containing more than res_cls_cutoff2 | 3 -restart | symbol | restart strategy: static, luby, ema or geometric | ema -restart.emafastglue | double | ema alpha factor for fast moving average | 0.03 -restart.emaslowglue | double | ema alpha factor for slow moving average | 1e-05 -restart.factor | double | restart increment factor for geometric strategy | 1.5 -restart.fast | bool | use fast restart approach only removing less active literals. | true -restart.initial | unsigned int | initial restart (number of conflicts) | 2 -restart.margin | double | margin between fast and slow restart factors. For ema | 1.1 -restart.max | unsigned int | maximal number of restarts. | 4294967295 -retain_blocked_clauses | bool | retain blocked clauses as lemmas | true -scc | bool | eliminate Boolean variables by computing strongly connected components | true -scc.tr | bool | apply transitive reduction, eliminate redundant binary clauses | true -search.sat.conflicts | unsigned int | period for solving for sat (in number of conflicts) | 400 -search.unsat.conflicts | unsigned int | period for solving for unsat (in number of conflicts) | 400 -simplify.delay | unsigned int | set initial delay of simplification by a conflict count | 0 -subsumption | bool | eliminate subsumed clauses | true -subsumption.limit | unsigned int | approx. maximum number of literals visited during subsumption (and subsumption resolution) | 100000000 -threads | unsigned int | number of parallel threads to use | 1 -variable_decay | unsigned int | multiplier (divided by 100) for the VSIDS activity increment | 110 - -## Module solver - -Description: solver parameters - Parameter | Type | Description | Default - ----------|------|-------------|-------- -axioms2files | bool | print negated theory axioms to separate files during search | false -cancel_backup_file | symbol | file to save partial search state if search is canceled | -lemmas2console | bool | print lemmas during search | false -smtlib2_log | symbol | file to save solver interaction | -timeout | unsigned int | timeout on the solver object; overwrites a global timeout | 4294967295 - -## Module opt - -Description: optimization parameters - Parameter | Type | Description | Default - ----------|------|-------------|-------- -dump_benchmarks | bool | dump benchmarks for profiling | false -dump_models | bool | display intermediary models to stdout | false -elim_01 | bool | eliminate 01 variables | true -enable_core_rotate | bool | enable core rotation to both sample cores and correction sets | false -enable_lns | bool | enable LNS during weighted maxsat | false -enable_sat | bool | enable the new SAT core for propositional constraints | true -enable_sls | bool | enable SLS tuning during weighted maxsat | false -incremental | bool | set incremental mode. It disables pre-processing and enables adding constraints in model event handler | false -lns_conflicts | unsigned int | initial conflict count for LNS search | 1000 -maxlex.enable | bool | enable maxlex heuristic for lexicographic MaxSAT problems | true -maxres.add_upper_bound_block | bool | restict upper bound with constraint | false -maxres.hill_climb | bool | give preference for large weight cores | true -maxres.max_core_size | unsigned int | break batch of generated cores if size reaches this number | 3 -maxres.max_correction_set_size | unsigned int | allow generating correction set constraints up to maximal size | 3 -maxres.max_num_cores | unsigned int | maximal number of cores per round | 200 -maxres.maximize_assignment | bool | find an MSS/MCS to improve current assignment | false -maxres.pivot_on_correction_set | bool | reduce soft constraints if the current correction set is smaller than current core | true -maxres.wmax | bool | use weighted theory solver to constrain upper bounds | false -maxsat_engine | symbol | select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'rc2' | maxres -optsmt_engine | symbol | select optimization engine: 'basic', 'symba' | basic -pb.compile_equality | bool | compile arithmetical equalities into pseudo-Boolean equality (instead of two inequalites) | false -pp.neat | bool | use neat (as opposed to less readable, but faster) pretty printer when displaying context | true -pp.wcnf | bool | print maxsat benchmark into wcnf format | false -priority | symbol | select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box' | lex -rc2.totalizer | bool | use totalizer for rc2 encoding | true -rlimit | unsigned int | resource limit (0 means no limit) | 0 -solution_prefix | symbol | path prefix to dump intermediary, but non-optimal, solutions | -timeout | unsigned int | timeout (in milliseconds) (UINT_MAX and 0 mean no timeout) | 4294967295 - -## Module parallel - -Description: parameters for parallel solver - Parameter | Type | Description | Default - ----------|------|-------------|-------- -conquer.backtrack_frequency | unsigned int | frequency to apply core minimization during conquer | 10 -conquer.batch_size | unsigned int | number of cubes to batch together for fast conquer | 100 -conquer.delay | unsigned int | delay of cubes until applying conquer | 10 -conquer.restart.max | unsigned int | maximal number of restarts during conquer phase | 5 -enable | bool | enable parallel solver by default on selected tactics (for QF_BV) | false -simplify.exp | double | restart and inprocess max is multiplied by simplify.exp ^ depth | 1 -simplify.inprocess.max | unsigned int | maximal number of inprocessing steps during simplification | 2 -simplify.max_conflicts | unsigned int | maximal number of conflicts during simplifcation phase | 4294967295 -simplify.restart.max | unsigned int | maximal number of restarts during simplification phase | 5000 -threads.max | unsigned int | caps maximal number of threads below the number of processors | 10000 - -## Module nnf - -Description: negation normal form - Parameter | Type | Description | Default - ----------|------|-------------|-------- -ignore_labels | bool | remove/ignore labels in the input formula, this option is ignored if proofs are enabled | false -max_memory | unsigned int | maximum amount of memory in megabytes | 4294967295 -mode | symbol | NNF translation mode: skolem (skolem normal form), quantifiers (skolem normal form + quantifiers in NNF), full | skolem -sk_hack | bool | hack for VCC | false - -## Module algebraic - -Description: real algebraic number package. Non-default parameter settings are not supported - Parameter | Type | Description | Default - ----------|------|-------------|-------- -factor | bool | use polynomial factorization to simplify polynomials representing algebraic numbers | true -factor_max_prime | unsigned int | parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. This parameter limits the maximum prime number p to be used in the first step | 31 -factor_num_primes | unsigned int | parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. The search space may be reduced by factoring the polynomial in different GF(p)'s. This parameter specify the maximum number of finite factorizations to be considered, before lifiting and searching | 1 -factor_search_size | unsigned int | parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. This parameter can be used to limit the search space | 5000 -min_mag | unsigned int | Z3 represents algebraic numbers using a (square-free) polynomial p and an isolating interval (which contains one and only one root of p). This interval may be refined during the computations. This parameter specifies whether to cache the value of a refined interval or not. It says the minimal size of an interval for caching purposes is 1/2^16 | 16 -zero_accuracy | unsigned int | one of the most time-consuming operations in the real algebraic number module is determining the sign of a polynomial evaluated at a sample point with non-rational algebraic number values. Let k be the value of this option. If k is 0, Z3 uses precise computation. Otherwise, the result of a polynomial evaluation is considered to be 0 if Z3 can show it is inside the interval (-1/2^k, 1/2^k) | 0 - -## Module combined_solver - -Description: combines two solvers: non-incremental (solver1) and incremental (solver2) - Parameter | Type | Description | Default - ----------|------|-------------|-------- -ignore_solver1 | bool | if true, solver 2 is always used | false -solver2_timeout | unsigned int | fallback to solver 1 after timeout even when in incremental model | 4294967295 -solver2_unknown | unsigned int | what should be done when solver 2 returns unknown: 0 - just return unknown, 1 - execute solver 1 if quantifier free problem, 2 - execute solver 1 | 1 - -## Module rcf - -Description: real closed fields - Parameter | Type | Description | Default - ----------|------|-------------|-------- -clean_denominators | bool | clean denominators before root isolation | true -inf_precision | unsigned int | a value k that is the initial interval size (i.e., (0, 1/2^l)) used as an approximation for infinitesimal values | 24 -initial_precision | unsigned int | a value k that is the initial interval size (as 1/2^k) when creating transcendentals and approximated division | 24 -lazy_algebraic_normalization | bool | during sturm-seq and square-free polynomial computations, only normalize algebraic polynomial expressions when the defining polynomial is monic | true -max_precision | unsigned int | during sign determination we switch from interval arithmetic to complete methods when the interval size is less than 1/2^k, where k is the max_precision | 128 -use_prem | bool | use pseudo-remainder instead of remainder when computing GCDs and Sturm-Tarski sequences | true -ERROR: unknown module 'rewriter, description: new formula simplification module used in the tactic framework' - -## Module ackermannization - -Description: solving UF via ackermannization - Parameter | Type | Description | Default - ----------|------|-------------|-------- -eager | bool | eagerly instantiate all congruence rules | true -inc_sat_backend | bool | use incremental SAT | false -sat_backend | bool | use SAT rather than SMT in qfufbv_ackr_tactic | false - -## Module nlsat - -Description: nonlinear solver - Parameter | Type | Description | Default - ----------|------|-------------|-------- -check_lemmas | bool | check lemmas on the fly using an independent nlsat solver | false -factor | bool | factor polynomials produced during conflict resolution. | true -inline_vars | bool | inline variables that can be isolated from equations (not supported in incremental mode) | false -lazy | unsigned int | how lazy the solver is. | 0 -log_lemmas | bool | display lemmas as self-contained SMT formulas | false -max_conflicts | unsigned int | maximum number of conflicts. | 4294967295 -max_memory | unsigned int | maximum amount of memory in megabytes | 4294967295 -minimize_conflicts | bool | minimize conflicts | false -randomize | bool | randomize selection of a witness in nlsat. | true -reorder | bool | reorder variables. | true -seed | unsigned int | random seed. | 0 -shuffle_vars | bool | use a random variable order. | false -simplify_conflicts | bool | simplify conflicts using equalities before resolving them in nlsat solver. | true - - -## Module fp - -Description: fixedpoint parameters - Parameter | Type | Description | Default - ----------|------|-------------|-------- -bmc.linear_unrolling_depth | unsigned int | Maximal level to explore | 4294967295 -datalog.all_or_nothing_deltas | bool | compile rules so that it is enough for the delta relation in union and widening operations to determine only whether the updated relation was modified or not | false -datalog.check_relation | symbol | name of default relation to check. operations on the default relation will be verified using SMT solving | null -datalog.compile_with_widening | bool | widening will be used to compile recursive rules | false -datalog.dbg_fpr_nonempty_relation_signature | bool | if true, finite_product_relation will attempt to avoid creating inner relation with empty signature by putting in half of the table columns, if it would have been empty otherwise | false -datalog.default_relation | symbol | default relation implementation: external_relation, pentagon | pentagon -datalog.default_table | symbol | default table implementation: sparse, hashtable, bitvector, interval | sparse -datalog.default_table_checked | bool | if true, the default table will be default_table inside a wrapper that checks that its results are the same as of default_table_checker table | false -datalog.default_table_checker | symbol | see default_table_checked | null -datalog.explanations_on_relation_level | bool | if true, explanations are generated as history of each relation, rather than per fact (generate_explanations must be set to true for this option to have any effect) | false -datalog.generate_explanations | bool | produce explanations for produced facts when using the datalog engine | false -datalog.initial_restart_timeout | unsigned int | length of saturation run before the first restart (in ms), zero means no restarts | 0 -datalog.magic_sets_for_queries | bool | magic set transformation will be used for queries | false -datalog.output_profile | bool | determines whether profile information should be output when outputting Datalog rules or instructions | false -datalog.print.tuples | bool | determines whether tuples for output predicates should be output | true -datalog.profile_timeout_milliseconds | unsigned int | instructions and rules that took less than the threshold will not be printed when printed the instruction/rule list | 0 -datalog.similarity_compressor | bool | rules that differ only in values of constants will be merged into a single rule | true -datalog.similarity_compressor_threshold | unsigned int | if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged | 11 -datalog.subsumption | bool | if true, removes/filters predicates with total transitions | true -datalog.timeout | unsigned int | Time limit used for saturation | 0 -datalog.unbound_compressor | bool | auxiliary relations will be introduced to avoid unbound variables in rule heads | true -datalog.use_map_names | bool | use names from map files when displaying tuples | true -engine | symbol | Select: auto-config, datalog, bmc, spacer | auto-config -generate_proof_trace | bool | trace for 'sat' answer as proof object | false -print_aig | symbol | Dump clauses in AIG text format (AAG) to the given file name | -print_answer | bool | print answer instance(s) to query | false -print_boogie_certificate | bool | print certificate for reachability or non-reachability using a format understood by Boogie | false -print_certificate | bool | print certificate for reachability or non-reachability | false -print_fixedpoint_extensions | bool | use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, when printing rules | true -print_low_level_smt2 | bool | use (faster) low-level SMT2 printer (the printer is scalable but the result may not be as readable) | false -print_statistics | bool | print statistics | false -print_with_variable_declarations | bool | use variable declarations when displaying rules (instead of attempting to use original names) | true -spacer.arith.solver | unsigned int | arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver | 2 -spacer.blast_term_ite_inflation | unsigned int | Maximum inflation for non-Boolean ite-terms expansion: 0 (none), k (multiplicative) | 3 -spacer.ctp | bool | Enable counterexample-to-pushing | true -spacer.dump_benchmarks | bool | Dump SMT queries as benchmarks | false -spacer.dump_threshold | double | Threshold in seconds on dumping benchmarks | 5.0 -spacer.elim_aux | bool | Eliminate auxiliary variables in reachability facts | true -spacer.eq_prop | bool | Enable equality and bound propagation in arithmetic | true -spacer.gpdr | bool | Use GPDR solving strategy for non-linear CHC | false -spacer.gpdr.bfs | bool | Use BFS exploration strategy for expanding model search | true -spacer.ground_pobs | bool | Ground pobs by using values from a model | true -spacer.iuc | unsigned int | 0 = use old implementation of unsat-core-generation, 1 = use new implementation of IUC generation, 2 = use new implementation of IUC + min-cut optimization | 1 -spacer.iuc.arith | unsigned int | 0 = use simple Farkas plugin, 1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation),2 = use Gaussian elimination optimization (broken), 3 = use additive IUC plugin | 1 -spacer.iuc.debug_proof | bool | prints proof used by unsat-core-learner for debugging purposes (debugging) | false -spacer.iuc.old_hyp_reducer | bool | use old hyp reducer instead of new implementation, for debugging only | false -spacer.iuc.print_farkas_stats | bool | prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut (for debugging) | false -spacer.iuc.split_farkas_literals | bool | Split Farkas literals | false -spacer.keep_proxy | bool | keep proxy variables (internal parameter) | true -spacer.logic | symbol | SMT-LIB logic to configure internal SMT solvers | -spacer.max_level | unsigned int | Maximum level to explore | 4294967295 -spacer.max_num_contexts | unsigned int | maximal number of contexts to create | 500 -spacer.mbqi | bool | Enable mbqi | true -spacer.min_level | unsigned int | Minimal level to explore | 0 -spacer.native_mbp | bool | Use native mbp of Z3 | true -spacer.order_children | unsigned int | SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse), 2 (random) | 0 -spacer.p3.share_invariants | bool | Share invariants lemmas | false -spacer.p3.share_lemmas | bool | Share frame lemmas | false -spacer.print_json | symbol | Print pobs tree in JSON format to a given file | -spacer.propagate | bool | Enable propagate/pushing phase | true -spacer.push_pob | bool | push blocked pobs to higher level | false -spacer.push_pob_max_depth | unsigned int | Maximum depth at which push_pob is enabled | 4294967295 -spacer.q3 | bool | Allow quantified lemmas in frames | true -spacer.q3.instantiate | bool | Instantiate quantified lemmas | true -spacer.q3.qgen.normalize | bool | normalize cube before quantified generalization | true -spacer.q3.use_qgen | bool | use quantified lemma generalizer | false -spacer.random_seed | unsigned int | Random seed to be used by SMT solver | 0 -spacer.reach_dnf | bool | Restrict reachability facts to DNF | true -spacer.reset_pob_queue | bool | SPACER: reset pob obligation queue when entering a new level | true -spacer.restart_initial_threshold | unsigned int | Initial threshold for restarts | 10 -spacer.restarts | bool | Enable resetting obligation queue | false -spacer.simplify_lemmas_post | bool | simplify derived lemmas after inductive propagation | false -spacer.simplify_lemmas_pre | bool | simplify derived lemmas before inductive propagation | false -spacer.simplify_pob | bool | simplify pobs by removing redundant constraints | false -spacer.trace_file | symbol | Log file for progress events | -spacer.use_array_eq_generalizer | bool | SPACER: attempt to generalize lemmas with array equalities | true -spacer.use_bg_invs | bool | Enable external background invariants | false -spacer.use_derivations | bool | SPACER: using derivation mechanism to cache intermediate results for non-linear rules | true -spacer.use_euf_gen | bool | Generalize lemmas and pobs using implied equalities | false -spacer.use_inc_clause | bool | Use incremental clause to represent trans | true -spacer.use_inductive_generalizer | bool | generalize lemmas using induction strengthening | true -spacer.use_lemma_as_cti | bool | SPACER: use a lemma instead of a CTI in flexible_trace | false -spacer.use_lim_num_gen | bool | Enable limit numbers generalizer to get smaller numbers | false -spacer.validate_lemmas | bool | Validate each lemma after generalization | false -spacer.weak_abs | bool | Weak abstraction | true -tab.selection | symbol | selection method for tabular strategy: weight (default), first, var-use | weight -validate | bool | validate result (by proof checking or model checking) | false -xform.array_blast | bool | try to eliminate local array terms using Ackermannization -- some array terms may remain | false -xform.array_blast_full | bool | eliminate all local array variables by QE | false -xform.bit_blast | bool | bit-blast bit-vectors | false -xform.coalesce_rules | bool | coalesce rules | false -xform.coi | bool | use cone of influence simplification | true -xform.compress_unbound | bool | compress tails with unbound variables | true -xform.elim_term_ite | bool | Eliminate term-ite expressions | false -xform.elim_term_ite.inflation | unsigned int | Maximum inflation for non-Boolean ite-terms blasting: 0 (none), k (multiplicative) | 3 -xform.fix_unbound_vars | bool | fix unbound variables in tail | false -xform.inline_eager | bool | try eager inlining of rules | true -xform.inline_linear | bool | try linear inlining method | true -xform.inline_linear_branch | bool | try linear inlining method with potential expansion | false -xform.instantiate_arrays | bool | Transforms P(a) into P(i, a[i] a) | false -xform.instantiate_arrays.enforce | bool | Transforms P(a) into P(i, a[i]), discards a from predicate | false -xform.instantiate_arrays.nb_quantifier | unsigned int | Gives the number of quantifiers per array | 1 -xform.instantiate_arrays.slice_technique | symbol | => GetId(i) = i, => GetId(i) = true | no-slicing -xform.instantiate_quantifiers | bool | instantiate quantified Horn clauses using E-matching heuristic | false -xform.magic | bool | perform symbolic magic set transformation | false -xform.quantify_arrays | bool | create quantified Horn clauses from clauses with arrays | false -xform.scale | bool | add scaling variable to linear real arithmetic clauses | false -xform.slice | bool | simplify clause set using slicing | true -xform.subsumption_checker | bool | Enable subsumption checker (no support for model conversion) | true -xform.tail_simplifier_pve | bool | propagate_variable_equivalences | true -xform.transform_arrays | bool | Rewrites arrays equalities and applies select over store | false -xform.unfold_rules | unsigned int | unfold rules statically using iterative squaring | 0 - -## Module smt - -Description: smt solver based on lazy smt - Parameter | Type | Description | Default - ----------|------|-------------|-------- -arith.auto_config_simplex | bool | force simplex solver in auto_config | false -arith.bprop_on_pivoted_rows | bool | propagate bounds on rows changed by the pivot operation | true -arith.branch_cut_ratio | unsigned int | branch/cut ratio for linear integer arithmetic | 2 -arith.dump_lemmas | bool | dump arithmetic theory lemmas to files | false -arith.eager_eq_axioms | bool | eager equality axioms | true -arith.enable_hnf | bool | enable hnf (Hermite Normal Form) cuts | true -arith.greatest_error_pivot | bool | Pivoting strategy | false -arith.ignore_int | bool | treat integer variables as real | false -arith.int_eq_branch | bool | branching using derived integer equations | false -arith.min | bool | minimize cost | false -arith.nl | bool | (incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2 | true -arith.nl.branching | bool | branching on integer variables in non linear clusters, relevant only if smt.arith.solver=2 | true -arith.nl.delay | unsigned int | number of calls to final check before invoking bounded nlsat check | 500 -arith.nl.expp | bool | expensive patching | false -arith.nl.gr_q | unsigned int | grobner's quota | 10 -arith.nl.grobner | bool | run grobner's basis heuristic | true -arith.nl.grobner_cnfl_to_report | unsigned int | grobner's maximum number of conflicts to report | 1 -arith.nl.grobner_eqs_growth | unsigned int | grobner's number of equalities growth | 10 -arith.nl.grobner_expr_degree_growth | unsigned int | grobner's maximum expr degree growth | 2 -arith.nl.grobner_expr_size_growth | unsigned int | grobner's maximum expr size growth | 2 -arith.nl.grobner_frequency | unsigned int | grobner's call frequency | 4 -arith.nl.grobner_max_simplified | unsigned int | grobner's maximum number of simplifications | 10000 -arith.nl.grobner_subs_fixed | unsigned int | 0 - no subs, 1 - substitute, 2 - substitute fixed zeros only | 1 -arith.nl.horner | bool | run horner's heuristic | true -arith.nl.horner_frequency | unsigned int | horner's call frequency | 4 -arith.nl.horner_row_length_limit | unsigned int | row is disregarded by the heuristic if its length is longer than the value | 10 -arith.nl.horner_subs_fixed | unsigned int | 0 - no subs, 1 - substitute, 2 - substitute fixed zeros only | 2 -arith.nl.nra | bool | call nra_solver when incremental linearization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6 | true -arith.nl.order | bool | run order lemmas | true -arith.nl.rounds | unsigned int | threshold for number of (nested) final checks for non linear arithmetic, relevant only if smt.arith.solver=2 | 1024 -arith.nl.tangents | bool | run tangent lemmas | true -arith.print_ext_var_names | bool | print external variable names | false -arith.print_stats | bool | print statistic | false -arith.propagate_eqs | bool | propagate (cheap) equalities | true -arith.propagation_mode | unsigned int | 0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds | 1 -arith.random_initial_value | bool | use random initial values in the simplex-based procedure for linear arithmetic | false -arith.rep_freq | unsigned int | the report frequency, in how many iterations print the cost and other info | 0 -arith.simplex_strategy | unsigned int | simplex strategy for the solver | 0 -arith.solver | unsigned int | arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver | 6 -array.extensional | bool | extensional array theory | true -array.weak | bool | weak array theory | false -auto_config | bool | automatically configure solver | true -bv.delay | bool | delay internalize expensive bit-vector operations | true -bv.enable_int2bv | bool | enable support for int2bv and bv2int operators | true -bv.eq_axioms | bool | enable redundant equality axioms for bit-vectors | true -bv.reflect | bool | create enode for every bit-vector term | true -bv.watch_diseq | bool | use watch lists instead of eager axioms for bit-vectors | false -candidate_models | bool | create candidate models even when quantifier or theory reasoning is incomplete | false -case_split | unsigned int | 0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal, 6 - activity-based case split with theory-aware branching activity | 1 -clause_proof | bool | record a clausal proof | false -core.extend_nonlocal_patterns | bool | extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier's body | false -core.extend_patterns | bool | extend unsat core with literals that trigger (potential) quantifier instances | false -core.extend_patterns.max_distance | unsigned int | limits the distance of a pattern-extended unsat core | 4294967295 -core.minimize | bool | minimize unsat core produced by SMT context | false -core.validate | bool | [internal] validate unsat core produced by SMT context. This option is intended for debugging | false -cube_depth | unsigned int | cube depth. | 1 -dack | unsigned int | 0 - disable dynamic ackermannization, 1 - expand Leibniz's axiom if a congruence is the root of a conflict, 2 - expand Leibniz's axiom if a congruence is used during conflict resolution | 1 -dack.eq | bool | enable dynamic ackermannization for transtivity of equalities | false -dack.factor | double | number of instance per conflict | 0.1 -dack.gc | unsigned int | Dynamic ackermannization garbage collection frequency (per conflict) | 2000 -dack.gc_inv_decay | double | Dynamic ackermannization garbage collection decay | 0.8 -dack.threshold | unsigned int | number of times the congruence rule must be used before Leibniz's axiom is expanded | 10 -delay_units | bool | if true then z3 will not restart when a unit clause is learned | false -delay_units_threshold | unsigned int | maximum number of learned unit clauses before restarting, ignored if delay_units is false | 32 -dt_lazy_splits | unsigned int | How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy | 1 -ematching | bool | E-Matching based quantifier instantiation | true -induction | bool | enable generation of induction lemmas | false -lemma_gc_strategy | unsigned int | lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none | 0 -logic | symbol | logic used to setup the SMT solver | -macro_finder | bool | try to find universally quantified formulas that can be viewed as macros | false -max_conflicts | unsigned int | maximum number of conflicts before giving up. | 4294967295 -mbqi | bool | model based quantifier instantiation (MBQI) | true -mbqi.force_template | unsigned int | some quantifiers can be used as templates for building interpretations for functions. Z3 uses heuristics to decide whether a quantifier will be used as a template or not. Quantifiers with weight >= mbqi.force_template are forced to be used as a template | 10 -mbqi.id | string | Only use model-based instantiation for quantifiers with id's beginning with string | -mbqi.max_cexs | unsigned int | initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation | 1 -mbqi.max_cexs_incr | unsigned int | increment for MBQI_MAX_CEXS, the increment is performed after each round of MBQI | 0 -mbqi.max_iterations | unsigned int | maximum number of rounds of MBQI | 1000 -mbqi.trace | bool | generate tracing messages for Model Based Quantifier Instantiation (MBQI). It will display a message before every round of MBQI, and the quantifiers that were not satisfied | false -pb.conflict_frequency | unsigned int | conflict frequency for Pseudo-Boolean theory | 1000 -pb.learn_complements | bool | learn complement literals for Pseudo-Boolean theory | true -phase_caching_off | unsigned int | number of conflicts while phase caching is off | 100 -phase_caching_on | unsigned int | number of conflicts while phase caching is on | 400 -phase_selection | unsigned int | phase selection heuristic: 0 - always false, 1 - always true, 2 - phase caching, 3 - phase caching conservative, 4 - phase caching conservative 2, 5 - random, 6 - number of occurrences, 7 - theory | 3 -pull_nested_quantifiers | bool | pull nested quantifiers | false -q.lift_ite | unsigned int | 0 - don not lift non-ground if-then-else, 1 - use conservative ite lifting, 2 - use full lifting of if-then-else under quantifiers | 0 -q.lite | bool | Use cheap quantifier elimination during pre-processing | false -qi.cost | string | expression specifying what is the cost of a given quantifier instantiation | (+ weight generation) -qi.eager_threshold | double | threshold for eager quantifier instantiation | 10.0 -qi.lazy_threshold | double | threshold for lazy quantifier instantiation | 20.0 -qi.max_instances | unsigned int | maximum number of quantifier instantiations | 4294967295 -qi.max_multi_patterns | unsigned int | specify the number of extra multi patterns | 0 -qi.profile | bool | profile quantifier instantiation | false -qi.profile_freq | unsigned int | how frequent results are reported by qi.profile | 4294967295 -qi.quick_checker | unsigned int | specify quick checker mode, 0 - no quick checker, 1 - using unsat instances, 2 - using both unsat and no-sat instances | 0 -quasi_macros | bool | try to find universally quantified formulas that are quasi-macros | false -random_seed | unsigned int | random seed for the smt solver | 0 -refine_inj_axioms | bool | refine injectivity axioms | true -relevancy | unsigned int | relevancy propagation heuristic: 0 - disabled, 1 - relevancy is tracked by only affects quantifier instantiation, 2 - relevancy is tracked, and an atom is only asserted if it is relevant | 2 -restart.max | unsigned int | maximal number of restarts. | 4294967295 -restart_factor | double | when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the current restart threshold | 1.1 -restart_strategy | unsigned int | 0 - geometric, 1 - inner-outer-geometric, 2 - luby, 3 - fixed, 4 - arithmetic | 1 -restricted_quasi_macros | bool | try to find universally quantified formulas that are restricted quasi-macros | false -seq.max_unfolding | unsigned int | maximal unfolding depth for checking string equations and regular expressions | 1000000000 -seq.split_w_len | bool | enable splitting guided by length constraints | true -seq.validate | bool | enable self-validation of theory axioms created by seq theory | false -str.aggressive_length_testing | bool | prioritize testing concrete length values over generating more options | false -str.aggressive_unroll_testing | bool | prioritize testing concrete regex unroll counts over generating more options | true -str.aggressive_value_testing | bool | prioritize testing concrete string constant values over generating more options | false -str.fast_length_tester_cache | bool | cache length tester constants instead of regenerating them | false -str.fast_value_tester_cache | bool | cache value tester constants instead of regenerating them | true -str.fixed_length_naive_cex | bool | construct naive counterexamples when fixed-length model construction fails for a given length assignment (Z3str3 only) | true -str.fixed_length_refinement | bool | use abstraction refinement in fixed-length equation solver (Z3str3 only) | false -str.overlap_priority | double | theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true | -0.1 -str.regex_automata_difficulty_threshold | unsigned int | difficulty threshold for regex automata heuristics | 1000 -str.regex_automata_failed_automaton_threshold | unsigned int | number of failed automaton construction attempts after which a full automaton is automatically built | 10 -str.regex_automata_failed_intersection_threshold | unsigned int | number of failed automaton intersection attempts after which intersection is always computed | 10 -str.regex_automata_intersection_difficulty_threshold | unsigned int | difficulty threshold for regex intersection heuristics | 1000 -str.regex_automata_length_attempt_threshold | unsigned int | number of length/path constraint attempts before checking unsatisfiability of regex terms | 10 -str.string_constant_cache | bool | cache all generated string constants generated from anywhere in theory_str | true -str.strong_arrangements | bool | assert equivalences instead of implications when generating string arrangement axioms | true -string_solver | symbol | solver for string/sequence theories. options are: 'z3str3' (specialized string solver), 'seq' (sequence solver), 'auto' (use static features to choose best solver), 'empty' (a no-op solver that forces an answer unknown if strings were used), 'none' (no solver) | seq -theory_aware_branching | bool | Allow the context to use extra information from theory solvers regarding literal branching prioritization. | false -theory_case_split | bool | Allow the context to use heuristics involving theory case splits, which are a set of literals of which exactly one can be assigned True. If this option is false, the context will generate extra axioms to enforce this instead. | false -threads | unsigned int | maximal number of parallel threads. | 1 -threads.cube_frequency | unsigned int | frequency for using cubing | 2 -threads.max_conflicts | unsigned int | maximal number of conflicts between rounds of cubing for parallel SMT | 400 - -## Module sls - -Description: Experimental Stochastic Local Search Solver (for QFBV only). - Parameter | Type | Description | Default - ----------|------|-------------|-------- -early_prune | bool | use early pruning for score prediction | true -max_memory | unsigned int | maximum amount of memory in megabytes | 4294967295 -max_restarts | unsigned int | maximum number of restarts | 4294967295 -paws_init | unsigned int | initial/minimum assertion weights | 40 -paws_sp | unsigned int | smooth assertion weights with probability paws_sp / 1024 | 52 -random_offset | bool | use random offset for candidate evaluation | true -random_seed | unsigned int | random seed | 0 -rescore | bool | rescore/normalize top-level score every base restart interval | true -restart_base | unsigned int | base restart interval given by moves per run | 100 -restart_init | bool | initialize to 0 or random value (= 1) after restart | false -scale_unsat | double | scale score of unsat expressions by this factor | 0.5 -track_unsat | bool | keep a list of unsat assertions as done in SAT - currently disabled internally | false -vns_mc | unsigned int | in local minima, try Monte Carlo sampling vns_mc many 2-bit-flips per bit | 0 -vns_repick | bool | in local minima, try picking a different assertion (only for walksat) | false -walksat | bool | use walksat assertion selection (instead of gsat) | true -walksat_repick | bool | repick assertion if randomizing in local minima | true -walksat_ucb | bool | use bandit heuristic for walksat assertion selection (instead of random) | true -walksat_ucb_constant | double | the ucb constant c in the term score + c * f(touched) | 20.0 -walksat_ucb_forget | double | scale touched by this factor every base restart interval | 1.0 -walksat_ucb_init | bool | initialize total ucb touched to formula size | false -walksat_ucb_noise | double | add noise 0 <= 256 * ucb_noise to ucb score for assertion selection | 0.0002 -wp | unsigned int | random walk with probability wp / 1024 | 100 diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index ca3486ac5..1f24222ad 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1560,9 +1560,9 @@ class BoolRef(ExprRef): """Create the Z3 expression `self * other`. """ if isinstance(other, int) and other == 1: - return self + return If(self, 1, 0) if isinstance(other, int) and other == 0: - return + return IntVal(0, self.ctx) if isinstance(other, BoolRef): other = If(other, 1, 0) return If(self, other, 0) From 47324af210500af2d840595e8d1b493c5f7b1c90 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 29 Dec 2022 11:08:57 +0000 Subject: [PATCH 435/477] be nicer when memout is reached in SMT internalize: return undef rather than crashing --- src/smt/smt_context.cpp | 41 ++++++++++++++++++++++++++---------- src/smt/smt_context.h | 2 ++ src/smt/smt_internalizer.cpp | 2 +- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index d1cf2d875..01e0aba7c 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2961,7 +2961,11 @@ namespace smt { pop_to_base_lvl(); setup_context(false); bool was_consistent = !inconsistent(); - internalize_assertions(); // internalize assertions before invoking m_asserted_formulas.push_scope + try { + internalize_assertions(); // internalize assertions before invoking m_asserted_formulas.push_scope + } catch (cancel_exception&) { + throw default_exception("Resource limits hit in push"); + } if (!m.inc()) throw default_exception("push canceled"); scoped_suspend_rlimit _suspend_cancel(m.limit()); @@ -3556,7 +3560,12 @@ namespace smt { return p(asms); } - internalize_assertions(); + try { + internalize_assertions(); + } catch (cancel_exception&) { + VERIFY(resource_limits_exceeded()); + return l_undef; + } expr_ref_vector theory_assumptions(m); add_theory_assumptions(theory_assumptions); if (!theory_assumptions.empty()) { @@ -3620,10 +3629,15 @@ namespace smt { do { pop_to_base_lvl(); expr_ref_vector asms(m, num_assumptions, assumptions); - internalize_assertions(); - add_theory_assumptions(asms); - TRACE("unsat_core_bug", tout << asms << "\n";); - init_assumptions(asms); + try { + internalize_assertions(); + add_theory_assumptions(asms); + TRACE("unsat_core_bug", tout << asms << '\n';); + init_assumptions(asms); + } catch (cancel_exception&) { + VERIFY(resource_limits_exceeded()); + return l_undef; + } TRACE("before_search", display(tout);); r = search(); r = mk_unsat_core(r); @@ -3641,11 +3655,16 @@ namespace smt { do { pop_to_base_lvl(); expr_ref_vector asms(cube); - internalize_assertions(); - add_theory_assumptions(asms); - // introducing proxies: if (!validate_assumptions(asms)) return l_undef; - for (auto const& clause : clauses) if (!validate_assumptions(clause)) return l_undef; - init_assumptions(asms); + try { + internalize_assertions(); + add_theory_assumptions(asms); + // introducing proxies: if (!validate_assumptions(asms)) return l_undef; + for (auto const& clause : clauses) if (!validate_assumptions(clause)) return l_undef; + init_assumptions(asms); + } catch (cancel_exception&) { + VERIFY(resource_limits_exceeded()); + return l_undef; + } for (auto const& clause : clauses) init_clause(clause); r = search(); r = mk_unsat_core(r); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index b6bf04a20..7a267fdec 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -62,6 +62,8 @@ namespace smt { class model_generator; + struct cancel_exception {}; + class context { friend class model_generator; friend class lookahead; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 26e23d92d..3a7b95e2c 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -353,7 +353,7 @@ namespace smt { */ void context::internalize(expr * n, bool gate_ctx) { if (memory::above_high_watermark()) - throw default_exception("resource limit exceeded during internalization"); + throw cancel_exception(); internalize_deep(n); internalize_rec(n, gate_ctx); } From 07ab4d38b659d525b4363d660c4526a725fbc182 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 09:55:10 -0800 Subject: [PATCH 436/477] fix #6513 Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/extract_eqs.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 5c2851e91..583f76206 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -83,7 +83,7 @@ namespace euf { class arith_extract_eq : public extract_eq { ast_manager& m; arith_util a; - expr_ref_vector m_args; + expr_ref_vector m_args, m_trail; expr_sparse_mark m_nonzero; bool m_enabled = true; @@ -216,20 +216,25 @@ namespace euf { } } + void mark_nonzero(expr* e) { + m_trail.push_back(e); + m_nonzero(e); + } + void add_pos(expr* f) { - expr* lhs = nullptr, * rhs = nullptr; + expr* lhs = nullptr, *rhs = nullptr; rational val; if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_neg()) - m_nonzero.mark(lhs); + mark_nonzero(lhs); else if (a.is_ge(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_pos()) - m_nonzero.mark(lhs); + mark_nonzero(lhs); else if (m.is_not(f, f)) { if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && !val.is_neg()) - m_nonzero.mark(lhs); + mark_nonzero(lhs); else if (a.is_ge(f, lhs, rhs) && a.is_numeral(rhs, val) && !val.is_pos()) - m_nonzero.mark(lhs); + mark_nonzero(lhs); else if (m.is_eq(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_zero()) - m_nonzero.mark(lhs); + mark_nonzero(lhs); } } @@ -241,7 +246,7 @@ namespace euf { public: - arith_extract_eq(ast_manager& m) : m(m), a(m), m_args(m) {} + arith_extract_eq(ast_manager& m) : m(m), a(m), m_args(m), m_trail(m) {} void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { if (!m_enabled) From 293627c889b4adef608d3204efcee1bb39826a7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 09:55:33 -0800 Subject: [PATCH 437/477] fix #6513 Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/extract_eqs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 583f76206..0c24a0b15 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -263,6 +263,7 @@ namespace euf { if (!m_enabled) return; m_nonzero.reset(); + m_trail.reset(); for (unsigned i = 0; i < fmls.qtail(); ++i) add_pos(fmls[i].fml()); } From 8002a51b82f703ce6dba5a429612e30bedb8b575 Mon Sep 17 00:00:00 2001 From: nikswamy Date: Fri, 30 Dec 2022 15:25:01 -0800 Subject: [PATCH 438/477] tiny fix to qprofdiff (#6497) --- contrib/qprofdiff/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/qprofdiff/main.cpp b/contrib/qprofdiff/main.cpp index 17b76081b..7833faa27 100644 --- a/contrib/qprofdiff/main.cpp +++ b/contrib/qprofdiff/main.cpp @@ -65,7 +65,7 @@ int parse(string const & filename, map & data) { inx != string::npos; inx = line.find(" : ", from)) { tokens[ti] = trim(line.substr(from, inx-from)); - from = inx+1; + from = inx+3; //3 is the length of " : " ti++; } if (from != line.length() && ti < 4) From 2c3ecceb03a2b14722d7436d977e6566c4ba122f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 15:47:24 -0800 Subject: [PATCH 439/477] fix build Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/extract_eqs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 0c24a0b15..66ebef85c 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -218,7 +218,7 @@ namespace euf { void mark_nonzero(expr* e) { m_trail.push_back(e); - m_nonzero(e); + m_nonzero.mark(e); } void add_pos(expr* f) { From 0d05e0649bb7e45eee1924ba158c0ba2a966b8d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 18:16:24 -0800 Subject: [PATCH 440/477] initialization order Signed-off-by: Nikolaj Bjorner --- src/tactic/dependent_expr_state_tactic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index 58507a850..bf33d7fd2 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -48,8 +48,8 @@ public: dependent_expr_state(m), m(m), m_params(p), - m_factory(f), - m_dep(m, nullptr, nullptr, nullptr) + m_dep(m, nullptr, nullptr, nullptr), + m_factory(f) {} /** From 5f6f2fc758bd68836ab2db1c9a3f580a25b9f75c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 18:39:02 -0800 Subject: [PATCH 441/477] rename bit_blaster class to bit_blaster_simplifier to avoid name clash --- src/ast/simplifiers/bit_blaster.cpp | 12 ++++++------ src/ast/simplifiers/bit_blaster.h | 4 ++-- src/sat/sat_solver/sat_smt_preprocess.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ast/simplifiers/bit_blaster.cpp b/src/ast/simplifiers/bit_blaster.cpp index c66cef826..eed751f39 100644 --- a/src/ast/simplifiers/bit_blaster.cpp +++ b/src/ast/simplifiers/bit_blaster.cpp @@ -18,12 +18,12 @@ Author: #include "ast/simplifiers/bit_blaster.h" -void bit_blaster::updt_params(params_ref const & p) { +void bit_blaster_simplifier::updt_params(params_ref const & p) { m_params.append(p); m_rewriter.updt_params(m_params); } -void bit_blaster::collect_param_descrs(param_descrs & r) { +void bit_blaster_simplifier::collect_param_descrs(param_descrs & r) { insert_max_memory(r); insert_max_steps(r); r.insert("blast_mul", CPK_BOOL, "(default: true) bit-blast multipliers (and dividers, remainders)."); @@ -32,7 +32,7 @@ void bit_blaster::collect_param_descrs(param_descrs & r) { r.insert("blast_full", CPK_BOOL, "(default: false) bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms."); } -void bit_blaster::reduce() { +void bit_blaster_simplifier::reduce() { m_rewriter.start_rewrite(); expr_ref new_curr(m); proof_ref new_pr(m); @@ -61,16 +61,16 @@ void bit_blaster::reduce() { } -void bit_blaster::collect_statistics(statistics& st) const { +void bit_blaster_simplifier::collect_statistics(statistics& st) const { st.update("bit-blaster-num-steps", m_num_steps); } -void bit_blaster::push() { +void bit_blaster_simplifier::push() { m_rewriter.push(); dependent_expr_simplifier::push(); } -void bit_blaster::pop(unsigned n) { +void bit_blaster_simplifier::pop(unsigned n) { dependent_expr_simplifier::pop(n); m_rewriter.pop(n); } diff --git a/src/ast/simplifiers/bit_blaster.h b/src/ast/simplifiers/bit_blaster.h index 231a1ca68..5724cc075 100644 --- a/src/ast/simplifiers/bit_blaster.h +++ b/src/ast/simplifiers/bit_blaster.h @@ -21,14 +21,14 @@ Author: #include "ast/simplifiers/dependent_expr_state.h" -class bit_blaster : public dependent_expr_simplifier { +class bit_blaster_simplifier : public dependent_expr_simplifier { bit_blaster_rewriter m_rewriter; unsigned m_num_steps = 0; params_ref m_params; public: - bit_blaster(ast_manager & m, params_ref const & p, dependent_expr_state& s): + bit_blaster_simplifier(ast_manager & m, params_ref const & p, dependent_expr_state& s): dependent_expr_simplifier(m, s), m_rewriter(m, p) { updt_params(p); diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index 7c716c481..31888251c 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -98,7 +98,7 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep s.add_simplifier(alloc(card2bv, m, p, st)); s.add_simplifier(alloc(rewriter_simplifier, m, simp1_p, st)); s.add_simplifier(mk_max_bv_sharing(m, p, st)); - s.add_simplifier(alloc(bit_blaster, m, p, st)); + s.add_simplifier(alloc(bit_blaster_simplifier, m, p, st)); s.add_simplifier(alloc(rewriter_simplifier, m, simp2_p, st)); } } From c0f1f338985898c059da924878715e5709f2eaa8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 18:47:32 -0800 Subject: [PATCH 442/477] dampen second setup of theory_bv --- src/smt/smt_setup.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index aed515ef0..854ddb9e0 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -689,9 +689,12 @@ namespace smt { } void setup::setup_bv() { + family_id bv_fid = m_manager.mk_family_id("bv"); + if (m_context.get_theory(bv_fid)) + return; switch(m_params.m_bv_mode) { case BS_NO_BV: - m_context.register_plugin(alloc(smt::theory_dummy, m_context, m_manager.mk_family_id("bv"), "no bit-vector")); + m_context.register_plugin(alloc(smt::theory_dummy, m_context, bv_fid, "no bit-vector")); break; case BS_BLASTER: m_context.register_plugin(alloc(smt::theory_bv, m_context)); From f6d411d54bbe80d5b305e9c2ae30b40c0ed358ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2022 21:41:27 -0800 Subject: [PATCH 443/477] experimental feature to access congruence closure of SimpleSolver This update includes an experimental feature to access a congruence closure data-structure after search. It comes with several caveats as pre-processing is free to eliminate terms. It is therefore necessary to use a solver that does not eliminate the terms you want to track for congruence of. This is partially addressed by using SimpleSolver or incremental mode solving. ```python from z3 import * s = SimpleSolver() x, y, z = Ints('x y z') s.add(x == y) s.add(y == z) s.check() print(s.root(x), s.root(y), s.root(z)) print(s.next(x), s.next(y), s.next(z)) ``` --- src/api/api_solver.cpp | 20 ++++++++++++++++++ src/api/python/z3/z3.py | 16 ++++++++++++++ src/api/z3_api.h | 20 ++++++++++++++++++ src/ast/converters/expr_inverter.cpp | 21 ++++++++++++------- src/ast/converters/expr_inverter.h | 7 +++++-- src/ast/simplifiers/elim_unconstrained.cpp | 7 ++++--- src/muz/spacer/spacer_iuc_solver.h | 2 ++ src/opt/opt_solver.h | 2 ++ src/sat/sat_solver/inc_sat_solver.cpp | 4 ++++ src/sat/sat_solver/sat_smt_solver.cpp | 3 +++ src/smt/smt_kernel.cpp | 14 +++++++++++++ src/smt/smt_kernel.h | 7 +++++++ src/smt/smt_solver.cpp | 4 ++++ src/solver/combined_solver.cpp | 4 ++++ src/solver/solver.h | 9 ++++++++ src/solver/solver_pool.cpp | 3 +++ src/solver/tactic2solver.cpp | 3 +++ .../fd_solver/bounded_int2bv_solver.cpp | 2 ++ src/tactic/fd_solver/enum2bv_solver.cpp | 3 +++ src/tactic/fd_solver/pb2bv_solver.cpp | 2 ++ src/tactic/fd_solver/smtfd_solver.cpp | 4 ++++ 21 files changed, 145 insertions(+), 12 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index b93fb42af..2ca54a599 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -903,6 +903,26 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } + Z3_ast Z3_API Z3_solver_congruence_root(Z3_context c, Z3_solver s, Z3_ast a) { + Z3_TRY; + LOG_Z3_solver_congruence_root(c, s, a); + RESET_ERROR_CODE(); + init_solver(c, s); + expr* r = to_solver_ref(s)->congruence_root(to_expr(a)); + RETURN_Z3(of_expr(r)); + Z3_CATCH_RETURN(nullptr); + } + + Z3_ast Z3_API Z3_solver_congruence_next(Z3_context c, Z3_solver s, Z3_ast a) { + Z3_TRY; + LOG_Z3_solver_congruence_next(c, s, a); + RESET_ERROR_CODE(); + init_solver(c, s); + expr* sib = to_solver_ref(s)->congruence_next(to_expr(a)); + RETURN_Z3(of_expr(sib)); + Z3_CATCH_RETURN(nullptr); + } + class api_context_obj : public user_propagator::context_obj { api::context* c; public: diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1f24222ad..695bb939f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7241,6 +7241,22 @@ class Solver(Z3PPObject): cube are likely more useful to cube on.""" return self.cube_vs + def root(self, t): + t = _py2expr(t, self.ctx) + """Retrieve congruence closure root of the term t relative to the current search state + The function primarily works for SimpleSolver. Terms and variables that are + eliminated during pre-processing are not visible to the congruence closure. + """ + return _to_expr_ref(Z3_solver_congruence_root(self.ctx.ref(), self.solver, t.ast), self.ctx) + + def next(self, t): + t = _py2expr(t, self.ctx) + """Retrieve congruence closure sibling of the term t relative to the current search state + The function primarily works for SimpleSolver. Terms and variables that are + eliminated during pre-processing are not visible to the congruence closure. + """ + return _to_expr_ref(Z3_solver_congruence_next(self.ctx.ref(), self.solver, t.ast), self.ctx) + def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" return _to_expr_ref(Z3_solver_get_proof(self.ctx.ref(), self.solver), self.ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7a0b47da0..ffa0d8665 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6882,6 +6882,26 @@ extern "C" { */ void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]); + /** + \brief retrieve the congruence closure root of an expression. + The root is retrieved relative to the state where the solver was in when it completed. + If it completed during a set of case splits, the congruence roots are relative to these case splits. + That is, the congruences are not consequences but they are true under the current state. + + def_API('Z3_solver_congruence_root', AST, (_in(CONTEXT), _in(SOLVER), _in(AST))) + */ + Z3_ast Z3_API Z3_solver_congruence_root(Z3_context c, Z3_solver s, Z3_ast a); + + + /** + \brief retrieve the next expression in the congruence class. The set of congruent siblings form a cyclic list. + Repeated calls on the siblings will result in returning to the original expression. + + def_API('Z3_solver_congruence_next', AST, (_in(CONTEXT), _in(SOLVER), _in(AST))) + */ + Z3_ast Z3_API Z3_solver_congruence_next(Z3_context c, Z3_solver s, Z3_ast a); + + /** \brief register a callback to that retrieves assumed, inferred and deleted clauses during search. diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index 5553420ad..41a60ccd5 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -81,7 +81,7 @@ public: * */ - bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, proof_ref& pr) override { SASSERT(f->get_family_id() == m.get_basic_family_id()); switch (f->get_decl_kind()) { case OP_ITE: @@ -233,7 +233,7 @@ public: } - bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, proof_ref& pr) override { SASSERT(f->get_family_id() == a.get_family_id()); switch (f->get_decl_kind()) { case OP_ADD: @@ -531,7 +531,7 @@ class bv_expr_inverter : public iexpr_inverter { * y := 0 * */ - bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, proof_ref& pr) override { SASSERT(f->get_family_id() == bv.get_family_id()); switch (f->get_decl_kind()) { case OP_BADD: @@ -611,7 +611,7 @@ public: family_id get_fid() const override { return a.get_family_id(); } - bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, proof_ref& pr) override { SASSERT(f->get_family_id() == a.get_family_id()); switch (f->get_decl_kind()) { case OP_SELECT: @@ -679,7 +679,7 @@ public: * head(x) -> fresh * x := cons(fresh, arb) */ - bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, expr_ref& side_cond) override { + bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r, proof_ref& pr) override { if (dt.is_accessor(f)) { SASSERT(num == 1); if (uncnstr(args[0])) { @@ -799,7 +799,7 @@ expr_inverter::expr_inverter(ast_manager& m): iexpr_inverter(m) { } -bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) { +bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& new_expr, proof_ref& pr) { if (num == 0) return false; @@ -812,7 +812,7 @@ bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, ex return false; auto* p = m_inverters.get(fid, nullptr); - return p && (*p)(f, num, args, new_expr, side_cond); + return p && (*p)(f, num, args, new_expr, pr); } bool expr_inverter::mk_diff(expr* t, expr_ref& r) { @@ -849,3 +849,10 @@ void expr_inverter::set_model_converter(generic_model_converter* mc) { if (p) p->set_model_converter(mc); } + +void expr_inverter::set_produce_proofs(bool pr) { + m_produce_proofs = pr; + for (auto* p : m_inverters) + if (p) + p->set_produce_proofs(pr); +} diff --git a/src/ast/converters/expr_inverter.h b/src/ast/converters/expr_inverter.h index 5b7965478..60540aff3 100644 --- a/src/ast/converters/expr_inverter.h +++ b/src/ast/converters/expr_inverter.h @@ -24,6 +24,7 @@ protected: ast_manager& m; std::function m_is_var; generic_model_converter_ref m_mc; + bool m_produce_proofs = false; bool uncnstr(expr* e) const { return m_is_var(e); } bool uncnstr(unsigned num, expr * const * args) const; @@ -37,8 +38,9 @@ public: virtual ~iexpr_inverter() {} virtual void set_is_var(std::function& is_var) { m_is_var = is_var; } virtual void set_model_converter(generic_model_converter* mc) { m_mc = mc; } + virtual void set_produce_proofs(bool p) { m_produce_proofs = true; } - virtual bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) = 0; + virtual bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, proof_ref& pr) = 0; virtual bool mk_diff(expr* t, expr_ref& r) = 0; virtual family_id get_fid() const = 0; }; @@ -49,9 +51,10 @@ class expr_inverter : public iexpr_inverter { public: expr_inverter(ast_manager& m); ~expr_inverter() override; - bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, expr_ref& side_cond) override; + bool operator()(func_decl* f, unsigned n, expr* const* args, expr_ref& new_expr, proof_ref& pr) override; bool mk_diff(expr* t, expr_ref& r) override; void set_is_var(std::function& is_var) override; void set_model_converter(generic_model_converter* mc) override; + void set_produce_proofs(bool p) override; family_id get_fid() const override { return null_family_id; } }; diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index df6f92251..41a905dea 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -62,7 +62,8 @@ bool elim_unconstrained::is_var_lt(int v1, int v2) const { void elim_unconstrained::eliminate() { while (!m_heap.empty()) { - expr_ref r(m), side_cond(m); + expr_ref r(m); + proof_ref pr(m); int v = m_heap.erase_min(); node& n = get_node(v); if (n.m_refcount == 0) @@ -84,7 +85,7 @@ void elim_unconstrained::eliminate() { unsigned sz = m_args.size(); for (expr* arg : *to_app(t)) m_args.push_back(reconstruct_term(get_node(arg))); - bool inverted = m_inverter(t->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz, r, side_cond); + bool inverted = m_inverter(t->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz, r, pr); n.m_refcount = 0; m_args.shrink(sz); if (!inverted) { @@ -113,7 +114,7 @@ void elim_unconstrained::eliminate() { IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(get_node(v).m_orig, m) << " " << mk_bounded_pp(t, m) << " -> " << r << " " << get_node(e).m_refcount << "\n";); - SASSERT(!side_cond && "not implemented to add side conditions\n"); + SASSERT(!pr && "not implemented to add proofs\n"); } } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 0d4712215..e201a1fe1 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -122,6 +122,8 @@ public: void set_phase(phase* p) override { m_solver.set_phase(p); } void move_to_front(expr* e) override { m_solver.move_to_front(e); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } + expr* congruence_root(expr* e) override { return e; } + expr* congruence_next(expr* e) override { return e; } void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); } expr_ref_vector get_trail(unsigned max_level) override { return m_solver.get_trail(max_level); } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 84d31ed0f..2682fca09 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -110,6 +110,8 @@ namespace opt { void get_levels(ptr_vector const& vars, unsigned_vector& depth) override; expr_ref_vector get_trail(unsigned max_level) override { return m_context.get_trail(max_level); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } + expr* congruence_root(expr* e) override { return e; } + expr* congruence_next(expr* e) override { return e; } void set_phase(expr* e) override { m_context.set_phase(e); } phase* get_phase() override { return m_context.get_phase(); } void set_phase(phase* p) override { m_context.set_phase(p); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 41b8e609c..0362d8d3e 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -463,6 +463,10 @@ public: } return fmls; } + + expr* congruence_next(expr* e) override { return e; } + expr* congruence_root(expr* e) override { return e; } + lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) override { init_preprocess(); diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index e37d513a0..f5872b05a 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -476,6 +476,9 @@ public: set_reason_unknown(m_solver.get_reason_unknown()); return fmls; } + + expr* congruence_next(expr* e) override { return e; } + expr* congruence_root(expr* e) override { return e; } lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index ae3338f52..c4ecf6787 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -213,6 +213,20 @@ namespace smt { return out; } + expr* kernel::congruence_root(expr * e) { + smt::enode* n = m_imp->m_kernel.find_enode(e); + if (!n) + return e; + return n->get_root()->get_expr(); + } + + expr* kernel::congruence_next(expr * e) { + smt::enode* n = m_imp->m_kernel.find_enode(e); + if (!n) + return e; + return n->get_next()->get_expr(); + } + void kernel::collect_statistics(::statistics & st) const { m_imp->m_kernel.collect_statistics(st); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index fa4a48406..ccea5caf8 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -239,6 +239,13 @@ namespace smt { */ expr_ref_vector cubes(unsigned depth); + /** + \brief access congruence closure + */ + expr* congruence_next(expr* e); + + expr* congruence_root(expr* e); + /** \brief retrieve depth of variables from decision stack. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 61c7fdda7..4be78b20a 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -330,6 +330,10 @@ namespace { m_context.get_units(units); } + expr* congruence_next(expr* e) override { return m_context.congruence_next(e); } + expr* congruence_root(expr* e) override { return m_context.congruence_root(e); } + + expr_ref_vector cube(expr_ref_vector& vars, unsigned cutoff) override { ast_manager& m = get_manager(); if (!m_cuber) { diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 7b1449637..53aa56753 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -275,6 +275,10 @@ public: return m_solver2->cube(vars, backtrack_level); } + expr* congruence_next(expr* e) override { switch_inc_mode(); return m_solver2->congruence_next(e); } + expr* congruence_root(expr* e) override { switch_inc_mode(); return m_solver2->congruence_root(e); } + + expr * get_assumption(unsigned idx) const override { unsigned c1 = m_solver1->get_num_assumptions(); if (idx < c1) return m_solver1->get_assumption(idx); diff --git a/src/solver/solver.h b/src/solver/solver.h index 957cb7c8e..7d7a3eec2 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -238,6 +238,15 @@ public: virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) = 0; + /** + \brief retrieve congruence closure root. + */ + virtual expr* congruence_root(expr* e) = 0; + + /** + \brief retrieve congruence closure sibling + */ + virtual expr* congruence_next(expr* e) = 0; /** \brief Display the content of this solver. diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index f5760bde3..411634162 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -262,6 +262,9 @@ public: expr_ref_vector cube(expr_ref_vector& vars, unsigned ) override { return expr_ref_vector(m); } + expr* congruence_next(expr* e) override { return e; } + expr* congruence_root(expr* e) override { return e; } + ast_manager& get_manager() const override { return m_base->get_manager(); } void refresh(solver* new_base) { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index b65ffde57..cc3ac9336 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -136,6 +136,9 @@ public: return expr_ref_vector(get_manager()); } + expr* congruence_next(expr* e) override { return e; } + expr* congruence_root(expr* e) override { return e; } + model_converter_ref get_model_converter() const override { return m_mc; } void get_levels(ptr_vector const& vars, unsigned_vector& depth) override { diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index 7b7ca630e..4ac82c0c2 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -210,6 +210,8 @@ public: void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } void get_labels(svector & r) override { m_solver->get_labels(r); } ast_manager& get_manager() const override { return m; } + expr* congruence_next(expr* e) override { return m_solver->congruence_next(e); } + expr* congruence_root(expr* e) override { return m_solver->congruence_root(e); } expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) override { flush_assertions(); return m_solver->cube(vars, backtrack_level); } lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_solver->find_mutexes(vars, mutexes); } lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { diff --git a/src/tactic/fd_solver/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp index 7ec5243e7..2690e7033 100644 --- a/src/tactic/fd_solver/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -131,6 +131,9 @@ public: expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) override { return m_solver->cube(vars, backtrack_level); } + expr* congruence_next(expr* e) override { return m_solver->congruence_next(e); } + expr* congruence_root(expr* e) override { return m_solver->congruence_root(e); } + lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { datatype_util dt(m); diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index 1a5f7d16a..19f2630f2 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -122,6 +122,8 @@ public: void get_labels(svector & r) override { m_solver->get_labels(r); } ast_manager& get_manager() const override { return m; } expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) override { flush_assertions(); return m_solver->cube(vars, backtrack_level); } + expr* congruence_next(expr* e) override { return m_solver->congruence_next(e); } + expr* congruence_root(expr* e) override { return m_solver->congruence_root(e); } lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_solver->find_mutexes(vars, mutexes); } lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { flush_assertions(); diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index 3729a2ad1..5676c6ee8 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -2086,6 +2086,10 @@ namespace smtfd { expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) override { return expr_ref_vector(m); } + + expr* congruence_root(expr* e) override { return e; } + + expr* congruence_next(expr* e) override { return e; } lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { return l_undef; From dbf93c5fbdf458396c38993fdcac54f4e0803824 Mon Sep 17 00:00:00 2001 From: Walden Yan Date: Sun, 1 Jan 2023 18:27:54 -0500 Subject: [PATCH 444/477] Fixing array select for lambda expressions in Python API (#6516) * fix: making array select work for lambda expressions * more elegant solution --- src/api/python/z3/z3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 695bb939f..074570b03 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4597,10 +4597,10 @@ class ArrayRef(ExprRef): def _array_select(ar, arg): if isinstance(arg, tuple): - args = [ar.domain_n(i).cast(arg[i]) for i in range(len(arg))] + args = [ar.sort().domain_n(i).cast(arg[i]) for i in range(len(arg))] _args, sz = _to_ast_array(args) return _to_expr_ref(Z3_mk_select_n(ar.ctx_ref(), ar.as_ast(), sz, _args), ar.ctx) - arg = ar.domain().cast(arg) + arg = ar.sort().domain().cast(arg) return _to_expr_ref(Z3_mk_select(ar.ctx_ref(), ar.as_ast(), arg.as_ast()), ar.ctx) From ea0d09b6c89c455271ecf16a1f7337fcaa395c9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Jan 2023 16:49:31 -0800 Subject: [PATCH 445/477] add pointer to build parameters to README #6518 Signed-off-by: Nikolaj Bjorner --- src/api/js/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/js/README.md b/src/api/js/README.md index 42c29518e..8c446b910 100644 --- a/src/api/js/README.md +++ b/src/api/js/README.md @@ -11,6 +11,9 @@ You'll need to have emscripten set up, along with all of its dependencies. The e Then run `npm i` to install dependencies, `npm run build:ts` to build the TypeScript wrapper, and `npm run build:wasm` to build the wasm artifact. +### Build on your own + +Consult the file [build-wasm.ts](https://github.com/Z3Prover/z3/blob/master/src/api/js/scripts/build-wasm.ts) for configurations used for building wasm. ## Tests From d30cb55bae24113468b3ae6f07d39536402b4891 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 3 Jan 2023 09:35:17 +0000 Subject: [PATCH 446/477] don't flush stream when printing param vals --- src/params/bit_blaster_params.h | 4 ++-- src/params/pattern_inference_params.cpp | 2 +- src/smt/params/dyn_ack_params.cpp | 2 +- src/smt/params/preprocessor_params.cpp | 2 +- src/smt/params/qi_params.cpp | 2 +- src/smt/params/smt_params.cpp | 2 +- src/smt/params/theory_arith_params.cpp | 2 +- src/smt/params/theory_array_params.cpp | 2 +- src/smt/params/theory_bv_params.cpp | 2 +- src/smt/params/theory_datatype_params.h | 2 +- src/smt/params/theory_pb_params.cpp | 2 +- src/smt/params/theory_str_params.cpp | 2 +- src/tactic/smtlogics/smt_tactic.cpp | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/params/bit_blaster_params.h b/src/params/bit_blaster_params.h index 527835d2a..9e405f187 100644 --- a/src/params/bit_blaster_params.h +++ b/src/params/bit_blaster_params.h @@ -33,8 +33,8 @@ struct bit_blaster_params { #endif void display(std::ostream & out) const { - out << "m_bb_ext_gates=" << m_bb_ext_gates << std::endl; - out << "m_bb_quantifiers=" << m_bb_quantifiers << std::endl; + out << "m_bb_ext_gates=" << m_bb_ext_gates << '\n'; + out << "m_bb_quantifiers=" << m_bb_quantifiers << '\n'; } }; diff --git a/src/params/pattern_inference_params.cpp b/src/params/pattern_inference_params.cpp index bb9b481ca..26f606b63 100644 --- a/src/params/pattern_inference_params.cpp +++ b/src/params/pattern_inference_params.cpp @@ -31,7 +31,7 @@ void pattern_inference_params::updt_params(params_ref const & _p) { m_pi_warnings = p.warnings(); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void pattern_inference_params::display(std::ostream & out) const { DISPLAY_PARAM(m_pi_max_multi_patterns); diff --git a/src/smt/params/dyn_ack_params.cpp b/src/smt/params/dyn_ack_params.cpp index b1e99cf21..57645903d 100644 --- a/src/smt/params/dyn_ack_params.cpp +++ b/src/smt/params/dyn_ack_params.cpp @@ -29,7 +29,7 @@ void dyn_ack_params::updt_params(params_ref const & _p) { m_dack_gc_inv_decay = p.dack_gc_inv_decay(); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void dyn_ack_params::display(std::ostream & out) const { DISPLAY_PARAM((unsigned)m_dack); diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 9fcb09843..f3c46f95c 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -34,7 +34,7 @@ void preprocessor_params::updt_params(params_ref const & p) { updt_local_params(p); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void preprocessor_params::display(std::ostream & out) const { pattern_inference_params::display(out); diff --git a/src/smt/params/qi_params.cpp b/src/smt/params/qi_params.cpp index 387df4dd5..d6b22d9f1 100644 --- a/src/smt/params/qi_params.cpp +++ b/src/smt/params/qi_params.cpp @@ -39,7 +39,7 @@ void qi_params::updt_params(params_ref const & _p) { m_qi_quick_checker = static_cast(p.qi_quick_checker()); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void qi_params::display(std::ostream & out) const { DISPLAY_PARAM(m_qi_cost); diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 37249fdac..3c63e2fff 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -85,7 +85,7 @@ void smt_params::updt_params(context_params const & p) { m_model = p.m_model; } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void smt_params::display(std::ostream & out) const { preprocessor_params::display(out); diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 565000ebe..7f3f1ca23 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -42,7 +42,7 @@ void theory_arith_params::updt_params(params_ref const & _p) { } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void theory_arith_params::display(std::ostream & out) const { DISPLAY_PARAM(m_arith_eq2ineq); diff --git a/src/smt/params/theory_array_params.cpp b/src/smt/params/theory_array_params.cpp index 892edb4ad..2283be256 100644 --- a/src/smt/params/theory_array_params.cpp +++ b/src/smt/params/theory_array_params.cpp @@ -25,7 +25,7 @@ void theory_array_params::updt_params(params_ref const & _p) { m_array_extensional = p.array_extensional(); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void theory_array_params::display(std::ostream & out) const { DISPLAY_PARAM(m_array_mode); diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index 35a62e7fc..09fa4513f 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -31,7 +31,7 @@ void theory_bv_params::updt_params(params_ref const & _p) { m_bv_size_reduce = p.bv_size_reduce(); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void theory_bv_params::display(std::ostream & out) const { DISPLAY_PARAM(m_bv_mode); diff --git a/src/smt/params/theory_datatype_params.h b/src/smt/params/theory_datatype_params.h index 05957bfe9..b16f4254a 100644 --- a/src/smt/params/theory_datatype_params.h +++ b/src/smt/params/theory_datatype_params.h @@ -32,7 +32,7 @@ struct theory_datatype_params { m_dt_lazy_splits = p.dt_lazy_splits(); } - void display(std::ostream & out) const { out << "m_dt_lazy_splits=" << m_dt_lazy_splits << std::endl; } + void display(std::ostream & out) const { out << "m_dt_lazy_splits=" << m_dt_lazy_splits << '\n'; } }; diff --git a/src/smt/params/theory_pb_params.cpp b/src/smt/params/theory_pb_params.cpp index 45a6ede10..2df8d6fee 100644 --- a/src/smt/params/theory_pb_params.cpp +++ b/src/smt/params/theory_pb_params.cpp @@ -25,7 +25,7 @@ void theory_pb_params::updt_params(params_ref const & _p) { m_pb_learn_complements = p.pb_learn_complements(); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void theory_pb_params::display(std::ostream & out) const { DISPLAY_PARAM(m_pb_conflict_frequency); diff --git a/src/smt/params/theory_str_params.cpp b/src/smt/params/theory_str_params.cpp index e0802b5d7..7f84a6cbe 100644 --- a/src/smt/params/theory_str_params.cpp +++ b/src/smt/params/theory_str_params.cpp @@ -37,7 +37,7 @@ void theory_str_params::updt_params(params_ref const & _p) { m_FixedLengthNaiveCounterexamples = p.str_fixed_length_naive_cex(); } -#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +#define DISPLAY_PARAM(X) out << #X"=" << X << '\n'; void theory_str_params::display(std::ostream & out) const { DISPLAY_PARAM(m_StrongArrangements); diff --git a/src/tactic/smtlogics/smt_tactic.cpp b/src/tactic/smtlogics/smt_tactic.cpp index d47650c34..aefe7ccad 100644 --- a/src/tactic/smtlogics/smt_tactic.cpp +++ b/src/tactic/smtlogics/smt_tactic.cpp @@ -23,7 +23,7 @@ Author: tactic * mk_smt_tactic(ast_manager & m, params_ref const & p) { sat_params sp(p); - if (sp.smt()) + if (sp.smt()) return mk_solver2tactic(mk_smt2_solver(m, p)); if (sp.euf()) return mk_sat_tactic(m, p); From a2cc504d4a85755f23df2f1d1b18dbff3fcaf0dc Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 3 Jan 2023 09:49:58 +0000 Subject: [PATCH 447/477] remove a couple more std::endl --- src/math/lp/mps_reader.h | 4 ++-- src/tactic/core/collect_statistics_tactic.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/math/lp/mps_reader.h b/src/math/lp/mps_reader.h index f2cf2d320..8093954b1 100644 --- a/src/math/lp/mps_reader.h +++ b/src/math/lp/mps_reader.h @@ -277,8 +277,8 @@ class mps_reader { } else { fail: set_m_ok_to_false(); - *m_message_stream << "cannot understand this line" << std::endl; - *m_message_stream << "line = " << m_line << ", line number is " << m_line_number << std::endl; + *m_message_stream << "cannot understand this line\n" + "line = " << m_line << ", line number is " << m_line_number << std::endl; return; } } diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index b02adad6e..b2c46cae6 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -73,10 +73,10 @@ public: for (unsigned i = 0; i < sz; i++) for_each_expr(cp, visited, g->form(i)); - std::cout << "(" << std::endl; + std::cout << "(\n"; for (auto const& kv : m_stats) - std::cout << " :" << kv.first << " " << kv.second << std::endl; - std::cout << ")" << std::endl; + std::cout << " :" << kv.first << " " << kv.second << '\n'; + std::cout << ")\n"; g->inc_depth(); result.push_back(g.get()); From e508ef17f6d6d716f88906d7f7acb35bece9bc92 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 3 Jan 2023 10:39:28 +0000 Subject: [PATCH 448/477] fix Alive bug #875: bit blaster not respecting soft memory limit --- src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index dc1df22a3..7a3ee0ea6 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -27,7 +27,7 @@ Revision History: template void bit_blaster_tpl::checkpoint() { - if (memory::get_allocation_size() > m_max_memory) + if (memory::get_allocation_size() > m_max_memory || memory::above_high_watermark()) throw rewriter_exception(Z3_MAX_MEMORY_MSG); if (!m().inc()) throw rewriter_exception(m().limit().get_cancel_msg()); From e448191212c319f9388e0ddf6845b55de1348465 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 3 Jan 2023 11:08:57 +0000 Subject: [PATCH 449/477] array rewriter: expand select of store with const array into an ite This: (simplify (select (store ((as const (Array (_ BitVec 4) (_ BitVec 4))) #x0) x #x1) y)) => (ite (= x y) #x1 #x0) --- src/ast/rewriter/array_rewriter.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index dd0e7e869..08173d430 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -228,14 +228,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, } return true; }; + expr *array = to_app(args[0])->get_arg(0); + bool is_leaf = m_util.is_const(array); bool should_expand = m_blast_select_store || + is_leaf || are_values() || - (m_expand_select_store && to_app(args[0])->get_arg(0)->get_ref_count() == 1); + (m_expand_select_store && array->get_ref_count() == 1); if (should_expand) { // select(store(a, I, v), J) --> ite(I=J, v, select(a, J)) ptr_buffer new_args; - new_args.push_back(to_app(args[0])->get_arg(0)); + new_args.push_back(array); new_args.append(num_args-1, args+1); expr * sel_a_j = m().mk_app(get_fid(), OP_SELECT, num_args, new_args.data()); expr * v = to_app(args[0])->get_arg(num_args); From 6f95c77023ea3793b3a631798eff02e04901938d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 11:56:28 -0800 Subject: [PATCH 450/477] fix bugs in flatten_clauses simplifier, switch proof/fml Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/dependent_expr.h | 3 ++- src/ast/simplifiers/flatten_clauses.h | 8 ++++---- src/sat/sat_solver/sat_smt_solver.cpp | 2 +- src/tactic/dependent_expr_state_tactic.h | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ast/simplifiers/dependent_expr.h b/src/ast/simplifiers/dependent_expr.h index c1ba9dd2d..3b7515fe9 100644 --- a/src/ast/simplifiers/dependent_expr.h +++ b/src/ast/simplifiers/dependent_expr.h @@ -32,6 +32,7 @@ public: m_fml(fml), m_proof(p), m_dep(d) { + SASSERT(fml); m.inc_ref(fml); m.inc_ref(d); m.inc_ref(p); @@ -122,4 +123,4 @@ public: inline std::ostream& operator<<(std::ostream& out, dependent_expr const& d) { return d.display(out); -} \ No newline at end of file +} diff --git a/src/ast/simplifiers/flatten_clauses.h b/src/ast/simplifiers/flatten_clauses.h index e2da2d182..ab02faca1 100644 --- a/src/ast/simplifiers/flatten_clauses.h +++ b/src/ast/simplifiers/flatten_clauses.h @@ -67,8 +67,8 @@ public: decomposed = true; if (decomposed) { for (expr* arg : *to_app(b)) - m_fmls.add(dependent_expr(m, nullptr, m.mk_or(a, mk_not(m, arg)), de.dep())); - m_fmls.update(idx, dependent_expr(m, nullptr, m.mk_true(), nullptr)); + m_fmls.add(dependent_expr(m, m.mk_or(a, mk_not(m, arg)), nullptr, de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr, nullptr)); ++m_num_flat; continue; } @@ -79,8 +79,8 @@ public: decomposed = true; if (decomposed) { for (expr * arg : *to_app(b)) - m_fmls.add(dependent_expr(m, nullptr, m.mk_or(a, arg), de.dep())); - m_fmls.update(idx, dependent_expr(m, nullptr, m.mk_true(), nullptr)); + m_fmls.add(dependent_expr(m, m.mk_or(a, arg), nullptr, de.dep())); + m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr, nullptr)); ++m_num_flat; continue; } diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index f5872b05a..cc138be9b 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -56,7 +56,7 @@ class sat_smt_solver : public solver { ~dep_expr_state() override {} virtual unsigned qtail() const override { return s.m_fmls.size(); } dependent_expr const& operator[](unsigned i) override { return s.m_fmls[i]; } - void update(unsigned i, dependent_expr const& j) override { s.m_fmls[i] = j; } + void update(unsigned i, dependent_expr const& j) override { SASSERT(j.fml()); s.m_fmls[i] = j; } void add(dependent_expr const& j) override { s.m_fmls.push_back(j); } bool inconsistent() override { return s.m_solver.inconsistent(); } model_reconstruction_trail& model_trail() override { return m_reconstruction_trail; } diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index bf33d7fd2..931fc7c26 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -48,7 +48,7 @@ public: dependent_expr_state(m), m(m), m_params(p), - m_dep(m, nullptr, nullptr, nullptr), + m_dep(m, m.mk_true(), nullptr, nullptr), m_factory(f) {} @@ -129,7 +129,7 @@ public: m_simp = nullptr; m_model_trail = nullptr; m_goal = nullptr; - m_dep = dependent_expr(m, nullptr, nullptr, nullptr); + m_dep = dependent_expr(m, m.mk_true(), nullptr, nullptr); } void collect_statistics(statistics & st) const override { From aa080a6b19cfcc10cd03c2a281ed0a98a27c09e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 12:22:38 -0800 Subject: [PATCH 451/477] update ignore-int handling #6429 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/arith_solver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index a69f3604e..c7318dbd7 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -971,6 +971,7 @@ namespace arith { } auto st = sat::check_result::CR_DONE; + bool int_undef = false; TRACE("arith", ctx.display(tout);); @@ -984,9 +985,7 @@ namespace arith { return sat::check_result::CR_CONTINUE; case l_undef: TRACE("arith", tout << "check-lia giveup\n";); - if (ctx.get_config().m_arith_ignore_int) - return sat::check_result::CR_GIVEUP; - + int_undef = true; st = sat::check_result::CR_CONTINUE; break; } @@ -1012,6 +1011,8 @@ namespace arith { } if (!check_delayed_eqs()) return sat::check_result::CR_CONTINUE; + if (ctx.get_config().m_arith_ignore_int && int_undef) + return sat::check_result::CR_GIVEUP; if (m_not_handled != nullptr) { TRACE("arith", tout << "unhandled operator " << mk_pp(m_not_handled, m) << "\n";); return sat::check_result::CR_GIVEUP; From ef101190056d5d856cf34135645916f01be6c20e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 13:05:45 -0800 Subject: [PATCH 452/477] #6429 fixes --- src/math/simplex/model_based_opt.cpp | 4 ++-- src/sat/sat_solver/sat_smt_solver.cpp | 2 +- src/sat/smt/euf_solver.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 8df04327d..f53ab6f8f 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1510,7 +1510,7 @@ namespace opt { for (unsigned v : vs) { - def v_def = project(v, false); + def v_def = project(v, compute_def); if (compute_def) eliminate(v, v_def); } @@ -1739,7 +1739,7 @@ namespace opt { for (unsigned i = 0; i < num_vars; ++i) { m_result.push_back(project(vars[i], compute_def)); eliminate(vars[i], m_result.back()); - TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n");); + TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n" << m_result << "\n");); } return m_result; } diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index cc138be9b..923594501 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -179,8 +179,8 @@ public: m_preprocess_state(*this), m_preprocess(m, p, m_preprocess_state), m_trail(m_preprocess_state.m_trail), - m_dep(m, m_trail), m_solver(p, m.limit()), + m_dep(m, m_trail), m_assumptions(m), m_core(m), m_ors(m), m_aux_fmls(m), m_internalized_fmls(m), m_map(m), m_mc(alloc(generic_model_converter, m, "sat-smt-solver")) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 865608339..e34a590f8 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -48,11 +48,11 @@ namespace euf { m_unhandled_functions(m), m_to_m(&m), m_to_si(&si), - m_values(m), m_clause_visitor(m), m_smt_proof_checker(m, p), - m_clause(m), - m_expr_args(m) + m_clause(m), + m_expr_args(m), + m_values(m) { updt_params(p); m_relevancy.set_enabled(get_config().m_relevancy_lvl > 2); From 21362c0b989456d7f842a639e08b63dcc3c7b63e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 15:00:25 -0800 Subject: [PATCH 453/477] make case-def and recfun-num-rounds re-parsable for logging --- src/ast/recfun_decl_plugin.cpp | 38 +++++++++++++------ src/ast/recfun_decl_plugin.h | 5 ++- src/cmd_context/cmd_context.cpp | 17 +++++---- src/tactic/bv/bit_blaster_model_converter.cpp | 1 + 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 86c3fcf3b..84d68d782 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -36,7 +36,6 @@ namespace recfun { ast_manager &m, family_id fid, def * d, - std::string & name, unsigned case_index, sort_ref_vector const & arg_sorts, expr_ref_vector const& guards, @@ -44,10 +43,10 @@ namespace recfun { : m_pred(m), m_guards(guards), m_rhs(expr_ref(rhs,m)), - m_def(d) { - parameter p(case_index); - func_decl_info info(fid, OP_FUN_CASE_PRED, 1, &p); - m_pred = m.mk_func_decl(symbol(name.c_str()), arg_sorts.size(), arg_sorts.data(), m.mk_bool_sort(), info); + m_def(d) { + parameter ps[2] = { parameter(case_index), parameter(d->get_decl()) }; + func_decl_info info(fid, OP_FUN_CASE_PRED, 2, ps); + m_pred = m.mk_func_decl(symbol("case-def"), arg_sorts.size(), arg_sorts.data(), m.mk_bool_sort(), info); } def::def(ast_manager &m, family_id fid, symbol const & s, @@ -220,11 +219,10 @@ namespace recfun { } - void def::add_case(std::string & name, unsigned case_index, expr_ref_vector const& conditions, expr * rhs, bool is_imm) { - case_def c(m, m_fid, this, name, case_index, get_domain(), conditions, rhs); + void def::add_case(unsigned case_index, expr_ref_vector const& conditions, expr * rhs, bool is_imm) { + case_def c(m, m_fid, this, case_index, get_domain(), conditions, rhs); c.set_is_immediate(is_imm); - TRACEFN("add_case " << name - << "\n" << mk_pp(rhs, m) + TRACEFN("add_case " << case_index << " " << mk_pp(rhs, m) << "\n:is_imm " << is_imm << "\n:guards " << conditions); m_cases.push_back(c); @@ -261,7 +259,7 @@ namespace recfun { // is the function a macro (unconditional body)? 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); + add_case(0, conditions, rhs); return; } @@ -347,7 +345,7 @@ namespace recfun { // yield new case bool is_imm = is_i(case_rhs); - add_case(name, case_idx++, conditions, case_rhs, is_imm); + add_case(case_idx++, conditions, case_rhs, is_imm); } } @@ -436,6 +434,12 @@ namespace recfun { return *(m_util.get()); } + void plugin::get_op_names(svector & op_names, symbol const & logic) { + op_names.push_back(builtin_name("case-def", OP_FUN_CASE_PRED)); + op_names.push_back(builtin_name("recfun-num-rounds", OP_NUM_ROUNDS)); + } + + promise_def plugin::mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated) { def* d = u().decl_fun(name, n, params, range, is_generated); SASSERT(!m_defs.contains(d->get_decl())); @@ -498,6 +502,18 @@ namespace recfun { func_decl * plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { + func_decl_info info(get_family_id(), k, num_parameters, parameters); + switch (k) { + case OP_FUN_CASE_PRED: + SASSERT(num_parameters == 2); + return m().mk_func_decl(symbol("case-def"), arity, domain, m().mk_bool_sort(), info); + case OP_NUM_ROUNDS: + SASSERT(num_parameters == 1); + SASSERT(arity == 0); + return m().mk_const_decl(symbol("recfun-num-rounds"), m().mk_bool_sort(), info); + default: + break; + } UNREACHABLE(); return nullptr; } diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index bb75a854c..ae9c060e9 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -72,7 +72,6 @@ namespace recfun { case_def(ast_manager & m, family_id fid, def * d, - std::string & name, unsigned case_index, sort_ref_vector const & arg_sorts, expr_ref_vector const& guards, @@ -124,7 +123,7 @@ namespace recfun { // compute cases for a function, given its RHS (possibly containing `ite`). void compute_cases(util& u, replace& subst, is_immediate_pred &, 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); + void add_case(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 public: @@ -190,6 +189,8 @@ namespace recfun { func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) override; + + void get_op_names(svector & op_names, symbol const & logic) override; promise_def mk_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 2d90b70c3..5602f53a3 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1085,7 +1085,12 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, throw cmd_exception("invalid function declaration reference, invalid builtin reference ", s); return f; } - throw cmd_exception("invalid function declaration reference, unknown function ", s); + if (num_indices > 0 && m_func_decls.find(s, fs)) + f = fs.find(m(), arity, domain, range); + if (f) + return f; + + throw cmd_exception("invalid function declaration reference, unknown indexed function ", s); } psort_decl * cmd_context::find_psort_decl(symbol const & s) const { @@ -1134,12 +1139,10 @@ bool cmd_context::try_mk_builtin_app(symbol const & s, unsigned num_args, expr * fid = d2.m_fid; k = d2.m_decl; } - if (num_indices == 0) { - result = m().mk_app(fid, k, 0, nullptr, num_args, args, range); - } - else { - result = m().mk_app(fid, k, num_indices, indices, num_args, args, range); - } + if (num_indices == 0) + result = m().mk_app(fid, k, 0, nullptr, num_args, args, range); + else + result = m().mk_app(fid, k, num_indices, indices, num_args, args, range); CHECK_SORT(result.get()); return nullptr != result.get(); } diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 88ff11683..9a423452f 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -148,6 +148,7 @@ struct bit_blaster_model_converter : public model_converter { for (expr* bit : *to_app(bs)) { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); + CTRACE("bv", !bit_val, tout << mk_pp(bit, m()) << " " << *old_model << "\n"); SASSERT(bit_val); vals.push_back(bit_val); } From 380c701cbe1a16380bf462e5d6ad5d97ebde28c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 15:01:40 -0800 Subject: [PATCH 454/477] restore debug clang/gcc build --- src/math/simplex/model_based_opt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index f53ab6f8f..3c38cfb0e 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1739,7 +1739,7 @@ namespace opt { for (unsigned i = 0; i < num_vars; ++i) { m_result.push_back(project(vars[i], compute_def)); eliminate(vars[i], m_result.back()); - TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n" << m_result << "\n");); + TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n");); } return m_result; } From e0099150ca63f16cdb98ada543492985baf62c10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 15:28:57 -0800 Subject: [PATCH 455/477] #6429 --- src/tactic/bv/bit_blaster_model_converter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 9a423452f..5958a9d38 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -148,8 +148,8 @@ struct bit_blaster_model_converter : public model_converter { for (expr* bit : *to_app(bs)) { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); - CTRACE("bv", !bit_val, tout << mk_pp(bit, m()) << " " << *old_model << "\n"); - SASSERT(bit_val); + if (!bit_val) + bit_val = m().mk_false(); vals.push_back(bit_val); } if (TO_BOOL) From 81ce57b5a84d8903d51b0a3b639da28d36448e15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 15:38:13 -0800 Subject: [PATCH 456/477] #6429 --- src/sat/smt/euf_solver.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index e34a590f8..b56093eb0 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -574,7 +574,7 @@ namespace euf { return sat::check_result::CR_CONTINUE; if (cont) return sat::check_result::CR_CONTINUE; - if (m_qsolver) + if (m_qsolver && !m_config.m_arith_ignore_int) apply_solver(m_qsolver); if (num_nodes < m_egraph.num_nodes()) return sat::check_result::CR_CONTINUE; @@ -582,7 +582,9 @@ namespace euf { return sat::check_result::CR_CONTINUE; TRACE("after_search", s().display(tout);); if (give_up) - return sat::check_result::CR_GIVEUP; + return sat::check_result::CR_GIVEUP; + if (m_qsolver && m_config.m_arith_ignore_int) + return sat::check_result::CR_GIVEUP; return sat::check_result::CR_DONE; } From 0d8a472aacd6541200466d83cf8b06f538751b07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2023 16:55:44 -0800 Subject: [PATCH 457/477] pass sign into literal definition for pbge --- src/sat/smt/pb_internalize.cpp | 12 ++++++------ src/sat/smt/pb_solver.cpp | 4 ++-- src/sat/smt/pb_solver.h | 2 +- src/tactic/tactic.cpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sat/smt/pb_internalize.cpp b/src/sat/smt/pb_internalize.cpp index af25e7a92..1a83dbc87 100644 --- a/src/sat/smt/pb_internalize.cpp +++ b/src/sat/smt/pb_internalize.cpp @@ -113,13 +113,13 @@ namespace pb { k1 += wl.first; } } - add_pb_ge(sat::null_bool_var, wlits, k1); + add_pb_ge(sat::null_bool_var, sign, wlits, k1); return sat::null_literal; } else { bool_var v = s().add_var(true); literal lit(v, sign); - add_pb_ge(v, wlits, k.get_unsigned()); + add_pb_ge(v, sign, wlits, k.get_unsigned()); TRACE("ba", tout << "root: " << root << " lit: " << lit << "\n";); return lit; } @@ -140,13 +140,13 @@ namespace pb { k1 += wl.first; } } - add_pb_ge(sat::null_bool_var, wlits, k1); + add_pb_ge(sat::null_bool_var, sign, wlits, k1); return sat::null_literal; } else { sat::bool_var v = s().add_var(true); sat::literal lit(v, sign); - add_pb_ge(v, wlits, k.get_unsigned()); + add_pb_ge(v, sign, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); return lit; } @@ -160,14 +160,14 @@ namespace pb { bool base_assert = (root && !sign && s().num_user_scopes() == 0); bool_var v1 = base_assert ? sat::null_bool_var : s().add_var(true); bool_var v2 = base_assert ? sat::null_bool_var : s().add_var(true); - add_pb_ge(v1, wlits, k.get_unsigned()); + add_pb_ge(v1, false, wlits, k.get_unsigned()); k.neg(); for (wliteral& wl : wlits) { wl.second.neg(); k += rational(wl.first); } check_unsigned(k); - add_pb_ge(v2, wlits, k.get_unsigned()); + add_pb_ge(v2, false, wlits, k.get_unsigned()); if (base_assert) { return sat::null_literal; } diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 424b20d4e..ade48c42b 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -1472,8 +1472,8 @@ namespace pb { return p; } - void solver::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { - literal lit = v == sat::null_bool_var ? sat::null_literal : literal(v, false); + void solver::add_pb_ge(bool_var v, bool sign, svector const& wlits, unsigned k) { + literal lit = v == sat::null_bool_var ? sat::null_literal : literal(v, sign); add_pb_ge(lit, wlits, k, m_is_redundant); } diff --git a/src/sat/smt/pb_solver.h b/src/sat/smt/pb_solver.h index f6a0c049e..99ea45983 100644 --- a/src/sat/smt/pb_solver.h +++ b/src/sat/smt/pb_solver.h @@ -371,7 +371,7 @@ namespace pb { ~solver() override; void set_lookahead(sat::lookahead* l) override { m_lookahead = l; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); - void add_pb_ge(bool_var v, svector const& wlits, unsigned k); + void add_pb_ge(bool_var v, bool sign, svector const& wlits, unsigned k); bool is_external(bool_var v) override; bool propagated(literal l, sat::ext_constraint_idx idx) override; diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 8bf6efac5..179a42ab8 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -51,7 +51,7 @@ struct tactic_report::imp { << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << " :before-memory " << std::fixed << std::setprecision(2) << m_start_memory << " :after-memory " << std::fixed << std::setprecision(2) << end_memory - << ")" << std::endl); + << ")\n"); IF_VERBOSE(20, m_goal.display(verbose_stream() << m_id << "\n")); SASSERT(m_goal.is_well_formed()); } @@ -71,7 +71,7 @@ tactic_report::~tactic_report() { void report_tactic_progress(char const * id, unsigned val) { if (val > 0) { - IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(" << id << " " << val << ")" << std::endl;); + IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(" << id << " " << val << ")\n"); } } @@ -166,7 +166,7 @@ void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result) { t.cleanup(); } catch (tactic_exception & ex) { - IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(tactic-exception \"" << escaped(ex.msg()) << "\")" << std::endl;); + IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(tactic-exception \"" << escaped(ex.msg()) << "\")\n"); t.cleanup(); throw ex; } From c07b6ab38faa03e5439a3b7c65f489bae1d53081 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Jan 2023 20:23:01 -0800 Subject: [PATCH 458/477] more tactic descriptions --- doc/mk_tactic_doc.py | 1 + src/tactic/bv/bv_bound_chk_tactic.h | 8 +++ src/tactic/bv/bv_slice_tactic.h | 28 ++++++++ src/tactic/core/dom_simplify_tactic.h | 24 ++++++- src/tactic/core/occf_tactic.h | 42 +++++++++--- src/tactic/core/symmetry_reduce_tactic.h | 15 ++++- src/tactic/core/tseitin_cnf_tactic.h | 84 +++++++++++++++--------- src/tactic/ufbv/macro_finder_tactic.h | 40 ++++++++++- src/tactic/ufbv/quasi_macros_tactic.cpp | 8 +++ src/tactic/ufbv/quasi_macros_tactic.h | 29 +++++++- 10 files changed, 233 insertions(+), 46 deletions(-) diff --git a/doc/mk_tactic_doc.py b/doc/mk_tactic_doc.py index 6f4837cdd..fe1a495c1 100644 --- a/doc/mk_tactic_doc.py +++ b/doc/mk_tactic_doc.py @@ -59,6 +59,7 @@ def find_tactic_name(path): m = is_tac_name.search(line) if m: return m.group(1) + print(f"no tactic in {path}") return "" def presort_files(): diff --git a/src/tactic/bv/bv_bound_chk_tactic.h b/src/tactic/bv/bv_bound_chk_tactic.h index bafd2ec51..bbf478353 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.h +++ b/src/tactic/bv/bv_bound_chk_tactic.h @@ -9,6 +9,14 @@ Author: Mikolas Janota +Tactic Documentation + +## Tactic bv_bound_chk + +### Short Description + +Attempts to detect inconsistencies of bounds on bv expressions. + ### Notes * does not support proofs, does not support cores diff --git a/src/tactic/bv/bv_slice_tactic.h b/src/tactic/bv/bv_slice_tactic.h index 23ed16680..77ff081d8 100644 --- a/src/tactic/bv/bv_slice_tactic.h +++ b/src/tactic/bv/bv_slice_tactic.h @@ -13,6 +13,34 @@ Author: Nikolaj Bjorner (nbjorner) 2022-10-30 +Tactic Documentation + +## Tactic bv-slice + +### Short Description + +Slices bit-vectors into sub-ranges to allow simplifying sub-ranges. + +### Long Description + +It rewrites a state using bit-vector slices. +Slices are extracted from bit-vector equality assertions. +An equality assertion may equate a sub-range of a bit-vector +with a constant. The tactic ensures that all occurrences of the +subrange are replaced by the constants to allow additional +simplification + +### Example + +```z3 ignore-errors +(declare-const x (_ BitVec 32)) +(declare-const y (_ BitVec 32)) + (assert (= ((_ extract 31 16) x) (_ bv123 16))) +(assert (= ((_ extract 15 0) x) ((_ extract 16 1) y))) +(assert (= (bvadd x x) y)) +(apply bv-slice) +``` + --*/ #pragma once diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 43e13d961..b4c83d04e 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -14,7 +14,29 @@ Author: Nikolaj and Nuno -Notes: +Tactic Documentation: + +## Tactic dom-simplify + +### Short Description + +Apply dominator simplification rules + +### Long Description + +Dominator-based simplification is a context dependent simplification function that uses a dominator tree to control the number of paths it +visits during simplification. The expression DAG may have an exponential number of paths, but only paths corresponding to a dominator +tree are visited. Since the paths selected by the dominator trees are limited, the simplifier may easily fail to simplify within a context. + +### Example + +```z3 +(declare-const a Bool) +(declare-const b Bool) +(assert (and a (or a b))) +(apply dom-simplify) +``` + --*/ diff --git a/src/tactic/core/occf_tactic.h b/src/tactic/core/occf_tactic.h index 2e211c9d7..efc9a769b 100644 --- a/src/tactic/core/occf_tactic.h +++ b/src/tactic/core/occf_tactic.h @@ -5,20 +5,42 @@ Module Name: occf_tactic.h -Abstract: - - Put clauses in the assertion set in - OOC (one constraint per clause) form. - Constraints occurring in formulas that - are not clauses are ignored. - The formula can be put into CNF by - using mk_sat_preprocessor strategy. - Author: Leonardo de Moura (leonardo) 2011-12-28. -Revision History: +Tactic Documentation: + +## Tactic occf + +### Short Description + +Put goal in one constraint per clause normal form + +### Long Description + +Put clauses in the assertion set in +OOC (one constraint per clause) form. +Constraints occurring in formulas that +are not clauses are ignored. +The formula can be put into CNF by +using `mk_sat_preprocessor` strategy. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) + +(assert (or (= x y) (> x (- y)))) +(assert (or (= x y) (< x (- y)))) +(apply occf) +``` + +### Notes + +* Does not support proofs +* only clauses are considered --*/ #pragma once diff --git a/src/tactic/core/symmetry_reduce_tactic.h b/src/tactic/core/symmetry_reduce_tactic.h index 90c032323..2544bb108 100644 --- a/src/tactic/core/symmetry_reduce_tactic.h +++ b/src/tactic/core/symmetry_reduce_tactic.h @@ -13,7 +13,20 @@ Author: Nikolaj (nbjorner) 2011-05-31 -Notes: + +Tactic Documentation: + +## Tactic symmetry-reduce + +### Short Description + +Apply symmetry reduction + +### Long Description + +The tactic applies symmetry reduction for uninterpreted functions and equalities. +It applies a straight-forward adaption of an algorithm proposed for veriT. + --*/ #pragma once diff --git a/src/tactic/core/tseitin_cnf_tactic.h b/src/tactic/core/tseitin_cnf_tactic.h index a5e116825..6942d1559 100644 --- a/src/tactic/core/tseitin_cnf_tactic.h +++ b/src/tactic/core/tseitin_cnf_tactic.h @@ -7,43 +7,63 @@ Module Name: Abstract: - Puts an assertion set in CNF. - Auxiliary variables are used to avoid blowup. - - Features: - - - Efficient encoding is used for commonly used patterns such as: - (iff a (iff b c)) - (or (not (or a b)) (not (or a c)) (not (or b c))) - - - Efficient encoding is used for chains of if-then-elses - - - Distributivity is applied to non-shared nodes if the blowup is acceptable. - - - The features above can be disabled/enabled using parameters. - - - The assertion-set is only modified if the resultant set of clauses - is "acceptable". - - Notes: - - - Term-if-then-else expressions are not handled by this strategy. - This kind of expression should be processed by other strategies. - - - Quantifiers are treated as "theory" atoms. They are viewed - as propositional variables by this strategy. - - - The assertion set may contain free variables. - - - This strategy assumes the assertion_set_rewriter was - used before invoking it. - In particular, it is more effective when "and" operators - were eliminated. Author: Leonardo (leonardo) 2011-12-29 +Tactic Documentation: + +## Tactic tseitin-cnf + +### Short Description + +Convert goal into CNF using tseitin-like encoding (note: quantifiers are ignored). + +### Long Description + +Puts an assertion set in CNF. +Auxiliary variables are used to avoid blowup. + +Features: + +- Efficient encoding is used for commonly used patterns such as: + `(iff a (iff b c))` + `(or (not (or a b)) (not (or a c)) (not (or b c)))` + +- Efficient encoding is used for chains of if-then-elses + +- Distributivity is applied to non-shared nodes if the blowup is acceptable. + +- The features above can be disabled/enabled using parameters. + +- The assertion-set is only modified if the resultant set of clauses is "acceptable". + +Notes: + +- Term-if-then-else expressions are not handled by this strategy. +This kind of expression should be processed by other strategies. + +- Quantifiers are treated as "theory" atoms. They are viewed +as propositional variables by this strategy. + +- The assertion set may contain free variables. + +- This strategy assumes the assertion_set_rewriter was used before invoking it. +In particular, it is more effective when "and" operators +were eliminated. + +### Example + +```z3 +(declare-const a Bool) +(declare-const b Bool) +(declare-const c Bool) + +(assert (= a (= b c))) +(apply tseitin-cnf) +``` + --*/ #pragma once diff --git a/src/tactic/ufbv/macro_finder_tactic.h b/src/tactic/ufbv/macro_finder_tactic.h index 03b5adc17..487cf1f0d 100644 --- a/src/tactic/ufbv/macro_finder_tactic.h +++ b/src/tactic/ufbv/macro_finder_tactic.h @@ -13,7 +13,45 @@ Author: Christoph (cwinter) 2012-10-26 -Notes: +Tactic Description + +## Tactic macro-finder + +### Short Description + +Identifies and applies macros. + +### Long Description + +It finds implicit macro definitions in quantifiers. +A main instance of a macro an equality that defines a function `f` using some term `t` that does not contain `f`. +Other instances of macros are also recognized by the macro finder. + +* `(forall (x) (= (f x) t))` + +* `not (= (p x) t)` is recognized as `(p x) = (not t)` + +* `(iff (= (f x) t) cond)` rewrites to `(f x) = (if cond t else (k x))` + * add clause `(not (= (k x) t))` + +* `(= (+ (f x) s) t)` becomes `(= (f x) (- t s))` + +* `(= (+ (* -1 (f x)) x) t)` becomes `(= (f x) (- (- t s)))` + +### Example + +```z3 +(declare-fun f (Int) Int) +(declare-fun p (Int) Bool) + +(assert (forall ((x Int)) (= (+ (f x) x) 3))) +(assert (p (f 8))) +(apply macro-finder) +``` + +### Notes + +* Supports proofs, unsat cores, but not goals with recursive function definitions. --*/ #pragma once diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 051ee4fed..12092cdc7 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -21,8 +21,10 @@ Notes: #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" #include "ast/macros/quasi_macros.h" +#include "ast/recfun_decl_plugin.h" #include "tactic/ufbv/quasi_macros_tactic.h" + class quasi_macros_tactic : public tactic { struct imp { @@ -41,6 +43,12 @@ class quasi_macros_tactic : public tactic { bool produce_proofs = g->proofs_enabled(); bool produce_unsat_cores = g->unsat_core_enabled(); + + recfun::util rec(m()); + if (!rec.get_rec_funs().empty()) { + result.push_back(g.get()); + return; + } macro_manager mm(m_manager); quasi_macros qm(m_manager, mm); diff --git a/src/tactic/ufbv/quasi_macros_tactic.h b/src/tactic/ufbv/quasi_macros_tactic.h index a33466e9b..872296dd9 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.h +++ b/src/tactic/ufbv/quasi_macros_tactic.h @@ -13,7 +13,34 @@ Author: Christoph (cwinter) 2012-10-26 -Notes: +Tactic Description + +## Tactic quasi-macro-finder + +### Short Description +dentifies and applies quasi-macros. + +### Long Description + +A quasi macro defines a function symbol that contains more arguments than the number of bound variables it defines. +The additional arguments are functions of the bound variables. + +### Example + +```z3 +(declare-fun f (Int Int Int) Int) +(declare-fun p (Int) Bool) +(declare-const a Int) + +(assert (forall ((x Int) (y Int)) (= (f x y 1) (* 2 x y)))) +(assert (p (f 8 a (+ a 8)))) +(apply quasi-macros) +``` + +### Notes + +* Supports proofs and cores + --*/ #pragma once From 25112e47b46691ef0007068858cae034b9d72055 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Jan 2023 20:59:28 -0800 Subject: [PATCH 459/477] bugfix to flatten-clases simplifier Signed-off-by: Nikolaj Bjorner --- src/ast/simplifiers/flatten_clauses.h | 2 +- src/tactic/arith/add_bounds_tactic.h | 24 ++++++++++++++++++++++-- src/tactic/arith/lia2pb_tactic.h | 24 ++++++++++++++++++++---- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/ast/simplifiers/flatten_clauses.h b/src/ast/simplifiers/flatten_clauses.h index ab02faca1..2d65fd76d 100644 --- a/src/ast/simplifiers/flatten_clauses.h +++ b/src/ast/simplifiers/flatten_clauses.h @@ -92,7 +92,7 @@ public: if (decomposed) { expr* na = mk_not(m, a); for (expr* arg : *to_app(b)) - m_fmls.add(dependent_expr(m, m.mk_or(na, arg), nullptr, de.dep())); + m_fmls.add(dependent_expr(m, m.mk_or(na, mk_not(m, arg)), nullptr, de.dep())); m_fmls.update(idx, dependent_expr(m, m.mk_true(), nullptr, nullptr)); ++m_num_flat; continue; diff --git a/src/tactic/arith/add_bounds_tactic.h b/src/tactic/arith/add_bounds_tactic.h index 0d42d8e61..b69128c3e 100644 --- a/src/tactic/arith/add_bounds_tactic.h +++ b/src/tactic/arith/add_bounds_tactic.h @@ -7,13 +7,33 @@ Module Name: Abstract: - Tactic for bounding unbounded variables. + Author: Leonardo de Moura (leonardo) 2011-06-30. -Revision History: +Tactic Documentation: + +## Tactic add-bounds + +### Short Description + +Tactic for bounding unbounded variables. + +### Long Description + +The tactic creates a stronger sub-goal by adding bounds to variables. +The new goal may not be satisfiable even if the original goal is. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(assert (> (+ x y) 10)) +(apply add-bounds) +``` --*/ #pragma once diff --git a/src/tactic/arith/lia2pb_tactic.h b/src/tactic/arith/lia2pb_tactic.h index 860b04d1c..cd9c40634 100644 --- a/src/tactic/arith/lia2pb_tactic.h +++ b/src/tactic/arith/lia2pb_tactic.h @@ -5,15 +5,31 @@ Module Name: lia2pb_tactic.h -Abstract: - - Reduce bounded LIA benchmark into 0-1 LIA benchmark. Author: Leonardo de Moura (leonardo) 2012-02-07. -Revision History: +Tactic Documentation: + +## Tactic lia2pb + +### Short Description + +Reduce bounded LIA benchmark into 0-1 LIA benchmark. + +### Example + +```z3 +(declare-const x Int) +(declare-const y Int) +(assert (<= 0 x)) +(assert (<= x 5)) +(assert (<= 0 y)) +(assert (<= y 5)) +(assert (>= (+ (* 2 x) y) 5)) +(apply lia2pb) +``` --*/ #pragma once From 95cb06d8cff3c70388dfdf295e2f2347e1945ffa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jan 2023 19:53:55 -0800 Subject: [PATCH 460/477] add quasi macro detection --- src/ast/simplifiers/eliminate_predicates.cpp | 168 ++++++++++++++++++- src/ast/simplifiers/eliminate_predicates.h | 5 + src/tactic/arith/degree_shift_tactic.h | 2 +- 3 files changed, 170 insertions(+), 5 deletions(-) diff --git a/src/ast/simplifiers/eliminate_predicates.cpp b/src/ast/simplifiers/eliminate_predicates.cpp index 118edf04d..2166913da 100644 --- a/src/ast/simplifiers/eliminate_predicates.cpp +++ b/src/ast/simplifiers/eliminate_predicates.cpp @@ -115,6 +115,8 @@ bool eliminate_predicates::can_be_macro_head(expr* _head, unsigned num_bound) { return false; if (f->is_associative()) return false; + if (!is_uninterp(f)) + return false; uint_set indices; for (expr* arg : *head) { if (!is_var(arg)) @@ -146,8 +148,14 @@ bool eliminate_predicates::can_be_quasi_macro_head(expr* _head, unsigned num_bou return false; if (f->is_associative()) return false; + if (!is_uninterp(f)) + return false; uint_set indices; for (expr* arg : *head) { + if (occurs(f, arg)) + return false; + if (!is_macro_safe(arg)) + return false; if (!is_var(arg)) continue; unsigned idx = to_var(arg)->get_idx(); @@ -161,6 +169,49 @@ bool eliminate_predicates::can_be_quasi_macro_head(expr* _head, unsigned num_bou } +// +// (= (f x y (+ x y)) s), where x y are all bound variables. +// then replace (f x y z) by (if (= z (+ x y)) s (f' x y z)) +// + +void eliminate_predicates::insert_quasi_macro(app* head, expr* body, clause const& cl) { + expr_ref _body(body, m); + uint_set indices; + expr_ref_vector args(m), eqs(m); + var_ref new_var(m); + app_ref lhs(m), rhs(m); + func_decl_ref f1(m); + sort_ref_vector sorts(m); + svector names; + + unsigned num_decls = cl.m_bound.size(); + func_decl* f = head->get_decl(); + + for (expr* arg : *head) { + sorts.push_back(arg->get_sort()); + names.push_back(symbol(std::string("x") + std::to_string(args.size()))); + if (is_var(arg)) { + unsigned idx = to_var(arg)->get_idx(); + if (!indices.contains(idx)) { + indices.insert(idx); + args.push_back(arg); + continue; + } + } + new_var = m.mk_var(eqs.size() + num_decls, arg->get_sort()); + args.push_back(new_var); + eqs.push_back(m.mk_eq(arg, new_var)); + } + + // forall vars . f(args) = if eqs then body else f'(args) + f1 = m.mk_fresh_func_decl(f->get_name(), symbol::null, sorts.size(), sorts.data(), f->get_range()); + lhs = m.mk_app(f, args); + rhs = m.mk_ite(mk_and(eqs), body, m.mk_app(f1, args)); + insert_macro(lhs, rhs, cl.m_dep); +} + + + expr_ref eliminate_predicates::bind_free_variables_in_def(clause& cl, app* head, expr* def) { unsigned num_bound = cl.m_bound.size(); if (head->get_num_args() == num_bound) @@ -208,7 +259,7 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea }; for (auto* cl : m_use_list.get(p, false)) { - if (cl->m_alive && cl->m_literals.size() == 2) { + if (cl->m_alive && cl->size() == 2) { auto const& [atom1, sign1] = cl->m_literals[0]; auto const& [atom2, sign2] = cl->m_literals[1]; add_def(*cl, atom1, sign1, atom2, sign2); @@ -242,7 +293,7 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea }; for (auto* cl : m_use_list.get(p, true)) { - if (cl->m_alive && cl->m_literals.size() == 2) { + if (cl->m_alive && cl->size() == 2) { if (is_def(0, 1, *cl)) return true; if (is_def(1, 0, *cl)) @@ -507,10 +558,45 @@ void eliminate_predicates::try_find_macro(clause& cl) { // // - // To review: quasi-macros + // quasi-macros // (= (f x y (+ x y)) s), where x y are all bound variables. - // then replace (f x y z) by (if (= z (+ x y)) s (f' x y)) + // then replace (f x y z) by (if (= z (+ x y)) s (f' x y z)) // + auto can_be_qdef = [&](expr* _x, expr* y) { + if (!is_app(_x)) + return false; + app* x = to_app(_x); + return + can_be_quasi_macro_head(x, cl.m_bound.size()) && + is_macro_safe(y) && + !occurs(x->get_decl(), y); + }; + + if (cl.is_unit() && m.is_eq(cl.atom(0), x, y)) { + if (!cl.sign(0) && can_be_qdef(x, y)) { + insert_quasi_macro(to_app(x), y, cl); + return; + } + else if (!cl.sign(0) && can_be_qdef(y, x)) { + insert_quasi_macro(to_app(y), x, cl); + return; + } + else if (cl.sign(0) && m.is_bool(y) && can_be_qdef(x, y)) { + insert_quasi_macro(to_app(x), m.mk_not(y), cl); + return; + } + else if (cl.sign(0) && m.is_bool(y) && can_be_qdef(y, x)) { + insert_quasi_macro(to_app(y), m.mk_not(x), cl); + return; + } + } + if (cl.is_unit()) { + expr* body = cl.sign(0) ? m.mk_false() : m.mk_true(); + if (can_be_qdef(cl.atom(0), body)) { + insert_quasi_macro(to_app(x), body, cl); + return; + } + } } @@ -791,6 +877,11 @@ eliminate_predicates::clause* eliminate_predicates::init_clause(expr* f, expr_de bool sign = m.is_not(lit, lit); cl->m_literals.push_back({ expr_ref(lit, m), sign }); } + + // extend macro detection to exploit bijective functions? + // f(+ x 1) = g(x) -> f(x) = g(- x 1) + // init_injective(*cl); + // init_surjective(*cl); return cl; } @@ -811,6 +902,73 @@ void eliminate_predicates::init_clauses() { process_to_exclude(m_disable_elimination); } +/** + * Ad hoc recognize surjectivity axioms + * - exists y . f(y) = x + */ +void eliminate_predicates::init_surjective(clause const& cl) { + if (!cl.is_unit()) + return; + if (cl.sign(0)) + return; + if (!is_exists(cl.atom(0))) + return; +} + +/** + * Ad hoc recognize injectivity axioms + * - f(x) = f(y) => x = y + */ +void eliminate_predicates::init_injective(clause const& cl) { + if (cl.size() != 2) + return; + if (cl.m_bound.size() != 2) + return; + if (cl.sign(0) == cl.sign(1)) + return; + expr* a = cl.atom(0), *b = cl.atom(1); + if (!cl.sign(0) && cl.sign(1)) + std::swap(a, b); + expr* x, *y, *fx, *fy; + if (!m.is_eq(a, fx, fy)) + return; + if (!m.is_eq(b, x, y)) + return; + + auto is_fx = [&](expr* _fx, func_decl*& f, unsigned& idx) { + if (!is_app(_fx)) + return false; + app* fx = to_app(_fx); + if (fx->get_num_args() != 1) + return false; + if (!is_var(fx->get_arg(0))) + return false; + f = fx->get_decl(); + idx = to_var(fx->get_arg(0))->get_idx(); + return true; + }; + func_decl* f1, *f2; + unsigned idx1, idx2; + if (!is_fx(fx, f1, idx1)) + return; + if (!is_fx(fy, f2, idx2)) + return; + if (idx1 == idx2 || f1 != f2) + return; + + auto check_var = [&](expr* x, unsigned& idx) { + if (!is_var(x)) + return false; + idx = to_var(x)->get_idx(); + return true; + }; + if (!check_var(x, idx1) || !check_var(y, idx2)) + return; + if (idx1 == idx2) + return; + m_is_injective.mark(f1, true); +} + /** * Convert clauses to m_fmls */ @@ -838,6 +996,8 @@ void eliminate_predicates::reset() { m_to_exclude.reset(); m_disable_elimination.reset(); m_is_macro.reset(); + m_is_injective.reset(); + m_is_surjective.reset(); for (auto const& [k, v] : m_macros) dealloc(v); m_macros.reset(); diff --git a/src/ast/simplifiers/eliminate_predicates.h b/src/ast/simplifiers/eliminate_predicates.h index d91922f9e..af0ede119 100644 --- a/src/ast/simplifiers/eliminate_predicates.h +++ b/src/ast/simplifiers/eliminate_predicates.h @@ -55,6 +55,7 @@ public: std::ostream& display(std::ostream& out) const; + unsigned size() const { return m_literals.size(); } expr* atom(unsigned i) const { return m_literals[i].first; } bool sign(unsigned i) const { return m_literals[i].second; } bool is_unit() const { return m_literals.size() == 1; } @@ -91,6 +92,7 @@ private: ast_mark m_disable_elimination, m_predicate_decls, m_is_macro; ptr_vector m_predicates; ptr_vector m_to_exclude; + ast_mark m_is_injective, m_is_surjective; stats m_stats; use_list m_use_list; der_rewriter m_der; @@ -101,6 +103,8 @@ private: clause* init_clause(unsigned i); clause* init_clause(expr* f, expr_dependency* d, unsigned i); + void init_injective(clause const& cl); + void init_surjective(clause const& cl); clause* resolve(func_decl* p, clause& pos, clause& neg); void add_use_list(clause& cl); @@ -109,6 +113,7 @@ private: void insert_macro(app* head, expr* def, expr_dependency* dep); expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def); bool can_be_macro_head(expr* head, unsigned num_bound); + void insert_quasi_macro(app* head, expr* body, clause const& cl); bool can_be_quasi_macro_head(expr* head, unsigned num_bound); bool is_macro_safe(expr* e); void try_find_macro(clause& cl); diff --git a/src/tactic/arith/degree_shift_tactic.h b/src/tactic/arith/degree_shift_tactic.h index cdc4823e2..01317ade5 100644 --- a/src/tactic/arith/degree_shift_tactic.h +++ b/src/tactic/arith/degree_shift_tactic.h @@ -28,7 +28,7 @@ Then, replace $x^n$ with a new fresh variable $y$. ```z3 (declare-const x Real) (declare-const y Real) -(assert (> (+ (* x x x 4) (* x x 3) 0))) +(assert (> (+ (* x x x 4) (* x x 3)) 0)) (assert (= (* x x) (* y y))) (apply degree-shift) ``` From fcea32344eafb4cbb4ca66161c1151f8f7c532aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Jan 2023 13:32:26 -0800 Subject: [PATCH 461/477] add missing tactic descriptions, add rewrite for tamagochi Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bool_rewriter.cpp | 4 ++- src/ast/rewriter/bv_rewriter.cpp | 36 +++++++++++++++++++ src/ast/rewriter/bv_rewriter.h | 10 ++++++ src/ast/rewriter/th_rewriter.cpp | 34 ++---------------- src/cmd_context/echo_tactic.h | 2 +- src/math/subpaving/tactic/subpaving_tactic.h | 2 ++ src/muz/fp/horn_tactic.h | 24 ++++++++++++- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/sat/sat_solver/sat_smt_solver.cpp | 2 -- src/smt/tactic/smt_tactic_core.cpp | 2 +- src/solver/CMakeLists.txt | 2 +- ...allel_tactic.cpp => parallel_tactical.cpp} | 4 +-- ...{parallel_tactic.h => parallel_tactical.h} | 2 -- src/tactic/aig/aig_tactic.h | 26 +++++++++++++- src/tactic/core/eliminate_predicates_tactic.h | 36 +++++++++++++++++++ src/tactic/fd_solver/fd_solver.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 2 +- src/tactic/ufbv/macro_finder_tactic.h | 2 +- src/tactic/ufbv/quasi_macros_tactic.h | 2 +- 19 files changed, 147 insertions(+), 49 deletions(-) rename src/solver/{parallel_tactic.cpp => parallel_tactical.cpp} (99%) rename src/solver/{parallel_tactic.h => parallel_tactical.h} (97%) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 5abfe01a6..392b2e681 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -857,6 +857,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re s = true; } + // (ite c (ite c t1 t2) t3) ==> (ite c t1 t3 if (m().is_ite(t) && to_app(t)->get_arg(0) == c) { // Remark: (ite c (ite (not c) t1 t2) t3) ==> (ite c t2 t3) does not happen if applying rewrites bottom up @@ -943,7 +944,6 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re } #if 0 - expr* t1, *t2; // (ite c (not (= t1 t2)) t1) ==> (not (= t1 (and c t2))) if (m().is_not(t, t1) && m().is_eq(t1, t1, t2) && e == t1) { expr_ref a(m()); @@ -960,6 +960,8 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re #endif + + if (m().is_ite(t) && m_ite_extra_rules && m_elim_ite) { // (ite c1 (ite c2 t1 t2) t1) ==> (ite (and c1 (not c2)) t2 t1) if (e == to_app(t)->get_arg(1)) { diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 179113241..a308cffc4 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2807,6 +2807,28 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res return BR_FAILED; } +bool bv_rewriter::is_bit(expr* t, unsigned& val) { + rational v; + unsigned sz; + return is_bv(t) && is_numeral(t, v, sz) && sz == 1 && (val = v.get_unsigned(), true); +} + +bool bv_rewriter::is_eq_bit(expr * t, expr * & x, unsigned & val) { + expr* lhs, *rhs; + if (!m.is_eq(t, lhs, rhs)) + return false; + if (is_bit(lhs, val)) { + x = rhs; + return true; + } + if (is_bit(rhs, val)) { + x = lhs; + return true; + } + return false; +} + + br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) { TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_ismt2_pp(c, m) << "?\n" << mk_ismt2_pp(t, m) << "\n:" << mk_ismt2_pp(e, m) << "\n";); @@ -2819,6 +2841,20 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu return BR_REWRITE1; } + // if x = 0 then 0 else 1 + expr* t1; + unsigned bit1, bit2, bit3; + if (is_bv(t) && is_eq_bit(c, t1, bit1) && is_bit(t, bit2) && is_bit(e, bit3)) { + if (bit1 == bit2 && bit3 != bit2) { + result = t1; + return BR_DONE; + } + if (bit1 == bit3 && bit3 != bit2) { + result = m_util.mk_bv_not(t1); + return BR_REWRITE1; + } + } + if (m_ite2id && m.is_eq(c) && is_bv(t) && is_bv(e)) { // detect when ite is actually some simple function based on the pattern (lhs=rhs) ? t : e expr * lhs = to_app(c)->get_arg(0); diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index ca999c793..25bd65b61 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -193,6 +193,16 @@ public: bv_util & get_util() { return m_util; } + // Return true if t is of the form + // (= t #b0) + // (= t #b1) + // (= #b0 t) + // (= #b1 t) + bool is_eq_bit(expr* t, expr*& x, unsigned& val); + + // return true if t is #b0 or #b1 + bool is_bit(expr* t, unsigned& val); + #define MK_BV_BINARY(OP) \ expr_ref OP(expr* a, expr* b) { \ expr_ref result(m); \ diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 456a7afba..c6ab22636 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -125,36 +125,6 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return num_steps > m_max_steps; } - // Return true if t is of the form - // (= t #b0) - // (= t #b1) - // (= #b0 t) - // (= #b1 t) - bool is_eq_bit(expr * t, expr * & x, unsigned & val) { - if (!m().is_eq(t)) - return false; - expr * lhs = to_app(t)->get_arg(0); - if (!m_bv_rw.is_bv(lhs)) - return false; - if (m_bv_rw.get_bv_size(lhs) != 1) - return false; - expr * rhs = to_app(t)->get_arg(1); - rational v; - unsigned sz; - if (m_bv_rw.is_numeral(lhs, v, sz)) { - x = rhs; - val = v.get_unsigned(); - SASSERT(val == 0 || val == 1); - return true; - } - if (m_bv_rw.is_numeral(rhs, v, sz)) { - x = lhs; - val = v.get_unsigned(); - SASSERT(val == 0 || val == 1); - return true; - } - return false; - } // (iff (= x bit1) A) // ---> @@ -162,11 +132,11 @@ struct th_rewriter_cfg : public default_rewriter_cfg { br_status apply_tamagotchi(expr * lhs, expr * rhs, expr_ref & result) { expr * x; unsigned val; - if (is_eq_bit(lhs, x, val)) { + if (m_bv_rw.is_eq_bit(lhs, x, val)) { result = m().mk_eq(x, m().mk_ite(rhs, m_bv_rw.mk_numeral(val, 1), m_bv_rw.mk_numeral(1-val, 1))); return BR_REWRITE2; } - if (is_eq_bit(rhs, x, val)) { + if (m_bv_rw.is_eq_bit(rhs, x, val)) { result = m().mk_eq(x, m().mk_ite(lhs, m_bv_rw.mk_numeral(val, 1), m_bv_rw.mk_numeral(1-val, 1))); return BR_REWRITE2; } diff --git a/src/cmd_context/echo_tactic.h b/src/cmd_context/echo_tactic.h index 050b8910b..ef4d1737b 100644 --- a/src/cmd_context/echo_tactic.h +++ b/src/cmd_context/echo_tactic.h @@ -13,7 +13,7 @@ Author: Leonardo (leonardo) 2012-10-20 -Notes: +## Tactic echo --*/ #pragma once diff --git a/src/math/subpaving/tactic/subpaving_tactic.h b/src/math/subpaving/tactic/subpaving_tactic.h index 9ddddbe6d..2bcb426bf 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.h +++ b/src/math/subpaving/tactic/subpaving_tactic.h @@ -15,6 +15,8 @@ Author: Revision History: +## Tactic subpaving + --*/ #pragma once diff --git a/src/muz/fp/horn_tactic.h b/src/muz/fp/horn_tactic.h index e4b21ffb7..8ceff9621 100644 --- a/src/muz/fp/horn_tactic.h +++ b/src/muz/fp/horn_tactic.h @@ -13,7 +13,29 @@ Author: Nikolaj Bjorner (nbjorner) 2012-11-16. -Revision History: +Tactic Documentation: + +## Tactic horn + +### Short Description + +Solve a set of Horn clauses using the SPACER engine. + +### Long Description + +The SPACER engine is specialized to solving Constrained Horn Clauses. +This tactic instructs + +## Tactic horn-simplify + +### Short Description + +Apply pre-processing simplification rules to a set of Horn clauses + +### Long Description +This tactic exposes pre-processing simplification rules for Constrained Horn Clauses. +They include a repertoire of simplification options that can be controlled by toggling +the `fp` parameters. --*/ #pragma once diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0362d8d3e..75351f053 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -26,7 +26,7 @@ Notes: #include "solver/solver.h" #include "solver/tactic2solver.h" #include "solver/parallel_params.hpp" -#include "solver/parallel_tactic.h" +#include "solver/parallel_tactical.h" #include "tactic/tactical.h" #include "tactic/aig/aig_tactic.h" #include "tactic/core/propagate_values_tactic.h" diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index 923594501..fd970a44a 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -33,8 +33,6 @@ Notes: #include "ast/ast_translation.h" #include "ast/ast_util.h" #include "solver/solver.h" -#include "solver/parallel_params.hpp" -#include "solver/parallel_tactic.h" #include "model/model_smt2_pp.h" #include "model/model_evaluator.h" #include "sat/sat_solver.h" diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index 5ef52a54c..2be2ace58 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -30,7 +30,7 @@ Notes: #include "solver/solver2tactic.h" #include "solver/solver.h" #include "solver/mus.h" -#include "solver/parallel_tactic.h" +#include "solver/parallel_tactical.h" #include "solver/parallel_params.hpp" typedef obj_map expr2expr_map; diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index e259adc3e..3bea76dd0 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -4,7 +4,7 @@ z3_add_component(solver check_logic.cpp combined_solver.cpp mus.cpp - parallel_tactic.cpp + parallel_tactical.cpp smt_logics.cpp solver.cpp solver_na2as.cpp diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactical.cpp similarity index 99% rename from src/solver/parallel_tactic.cpp rename to src/solver/parallel_tactical.cpp index 1d24ed1e6..6d68df8a8 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactical.cpp @@ -3,7 +3,7 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - parallel_tactic.cpp + parallel_tactical.cpp Abstract: @@ -36,7 +36,7 @@ Notes: #include "solver/solver2tactic.h" #include "tactic/tactic.h" #include "tactic/tactical.h" -#include "solver/parallel_tactic.h" +#include "solver/parallel_tactical.h" #include "solver/parallel_params.hpp" diff --git a/src/solver/parallel_tactic.h b/src/solver/parallel_tactical.h similarity index 97% rename from src/solver/parallel_tactic.h rename to src/solver/parallel_tactical.h index 18843077b..5d21ad18d 100644 --- a/src/solver/parallel_tactic.h +++ b/src/solver/parallel_tactical.h @@ -12,8 +12,6 @@ Abstract: Author: Nikolaj Bjorner (nbjorner) 2017-10-9 - -Notes: --*/ #pragma once diff --git a/src/tactic/aig/aig_tactic.h b/src/tactic/aig/aig_tactic.h index 33c00d692..ca2f82d8b 100644 --- a/src/tactic/aig/aig_tactic.h +++ b/src/tactic/aig/aig_tactic.h @@ -13,7 +13,31 @@ Author: Leonardo (leonardo) 2011-10-24 -Notes: +Tactic Documentation: + +## Tactic aig + +### Short Description + +Simplify Boolean structure using AIGs (And-inverter graphs). + +### Long Description + +And-inverter graphs (AIGs) uses just the Boolean connectives `and` and `not` to encode Boolean +formulas. The circuit representation using AIGs first converts formulas using other connectives to this normal form, +then performs local simplification steps to minimize the circuit representation. +Note that the simplification steps used by this tactic are heuristic, trading speed for power, +and do not represent a high-quality circuit minimization approach. + +### Example + +```z3 +(declare-const a Bool) +(declare-const b Bool) +(declare-const c Bool) +(assert (or (and a b) (and b a c))) +(apply aig) +``` --*/ #pragma once diff --git a/src/tactic/core/eliminate_predicates_tactic.h b/src/tactic/core/eliminate_predicates_tactic.h index d89f369dc..4d90b1acf 100644 --- a/src/tactic/core/eliminate_predicates_tactic.h +++ b/src/tactic/core/eliminate_predicates_tactic.h @@ -13,6 +13,42 @@ Author: Nikolaj Bjorner (nbjorner) 2022-10-30 +Tactic Documentation: + +## Tactic elim-predicates + +### Short Description +Eliminates predicates and macros from a formula. + +### Long Description +The tactic subsumes the functionality of `macro-finder` and `quasi-macros`. +Besides finding macros, it eliminates predicates using Davis-Putnam +resolution. + +### Example + +the predicate `p` occurs once positively. All negative occurrences of `p` are resolved against this positive occurrence. +The result of resolution is a set of equalities between arguments to `p`. The function `f` is replaced by a partial solution. + +``` +(declare-fun f (Int Int Int) Int) +(declare-fun p (Int) Bool) +(declare-const a Int) +(declare-const b Int) + +(assert (forall ((x Int) (y Int)) (= (f x y (+ x y)) (* 2 x y)))) +(assert (p (f 8 a (+ a 8)))) +(assert (not (p (f 0 a (+ a 8))))) +(assert (not (p (f 2 a (+ a 8))))) +(assert (not (p (f 1 a (+ a b))))) +(apply elim-predicates) +``` + +### Notes + +* support unsat cores +* does not support proofs + --*/ #pragma once diff --git a/src/tactic/fd_solver/fd_solver.cpp b/src/tactic/fd_solver/fd_solver.cpp index 8e32b74d0..4f1f6b625 100644 --- a/src/tactic/fd_solver/fd_solver.cpp +++ b/src/tactic/fd_solver/fd_solver.cpp @@ -24,7 +24,7 @@ Notes: #include "tactic/fd_solver/pb2bv_solver.h" #include "tactic/fd_solver/bounded_int2bv_solver.h" #include "solver/solver2tactic.h" -#include "solver/parallel_tactic.h" +#include "solver/parallel_tactical.h" #include "solver/parallel_params.hpp" solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mode) { diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 8acfbe40d..138c6e646 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -43,7 +43,7 @@ Notes: #include "sat/sat_solver/sat_smt_solver.h" #include "ast/rewriter/bv_rewriter.h" #include "solver/solver2tactic.h" -#include "solver/parallel_tactic.h" +#include "solver/parallel_tactical.h" #include "solver/parallel_params.hpp" #include "params/tactic_params.hpp" #include "parsers/smt2/smt2parser.h" diff --git a/src/tactic/ufbv/macro_finder_tactic.h b/src/tactic/ufbv/macro_finder_tactic.h index 487cf1f0d..f1cf7080e 100644 --- a/src/tactic/ufbv/macro_finder_tactic.h +++ b/src/tactic/ufbv/macro_finder_tactic.h @@ -13,7 +13,7 @@ Author: Christoph (cwinter) 2012-10-26 -Tactic Description +Tactic Documentation ## Tactic macro-finder diff --git a/src/tactic/ufbv/quasi_macros_tactic.h b/src/tactic/ufbv/quasi_macros_tactic.h index 872296dd9..faa939954 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.h +++ b/src/tactic/ufbv/quasi_macros_tactic.h @@ -13,7 +13,7 @@ Author: Christoph (cwinter) 2012-10-26 -Tactic Description +Tactic Documentation ## Tactic quasi-macro-finder From 61b90e64b25629d14811921d0198079d96bf6b63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Jan 2023 14:17:49 -0800 Subject: [PATCH 462/477] disable new simplifcation for multiplier until really understood Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index a308cffc4..894286a02 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2282,7 +2282,7 @@ br_status bv_rewriter::mk_mul_hoist(unsigned num_args, expr * const * args, expr expr* z = nullptr, *u = nullptr; for (unsigned i = 0; i < num_args; ++i) { // ~x = -1 - x - if (m_util.is_bv_not(args[i], z)) { + if (false && m_util.is_bv_not(args[i], z)) { unsigned sz = m_util.get_bv_size(z); ptr_vector new_args(num_args, args); rational p = rational(2).expt(sz) - 1; From 1ddef117a21de30909fd1166095caaa85c39da82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Jan 2023 16:11:31 -0800 Subject: [PATCH 463/477] several fixes to proof logging in legacy solver Signed-off-by: Nikolaj Bjorner --- src/smt/smt_clause_proof.cpp | 29 +++++++++++++++++++++++------ src/smt/smt_clause_proof.h | 3 +++ src/smt/smt_model_checker.cpp | 4 +++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index 096a0994f..d533ae161 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -16,15 +16,27 @@ Revision History: #include "smt/smt_context.h" #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" +#include namespace smt { clause_proof::clause_proof(context& ctx): ctx(ctx), m(ctx.get_manager()), m_lits(m), m_pp(m) { + auto proof_log = ctx.get_fparams().m_proof_log; - m_enabled = ctx.get_fparams().m_clause_proof || proof_log.is_non_empty_string(); - if (proof_log.is_non_empty_string()) { - m_pp_out = alloc(std::ofstream, proof_log.str()); + m_has_log = proof_log.is_non_empty_string(); + m_enabled = ctx.get_fparams().m_clause_proof || m_has_log; + } + + void clause_proof::init_pp_out() { + if (m_has_log && !m_pp_out) { + static unsigned id = 0; + auto proof_log = ctx.get_fparams().m_proof_log; + std::string log_name = proof_log.str(); + if (id > 0) + log_name = std::to_string(id) + log_name; + ++id; + m_pp_out = alloc(std::ofstream, log_name); if (!*m_pp_out) throw default_exception(std::string("Could not open file ") + proof_log.str()); } @@ -170,14 +182,18 @@ namespace smt { m_trail.push_back(info(st, v, p)); if (m_on_clause_eh) m_on_clause_eh(m_on_clause_ctx, p, v.size(), v.data()); - if (m_pp_out) { + if (m_has_log) { + init_pp_out(); auto& out = *m_pp_out; for (auto* e : v) declare(out, e); switch (st) { case clause_proof::status::assumption: - display_literals(out << "(assume", v) << ")\n"; - break; + if (!p || p->get_decl()->get_name() == "assumption") { + display_literals(out << "(assume", v) << ")\n"; + break; + } + Z3_fallthrough; case clause_proof::status::lemma: case clause_proof::status::th_lemma: case clause_proof::status::th_assumption: @@ -191,6 +207,7 @@ namespace smt { default: UNREACHABLE(); } + out.flush(); } } diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index 42f283f1d..b247a0454 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -58,10 +58,13 @@ namespace smt { expr_ref_vector m_lits; vector m_trail; bool m_enabled = false; + bool m_has_log = false; user_propagator::on_clause_eh_t m_on_clause_eh; void* m_on_clause_ctx = nullptr; ast_pp_util m_pp; scoped_ptr m_pp_out; + + void init_pp_out(); void update(status st, expr_ref_vector& v, proof* p); void update(clause& c, status st, proof* p); diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 72094f78a..61173907b 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -405,13 +405,15 @@ namespace smt { m_fparams->m_relevancy_lvl = 0; // no relevancy since the model checking problems are quantifier free m_fparams->m_case_split_strategy = CS_ACTIVITY; // avoid warning messages about smt.case_split >= 3. m_fparams->m_axioms2files = false; - m_fparams->m_lemmas2console = false; + m_fparams->m_lemmas2console = false; + m_fparams->m_proof_log = symbol::null; } if (!m_aux_context) { symbol logic; params_ref p; p.set_bool("solver.axioms2files", false); p.set_bool("solver.lemmas2console", false); + p.set_sym("solver.proof.log", symbol::null); m_aux_context = m_context->mk_fresh(&logic, m_fparams.get(), p); } } From 5899fe3cea8042d21203089f01d700fd22a1b7fb Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 9 Jan 2023 03:09:01 +0000 Subject: [PATCH 464/477] Add rewrite for array selects of chain of stores of a same value (#6526) * Add rewrite for array selects of chain of stores of a same value Example: ```smt (declare-fun mem () (Array (_ BitVec 4) (_ BitVec 4))) (declare-const x (_ BitVec 4)) (declare-const y (_ BitVec 4)) ; simplifies to #x1 (simplify (select (store (store (store mem #x1 #x1) y #x1) x #x1) #x1)) ``` * Update array_rewriter.cpp * Update array_rewriter.cpp --- src/ast/rewriter/array_rewriter.cpp | 134 ++++++++++++++++++---------- 1 file changed, 86 insertions(+), 48 deletions(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 08173d430..85cdeb50a 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -198,13 +198,96 @@ bool array_rewriter::squash_store(unsigned n, expr* const* args, expr_ref& resul br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(num_args >= 2); + expr *arg0 = args[0]; + expr_ref tmp(m()); + bool first = true; + +#define RET(x, status) \ + tmp = x; \ + if (first || tmp == result) { \ + result = std::move(tmp); \ + return status; \ + } \ + goto exit + + while (true) { + if (m_util.is_store(arg0)) { + SASSERT(to_app(arg0)->get_num_args() == num_args+1); + switch (compare_args(num_args - 1, args+1, to_app(arg0)->get_args()+1)) { + case l_true: + // select(store(a, I, v), I) --> v + RET(to_app(arg0)->get_arg(num_args), BR_DONE); + + case l_false: + // select(store(a, I, v), J) --> select(a, J) if I != J + arg0 = to_app(arg0)->get_arg(0); + continue; + + case l_undef: + // check if loading from subsequent arrays yields the same value + if (first) { + result = to_app(arg0)->get_arg(num_args); + first = false; + } else if (result != to_app(arg0)->get_arg(num_args)) { + goto exit; + } + arg0 = to_app(arg0)->get_arg(0); + continue; + } + } + + if (m_util.is_const(arg0)) { + // select(const(v), I) --> v + RET(to_app(arg0)->get_arg(0), BR_DONE); + } + + if (is_lambda(arg0)) { + // anywhere lambda reduction as opposed to whnf + // select(lambda(X) M, N) -> M[N/X] + quantifier* q = to_quantifier(arg0); + SASSERT(q->get_num_decls() == num_args - 1); + var_subst subst(m()); + expr_ref_vector _args(m()); + var_shifter sh(m()); + for (unsigned i = 1; i < num_args; ++i) { + sh(args[i], num_args-1, result); + _args.push_back(result); + } + expr_ref tmp2 = subst(q->get_expr(), _args.size(), _args.data()); + inv_var_shifter invsh(m()); + invsh(tmp2, _args.size(), tmp2); + RET(std::move(tmp2), BR_REWRITE_FULL); + } + + if (m_util.is_map(arg0)) { + app* a = to_app(arg0); + func_decl* f0 = m_util.get_map_func_decl(a); + expr_ref_vector args0(m()); + for (expr* arg : *a) { + ptr_vector args1; + args1.push_back(arg); + args1.append(num_args-1, args + 1); + args0.push_back(m_util.mk_select(args1.size(), args1.data())); + } + RET(m().mk_app(f0, args0.size(), args0.data()), BR_REWRITE2); + } + + if (m_util.is_as_array(arg0)) { + // select(as-array[f], I) --> f(I) + func_decl * f = m_util.get_as_array_func_decl(to_app(arg0)); + RET(m().mk_app(f, num_args - 1, args + 1), BR_REWRITE1); + } + break; + } + +exit: + result.reset(); + if (m_util.is_store(args[0])) { SASSERT(to_app(args[0])->get_num_args() == num_args+1); switch (compare_args(num_args - 1, args+1, to_app(args[0])->get_args()+1)) { case l_true: - // select(store(a, I, v), I) --> v - result = to_app(args[0])->get_arg(num_args); - return BR_DONE; + UNREACHABLE(); case l_false: { expr* arg0 = to_app(args[0])->get_arg(0); while (m_util.is_store(arg0) && compare_args(num_args-1, args + 1, to_app(arg0)->get_args() + 1) == l_false) { @@ -261,51 +344,6 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, } } - if (m_util.is_const(args[0])) { - // select(const(v), I) --> v - result = to_app(args[0])->get_arg(0); - return BR_DONE; - } - - if (is_lambda(args[0])) { - // anywhere lambda reduction as opposed to whnf - // select(lambda(X) M, N) -> M[N/X] - quantifier* q = to_quantifier(args[0]); - SASSERT(q->get_num_decls() == num_args - 1); - var_subst subst(m()); - expr_ref_vector _args(m()); - var_shifter sh(m()); - for (unsigned i = 1; i < num_args; ++i) { - sh(args[i], num_args-1, result); - _args.push_back(result); - } - result = subst(q->get_expr(), _args.size(), _args.data()); - inv_var_shifter invsh(m()); - invsh(result, _args.size(), result); - return BR_REWRITE_FULL; - } - - if (m_util.is_map(args[0])) { - app* a = to_app(args[0]); - func_decl* f0 = m_util.get_map_func_decl(a); - expr_ref_vector args0(m()); - for (expr* arg : *a) { - ptr_vector args1; - args1.push_back(arg); - args1.append(num_args-1, args + 1); - args0.push_back(m_util.mk_select(args1.size(), args1.data())); - } - result = m().mk_app(f0, args0.size(), args0.data()); - return BR_REWRITE2; - } - - if (m_util.is_as_array(args[0])) { - // select(as-array[f], I) --> f(I) - func_decl * f = m_util.get_as_array_func_decl(to_app(args[0])); - result = m().mk_app(f, num_args - 1, args + 1); - return BR_REWRITE1; - } - expr* c, *th, *el; if (m().is_ite(args[0], c, th, el) && (m_expand_select_ite || (th->get_ref_count() == 1 || el->get_ref_count() == 1))) { ptr_vector args1, args2; From 49ee570b09047cbea94f7d26e3df10c86c9ce596 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Jan 2023 19:16:46 -0800 Subject: [PATCH 465/477] split into separate function Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/array_rewriter.cpp | 17 ++++++++++++----- src/ast/rewriter/array_rewriter.h | 9 +++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 85cdeb50a..58e807fd7 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -196,10 +196,9 @@ bool array_rewriter::squash_store(unsigned n, expr* const* args, expr_ref& resul } -br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 2); - expr *arg0 = args[0]; +br_status array_rewriter::mk_select_same_store(unsigned num_args, expr * const * args, expr_ref & result) { expr_ref tmp(m()); + expr *arg0 = args[0]; bool first = true; #define RET(x, status) \ @@ -228,9 +227,9 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, if (first) { result = to_app(arg0)->get_arg(num_args); first = false; - } else if (result != to_app(arg0)->get_arg(num_args)) { - goto exit; } + else if (result != to_app(arg0)->get_arg(num_args)) + goto exit; arg0 = to_app(arg0)->get_arg(0); continue; } @@ -281,6 +280,14 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, } exit: + return BR_FAILED; +} + +br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) { + SASSERT(num_args >= 2); + br_status st = mk_select_same_store(num_args, args, result); + if (st != BR_FAILED) + return st; result.reset(); if (m_util.is_store(args[0])) { diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index 4e52b237e..689aea1f9 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -46,6 +46,11 @@ class array_rewriter { expr_ref expand_store(expr* s); bool squash_store(unsigned n, expr* const* args, expr_ref& result); + + br_status mk_store_core(unsigned num_args, expr * const * args, expr_ref & result); + br_status mk_select_core(unsigned num_args, expr * const * args, expr_ref & result); + br_status mk_select_same_store(unsigned num_args, expr * const * args, expr_ref & result); + br_status mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); public: array_rewriter(ast_manager & m, params_ref const & p = params_ref()): @@ -63,10 +68,6 @@ public: br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - br_status mk_store_core(unsigned num_args, expr * const * args, expr_ref & result); - br_status mk_select_core(unsigned num_args, expr * const * args, expr_ref & result); - br_status mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - void mk_store(unsigned num_args, expr * const * args, expr_ref & result); void mk_select(unsigned num_args, expr * const * args, expr_ref & result); void mk_map(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); From a4f2a1bb2e4ee9bcc2484f0e1088c8597ced6ad8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jan 2023 09:16:55 +0000 Subject: [PATCH 466/477] Bump json5 from 2.2.1 to 2.2.3 in /src/api/js (#6527) Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/api/js/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/js/package-lock.json b/src/api/js/package-lock.json index c0ece3ae4..f6969a933 100644 --- a/src/api/js/package-lock.json +++ b/src/api/js/package-lock.json @@ -3925,9 +3925,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsonc-parser": { From 30e0f78c16c23b4baf945f2872aff541cc2fc503 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jan 2023 10:00:33 -0800 Subject: [PATCH 467/477] remove exit Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/array_rewriter.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 58e807fd7..e580eb82d 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -207,7 +207,7 @@ br_status array_rewriter::mk_select_same_store(unsigned num_args, expr * const * result = std::move(tmp); \ return status; \ } \ - goto exit + return BR_FAILED; while (true) { if (m_util.is_store(arg0)) { @@ -228,8 +228,8 @@ br_status array_rewriter::mk_select_same_store(unsigned num_args, expr * const * result = to_app(arg0)->get_arg(num_args); first = false; } - else if (result != to_app(arg0)->get_arg(num_args)) - goto exit; + else if (result != to_app(arg0)->get_arg(num_args)) + return BR_FAILED; arg0 = to_app(arg0)->get_arg(0); continue; } @@ -278,8 +278,6 @@ br_status array_rewriter::mk_select_same_store(unsigned num_args, expr * const * } break; } - -exit: return BR_FAILED; } From 64ec8acd306ea6adb8e883860cce611665522f18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jan 2023 15:18:19 -0800 Subject: [PATCH 468/477] fix model reconstruction ordering for elim_unconstrained --- src/ast/simplifiers/elim_unconstrained.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 41a905dea..982a3c7dc 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -357,6 +357,7 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< trail.hide(entry.m_f); break; case generic_model_converter::instruction::ADD: + // trail.push(entry.m_f, entry.m_def, nullptr, old_fmls); break; } } @@ -364,7 +365,8 @@ void elim_unconstrained::update_model_trail(generic_model_converter& mc, vector< scoped_ptr sub = alloc(expr_substitution, m, true, false); rp->set_substitution(sub.get()); expr_ref new_def(m); - for (auto const& entry : mc.entries()) { + for (unsigned i = mc.entries().size(); i-- > 0; ) { + auto const& entry = mc.entries()[i]; switch (entry.m_instruction) { case generic_model_converter::instruction::HIDE: break; From a4d4e2e48300369a2670d7feb26780defc85faa9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jan 2023 15:18:33 -0800 Subject: [PATCH 469/477] track assertions --- src/sat/smt/q_mbi.cpp | 17 ++++++++++++----- src/sat/smt/q_mbi.h | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 6f2db37e1..6702cbf99 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -107,7 +107,7 @@ namespace q { if (ctx.values2root().find(e, n) && n->class_generation() <= generation_min) eqs.push_back(m.mk_eq(sk, e)); } - m_solver->assert_expr(mk_or(eqs)); + assert_expr(mk_or(eqs)); } expr_ref mbqi::replace_model_value(expr* e) { @@ -168,7 +168,7 @@ namespace q { while (true) { ::solver::scoped_push _sp(*m_solver); add_universe_restriction(*qb); - m_solver->assert_expr(qb->mbody); + assert_expr(qb->mbody); ++m_stats.m_num_checks; lbool r = m_solver->check_sat(0, nullptr); if (r == l_undef) @@ -219,7 +219,7 @@ namespace q { if (!proj) break; add_instantiation(q, proj); - m_solver->assert_expr(m.mk_not(mk_and(eqs))); + assert_expr(m.mk_not(mk_and(eqs))); } return i > 0; } @@ -392,7 +392,7 @@ namespace q { if (!m_model->eval_expr(bounds, mbounds, true)) return; mbounds = subst(mbounds, qb.vars); - m_solver->assert_expr(mbounds); + assert_expr(mbounds); qb.domain_eqs.push_back(vbounds); } @@ -425,11 +425,18 @@ namespace q { continue; expr_ref meq = mk_or(meqs); expr_ref veq = mk_or(veqs); - m_solver->assert_expr(meq); + assert_expr(meq); qb.domain_eqs.push_back(veq); } } + void mbqi::assert_expr(expr* e) { + expr_ref _e(e, m); + TRACE("q", tout << _e << "\n"); + m_solver->assert_expr(e); + } + + /* * Add bounds to sub-terms under uninterpreted functions for projection. */ diff --git a/src/sat/smt/q_mbi.h b/src/sat/smt/q_mbi.h index 2cc5655bf..96e3ba56f 100644 --- a/src/sat/smt/q_mbi.h +++ b/src/sat/smt/q_mbi.h @@ -93,6 +93,7 @@ namespace q { void extract_free_vars(quantifier* q, q_body& qb); void init_model(); void init_solver(); + void assert_expr(expr* e); mbp::project_plugin* get_plugin(app* var); void add_plugin(mbp::project_plugin* p); void add_instantiation(quantifier* q, expr_ref& proj); From c3e31149a5614e813909ef1041e007dad4f6abfd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jan 2023 13:43:17 -0800 Subject: [PATCH 470/477] fix #6530 Signed-off-by: Nikolaj Bjorner --- src/ast/format.cpp | 10 +++------- src/ast/proofs/proof_checker.cpp | 8 ++------ src/sat/smt/q_mbi.cpp | 7 ++++++- src/smt/theory_arith_pp.h | 7 +------ src/util/debug.cpp | 6 +++--- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/ast/format.cpp b/src/ast/format.cpp index a14d4b758..6583e9893 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -147,17 +147,13 @@ namespace format_ns { parameter p(s); return fm(m).mk_app(fid(m), OP_STRING, 1, &p, 0, nullptr); } - + format * mk_int(ast_manager & m, int i) { - char buffer[128]; - SPRINTF_D(buffer, i); - return mk_string(m, buffer); + return mk_string(m, std::to_string(i)); } format * mk_unsigned(ast_manager & m, unsigned u) { - char buffer[128]; - SPRINTF_U(buffer, u); - return mk_string(m, buffer); + return mk_string(m, std::to_string(u)); } format * mk_indent(ast_manager & m, unsigned i, format * f) { diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 86ef1793c..dd7cdc851 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -1245,12 +1245,8 @@ void proof_checker::dump_proof(proof const* pr) { } void proof_checker::dump_proof(unsigned num_antecedents, expr * const * antecedents, expr * consequent) { - char buffer[128]; -#ifdef _WINDOWS - sprintf_s(buffer, Z3_ARRAYSIZE(buffer), "proof_lemma_%d.smt2", m_proof_lemma_id); -#else - sprintf(buffer, "proof_lemma_%d.smt2", m_proof_lemma_id); -#endif + std::string buffer; + buffer = "proof_lemma_" + std::to_string(m_proof_lemma_id) + ".smt2"; std::ofstream out(buffer); ast_smt_pp pp(m); pp.set_benchmark_name("lemma"); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 6702cbf99..21830c162 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -170,7 +170,9 @@ namespace q { add_universe_restriction(*qb); assert_expr(qb->mbody); ++m_stats.m_num_checks; + IF_VERBOSE(2, verbose_stream() << "(mbqi.check)\n"); lbool r = m_solver->check_sat(0, nullptr); + IF_VERBOSE(2, verbose_stream() << "(mbqi.check " << r << ")\n"); if (r == l_undef) return r; if (r == l_true) { @@ -212,7 +214,10 @@ namespace q { add_domain_eqs(mdl0, qb); for (; i < m_max_cex; ++i) { ++m_stats.m_num_checks; - if (l_true != m_solver->check_sat(0, nullptr)) + IF_VERBOSE(2, verbose_stream() << "(mbqi.check)\n"); + lbool r = m_solver->check_sat(0, nullptr); + IF_VERBOSE(2, verbose_stream() << "(mbqi.check " << r << ")\n"); + if (l_true != r) break; m_solver->get_model(mdl1); auto proj = solver_project(*mdl1, qb, eqs, true); diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 049528f79..d10bfca55 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -516,13 +516,8 @@ namespace smt { template void theory_arith::display_bounds_in_smtlib() const { - char buffer[128]; static int id = 0; -#ifdef _WINDOWS - sprintf_s(buffer, Z3_ARRAYSIZE(buffer), "arith_%d.smt", id); -#else - sprintf(buffer, "arith_%d.smt", id); -#endif + std::string buffer = "arith_" + std::to_string(id) + ".smt2"; std::ofstream out(buffer); display_bounds_in_smtlib(out); out.close(); diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 4380a0548..f97a2b57b 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -77,7 +77,7 @@ bool is_debug_enabled(const char * tag) { #if !defined(_WINDOWS) && !defined(NO_Z3_DEBUGGER) void invoke_gdb() { - char buffer[1024]; + std::string buffer; int * x = nullptr; for (;;) { std::cerr << "(C)ontinue, (A)bort, (S)top, (T)hrow exception, Invoke (G)DB\n"; @@ -101,9 +101,9 @@ void invoke_gdb() { throw default_exception("assertion violation"); case 'G': case 'g': - sprintf(buffer, "gdb -nw /proc/%d/exe %d", getpid(), getpid()); + buffer = "gdb -nw /proc/" + std::to_string(getpid()) + "/exe " + std::to_string(getpid()); std::cerr << "invoking GDB...\n"; - if (system(buffer) == 0) { + if (system(buffer.c_str()) == 0) { std::cerr << "continuing the execution...\n"; } else { From 2bd933d87f9fec351fdff9c2a85698d42d32529d Mon Sep 17 00:00:00 2001 From: Brecht Sanders Date: Tue, 10 Jan 2023 22:44:11 +0100 Subject: [PATCH 471/477] Fix hwf.cpp for MinGW-w64 32-bit clang (#6529) Fix src/util/hwf.cpp for building with MinGW-w64 clang targetting Windows 32-bit. Without this fix there is an arror about `__control87_2` not being defined. --- src/util/hwf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index b1f0c3cbe..8c20a4cda 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -48,7 +48,7 @@ Revision History: // clear to the compiler what instructions should be used. E.g., for sqrt(), the Windows compiler selects // the x87 FPU, even when /arch:SSE2 is on. // Luckily, these are kind of standardized, at least for Windows/Linux/macOS. -#if defined(__clang__) || defined(_M_ARM) && defined(_M_ARM64) +#if (defined(__clang__) && !defined(__MINGW32__)) || defined(_M_ARM) && defined(_M_ARM64) #undef USE_INTRINSICS #endif From b700dbffce68682d53530208918a8f1bb0a450b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jan 2023 14:42:19 -0800 Subject: [PATCH 472/477] fix #6528 --- src/solver/parallel_tactical.cpp | 44 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/solver/parallel_tactical.cpp b/src/solver/parallel_tactical.cpp index 6d68df8a8..f748379b1 100644 --- a/src/solver/parallel_tactical.cpp +++ b/src/solver/parallel_tactical.cpp @@ -377,9 +377,10 @@ private: solver_ref m_solver; ast_manager& m_manager; + scoped_ptr m_serialize_manager; params_ref m_params; sref_vector m_models; - expr_ref_vector m_core; + scoped_ptr m_core; unsigned m_num_threads; statistics m_stats; task_queue m_queue; @@ -409,7 +410,7 @@ private: m_conquer_delay = pp.conquer_delay(); m_exn_code = 0; m_params.set_bool("override_incremental", true); - m_core.reset(); + m_core = nullptr; } void log_branches(lbool status) { @@ -436,10 +437,15 @@ private: void collect_core(expr_ref_vector const& core) { std::lock_guard lock(m_mutex); - ast_translation tr(core.get_manager(), m_manager); + if (!m_serialize_manager) + m_serialize_manager = alloc(ast_manager, core.get_manager(), true); + m_core = nullptr; + m_core = alloc(expr_ref_vector, *m_serialize_manager); + ast_translation tr(core.get_manager(), *m_serialize_manager); expr_ref_vector core1(tr(core)); for (expr* c : core1) { - if (!m_core.contains(c)) m_core.push_back(c); + if (!m_core->contains(c)) + m_core->push_back(c); } } @@ -463,11 +469,12 @@ private: s.get_solver().get_model(mdl); } if (mdl) { + // serialize access to m_serialize_manager std::lock_guard lock(m_mutex); - if (&s.m() != &m_manager) { - ast_translation tr(s.m(), m_manager); - mdl = mdl->translate(tr); - } + if (!m_serialize_manager) + m_serialize_manager = alloc(ast_manager, s.m(), true); + ast_translation tr(s.m(), *m_serialize_manager); + mdl = mdl->translate(tr); m_models.push_back(mdl.get()); } else if (m_models.empty()) { @@ -738,9 +745,14 @@ private: if (m_exn_code == -1) throw default_exception(std::move(m_exn_msg)); if (m_exn_code != 0) - throw z3_error(m_exn_code); + throw z3_error(m_exn_code); + + // retrieve model. The ast manager of the model is m_serialize_manager. + // the asts have to be translated into m_manager. if (!m_models.empty()) { - mdl = m_models.back(); + mdl = m_models.back(); + ast_translation tr(mdl->get_manager(), m_manager); + mdl = mdl->translate(tr); return l_true; } if (m_has_undef) @@ -770,8 +782,7 @@ public: parallel_tactic(solver* s, params_ref const& p) : m_solver(s), m_manager(s->get_manager()), - m_params(p), - m_core(m_manager) { + m_params(p) { init(); } @@ -806,10 +817,13 @@ public: g->add(concat(fmc.get(), model2model_converter(mdl.get()))); } break; - case l_false: + case l_false: SASSERT(!g->proofs_enabled()); - for (expr * c : m_core) { - lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(c))); + if (m_core) { + ast_translation tr(m_core->get_manager(), m); + expr_ref_vector core(tr(*m_core)); + for (expr * c : core) + lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(c))); } g->assert_expr(m.mk_false(), pr, lcore); break; From d415f073866b4dc729587d3ce8fe3e2166f7ac02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jan 2023 17:22:21 -0800 Subject: [PATCH 473/477] memory leak on proof justifications Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 7 ++++-- src/smt/smt_clause_proof.cpp | 37 ++++++++++++++++++++------------ src/smt/smt_clause_proof.h | 3 ++- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 894286a02..1c374dcb8 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2286,8 +2286,11 @@ br_status bv_rewriter::mk_mul_hoist(unsigned num_args, expr * const * args, expr unsigned sz = m_util.get_bv_size(z); ptr_vector new_args(num_args, args); rational p = rational(2).expt(sz) - 1; - new_args[i] = m_util.mk_bv_sub(mk_numeral(p, sz), z); - result = m_util.mk_bv_mul(num_args, new_args.data()); + new_args[i] = mk_numeral(p, sz); + expr_ref a(m_util.mk_bv_mul(num_args, new_args.data()), m); + new_args[i] = z; + expr_ref b(m_util.mk_bv_mul(num_args, new_args.data()), m); + result = m_util.mk_bv_sub(a, b); return BR_REWRITE3; } // shl(z, u) * x = shl(x * z, u) diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index d533ae161..521510b59 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -21,7 +21,8 @@ Revision History: namespace smt { clause_proof::clause_proof(context& ctx): - ctx(ctx), m(ctx.get_manager()), m_lits(m), m_pp(m) { + ctx(ctx), m(ctx.get_manager()), m_lits(m), m_pp(m), + m_assumption(m), m_rup(m), m_del(m), m_smt(m) { auto proof_log = ctx.get_fparams().m_proof_log; m_has_log = proof_log.is_non_empty_string(); @@ -58,27 +59,35 @@ namespace smt { } } - proof* clause_proof::justification2proof(status st, justification* j) { + proof_ref clause_proof::justification2proof(status st, justification* j) { proof* r = nullptr; if (j) r = j->mk_proof(ctx.get_cr()); if (r) - return r; + return proof_ref(r, m); if (!is_enabled()) - return nullptr; + return proof_ref(m); switch (st) { case status::assumption: - return m.mk_const("assumption", m.mk_proof_sort()); + if (!m_assumption) + m_assumption = m.mk_const("assumption", m.mk_proof_sort()); + return m_assumption; case status::lemma: - return m.mk_const("rup", m.mk_proof_sort()); + if (!m_rup) + m_rup = m.mk_const("rup", m.mk_proof_sort()); + return m_rup; case status::th_lemma: case status::th_assumption: - return m.mk_const("smt", m.mk_proof_sort()); + if (!m_smt) + m_smt = m.mk_const("smt", m.mk_proof_sort()); + return m_smt; case status::deleted: - return m.mk_const("del", m.mk_proof_sort()); + if (!m_del) + m_del = m.mk_const("del", m.mk_proof_sort()); + return m_del; } UNREACHABLE(); - return nullptr; + return proof_ref(m); } void clause_proof::add(clause& c) { @@ -86,7 +95,7 @@ namespace smt { return; justification* j = c.get_justification(); auto st = kind2st(c.get_kind()); - proof_ref pr(justification2proof(st, j), m); + auto pr = justification2proof(st, j); CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); update(c, st, pr); } @@ -95,7 +104,7 @@ namespace smt { if (!is_enabled()) return; auto st = kind2st(k); - proof_ref pr(justification2proof(st, j), m); + auto pr = justification2proof(st, j); CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); m_lits.reset(); for (unsigned i = 0; i < n; ++i) @@ -110,7 +119,7 @@ namespace smt { m_lits.reset(); for (unsigned i = 0; i < new_size; ++i) m_lits.push_back(ctx.literal2expr(c[i])); - proof* p = justification2proof(status::lemma, nullptr); + auto p = justification2proof(status::lemma, nullptr); update(status::lemma, m_lits, p); for (unsigned i = new_size; i < c.get_num_literals(); ++i) m_lits.push_back(ctx.literal2expr(c[i])); @@ -124,7 +133,7 @@ namespace smt { m_lits.reset(); m_lits.push_back(ctx.literal2expr(lit)); auto st = kind2st(k); - proof* pr = justification2proof(st, j); + auto pr = justification2proof(st, j); update(st, m_lits, pr); } @@ -135,7 +144,7 @@ namespace smt { m_lits.push_back(ctx.literal2expr(lit1)); m_lits.push_back(ctx.literal2expr(lit2)); auto st = kind2st(k); - proof* pr = justification2proof(st, j); + auto pr = justification2proof(st, j); update(st, m_lits, pr); } diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index b247a0454..1c5931136 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -63,13 +63,14 @@ namespace smt { void* m_on_clause_ctx = nullptr; ast_pp_util m_pp; scoped_ptr m_pp_out; + proof_ref m_assumption, m_rup, m_del, m_smt; void init_pp_out(); void update(status st, expr_ref_vector& v, proof* p); void update(clause& c, status st, proof* p); status kind2st(clause_kind k); - proof* justification2proof(status st, justification* j); + proof_ref justification2proof(status st, justification* j); void log(status st, proof* p); void declare(std::ostream& out, expr* e); std::ostream& display_literals(std::ostream& out, expr_ref_vector const& v); From 1c7ff72ae21c3da0f39c4d3c96e90764d6aeadce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jan 2023 18:58:20 -0800 Subject: [PATCH 474/477] add tactic doc Signed-off-by: Nikolaj Bjorner --- src/tactic/core/split_clause_tactic.h | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/tactic/core/split_clause_tactic.h b/src/tactic/core/split_clause_tactic.h index 7573f075e..ef9c36a38 100644 --- a/src/tactic/core/split_clause_tactic.h +++ b/src/tactic/core/split_clause_tactic.h @@ -5,16 +5,28 @@ Module Name: split_clause_tactic.h -Abstract: - - Tactic that creates a subgoal for each literal in a clause (l_1 or ... or l_n). - The tactic fails if the main goal does not contain any clause. - Author: Leonardo (leonardo) 2011-11-21 -Notes: +Tactic Documentation: + +## Tactic split-clause + +### Short Description + +Tactic that creates a subgoal for each literal in a clause `(l_1 or ... or l_n)`. +The tactic fails if the main goal does not contain any clause. + +### Example + +```z3 +(declare-const p Bool) +(declare-const q Bool) +(assert (or p q)) +(apply split-clause) +``` + --*/ #pragma once From 8970a54eaa5241d76a5b3699d0c644110b42c7f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jan 2023 22:06:19 -0800 Subject: [PATCH 475/477] expose parameters to control behavior for #5660 --- src/sat/sat_solver/sat_smt_preprocess.cpp | 6 +-- src/sat/smt/euf_solver.cpp | 1 + src/sat/smt/q_ematch.cpp | 9 ++-- src/smt/params/preprocessor_params.cpp | 5 +++ src/smt/params/preprocessor_params.h | 52 +++++++++-------------- src/smt/params/smt_params_helper.pyg | 9 ++-- 6 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/sat/sat_solver/sat_smt_preprocess.cpp b/src/sat/sat_solver/sat_smt_preprocess.cpp index 31888251c..c1a4acc9e 100644 --- a/src/sat/sat_solver/sat_smt_preprocess.cpp +++ b/src/sat/sat_solver/sat_smt_preprocess.cpp @@ -46,9 +46,9 @@ void init_preprocess(ast_manager& m, params_ref const& p, seq_simplifier& s, dep smt_params smtp(p); if (sp.euf() || sp.smt()) { s.add_simplifier(alloc(rewriter_simplifier, m, p, st)); - s.add_simplifier(alloc(propagate_values, m, p, st)); - s.add_simplifier(alloc(euf::solve_eqs, m, st)); - s.add_simplifier(alloc(elim_unconstrained, m, st)); + if (smtp.m_propagate_values) s.add_simplifier(alloc(propagate_values, m, p, st)); + if (smtp.m_solve_eqs) s.add_simplifier(alloc(euf::solve_eqs, m, st)); + if (smtp.m_elim_unconstrained) s.add_simplifier(alloc(elim_unconstrained, m, st)); if (smtp.m_nnf_cnf) s.add_simplifier(alloc(cnf_nnf_simplifier, m, p, st)); if (smtp.m_macro_finder || smtp.m_quasi_macros) s.add_simplifier(alloc(eliminate_predicates, m, st)); if (smtp.m_qe_lite) s.add_simplifier(mk_qe_lite_simplifer(m, p, st)); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index b56093eb0..c9b0430b5 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -540,6 +540,7 @@ namespace euf { sat::check_result solver::check() { ++m_stats.m_final_checks; TRACE("euf", s().display(tout);); + TRACE("final_check", s().display(tout);); bool give_up = false; bool cont = false; diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 573003305..df832a675 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -69,9 +69,12 @@ namespace q { [&](euf::enode* n) { m_mam->add_node(n, false); }; - ctx.get_egraph().set_on_merge(_on_merge); - if (!ctx.relevancy_enabled()) - ctx.get_egraph().set_on_make(_on_make); + + if (ctx.get_config().m_ematching) { + ctx.get_egraph().set_on_merge(_on_merge); + if (!ctx.relevancy_enabled()) + ctx.get_egraph().set_on_make(_on_make); + } m_mam = mam::mk(ctx, *this); } diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index f3c46f95c..180242f85 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -26,6 +26,9 @@ void preprocessor_params::updt_local_params(params_ref const & _p) { m_restricted_quasi_macros = p.restricted_quasi_macros(); m_pull_nested_quantifiers = p.pull_nested_quantifiers(); m_refine_inj_axiom = p.refine_inj_axioms(); + m_propagate_values = p.propagate_values(); + m_elim_unconstrained = p.elim_unconstrained(); + m_solve_eqs = p.solve_eqs(); m_ng_lift_ite = static_cast(p.q_lift_ite()); } @@ -47,6 +50,8 @@ void preprocessor_params::display(std::ostream & out) const { DISPLAY_PARAM(m_eliminate_term_ite); DISPLAY_PARAM(m_macro_finder); DISPLAY_PARAM(m_propagate_values); + DISPLAY_PARAM(m_solve_eqs); + DISPLAY_PARAM(m_elim_unconstrained); DISPLAY_PARAM(m_refine_inj_axiom); DISPLAY_PARAM(m_eliminate_bounds); DISPLAY_PARAM(m_simplify_bit2int); diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index 53568c366..55a55980b 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -31,43 +31,29 @@ struct preprocessor_params : public pattern_inference_params, public bit_blaster_params { lift_ite_kind m_lift_ite; lift_ite_kind m_ng_lift_ite; // lift ite for non ground terms - bool m_pull_cheap_ite; - bool m_pull_nested_quantifiers; - bool m_eliminate_term_ite; - bool m_macro_finder; - bool m_propagate_values; - bool m_refine_inj_axiom; - bool m_eliminate_bounds; - bool m_simplify_bit2int; - bool m_nnf_cnf; - bool m_distribute_forall; - bool m_reduce_args; - bool m_quasi_macros; - bool m_restricted_quasi_macros; - bool m_max_bv_sharing; - bool m_pre_simplifier; - bool m_nlquant_elim; + bool m_pull_cheap_ite = false; + bool m_pull_nested_quantifiers = false; + bool m_eliminate_term_ite = false; + bool m_macro_finder = false; + bool m_propagate_values = true; + bool m_elim_unconstrained = true; + bool m_solve_eqs = true; + bool m_refine_inj_axiom = true; + bool m_eliminate_bounds = false; + bool m_simplify_bit2int = false; + bool m_nnf_cnf = true; + bool m_distribute_forall = false; + bool m_reduce_args = false; + bool m_quasi_macros = false; + bool m_restricted_quasi_macros = false; + bool m_max_bv_sharing = true; + bool m_pre_simplifier = true; + bool m_nlquant_elim = false; public: preprocessor_params(params_ref const & p = params_ref()): m_lift_ite(lift_ite_kind::LI_NONE), - m_ng_lift_ite(lift_ite_kind::LI_NONE), - m_pull_cheap_ite(false), - m_pull_nested_quantifiers(false), - m_eliminate_term_ite(false), - m_macro_finder(false), - m_propagate_values(true), - m_refine_inj_axiom(true), - m_eliminate_bounds(false), - m_simplify_bit2int(false), - m_nnf_cnf(true), - m_distribute_forall(false), - m_reduce_args(false), - m_quasi_macros(false), - m_restricted_quasi_macros(false), - m_max_bv_sharing(true), - m_pre_simplifier(true), - m_nlquant_elim(false) { + m_ng_lift_ite(lift_ite_kind::LI_NONE) { updt_local_params(p); } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 8dfcf5d3b..86a0371f2 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -18,8 +18,11 @@ def_module_params(module_name='smt', ('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal, 6 - activity-based case split with theory-aware branching activity'), ('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'), ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'), - ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'), - ('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'), + ('elim_unconstrained', BOOL, True, 'pre-processing: eliminate unconstrained subterms'), + ('solve_eqs', BOOL, True, 'pre-processing: solve equalities'), + ('propagate_values', BOOL, True, 'pre-processing: propagate values'), + ('pull_nested_quantifiers', BOOL, False, 'pre-processing: pull nested quantifiers'), + ('refine_inj_axioms', BOOL, True, 'pre-processing: refine injectivity axioms'), ('candidate_models', BOOL, False, 'create candidate models even when quantifier or theory reasoning is incomplete'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts before giving up.'), ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), @@ -50,7 +53,7 @@ def_module_params(module_name='smt', ('bv.watch_diseq', BOOL, False, 'use watch lists instead of eager axioms for bit-vectors'), ('bv.delay', BOOL, False, 'delay internalize expensive bit-vector operations'), ('bv.eq_axioms', BOOL, True, 'enable redundant equality axioms for bit-vectors'), - ('bv.size_reduce', BOOL, False, 'turn assertions that set the upper bits of a bit-vector to constants into a substitution that replaces the bit-vector with constant bits. Useful for minimizing circuits as many input bits to circuits are constant'), + ('bv.size_reduce', BOOL, False, 'pre-processing; turn assertions that set the upper bits of a bit-vector to constants into a substitution that replaces the bit-vector with constant bits. Useful for minimizing circuits as many input bits to circuits are constant'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2'), From e5e16268cc4ed46f7f98cd3e96d72115af59993c Mon Sep 17 00:00:00 2001 From: Jerry James Date: Thu, 12 Jan 2023 12:20:28 -0700 Subject: [PATCH 476/477] Initialize m_istamp_id in lookahead::init (#6533) --- src/sat/sat_lookahead.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 83e5b9ca5..2fa7ed040 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1001,6 +1001,7 @@ namespace sat { m_inconsistent = false; m_qhead = 0; m_bstamp_id = 0; + m_istamp_id = 0; for (unsigned i = 0; i < m_num_vars; ++i) { init_var(i); From 25b0b1430c40d24f151756f84198b61d3091e272 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Jan 2023 12:42:20 -0800 Subject: [PATCH 477/477] move bound_manager to simplifiers, add bound manager to extract_eqs for solve-eqs #6532 --- src/ast/rewriter/arith_rewriter.cpp | 5 +- src/ast/simplifiers/CMakeLists.txt | 1 + .../simplifiers}/bound_manager.cpp | 19 +++---- .../arith => ast/simplifiers}/bound_manager.h | 4 +- src/ast/simplifiers/extract_eqs.cpp | 49 +++++++++++++++---- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- src/tactic/arith/CMakeLists.txt | 1 - src/tactic/arith/add_bounds_tactic.cpp | 5 +- src/tactic/arith/eq2bv_tactic.cpp | 5 +- src/tactic/arith/lia2card_tactic.cpp | 5 +- src/tactic/arith/lia2pb_tactic.cpp | 5 +- src/tactic/arith/nla2bv_tactic.cpp | 5 +- src/tactic/arith/normalize_bounds_tactic.cpp | 15 +++--- src/tactic/arith/pb2bv_model_converter.h | 2 +- src/tactic/arith/pb2bv_tactic.cpp | 10 ++-- .../fd_solver/bounded_int2bv_solver.cpp | 7 ++- src/tactic/smtlogics/qflia_tactic.cpp | 5 +- 17 files changed, 86 insertions(+), 59 deletions(-) rename src/{tactic/arith => ast/simplifiers}/bound_manager.cpp (95%) rename src/{tactic/arith => ast/simplifiers}/bound_manager.h (95%) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index c2a9b4cf4..15456d41e 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -23,9 +23,8 @@ Notes: #include "ast/ast_pp.h" seq_util& arith_rewriter_core::seq() { - if (!m_seq) { - m_seq = alloc(seq_util, m); - } + if (!m_seq) + m_seq = alloc(seq_util, m); return *m_seq; } diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index b807b00e3..bd39395c0 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(simplifiers SOURCES bit_blaster.cpp + bound_manager.cpp bv_slice.cpp card2bv.cpp demodulator_simplifier.cpp diff --git a/src/tactic/arith/bound_manager.cpp b/src/ast/simplifiers/bound_manager.cpp similarity index 95% rename from src/tactic/arith/bound_manager.cpp rename to src/ast/simplifiers/bound_manager.cpp index d6422abff..0770bf421 100644 --- a/src/tactic/arith/bound_manager.cpp +++ b/src/ast/simplifiers/bound_manager.cpp @@ -16,10 +16,11 @@ Author: Notes: --*/ -#include "tactic/arith/bound_manager.h" + #include "ast/ast_smt2_pp.h" #include "ast/ast_pp.h" -#include "tactic/goal.h" +#include "ast/ast_translation.h" +#include "ast/simplifiers/bound_manager.h" bound_manager::bound_manager(ast_manager & m): m_util(m), @@ -103,7 +104,9 @@ bool bound_manager::is_numeral(expr* v, numeral& n, bool& is_int) { return m_util.is_numeral(v, n, is_int); } -void bound_manager::operator()(expr * f, expr_dependency * d) { +void bound_manager::operator()(expr * f, expr_dependency * d, proof* p) { + if (p) + return; TRACE("bound_manager", tout << "processing:\n" << mk_ismt2_pp(f, m()) << "\n";); expr * v; numeral n; @@ -243,16 +246,6 @@ bool bound_manager::is_disjunctive_bound(expr * f, expr_dependency * d) { return true; } -void bound_manager::operator()(goal const & g) { - if (g.proofs_enabled()) - return; - unsigned sz = g.size(); - for (unsigned i = 0; i < sz; i++) { - operator()(g.form(i), g.dep(i)); - } -} - - void bound_manager::reset() { m_bounded_vars.finalize(); m_lowers.finalize(); diff --git a/src/tactic/arith/bound_manager.h b/src/ast/simplifiers/bound_manager.h similarity index 95% rename from src/tactic/arith/bound_manager.h rename to src/ast/simplifiers/bound_manager.h index 6047dd36d..967ac2e04 100644 --- a/src/tactic/arith/bound_manager.h +++ b/src/ast/simplifiers/bound_manager.h @@ -21,7 +21,6 @@ Notes: #include "ast/ast.h" #include "ast/arith_decl_plugin.h" -class goal; class bound_manager { public: @@ -50,8 +49,7 @@ public: ast_manager & m() const { return m_util.get_manager(); } - void operator()(goal const & g); - void operator()(expr * n, expr_dependency * d = nullptr); + void operator()(expr * n, expr_dependency * d, proof* p); bool has_lower(expr * c, numeral & v, bool & strict) const { limit l; diff --git a/src/ast/simplifiers/extract_eqs.cpp b/src/ast/simplifiers/extract_eqs.cpp index 66ebef85c..37d92bcbb 100644 --- a/src/ast/simplifiers/extract_eqs.cpp +++ b/src/ast/simplifiers/extract_eqs.cpp @@ -21,6 +21,7 @@ Author: #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/simplifiers/extract_eqs.h" +#include "ast/simplifiers/bound_manager.h" #include "params/tactic_params.hpp" @@ -83,6 +84,7 @@ namespace euf { class arith_extract_eq : public extract_eq { ast_manager& m; arith_util a; + bound_manager m_bm; expr_ref_vector m_args, m_trail; expr_sparse_mark m_nonzero; bool m_enabled = true; @@ -107,6 +109,17 @@ namespace euf { solve_eq(orig, u, term, d, eqs); } + void solve_to_real(expr* orig, expr* x, expr* y, expr_dependency* d, dep_eq_vector& eqs) { + expr* z, *u; + rational r; + if (!a.is_to_real(x, z) || !is_uninterp_const(z)) + return; + if (a.is_to_real(y, u)) + eqs.push_back(dependent_eq(orig, to_app(z), expr_ref(u, m), d)); + else if (a.is_numeral(y, r) && r.is_int()) + eqs.push_back(dependent_eq(orig, to_app(z), expr_ref(a.mk_int(r), m), d)); + } + /*** * Solve * x + Y = Z -> x = Z - Y @@ -157,8 +170,8 @@ namespace euf { for (expr* yarg : *to_app(arg)) { ++k; nonzero = k == j || m_nonzero.is_marked(yarg) || (a.is_numeral(yarg, r) && r != 0); - if (!nonzero) - break; +if (!nonzero) +break; } if (!nonzero) continue; @@ -222,12 +235,12 @@ namespace euf { } void add_pos(expr* f) { - expr* lhs = nullptr, *rhs = nullptr; + expr* lhs = nullptr, * rhs = nullptr; rational val; - if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_neg()) - mark_nonzero(lhs); + if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_neg()) + mark_nonzero(lhs); else if (a.is_ge(f, lhs, rhs) && a.is_numeral(rhs, val) && val.is_pos()) - mark_nonzero(lhs); + mark_nonzero(lhs); else if (m.is_not(f, f)) { if (a.is_le(f, lhs, rhs) && a.is_numeral(rhs, val) && !val.is_neg()) mark_nonzero(lhs); @@ -242,11 +255,12 @@ namespace euf { solve_add(orig, x, y, d, eqs); solve_mod(orig, x, y, d, eqs); solve_mul(orig, x, y, d, eqs); + solve_to_real(orig, x, y, d, eqs); } public: - arith_extract_eq(ast_manager& m) : m(m), a(m), m_args(m), m_trail(m) {} + arith_extract_eq(ast_manager& m) : m(m), a(m), m_bm(m), m_args(m), m_trail(m) {} void get_eqs(dependent_expr const& e, dep_eq_vector& eqs) override { if (!m_enabled) @@ -257,6 +271,18 @@ namespace euf { solve_eq(f, x, y, d, eqs); solve_eq(f, y, x, d, eqs); } + bool str; + rational lo, hi; + if (a.is_le(f, x, y) && a.is_numeral(y, hi) && m_bm.has_lower(x, lo, str) && !str && lo == hi) { + expr_dependency_ref d2(m); + d2 = m.mk_join(d, m_bm.lower_dep(x)); + if (is_uninterp_const(x)) + eqs.push_back(dependent_eq(f, to_app(x), expr_ref(y, m), d2)); + else { + solve_eq(f, x, y, d2, eqs); + solve_eq(f, y, x, d2, eqs); + } + } } void pre_process(dependent_expr_state& fmls) override { @@ -264,8 +290,13 @@ namespace euf { return; m_nonzero.reset(); m_trail.reset(); - for (unsigned i = 0; i < fmls.qtail(); ++i) - add_pos(fmls[i].fml()); + m_bm.reset(); + for (unsigned i = 0; i < fmls.qtail(); ++i) { + auto [f, p, d] = fmls[i](); + add_pos(f); + m_bm(f, d, p); + } + } diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 278c0a205..b18d43528 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -26,7 +26,7 @@ Notes: #include "ast/ast_lt.h" #include "cmd_context/simplify_cmd.h" #include "ast/ast_smt2_pp.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "ast/used_vars.h" #include "ast/rewriter/var_subst.h" #include "ast/ast_util.h" diff --git a/src/tactic/arith/CMakeLists.txt b/src/tactic/arith/CMakeLists.txt index d5c7557e6..11aa87242 100644 --- a/src/tactic/arith/CMakeLists.txt +++ b/src/tactic/arith/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(arith_tactics SOURCES add_bounds_tactic.cpp arith_bounds_tactic.cpp - bound_manager.cpp bound_propagator.cpp bv2int_rewriter.cpp bv2real_rewriter.cpp diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index a544c6810..3d9f0bd25 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -19,7 +19,7 @@ Revision History: #include "tactic/tactical.h" #include "ast/arith_decl_plugin.h" #include "ast/ast_smt2_pp.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" struct is_unbounded_proc { struct found {}; @@ -41,7 +41,8 @@ struct is_unbounded_proc { bool is_unbounded(goal const & g) { ast_manager & m = g.m(); bound_manager bm(m); - bm(g); + for (unsigned i = 0; i < g.size(); ++i) + bm(g.form(i), g.dep(i), g.pr(i)); is_unbounded_proc proc(bm); return test(g, proc); } diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 1711a34ac..0b2630236 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -18,7 +18,7 @@ Notes: --*/ #include "tactic/tactical.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" @@ -179,7 +179,8 @@ public: tactic_report report("eq2bv", *g); - m_bounds(*g); + for (unsigned i = 0; i < g->size(); ++i) + m_bounds(g->form(i), g->dep(i), g->pr(i)); if (m_bounds.inconsistent() || g->proofs_enabled()) { g->inc_depth(); diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index cb6f6c228..f8cd3674a 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -24,7 +24,7 @@ Notes: #include "ast/ast_util.h" #include "ast/ast_pp_util.h" #include "tactic/tactical.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "ast/converters/generic_model_converter.h" class lia2card_tactic : public tactic { @@ -180,7 +180,8 @@ public: tactic_report report("lia2card", *g); bound_manager bounds(m); - bounds(*g); + for (unsigned i = 0; i < g->size(); ++i) + bounds(g->form(i), g->dep(i), g->pr(i)); for (expr* x : bounds) { checkpoint(); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index f78e85621..450a7d25a 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -17,7 +17,7 @@ Revision History: --*/ #include "tactic/tactical.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "ast/rewriter/th_rewriter.h" #include "ast/for_each_expr.h" #include "ast/converters/generic_model_converter.h" @@ -197,7 +197,8 @@ class lia2pb_tactic : public tactic { return; } - m_bm(*g); + for (unsigned i = 0; i < g->size(); ++i) + m_bm(g->form(i), g->dep(i), g->pr(i)); TRACE("lia2pb", m_bm.display(tout);); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index cd37db402..c791841ec 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -28,7 +28,7 @@ Notes: #include "tactic/arith/bv2int_rewriter.h" #include "tactic/arith/bv2real_rewriter.h" #include "ast/converters/generic_model_converter.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "util/obj_pair_hashtable.h" #include "ast/ast_smt2_pp.h" @@ -89,7 +89,8 @@ class nla2bv_tactic : public tactic { ); tactic_report report("nla->bv", g); m_fmc = alloc(generic_model_converter, m_manager, "nla2bv"); - m_bounds(g); + for (unsigned i = 0; i < g.size(); ++i) + m_bounds(g.form(i), g.dep(i), g.pr(i)); collect_power2(g); switch (collect_vars(g)) { case has_num: diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index b20eaf53a..7c09703eb 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -19,7 +19,7 @@ Revision History: --*/ #include "tactic/tactical.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "ast/rewriter/th_rewriter.h" #include "ast/converters/generic_model_converter.h" #include "ast/arith_decl_plugin.h" @@ -67,13 +67,11 @@ class normalize_bounds_tactic : public tactic { } bool has_lowers() { - bound_manager::iterator it = m_bm.begin(); - bound_manager::iterator end = m_bm.end(); - for (; it != end; ++it) { + for (auto* e : m_bm) { TRACE("normalize_bounds_tactic", rational val; bool strict; - tout << mk_ismt2_pp(*it, m) << " has_lower: " << m_bm.has_lower(*it, val, strict) << " val: " << val << "\n";); - if (is_target(*it)) + tout << mk_ismt2_pp(e, m) << " has_lower: " << m_bm.has_lower(e, val, strict) << " val: " << val << "\n";); + if (is_target(e)) return true; } return false; @@ -83,8 +81,9 @@ class normalize_bounds_tactic : public tactic { bool produce_models = in->models_enabled(); bool produce_proofs = in->proofs_enabled(); tactic_report report("normalize-bounds", *in); - - m_bm(*in); + + for (unsigned i = 0; i < in->size(); ++i) + m_bm(in->form(i), in->dep(i), in->pr(i)); if (!has_lowers()) { result.push_back(in.get()); diff --git a/src/tactic/arith/pb2bv_model_converter.h b/src/tactic/arith/pb2bv_model_converter.h index 2de873ba2..3477a2081 100644 --- a/src/tactic/arith/pb2bv_model_converter.h +++ b/src/tactic/arith/pb2bv_model_converter.h @@ -19,7 +19,7 @@ Notes: #pragma once #include "ast/converters/model_converter.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" class pb2bv_model_converter : public model_converter { typedef std::pair func_decl_pair; diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 5ff7425ba..507a54b6a 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -28,7 +28,7 @@ Notes: #include "ast/rewriter/rewriter_def.h" #include "ast/rewriter/pb2bv_rewriter.h" #include "tactic/tactical.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "ast/converters/generic_model_converter.h" #include "tactic/arith/pb2bv_model_converter.h" #include "tactic/arith/pb2bv_tactic.h" @@ -913,7 +913,9 @@ private: return; } - m_bm(*g); + unsigned size = g->size(); + for (unsigned i = 0; i < size; i++) + m_bm(g->form(i), g->dep(i), g->pr(i)); TRACE("pb2bv", m_bm.display(tout);); @@ -924,7 +926,6 @@ private: throw_tactic(p.e); } - unsigned size = g->size(); expr_ref_vector new_exprs(m); expr_dependency_ref_vector new_deps(m); @@ -1042,7 +1043,8 @@ struct is_pb_probe : public probe { try { ast_manager & m = g.m(); bound_manager bm(m); - bm(g); + for (unsigned i = 0; i < g.size(); i++) + bm(g.form(i), g.dep(i), g.pr(i)); arith_util a_util(m); pb_util pb(m); expr_fast_mark1 visited; diff --git a/src/tactic/fd_solver/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp index 4ac82c0c2..317286e1e 100644 --- a/src/tactic/fd_solver/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -23,7 +23,7 @@ Notes: #include "ast/converters/generic_model_converter.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "tactic/arith/bv2int_rewriter.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/bv_decl_plugin.h" @@ -330,9 +330,8 @@ private: if (m_assertions.empty()) return; m_flushed = true; bound_manager& bm = *m_bounds.back(); - for (expr* a : m_assertions) { - bm(a); - } + for (expr* a : m_assertions) + bm(a, nullptr, nullptr); TRACE("int2bv", bm.display(tout);); expr_safe_replace sub(m); accumulate_sub(sub); diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index b8ebbd8a9..e72a63087 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -32,14 +32,15 @@ Notes: #include "tactic/aig/aig_tactic.h" #include "tactic/smtlogics/smt_tactic.h" #include "sat/tactic/sat_tactic.h" -#include "tactic/arith/bound_manager.h" +#include "ast/simplifiers/bound_manager.h" #include "tactic/arith/probe_arith.h" struct quasi_pb_probe : public probe { result operator()(goal const & g) override { bool found_non_01 = false; bound_manager bm(g.m()); - bm(g); + for (unsigned i = 0; i < g.size(); ++i) + bm(g.form(i), g.dep(i), g.pr(i)); rational l, u; bool st; for (expr * t : bm) { if (bm.has_lower(t, l, st) && bm.has_upper(t, u, st) && (l.is_zero() || l.is_one()) && (u.is_zero() || u.is_one()))