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.