diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 849d271ac..b947885ba 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -27,7 +27,7 @@ def init_project_def(): add_lib('params', ['util']) add_lib('smt_params', ['params'], 'smt/params') add_lib('grobner', ['ast', 'dd', 'simplex'], 'math/grobner') - add_lib('sat', ['util', 'dd', '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') diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index a53a4b856..b911ee971 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -20,6 +20,7 @@ Revision History: #include "sat/sat_types.h" #include "sat/sat_params.hpp" #include "sat/sat_simplifier_params.hpp" +#include "params/solver_params.hpp" namespace sat { @@ -31,6 +32,8 @@ namespace sat { void config::updt_params(params_ref const & _p) { sat_params p(_p); + solver_params sp(_p); + m_max_memory = megabytes_to_bytes(p.max_memory()); symbol s = p.restart(); @@ -194,7 +197,7 @@ 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_drat = (m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1; + m_drat = !p.drat_disable() && (sp.lemmas2console() || m_drat_check_unsat || m_drat_file.is_non_empty_string() || m_drat_check_sat) && p.threads() == 1; m_drat_binary = p.drat_binary(); m_drat_activity = p.drat_activity(); m_drup_trim = p.drup_trim(); @@ -248,8 +251,8 @@ namespace sat { m_card_solver = p.cardinality_solver(); m_xor_solver = false; // prevent users from playing with this option - sat_simplifier_params sp(_p); - m_elim_vars = sp.elim_vars(); + sat_simplifier_params ssp(_p); + m_elim_vars = ssp.elim_vars(); #if 0 if (m_drat && (m_xor_solver || m_card_solver)) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 9cac2e5ef..b63b84e2e 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -690,6 +690,7 @@ namespace sat { if (m_out) dump(1, &l, st); if (m_bout) bdump(1, &l, st); if (m_check) append(l, st); + if (m_print_clause) m_print_clause(1, &l, st); } void drat::add(literal l1, literal l2, status st) { if (st.is_deleted()) @@ -700,6 +701,7 @@ namespace sat { if (m_out) dump(2, ls, st); if (m_bout) bdump(2, ls, st); if (m_check) append(l1, l2, st); + if (m_print_clause) m_print_clause(2, ls, st); } void drat::add(clause& c, status st) { if (st.is_deleted()) @@ -709,6 +711,7 @@ namespace sat { if (m_out) dump(c.size(), c.begin(), st); if (m_bout) bdump(c.size(), c.begin(), st); if (m_check) append(mk_clause(c), st); + if (m_print_clause) m_print_clause(c.size(), c.begin(), st); } void drat::add(literal_vector const& lits, status st) { @@ -729,6 +732,9 @@ namespace sat { } if (m_out) dump(sz, lits, st); + + if (m_print_clause) + m_print_clause(sz, lits, st); } void drat::add(literal_vector const& c) { @@ -748,6 +754,8 @@ namespace sat { } } } + if (m_print_clause) + m_print_clause(c.size(), c.data(), status::redundant()); } void drat::del(literal l) { diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 18ca7b7b8..838b0879a 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -92,6 +92,8 @@ namespace sat { bool m_trim = false; stats m_stats; + std::function m_print_clause; + void dump_activity(); void dump(unsigned n, literal const* c, status st); void bdump(unsigned n, literal const* c, status st); @@ -138,6 +140,10 @@ namespace sat { void add(literal_vector const& c); // add learned clause void add(unsigned sz, literal const* lits, status st); + void set_print_clause(std::function& print_clause) { + m_print_clause = print_clause; + } + // support for SMT - connect Boolean variables with AST nodes // associate AST node id with Boolean variable v void bool_def(bool_var v, unsigned n); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 71ac81715..f322d98f8 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -46,6 +46,7 @@ def_module_params('sat', ('backtrack.conflicts', UINT, 4000, 'number of conflicts before enabling chronological backtracking'), ('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'), ('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 5b9f03188..d393cc94e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -412,6 +412,7 @@ namespace sat { clause * solver::mk_clause_core(unsigned num_lits, literal * lits, sat::status st) { bool redundant = st.is_redundant(); TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (redundant?" learned":" aux") << "\n";); + bool logged = false; if (!redundant || !st.is_sat()) { unsigned old_sz = num_lits; bool keep = simplify_clause(num_lits, lits); @@ -420,8 +421,10 @@ namespace sat { return nullptr; // clause is equivalent to true. } // if an input clause is simplified, then log the simplified version as learned - if (m_config.m_drat && old_sz > num_lits) + if (m_config.m_drat && old_sz > num_lits) { drat_log_clause(num_lits, lits, st); + logged = true; + } ++m_stats.m_non_learned_generation; if (!m_searching) { @@ -435,7 +438,7 @@ namespace sat { set_conflict(); return nullptr; case 1: - if (m_config.m_drat && (!st.is_sat() || st.is_input())) + if (!logged && m_config.m_drat && (!st.is_sat() || st.is_input())) drat_log_clause(num_lits, lits, st); assign_unit(lits[0]); return nullptr; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index dc63c2943..3228bcf60 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -84,7 +84,7 @@ namespace sat { }; struct no_drat_params : public params_ref { - no_drat_params() { set_sym("drat.file", symbol()); } + no_drat_params() { set_bool("drat.disable", true); } }; class solver : public solver_core { diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 59878c429..dd4340c2b 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -16,6 +16,8 @@ Author: --*/ #include "sat/smt/euf_solver.h" +#include "ast/ast_util.h" +#include namespace euf { @@ -192,4 +194,23 @@ namespace euf { get_drat().bool_def(lit.var(), eq->get_id()); } + void solver::log_clause(unsigned n, literal const* lits, sat::status st) { + if (get_config().m_lemmas2console) { + std::function ppth = [&](int th) { + return m.get_family_name(th); + }; + if (st.is_redundant() || st.is_asserted()) { + expr_ref_vector clause(m); + for (unsigned i = 0; i < n; ++i) { + expr_ref e = literal2expr(lits[i]); + if (!e) + return; + clause.push_back(e); + } + expr_ref cl = mk_or(clause); + std::cout << sat::status_pp(st, ppth) << " " << cl << "\n"; + } + } + } + } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index d5cf08383..cf99496a1 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -169,6 +169,14 @@ namespace euf { TRACE("before_search", s().display(tout);); for (auto* s : m_solvers) s->init_search(); + + if (get_config().m_lemmas2console) { + std::function on_clause = + [&](unsigned n, sat::literal const* lits, sat::status st) { + log_clause(n, lits, st); + }; + get_drat().set_print_clause(on_clause); + } } bool solver::is_external(bool_var v) { diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 7d5d8e902..d968139a7 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -182,6 +182,7 @@ namespace euf { obj_hashtable m_drat_asts; bool m_drat_initialized{ false }; void init_drat(); + void log_clause(unsigned n, literal const* lits, sat::status st); // relevancy //bool_vector m_relevant_expr_ids; diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 29db324f9..d3988e1a7 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -379,9 +379,14 @@ namespace q { else { ++m_stats.m_num_propagations; auto& j = justification::from_index(j_idx); - auto lit = instantiate(j.m_clause, j.m_binding, j.m_clause[idx]); - ctx.propagate(lit, j_idx); + 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])); + m_qs.log_instantiation(lits); + m_qs.add_clause(lits); } + } bool ematch::flush_prop_queue() { @@ -408,6 +413,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())); + m_qs.log_instantiation(~c.m_literal, lit); } sat::literal ematch::instantiate(clause& c, euf::enode* const* binding, lit const& l) { diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index a87c5ec0d..ae79dbeee 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -47,21 +47,21 @@ namespace q { unsigned lim = m_indirect_nodes.size(); lit l = c[i]; lbool cmp = compare(n, binding, l.lhs, l.rhs, evidence); + TRACE("q", tout << l.lhs << " ~~ " << l.rhs << " is " << cmp << "\n";); switch (cmp) { - case l_false: + case l_false: m_indirect_nodes.shrink(lim); if (!l.sign) break; c.m_watch = i; return l_true; - case l_true: + case l_true: m_indirect_nodes.shrink(lim); if (l.sign) - break; + break; c.m_watch = i; return l_true; case l_undef: - TRACE("q", tout << l.lhs << " ~~ " << l.rhs << " is undef\n";); if (idx != UINT_MAX) { idx = UINT_MAX; return l_undef; diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index af49f4eda..669347d68 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -71,6 +71,7 @@ namespace q { for (auto const& [qlit, fml, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ctx.mk_literal(fml); + m_qs.log_instantiation(~qlit, ~lit); m_qs.add_clause(~qlit, ~lit); } m_instantiations.reset(); diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 7c1c19040..450884374 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -356,4 +356,7 @@ namespace q { m_ematch.get_antecedents(l, idx, r, probing); } + void solver::log_instantiation(unsigned n, sat::literal const* lits) { + TRACE("q", for (unsigned i = 0; i < n; ++i) tout << literal2expr(lits[i]) << "\n";); + } } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 32025888b..f84987500 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -88,5 +88,9 @@ namespace q { sat::literal_vector const& universal() const { return m_universal; } quantifier* flatten(quantifier* q); + void log_instantiation(sat::literal q, sat::literal i) { sat::literal lits[2] = { q, i }; log_instantiation(2, lits); } + void log_instantiation(sat::literal_vector const& lits) { log_instantiation(lits.size(), lits.data()); } + void log_instantiation(unsigned n, sat::literal const* lits); + }; }