PageRenderTime 57ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sat/sat_scc.cpp

https://bitbucket.org/chyh1990/z3
C++ | 241 lines | 198 code | 19 blank | 24 comment | 46 complexity | e89b4e26f260508d6a5bff10e85b876d MD5 | raw file
  1. /*++
  2. Copyright (c) 2011 Microsoft Corporation
  3. Module Name:
  4. sat_scc.cpp
  5. Abstract:
  6. Use binary clauses to compute strongly connected components.
  7. Author:
  8. Leonardo de Moura (leonardo) 2011-05-26.
  9. Revision History:
  10. --*/
  11. #include"sat_scc.h"
  12. #include"sat_solver.h"
  13. #include"sat_elim_eqs.h"
  14. #include"stopwatch.h"
  15. #include"trace.h"
  16. namespace sat {
  17. scc::scc(solver & s, params_ref const & p):
  18. m_solver(s) {
  19. reset_statistics();
  20. updt_params(p);
  21. }
  22. struct frame {
  23. unsigned m_lidx;
  24. bool m_first;
  25. watched * m_it;
  26. watched * m_end;
  27. frame(unsigned lidx, watched * it, watched * end):m_lidx(lidx), m_first(true), m_it(it), m_end(end) {}
  28. };
  29. typedef svector<frame> frames;
  30. struct scc::report {
  31. scc & m_scc;
  32. stopwatch m_watch;
  33. unsigned m_num_elim;
  34. report(scc & c):
  35. m_scc(c),
  36. m_num_elim(c.m_num_elim) {
  37. m_watch.start();
  38. }
  39. ~report() {
  40. m_watch.stop();
  41. IF_VERBOSE(SAT_VB_LVL,
  42. verbose_stream() << " (sat-scc :elim-vars " << (m_scc.m_num_elim - m_num_elim)
  43. << mk_stat(m_scc.m_solver)
  44. << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";);
  45. }
  46. };
  47. unsigned scc::operator()() {
  48. if (m_solver.m_inconsistent)
  49. return 0;
  50. if (!m_scc)
  51. return 0;
  52. CASSERT("scc_bug", m_solver.check_invariant());
  53. report rpt(*this);
  54. TRACE("scc", m_solver.display(tout););
  55. TRACE("scc_details", m_solver.display_watches(tout););
  56. unsigned_vector index;
  57. unsigned_vector lowlink;
  58. unsigned_vector s;
  59. svector<char> in_s;
  60. unsigned num_lits = m_solver.num_vars() * 2;
  61. index.resize(num_lits, UINT_MAX);
  62. lowlink.resize(num_lits, UINT_MAX);
  63. in_s.resize(num_lits, false);
  64. literal_vector roots;
  65. roots.resize(m_solver.num_vars(), null_literal);
  66. unsigned next_index = 0;
  67. svector<frame> frames;
  68. bool_var_vector to_elim;
  69. for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) {
  70. if (index[l_idx] != UINT_MAX)
  71. continue;
  72. if (m_solver.was_eliminated(to_literal(l_idx).var()))
  73. continue;
  74. m_solver.checkpoint();
  75. #define NEW_NODE(LIDX) { \
  76. index[LIDX] = next_index; \
  77. lowlink[LIDX] = next_index; \
  78. next_index++; \
  79. s.push_back(LIDX); \
  80. in_s[LIDX] = true; \
  81. watch_list & wlist = m_solver.get_wlist(LIDX); \
  82. frames.push_back(frame(LIDX, wlist.begin(), wlist.end())); \
  83. }
  84. NEW_NODE(l_idx);
  85. while (!frames.empty()) {
  86. loop:
  87. frame & fr = frames.back();
  88. unsigned l_idx = fr.m_lidx;
  89. if (!fr.m_first) {
  90. // after visiting child
  91. literal l2 = fr.m_it->get_literal();
  92. unsigned l2_idx = l2.index();
  93. SASSERT(index[l2_idx] != UINT_MAX);
  94. if (lowlink[l2_idx] < lowlink[l_idx])
  95. lowlink[l_idx] = lowlink[l2_idx];
  96. fr.m_it++;
  97. }
  98. fr.m_first = false;
  99. while (fr.m_it != fr.m_end) {
  100. if (!fr.m_it->is_binary_clause()) {
  101. fr.m_it++;
  102. continue;
  103. }
  104. literal l2 = fr.m_it->get_literal();
  105. unsigned l2_idx = l2.index();
  106. if (index[l2_idx] == UINT_MAX) {
  107. NEW_NODE(l2_idx);
  108. goto loop;
  109. }
  110. else if (in_s[l2_idx]) {
  111. if (index[l2_idx] < lowlink[l_idx])
  112. lowlink[l_idx] = index[l2_idx];
  113. }
  114. fr.m_it++;
  115. }
  116. // visited all successors
  117. if (lowlink[l_idx] == index[l_idx]) {
  118. // found new SCC
  119. CTRACE("scc_cycle", s.back() != l_idx, {
  120. tout << "cycle: ";
  121. unsigned j = s.size() - 1;
  122. unsigned l2_idx;
  123. do {
  124. l2_idx = s[j];
  125. j--;
  126. tout << to_literal(l2_idx) << " ";
  127. }
  128. while (l2_idx != l_idx);
  129. tout << "\n";
  130. });
  131. SASSERT(!s.empty());
  132. literal l = to_literal(l_idx);
  133. bool_var v = l.var();
  134. if (roots[v] != null_literal) {
  135. // variable was already assigned... just consume stack
  136. TRACE("scc_detail", tout << "consuming stack...\n";);
  137. unsigned l2_idx;
  138. do {
  139. l2_idx = s.back();
  140. s.pop_back();
  141. in_s[l2_idx] = false;
  142. SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var());
  143. }
  144. while (l2_idx != l_idx);
  145. }
  146. else {
  147. // check if the SCC has an external variable, and check for conflicts
  148. TRACE("scc_detail", tout << "assigning roots...\n";);
  149. literal r = null_literal;
  150. unsigned j = s.size() - 1;
  151. unsigned l2_idx;
  152. do {
  153. l2_idx = s[j];
  154. j--;
  155. if (to_literal(l2_idx) == ~l) {
  156. m_solver.set_conflict(justification());
  157. return 0;
  158. }
  159. if (m_solver.is_external(to_literal(l2_idx).var())) {
  160. r = to_literal(l2_idx);
  161. break;
  162. }
  163. }
  164. while (l2_idx != l_idx);
  165. if (r == null_literal) {
  166. // SCC does not contain external variable
  167. r = to_literal(l_idx);
  168. }
  169. TRACE("scc_detail", tout << "r: " << r << "\n";);
  170. do {
  171. l2_idx = s.back();
  172. s.pop_back();
  173. in_s[l2_idx] = false;
  174. literal l2 = to_literal(l2_idx);
  175. bool_var v2 = l2.var();
  176. if (roots[v2] == null_literal) {
  177. if (l2.sign()) {
  178. roots[v2] = ~r;
  179. }
  180. else {
  181. roots[v2] = r;
  182. }
  183. if (v2 != r.var())
  184. to_elim.push_back(v2);
  185. }
  186. }
  187. while (l2_idx != l_idx);
  188. }
  189. }
  190. frames.pop_back();
  191. }
  192. }
  193. TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; }
  194. tout << "to_elim: "; for (unsigned i = 0; i < to_elim.size(); i++) tout << to_elim[i] << " "; tout << "\n";);
  195. m_num_elim += to_elim.size();
  196. elim_eqs eliminator(m_solver);
  197. eliminator(roots, to_elim);
  198. TRACE("scc_detail", m_solver.display(tout););
  199. CASSERT("scc_bug", m_solver.check_invariant());
  200. return to_elim.size();
  201. }
  202. void scc::collect_statistics(statistics & st) {
  203. st.update("elim bool vars", m_num_elim);
  204. }
  205. void scc::reset_statistics() {
  206. m_num_elim = 0;
  207. }
  208. void scc::updt_params(params_ref const & p) {
  209. m_scc = p.get_bool(":scc", true);
  210. }
  211. void scc::collect_param_descrs(param_descrs & d) {
  212. d.insert(":scc", CPK_BOOL, "(default: true) eliminate Boolean variables by computing strongly connected components.");
  213. }
  214. };