/src/sat/sat_scc.cpp
C++ | 241 lines | 198 code | 19 blank | 24 comment | 46 complexity | e89b4e26f260508d6a5bff10e85b876d MD5 | raw file
- /*++
- Copyright (c) 2011 Microsoft Corporation
- Module Name:
- sat_scc.cpp
- Abstract:
- Use binary clauses to compute strongly connected components.
- Author:
- Leonardo de Moura (leonardo) 2011-05-26.
- Revision History:
- --*/
- #include"sat_scc.h"
- #include"sat_solver.h"
- #include"sat_elim_eqs.h"
- #include"stopwatch.h"
- #include"trace.h"
- namespace sat {
- scc::scc(solver & s, params_ref const & p):
- m_solver(s) {
- reset_statistics();
- updt_params(p);
- }
- struct frame {
- unsigned m_lidx;
- bool m_first;
- watched * m_it;
- watched * m_end;
- frame(unsigned lidx, watched * it, watched * end):m_lidx(lidx), m_first(true), m_it(it), m_end(end) {}
- };
- typedef svector<frame> frames;
- struct scc::report {
- scc & m_scc;
- stopwatch m_watch;
- unsigned m_num_elim;
- report(scc & c):
- m_scc(c),
- m_num_elim(c.m_num_elim) {
- m_watch.start();
- }
- ~report() {
- m_watch.stop();
- IF_VERBOSE(SAT_VB_LVL,
- verbose_stream() << " (sat-scc :elim-vars " << (m_scc.m_num_elim - m_num_elim)
- << mk_stat(m_scc.m_solver)
- << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
- }
- };
- unsigned scc::operator()() {
- if (m_solver.m_inconsistent)
- return 0;
- if (!m_scc)
- return 0;
- CASSERT("scc_bug", m_solver.check_invariant());
- report rpt(*this);
- TRACE("scc", m_solver.display(tout););
- TRACE("scc_details", m_solver.display_watches(tout););
- unsigned_vector index;
- unsigned_vector lowlink;
- unsigned_vector s;
- svector<char> in_s;
- unsigned num_lits = m_solver.num_vars() * 2;
- index.resize(num_lits, UINT_MAX);
- lowlink.resize(num_lits, UINT_MAX);
- in_s.resize(num_lits, false);
- literal_vector roots;
- roots.resize(m_solver.num_vars(), null_literal);
- unsigned next_index = 0;
- svector<frame> frames;
- bool_var_vector to_elim;
-
- for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
- if (index[l_idx] != UINT_MAX)
- continue;
- if (m_solver.was_eliminated(to_literal(l_idx).var()))
- continue;
-
- m_solver.checkpoint();
- #define NEW_NODE(LIDX) { \
- index[LIDX] = next_index; \
- lowlink[LIDX] = next_index; \
- next_index++; \
- s.push_back(LIDX); \
- in_s[LIDX] = true; \
- watch_list & wlist = m_solver.get_wlist(LIDX); \
- frames.push_back(frame(LIDX, wlist.begin(), wlist.end())); \
- }
-
- NEW_NODE(l_idx);
-
- while (!frames.empty()) {
- loop:
- frame & fr = frames.back();
- unsigned l_idx = fr.m_lidx;
- if (!fr.m_first) {
- // after visiting child
- literal l2 = fr.m_it->get_literal();
- unsigned l2_idx = l2.index();
- SASSERT(index[l2_idx] != UINT_MAX);
- if (lowlink[l2_idx] < lowlink[l_idx])
- lowlink[l_idx] = lowlink[l2_idx];
- fr.m_it++;
- }
- fr.m_first = false;
- while (fr.m_it != fr.m_end) {
- if (!fr.m_it->is_binary_clause()) {
- fr.m_it++;
- continue;
- }
- literal l2 = fr.m_it->get_literal();
- unsigned l2_idx = l2.index();
- if (index[l2_idx] == UINT_MAX) {
- NEW_NODE(l2_idx);
- goto loop;
- }
- else if (in_s[l2_idx]) {
- if (index[l2_idx] < lowlink[l_idx])
- lowlink[l_idx] = index[l2_idx];
- }
- fr.m_it++;
- }
- // visited all successors
- if (lowlink[l_idx] == index[l_idx]) {
- // found new SCC
- CTRACE("scc_cycle", s.back() != l_idx, {
- tout << "cycle: ";
- unsigned j = s.size() - 1;
- unsigned l2_idx;
- do {
- l2_idx = s[j];
- j--;
- tout << to_literal(l2_idx) << " ";
- }
- while (l2_idx != l_idx);
- tout << "\n";
- });
-
- SASSERT(!s.empty());
- literal l = to_literal(l_idx);
- bool_var v = l.var();
- if (roots[v] != null_literal) {
- // variable was already assigned... just consume stack
- TRACE("scc_detail", tout << "consuming stack...\n";);
- unsigned l2_idx;
- do {
- l2_idx = s.back();
- s.pop_back();
- in_s[l2_idx] = false;
- SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var());
- }
- while (l2_idx != l_idx);
- }
- else {
- // check if the SCC has an external variable, and check for conflicts
- TRACE("scc_detail", tout << "assigning roots...\n";);
- literal r = null_literal;
- unsigned j = s.size() - 1;
- unsigned l2_idx;
- do {
- l2_idx = s[j];
- j--;
- if (to_literal(l2_idx) == ~l) {
- m_solver.set_conflict(justification());
- return 0;
- }
- if (m_solver.is_external(to_literal(l2_idx).var())) {
- r = to_literal(l2_idx);
- break;
- }
- }
- while (l2_idx != l_idx);
-
- if (r == null_literal) {
- // SCC does not contain external variable
- r = to_literal(l_idx);
- }
-
- TRACE("scc_detail", tout << "r: " << r << "\n";);
- do {
- l2_idx = s.back();
- s.pop_back();
- in_s[l2_idx] = false;
- literal l2 = to_literal(l2_idx);
- bool_var v2 = l2.var();
- if (roots[v2] == null_literal) {
- if (l2.sign()) {
- roots[v2] = ~r;
- }
- else {
- roots[v2] = r;
- }
- if (v2 != r.var())
- to_elim.push_back(v2);
- }
- }
- while (l2_idx != l_idx);
- }
- }
- frames.pop_back();
- }
- }
- TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; }
- tout << "to_elim: "; for (unsigned i = 0; i < to_elim.size(); i++) tout << to_elim[i] << " "; tout << "\n";);
- m_num_elim += to_elim.size();
- elim_eqs eliminator(m_solver);
- eliminator(roots, to_elim);
- TRACE("scc_detail", m_solver.display(tout););
- CASSERT("scc_bug", m_solver.check_invariant());
- return to_elim.size();
- }
- void scc::collect_statistics(statistics & st) {
- st.update("elim bool vars", m_num_elim);
- }
-
- void scc::reset_statistics() {
- m_num_elim = 0;
- }
- void scc::updt_params(params_ref const & p) {
- m_scc = p.get_bool(":scc", true);
- }
- void scc::collect_param_descrs(param_descrs & d) {
- d.insert(":scc", CPK_BOOL, "(default: true) eliminate Boolean variables by computing strongly connected components.");
- }
- };