diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 6ea07e84c..7ea5f4589 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -92,6 +92,7 @@ add_executable(test-z3 rational.cpp rcf.cpp region.cpp + sat_lookahead.cpp sat_user_scope.cpp simple_parser.cpp simplex.cpp diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index f6bff3cd5..8fd0d89a8 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -709,6 +709,37 @@ namespace sat { return result; } + void card_extension::find_mutexes(literal_vector& lits, vector & mutexes) { + literal_set slits(lits); + bool change = false; + for (unsigned i = 0; i < m_constraints.size(); ++i) { + card& c = *m_constraints[i]; + if (c.size() == c.k() + 1) { + literal_vector mux; + for (unsigned j = 0; j < c.size(); ++j) { + literal lit = ~c[j]; + if (slits.contains(lit)) { + mux.push_back(lit); + } + } + if (mux.size() <= 1) { + continue; + } + + for (unsigned j = 0; j < mux.size(); ++j) { + slits.remove(mux[j]); + } + change = true; + mutexes.push_back(mux); + } + } + if (!change) return; + literal_set::iterator it = slits.begin(), end = slits.end(); + lits.reset(); + for (; it != end; ++it) { + lits.push_back(*it); + } + } void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { watch const* w = m_var_infos[v].m_lit_watch[sign]; @@ -957,7 +988,6 @@ namespace sat { tout << lits << "\n";); return value < p.m_k; } - }; diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 3b65afb6b..65a991ec2 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -163,6 +163,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); + virtual void find_mutexes(literal_vector& lits, vector & mutexes); }; }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index cd756d79b..e5fac42ae 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -113,9 +113,9 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); - m_drat = p.drat() && p.threads() == 1; m_drat_check = p.drat_check(); m_drat_file = p.drat_file(); + m_drat = (m_drat_check || m_drat_file != symbol("")) && p.threads() == 1; m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 8cde147cc..36dc3a8d9 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -151,8 +151,6 @@ namespace sat { break; default: SASSERT(*it == &c); - *it2 = *it; - it2++; if (j < sz) { if (m_solver.m_config.m_drat) m_solver.m_drat.del(c); c.shrink(j); @@ -162,10 +160,12 @@ namespace sat { c.update_approx(); DEBUG_CODE({ - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < j; i++) { SASSERT(c[i] == norm(roots, c[i])); } }); + *it2 = *it; + it2++; if (!c.frozen()) { m_solver.attach_clause(c); } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 042f68e24..aae99c28f 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -47,6 +47,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; + virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; }; }; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h new file mode 100644 index 000000000..f70ceab38 --- /dev/null +++ b/src/sat/sat_lookahead.h @@ -0,0 +1,394 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_lookahead.h + +Abstract: + + Lookahead SAT solver in the style of March. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-2-11 + +Notes: + +--*/ +#ifndef _SAT_LOOKAHEAD_H_ +#define _SAT_LOOKAHEAD_H_ + +namespace sat { + class lookahead { + solver& s; + + struct config { + double m_dl_success; + }; + + config m_config; + double m_delta_trigger; + literal_vector m_trail; + literal_vector m_units; + unsigned_vector m_units_lim; + unsigned_vector m_learned_lim; + + + void init() { + m_delta_trigger = s.num_vars()/10; + m_config.m_dl_success = 0.8; + } + + void push(literal lit) { + m_learned_lim.push_back(s.m_learned.size()); + m_units_lim.push_back(m_units.size()); + m_trail.push_back(lit); + s.push(); + assign(lit); + } + + void pop() { + s.pop(1); + unsigned old_sz = m_learned_lim.back(); + m_learned_lim.pop_back(); + for (unsigned i = old_sz; i < s.m_learned.size(); ++i) { + clause* r = s.m_learned[i]; + s.dettach_clause(*r); + s.m_cls_allocator.del_clause(r); + } + s.m_learned.shrink(old_sz); + literal lits[2] = { m_trail.back(), null_literal }; + unsigned new_unit_sz = m_units_lim.back(); + for (unsigned i = m_units.size(); i > new_unit_sz; ) { + --i; + lits[1] = m_units[i]; + clause * r = s.m_cls_allocator.mk_clause(2, lits, true); + s.m_learned.push_back(r); + } + m_units.shrink(new_unit_sz); + m_units_lim.pop_back(); + m_trail.pop_back(); + } + + unsigned diff(unsigned value0) const { + unsigned value1 = get_state_value(); + SASSERT(value1 >= value0); + return value1 - value0; + } + + unsigned mix_diff(unsigned l, unsigned r) const { + return l + r + (1 << 10) * l * r; + } + + void get_resolvent_units(literal lit) { + if (inconsistent()) return; + for (unsigned i = s.m_trail.size(); i > 0; ) { + --i; + literal l = s.m_trail[i]; + if (l == lit) break; + SASSERT(s.lvl(l) == s.scope_lvl()); + watch_list& wlist = s.m_watches[(~l).index()]; + watch_list::iterator it = wlist.begin(), end = wlist.end(); + for (; it != end; ++it) { + switch (it->get_kind()) { + case watched::TERNARY: + if (s.value(it->get_literal1()) == l_false && + s.value(it->get_literal()) == l_false) { + m_units.push_back(l); + goto done_watch_list; + } + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.size() == 2) break; + SASSERT(c.size() > 2); + if (c[0] == l && s.value(c[1]) == l_false) { + DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + m_units.push_back(l); + goto done_watch_list; + } + if (c[1] == l && s.value(c[0]) == l_false) { + DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + m_units.push_back(l); + goto done_watch_list; + } + break; + } + default: + break; + } + } + done_watch_list: + continue; + } + } + + literal choose() { + literal l; + while (!choose1(l)) {}; + return l; + } + + unsigned get_state_value() const { + return s.m_learned.size(); + } + + bool choose1(literal& l) { + literal_vector P; + pre_select(P); + l = null_literal; + if (P.empty()) { + return true; + } + unsigned value0 = get_state_value(); + unsigned h = 0, count = 1; + literal_vector& units = m_units;; + for (unsigned i = 0; i < P.size(); ++i) { + literal lit = P[i]; + + push(lit); + if (do_double(value0)) double_look(); + if (inconsistent()) { + pop(); + assign(~lit); + if (do_double(value0)) double_look(); + if (inconsistent()) return true; + continue; + } + unsigned diff1 = diff(value0); + pop(); + + push(~lit); + if (do_double(value0)) double_look(); + bool unsat2 = inconsistent(); + unsigned diff2 = diff(value0); + pop(); + + if (unsat2) { + assign(lit); + continue; + } + + unsigned mixd = mix_diff(diff1, diff2); + + if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { + h = mixd; + l = diff1 < diff2 ? lit : ~lit; + ++count; + } + } + return l != null_literal; + } + + void double_look() { + literal_vector P; + pre_select(P); + for (unsigned i = 0; !inconsistent() && i < P.size(); ++i) { + literal lit = P[i]; + + push(lit); + bool unsat = inconsistent(); + pop(); + if (unsat) { + assign(~lit); + continue; + } + + push(~lit); + unsat = inconsistent(); + pop(); + if (unsat) { + assign(lit); + } + + } + update_delta_trigger(); + } + + void assign(literal l) { + s.assign(l, justification()); + s.propagate(false); + get_resolvent_units(l); + } + + bool inconsistent() { return s.inconsistent(); } + + void pre_select(literal_vector& P) { + select_variables(P); + order_by_implication_trees(P); + } + + void order_by_implication_trees(literal_vector& P) { + literal_set roots; + literal_vector nodes, parent; + + // + // Extract binary clauses in watch list. + // Produce implication graph between literals in P. + // + + for (unsigned i = 0; i < P.size(); ++i) { + literal lit1 = P[i], lit2; + + // + // lit2 => lit1, where lit2 is a root. + // make lit1 a root instead of lit2 + // + + watch_list& wlist = s.m_watches[(~lit1).index()]; + watch_list::iterator it = wlist.begin(), end = wlist.end(); + lit2 = null_literal; + for (; it != end; ++it) { + switch (it->get_kind()) { + case watched::BINARY: + lit2 = it->get_literal(); + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.size() == 2) { + if (c[0] == ~lit1) { + lit2 = c[1]; + } + else { + SASSERT(c[1] == ~lit1); + lit2 = c[0]; + } + } + break; + } + default: + break; + } + + if (lit2 != null_literal && roots.contains(lit2)) { + // lit2 => lit1 + // if lit2 is a root, put it under lit2 + parent.setx(lit2.index(), lit1, null_literal); + roots.remove(lit2); + roots.insert(lit1); + goto found; + } + } + + // + // lit1 => lit2. + // if lit2 is a node, put lit1 above lit2 + // + + it = s.m_watches[lit1.index()].begin(); + end = s.m_watches[lit1.index()].end(); + for (; it != end; ++it) { + lit2 = null_literal; + switch (it->get_kind()) { + case watched::BINARY: + lit2 = it->get_literal(); + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.size() == 2) { + if (c[0] == lit1) { + lit2 = c[1]; + } + else { + SASSERT(c[1] == lit1); + lit2 = c[0]; + } + } + break; + } + default: + break; + } + + if (lit2 != null_literal && nodes.contains(lit2)) { + // lit1 => lit2 + parent.setx(lit1.index(), lit2, null_literal); + nodes.insert(lit1); + goto found; + } + } + std::cout << "no parents or children of literal " << lit1 << "\n"; + nodes.push_back(lit1); + roots.insert(lit1); + found: + ; + } + std::cout << "implication trees\n"; + for (unsigned i = 0; i < parent.size(); ++i) { + literal p = parent[i]; + if (p != null_literal) { + std::cout << to_literal(i) << " |-> " << p << "\n"; + } + } + + } + + void select_variables(literal_vector& P) { + for (unsigned i = 0; i < s.num_vars(); ++i) { + if (s.value(i) == l_undef) { + P.push_back(literal(i, false)); + } + } + } + + bool do_double(unsigned value0) { + unsigned value1 = get_state_value(); + return !inconsistent() && value1 - value0 > m_delta_trigger; + } + + void update_delta_trigger() { + if (inconsistent()) { + m_delta_trigger -= (1 - m_config.m_dl_success) / m_config.m_dl_success; + } + else { + m_delta_trigger += 1; + } + if (m_delta_trigger >= s.num_vars()) { + // reset it. + } + } + + lbool search() { + literal_vector trail; + +#define BACKTRACK \ + if (inconsistent()) { \ + if (trail.empty()) return l_false; \ + pop(); \ + assign(~trail.back()); \ + trail.pop_back(); \ + continue; \ + } \ + + while (true) { + s.checkpoint(); + BACKTRACK; + literal l = choose(); + TRACE("sat", tout << l << "\n";); + BACKTRACK; + if (l == null_literal) { + return l_true; + } + push(l); + trail.push_back(l); + } + } + + public: + lookahead(solver& s) : s(s) { + init(); + } + + lbool check() { + return search(); + } + + }; +} + +#endif + diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 493e9fe18..bc7ac408e 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -185,12 +185,17 @@ namespace sat { unsigned owner = s.m_par_id; while (m_pool.get_vector(owner, n, ptr)) { m_lits.reset(); - for (unsigned i = 0; i < n; ++i) { - m_lits.push_back(to_literal(ptr[i])); + bool usable_clause = true; + for (unsigned i = 0; usable_clause && i < n; ++i) { + literal lit(to_literal(ptr[i])); + m_lits.push_back(lit); + usable_clause = lit.var() <= s.m_par_num_vars && !s.was_eliminated(lit.var()); } IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": retrieve " << m_lits << "\n";); SASSERT(n >= 2); - s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true); + if (usable_clause) { + s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true); + } } } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 4a013a7fd..3413d5e6a 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -24,7 +24,6 @@ def_module_params('sat', ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), - ('drat', BOOL, False, 'produce DRAT proofs'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), )) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3c4d784cb..03ff7ec98 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -35,6 +35,10 @@ namespace sat { void use_list::insert(clause & c) { unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { + if (m_use_list.size() <= c[i].index()) { + std::cout << c[i] << "\n"; + std::cout << m_use_list.size() << "\n"; + } m_use_list[c[i].index()].insert(c); } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3b96fa098..476295f7a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -836,7 +836,7 @@ namespace sat { int num_threads = static_cast(m_config.m_num_threads); int num_extra_solvers = num_threads - 1; sat::parallel par(*this); - par.reserve(num_threads, 1 << 9); + par.reserve(num_threads, 1 << 12); par.init_solvers(*this, num_extra_solvers); int finished_id = -1; std::string ex_msg; @@ -3076,17 +3076,21 @@ namespace sat { } } vector _mutexes; + literal_vector _lits(lits); + if (m_ext) { + m_ext->find_mutexes(_lits, mutexes); + } unsigned_vector ps; - for (unsigned i = 0; i < lits.size(); ++i) { - ps.push_back(lits[i].index()); + for (unsigned i = 0; i < _lits.size(); ++i) { + ps.push_back(_lits[i].index()); } mc.cliques(ps, _mutexes); for (unsigned i = 0; i < _mutexes.size(); ++i) { - literal_vector lits; + literal_vector clique; for (unsigned j = 0; j < _mutexes[i].size(); ++j) { - lits.push_back(to_literal(_mutexes[i][j])); + clique.push_back(to_literal(_mutexes[i][j])); } - mutexes.push_back(lits); + mutexes.push_back(clique); } return l_true; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 30d4ca4ad..37e5f1bb6 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -154,6 +154,7 @@ namespace sat { friend class drat; friend class card_extension; friend class parallel; + friend class lookahead; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l); diff --git a/src/test/main.cpp b/src/test/main.cpp index 9239d0119..18b83e90e 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -229,6 +229,7 @@ int main(int argc, char ** argv) { TST(model_evaluator); TST(get_consequences); TST(pb2bv); + TST_ARGV(sat_lookahead); //TST_ARGV(hs); }