cadical 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +26 -0
  3. data/README.md +101 -0
  4. data/ext/cadical/cadical/LICENSE +28 -0
  5. data/ext/cadical/cadical/README.md +65 -0
  6. data/ext/cadical/cadical/VERSION +1 -0
  7. data/ext/cadical/cadical/src/analyze.cpp +1360 -0
  8. data/ext/cadical/cadical/src/arena.cpp +30 -0
  9. data/ext/cadical/cadical/src/arena.hpp +105 -0
  10. data/ext/cadical/cadical/src/assume.cpp +616 -0
  11. data/ext/cadical/cadical/src/averages.cpp +34 -0
  12. data/ext/cadical/cadical/src/averages.hpp +37 -0
  13. data/ext/cadical/cadical/src/backbone.cpp +631 -0
  14. data/ext/cadical/cadical/src/backtrack.cpp +177 -0
  15. data/ext/cadical/cadical/src/backward.cpp +231 -0
  16. data/ext/cadical/cadical/src/bins.cpp +22 -0
  17. data/ext/cadical/cadical/src/bins.hpp +22 -0
  18. data/ext/cadical/cadical/src/block.cpp +824 -0
  19. data/ext/cadical/cadical/src/block.hpp +37 -0
  20. data/ext/cadical/cadical/src/cadical.cpp +1026 -0
  21. data/ext/cadical/cadical/src/cadical.hpp +1419 -0
  22. data/ext/cadical/cadical/src/ccadical.cpp +208 -0
  23. data/ext/cadical/cadical/src/ccadical.h +74 -0
  24. data/ext/cadical/cadical/src/checker.cpp +649 -0
  25. data/ext/cadical/cadical/src/checker.hpp +173 -0
  26. data/ext/cadical/cadical/src/clause.cpp +689 -0
  27. data/ext/cadical/cadical/src/clause.hpp +190 -0
  28. data/ext/cadical/cadical/src/collect.cpp +545 -0
  29. data/ext/cadical/cadical/src/compact.cpp +550 -0
  30. data/ext/cadical/cadical/src/condition.cpp +940 -0
  31. data/ext/cadical/cadical/src/config.cpp +101 -0
  32. data/ext/cadical/cadical/src/config.hpp +20 -0
  33. data/ext/cadical/cadical/src/congruence.cpp +7880 -0
  34. data/ext/cadical/cadical/src/congruence.hpp +757 -0
  35. data/ext/cadical/cadical/src/constrain.cpp +64 -0
  36. data/ext/cadical/cadical/src/contract.cpp +27 -0
  37. data/ext/cadical/cadical/src/contract.hpp +139 -0
  38. data/ext/cadical/cadical/src/cover.cpp +704 -0
  39. data/ext/cadical/cadical/src/cover.hpp +34 -0
  40. data/ext/cadical/cadical/src/decide.cpp +347 -0
  41. data/ext/cadical/cadical/src/decompose.cpp +738 -0
  42. data/ext/cadical/cadical/src/decompose.hpp +23 -0
  43. data/ext/cadical/cadical/src/deduplicate.cpp +275 -0
  44. data/ext/cadical/cadical/src/definition.cpp +283 -0
  45. data/ext/cadical/cadical/src/delay.hpp +38 -0
  46. data/ext/cadical/cadical/src/drattracer.cpp +153 -0
  47. data/ext/cadical/cadical/src/drattracer.hpp +55 -0
  48. data/ext/cadical/cadical/src/elim.cpp +1171 -0
  49. data/ext/cadical/cadical/src/elim.hpp +53 -0
  50. data/ext/cadical/cadical/src/elimfast.cpp +570 -0
  51. data/ext/cadical/cadical/src/ema.cpp +95 -0
  52. data/ext/cadical/cadical/src/ema.hpp +68 -0
  53. data/ext/cadical/cadical/src/extend.cpp +289 -0
  54. data/ext/cadical/cadical/src/external.cpp +1034 -0
  55. data/ext/cadical/cadical/src/external.hpp +487 -0
  56. data/ext/cadical/cadical/src/external_propagate.cpp +1316 -0
  57. data/ext/cadical/cadical/src/factor.cpp +1011 -0
  58. data/ext/cadical/cadical/src/factor.hpp +54 -0
  59. data/ext/cadical/cadical/src/file.cpp +506 -0
  60. data/ext/cadical/cadical/src/file.hpp +210 -0
  61. data/ext/cadical/cadical/src/flags.cpp +135 -0
  62. data/ext/cadical/cadical/src/flags.hpp +93 -0
  63. data/ext/cadical/cadical/src/flip.cpp +269 -0
  64. data/ext/cadical/cadical/src/format.cpp +89 -0
  65. data/ext/cadical/cadical/src/format.hpp +36 -0
  66. data/ext/cadical/cadical/src/frattracer.cpp +277 -0
  67. data/ext/cadical/cadical/src/frattracer.hpp +67 -0
  68. data/ext/cadical/cadical/src/gates.cpp +766 -0
  69. data/ext/cadical/cadical/src/heap.hpp +212 -0
  70. data/ext/cadical/cadical/src/idruptracer.cpp +566 -0
  71. data/ext/cadical/cadical/src/idruptracer.hpp +112 -0
  72. data/ext/cadical/cadical/src/instantiate.cpp +365 -0
  73. data/ext/cadical/cadical/src/instantiate.hpp +45 -0
  74. data/ext/cadical/cadical/src/internal.cpp +1265 -0
  75. data/ext/cadical/cadical/src/internal.hpp +1941 -0
  76. data/ext/cadical/cadical/src/inttypes.hpp +34 -0
  77. data/ext/cadical/cadical/src/ipasir.cpp +47 -0
  78. data/ext/cadical/cadical/src/ipasir.h +37 -0
  79. data/ext/cadical/cadical/src/kitten.c +2599 -0
  80. data/ext/cadical/cadical/src/kitten.h +97 -0
  81. data/ext/cadical/cadical/src/level.hpp +33 -0
  82. data/ext/cadical/cadical/src/lidruptracer.cpp +657 -0
  83. data/ext/cadical/cadical/src/lidruptracer.hpp +122 -0
  84. data/ext/cadical/cadical/src/limit.cpp +146 -0
  85. data/ext/cadical/cadical/src/limit.hpp +168 -0
  86. data/ext/cadical/cadical/src/logging.cpp +214 -0
  87. data/ext/cadical/cadical/src/logging.hpp +98 -0
  88. data/ext/cadical/cadical/src/lookahead.cpp +520 -0
  89. data/ext/cadical/cadical/src/lratchecker.cpp +833 -0
  90. data/ext/cadical/cadical/src/lratchecker.hpp +168 -0
  91. data/ext/cadical/cadical/src/lrattracer.cpp +200 -0
  92. data/ext/cadical/cadical/src/lrattracer.hpp +61 -0
  93. data/ext/cadical/cadical/src/lucky.cpp +506 -0
  94. data/ext/cadical/cadical/src/message.cpp +218 -0
  95. data/ext/cadical/cadical/src/message.hpp +65 -0
  96. data/ext/cadical/cadical/src/minimize.cpp +224 -0
  97. data/ext/cadical/cadical/src/mobical.cpp +5588 -0
  98. data/ext/cadical/cadical/src/occs.cpp +52 -0
  99. data/ext/cadical/cadical/src/occs.hpp +36 -0
  100. data/ext/cadical/cadical/src/options.cpp +359 -0
  101. data/ext/cadical/cadical/src/options.hpp +442 -0
  102. data/ext/cadical/cadical/src/parse.cpp +471 -0
  103. data/ext/cadical/cadical/src/parse.hpp +75 -0
  104. data/ext/cadical/cadical/src/phases.cpp +56 -0
  105. data/ext/cadical/cadical/src/phases.hpp +19 -0
  106. data/ext/cadical/cadical/src/probe.cpp +990 -0
  107. data/ext/cadical/cadical/src/profile.cpp +107 -0
  108. data/ext/cadical/cadical/src/profile.hpp +283 -0
  109. data/ext/cadical/cadical/src/proof.cpp +691 -0
  110. data/ext/cadical/cadical/src/proof.hpp +125 -0
  111. data/ext/cadical/cadical/src/propagate.cpp +584 -0
  112. data/ext/cadical/cadical/src/queue.cpp +90 -0
  113. data/ext/cadical/cadical/src/queue.hpp +74 -0
  114. data/ext/cadical/cadical/src/radix.hpp +180 -0
  115. data/ext/cadical/cadical/src/random.cpp +207 -0
  116. data/ext/cadical/cadical/src/random.h +44 -0
  117. data/ext/cadical/cadical/src/random.hpp +98 -0
  118. data/ext/cadical/cadical/src/range.hpp +125 -0
  119. data/ext/cadical/cadical/src/reap.cpp +127 -0
  120. data/ext/cadical/cadical/src/reap.hpp +28 -0
  121. data/ext/cadical/cadical/src/reduce.cpp +278 -0
  122. data/ext/cadical/cadical/src/reluctant.hpp +82 -0
  123. data/ext/cadical/cadical/src/rephase.cpp +402 -0
  124. data/ext/cadical/cadical/src/report.cpp +313 -0
  125. data/ext/cadical/cadical/src/resources.cpp +160 -0
  126. data/ext/cadical/cadical/src/resources.hpp +16 -0
  127. data/ext/cadical/cadical/src/restart.cpp +178 -0
  128. data/ext/cadical/cadical/src/restore.cpp +267 -0
  129. data/ext/cadical/cadical/src/score.cpp +51 -0
  130. data/ext/cadical/cadical/src/score.hpp +16 -0
  131. data/ext/cadical/cadical/src/shrink.cpp +507 -0
  132. data/ext/cadical/cadical/src/signal.cpp +136 -0
  133. data/ext/cadical/cadical/src/signal.hpp +33 -0
  134. data/ext/cadical/cadical/src/solution.cpp +50 -0
  135. data/ext/cadical/cadical/src/solver.cpp +1871 -0
  136. data/ext/cadical/cadical/src/stable.cpp +31 -0
  137. data/ext/cadical/cadical/src/stack.h +110 -0
  138. data/ext/cadical/cadical/src/stats.cpp +920 -0
  139. data/ext/cadical/cadical/src/stats.hpp +418 -0
  140. data/ext/cadical/cadical/src/subsume.cpp +645 -0
  141. data/ext/cadical/cadical/src/sweep.cpp +1960 -0
  142. data/ext/cadical/cadical/src/sweep.hpp +61 -0
  143. data/ext/cadical/cadical/src/terminal.cpp +38 -0
  144. data/ext/cadical/cadical/src/terminal.hpp +96 -0
  145. data/ext/cadical/cadical/src/ternary.cpp +450 -0
  146. data/ext/cadical/cadical/src/testing.hpp +24 -0
  147. data/ext/cadical/cadical/src/tier.cpp +189 -0
  148. data/ext/cadical/cadical/src/tracer.hpp +186 -0
  149. data/ext/cadical/cadical/src/transred.cpp +253 -0
  150. data/ext/cadical/cadical/src/unstable.cpp +29 -0
  151. data/ext/cadical/cadical/src/util.cpp +129 -0
  152. data/ext/cadical/cadical/src/util.hpp +181 -0
  153. data/ext/cadical/cadical/src/var.cpp +39 -0
  154. data/ext/cadical/cadical/src/var.hpp +22 -0
  155. data/ext/cadical/cadical/src/veripbtracer.cpp +427 -0
  156. data/ext/cadical/cadical/src/veripbtracer.hpp +106 -0
  157. data/ext/cadical/cadical/src/version.cpp +107 -0
  158. data/ext/cadical/cadical/src/version.hpp +13 -0
  159. data/ext/cadical/cadical/src/vivify.cpp +1893 -0
  160. data/ext/cadical/cadical/src/vivify.hpp +50 -0
  161. data/ext/cadical/cadical/src/walk.cpp +1088 -0
  162. data/ext/cadical/cadical/src/walk.hpp +91 -0
  163. data/ext/cadical/cadical/src/walk_full_occs.cpp +966 -0
  164. data/ext/cadical/cadical/src/warmup.cpp +403 -0
  165. data/ext/cadical/cadical/src/watch.cpp +126 -0
  166. data/ext/cadical/cadical/src/watch.hpp +77 -0
  167. data/ext/cadical/cadical_ext.c +778 -0
  168. data/ext/cadical/extconf.rb +26 -0
  169. data/lib/cadical/version.rb +3 -0
  170. data/lib/cadical.rb +12 -0
  171. metadata +218 -0
@@ -0,0 +1,738 @@
1
+ #include "internal.hpp"
2
+
3
+ namespace CaDiCaL {
4
+
5
+ void Internal::decompose_analyze_binary_chain (DFS *dfs, int from) {
6
+ if (!lrat)
7
+ return;
8
+ LOG ("binary chain starting at %d", from);
9
+ DFS &from_dfs = dfs[vlit (from)];
10
+ Clause *reason = from_dfs.parent;
11
+ if (!reason)
12
+ return;
13
+ assert (reason->size == 2);
14
+ mini_chain.push_back (reason->id);
15
+ int other = reason->literals[0];
16
+ other = other == from ? -reason->literals[1] : -other;
17
+ Flags &f = flags (other);
18
+ if (f.seen)
19
+ return;
20
+ f.seen = true;
21
+ analyzed.push_back (other);
22
+ decompose_analyze_binary_chain (dfs, other);
23
+ }
24
+
25
+ vector<Clause *> Internal::decompose_analyze_binary_clauses (DFS *dfs,
26
+ int from) {
27
+ vector<Clause *> result;
28
+ LOG ("binary chain starting at %d", from);
29
+ DFS &from_dfs = dfs[vlit (from)];
30
+ Clause *reason = from_dfs.parent;
31
+ while (reason) {
32
+ result.push_back (reason);
33
+ assert (reason->size == 2);
34
+ int other = reason->literals[0];
35
+ other = other == from ? -reason->literals[1] : -other;
36
+ Flags &f = flags (other);
37
+ if (f.seen)
38
+ break;
39
+ f.seen = true;
40
+ analyzed.push_back (other);
41
+ from = other;
42
+ DFS &from_dfs = dfs[vlit (from)];
43
+ reason = from_dfs.parent;
44
+ }
45
+ return result;
46
+ }
47
+
48
+ void Internal::decompose_conflicting_scc_lrat (DFS *dfs, vector<int> &scc) {
49
+ if (!lrat)
50
+ return;
51
+ assert (lrat_chain.empty ());
52
+ assert (mini_chain.empty ());
53
+ for (auto &lit : scc) {
54
+ Flags &f = flags (lit);
55
+ if (f.seen)
56
+ return;
57
+ f.seen = true;
58
+ analyzed.push_back (lit);
59
+ decompose_analyze_binary_chain (dfs, lit);
60
+ for (auto p = mini_chain.rbegin (); p != mini_chain.rend (); p++) {
61
+ lrat_chain.push_back (*p);
62
+ }
63
+ mini_chain.clear ();
64
+ }
65
+ clear_analyzed_literals ();
66
+ }
67
+
68
+ void Internal::build_lrat_for_clause (
69
+ const vector<vector<Clause *>> &dfs_chains, bool invert) {
70
+ assert (lrat);
71
+ LOG ("building chain for not subsumed clause");
72
+ assert (lrat_chain.empty ());
73
+ assert (sign_marked.empty ());
74
+ // build chain for each replaced literal
75
+ for (const auto lit : clause) {
76
+ auto other = lit;
77
+ if (val (other) > 0) {
78
+ if (marked_decomposed (other))
79
+ continue;
80
+ mark_decomposed (other);
81
+ int64_t id = unit_id (other);
82
+ lrat_chain.push_back (id);
83
+ continue;
84
+ }
85
+ assert (mini_chain.empty ());
86
+ for (auto p : dfs_chains[vlit (other)]) {
87
+ if (marked_decomposed (other))
88
+ continue;
89
+ mark_decomposed (other);
90
+ int implied = p->literals[0];
91
+ implied = implied == other ? -p->literals[1] : -implied;
92
+ LOG ("ADDED %d -> %d (%" PRId64 ")", implied, other, p->id);
93
+ other = implied;
94
+ mini_chain.push_back (p->id);
95
+ if (val (implied) <= 0)
96
+ continue;
97
+ if (marked_decomposed (implied))
98
+ break;
99
+ mark_decomposed (implied);
100
+ int64_t id = unit_id (implied);
101
+ mini_chain.push_back (id);
102
+ break;
103
+ }
104
+ if (invert)
105
+ for (auto p = mini_chain.rbegin (); p != mini_chain.rend (); p++)
106
+ lrat_chain.push_back (*p);
107
+ else
108
+ for (auto p = mini_chain.begin (); p != mini_chain.end (); p++)
109
+ lrat_chain.push_back (*p);
110
+ mini_chain.clear ();
111
+ }
112
+ clear_sign_marked_literals ();
113
+ LOG (lrat_chain, "lrat_chain:");
114
+ }
115
+
116
+ void Internal::clear_sign_marked_literals () {
117
+ LOG ("clearing %zd marked literals", sign_marked.size ());
118
+ for (const auto &lit : sign_marked) {
119
+ // assert (marked_signed (lit)); violated on purpose in factor
120
+ unmark_decomposed (lit);
121
+ }
122
+ sign_marked.clear ();
123
+ }
124
+
125
+ // This performs one round of Tarjan's algorithm, e.g., equivalent literal
126
+ // detection and substitution, on the whole formula. We might want to
127
+ // repeat it since its application might produce new binary clauses or
128
+ // units. Such units might even result in an empty clause.
129
+
130
+ bool Internal::decompose_round () {
131
+
132
+ if (!opts.decompose)
133
+ return false;
134
+ if (unsat)
135
+ return false;
136
+ if (terminated_asynchronously ())
137
+ return false;
138
+
139
+ assert (!level);
140
+
141
+ START_SIMPLIFIER (decompose, DECOMP);
142
+
143
+ stats.decompositions++;
144
+
145
+ const size_t size_dfs = 2 * (1 + (size_t) max_var);
146
+ DFS *dfs = new DFS[size_dfs];
147
+ DeferDeleteArray<DFS> dfs_delete (dfs);
148
+ int *reprs = new int[size_dfs];
149
+ DeferDeleteArray<int> reprs_delete (reprs);
150
+ clear_n (reprs, size_dfs);
151
+ vector<vector<Clause *>> dfs_chains;
152
+ dfs_chains.resize (size_dfs);
153
+ if (lrat) {
154
+ for (size_t i = 0; i > size_dfs; i++) {
155
+ vector<Clause *> empty;
156
+ dfs_chains[i] = empty;
157
+ }
158
+ }
159
+
160
+ int substituted = 0;
161
+ #ifndef QUIET
162
+ int non_trivial_sccs = 0;
163
+ int before = active ();
164
+ #endif
165
+ unsigned dfs_idx = 0;
166
+
167
+ vector<int> work; // depth first search working stack
168
+ vector<int> scc; // collects members of one SCC
169
+
170
+ // The binary implication graph might have disconnected components and
171
+ // thus we have in general to start several depth first searches.
172
+
173
+ for (auto root_idx : vars) {
174
+ if (unsat)
175
+ break;
176
+ if (!active (root_idx))
177
+ continue;
178
+ for (int root_sign = -1; !unsat && root_sign <= 1; root_sign += 2) {
179
+ int root = root_sign * root_idx;
180
+ if (dfs[vlit (root)].min == TRAVERSED)
181
+ continue; // skip traversed
182
+ LOG ("new dfs search starting at root %d", root);
183
+ assert (work.empty ());
184
+ assert (scc.empty ());
185
+ work.push_back (root);
186
+ while (!unsat && !work.empty ()) {
187
+ int parent = work.back ();
188
+ DFS &parent_dfs = dfs[vlit (parent)];
189
+ if (parent_dfs.min == TRAVERSED) { // skip traversed
190
+ assert (reprs[vlit (parent)]);
191
+ work.pop_back ();
192
+ } else {
193
+ assert (!reprs[vlit (parent)]);
194
+
195
+ // Go over all implied literals, thus need to iterate over all
196
+ // binary watched clauses with the negation of 'parent'.
197
+
198
+ Watches &ws = watches (-parent);
199
+
200
+ // Two cases: Either the node has never been visited before, i.e.,
201
+ // it's depth first search index is zero, then perform the
202
+ // 'pre-fix' work before visiting it's children. Otherwise all
203
+ // it's children and nodes reachable from those children have been
204
+ // visited and their minimum reachable depth first search index
205
+ // has been computed. This second case is the 'post-fix' work.
206
+
207
+ if (parent_dfs.idx) { // post-fix
208
+
209
+ work.pop_back (); // 'parent' done
210
+
211
+ // Get the minimum reachable depth first search index reachable
212
+ // from the children of 'parent'.
213
+
214
+ unsigned new_min = parent_dfs.min;
215
+
216
+ for (const auto &w : ws) {
217
+ if (!w.binary ())
218
+ continue;
219
+ const int child = w.blit;
220
+ if (!active (child))
221
+ continue;
222
+ DFS &child_dfs = dfs[vlit (child)];
223
+ if (new_min > child_dfs.min)
224
+ new_min = child_dfs.min;
225
+ }
226
+
227
+ LOG ("post-fix work dfs search %d index %u reaches minimum %u",
228
+ parent, parent_dfs.idx, new_min);
229
+
230
+ if (parent_dfs.idx == new_min) { // entry to SCC
231
+
232
+ // All nodes on the 'scc' stack after and including 'parent'
233
+ // are in the same SCC. Their representative is computed as
234
+ // the smallest literal (index-wise) in the SCC. If the SCC
235
+ // contains both a literal and its negation, then the formula
236
+ // becomes unsatisfiable.
237
+
238
+ if (lrat) {
239
+ assert (analyzed.empty ());
240
+ int other, first = 0;
241
+ bool conflicting = false;
242
+ size_t j = scc.size ();
243
+ do {
244
+ assert (j > 0);
245
+ other = scc[--j];
246
+ if (!first || vlit (other) < vlit (first))
247
+ first = other;
248
+ Flags &f = flags (other);
249
+ if (other == -parent) {
250
+ conflicting = true; // conflicting scc
251
+ }
252
+ if (f.seen) {
253
+ continue; // also conflicting scc
254
+ }
255
+ f.seen = true;
256
+ analyzed.push_back (other);
257
+ } while (other != parent);
258
+
259
+ assert (!conflicting || first > 0);
260
+ vector<int> to_justify;
261
+ if (conflicting) {
262
+ LOG ("conflicting scc simulating up at %d", parent);
263
+ to_justify.push_back (-parent);
264
+ } else
265
+ to_justify.push_back (first);
266
+ while (!to_justify.empty ()) {
267
+ const int next = to_justify.back ();
268
+ to_justify.pop_back ();
269
+ Watches &next_ws = watches (-next);
270
+ for (const auto &w : next_ws) {
271
+ if (!w.binary ())
272
+ continue;
273
+ const int child = w.blit;
274
+ if (!active (child))
275
+ continue;
276
+ if (!flags (child).seen)
277
+ continue;
278
+ DFS &child_dfs = dfs[vlit (child)];
279
+ if (child_dfs.parent)
280
+ continue;
281
+ child_dfs.parent = w.clause;
282
+ to_justify.push_back (child);
283
+ }
284
+ }
285
+
286
+ clear_analyzed_literals ();
287
+ }
288
+
289
+ int other, repr = parent;
290
+ #ifndef QUIET
291
+ int size = 0;
292
+ #endif
293
+ assert (!scc.empty ());
294
+ size_t j = scc.size ();
295
+ do {
296
+ assert (j > 0);
297
+ other = scc[--j];
298
+ if (other == -parent) {
299
+ LOG ("both %d and %d in one SCC", parent, -parent);
300
+ if (lrat) {
301
+ Flags &f = flags (-parent);
302
+ f.seen = true;
303
+ analyzed.push_back (-parent);
304
+ decompose_analyze_binary_chain (dfs, parent);
305
+ for (auto p : mini_chain)
306
+ lrat_chain.push_back (p);
307
+ mini_chain.clear ();
308
+ }
309
+ assign_unit (parent);
310
+ #ifndef NDEBUG
311
+ bool ok =
312
+ #endif
313
+ propagate ();
314
+ assert (!ok);
315
+ learn_empty_clause ();
316
+ lrat_chain.clear ();
317
+ } else {
318
+ if (abs (other) < abs (repr))
319
+ repr = other;
320
+ #ifndef QUIET
321
+ size++;
322
+ #endif
323
+ }
324
+ } while (!unsat && other != parent);
325
+
326
+ if (unsat)
327
+ break;
328
+ #ifndef QUIET
329
+ LOG ("SCC of representative %d of size %d", repr, size);
330
+ #endif
331
+ do {
332
+ assert (!scc.empty ());
333
+ other = scc.back ();
334
+ scc.pop_back ();
335
+ dfs[vlit (other)].min = TRAVERSED;
336
+ if (frozen (other)) {
337
+ reprs[vlit (other)] = other;
338
+ continue;
339
+ }
340
+ reprs[vlit (other)] = repr;
341
+ if (other == repr)
342
+ continue;
343
+ substituted++;
344
+ LOG ("literal %d in SCC of %d", other, repr);
345
+ if (!lrat)
346
+ continue;
347
+ assert (mini_chain.empty ());
348
+ Flags &f = flags (repr);
349
+ f.seen = true;
350
+ analyzed.push_back (repr);
351
+ // no need to reverse dfs_chain because this is handled by
352
+ // build_lrat_for_clause.
353
+ dfs_chains[vlit (other)] =
354
+ decompose_analyze_binary_clauses (dfs, other);
355
+ clear_analyzed_literals ();
356
+ } while (other != parent);
357
+
358
+ #ifndef QUIET
359
+ if (size > 1)
360
+ non_trivial_sccs++;
361
+ #endif
362
+
363
+ } else {
364
+
365
+ // Current node 'parent' is in a non-trivial SCC but is not
366
+ // the entry point of the SCC in this depth first search, so
367
+ // keep it on the SCC stack until the entry point is reached.
368
+
369
+ parent_dfs.min = new_min;
370
+ }
371
+
372
+ } else { // pre-fix
373
+
374
+ dfs_idx++;
375
+ assert (dfs_idx < TRAVERSED);
376
+ parent_dfs.idx = parent_dfs.min = dfs_idx;
377
+ scc.push_back (parent);
378
+
379
+ LOG ("pre-fix work dfs search %d index %u", parent, dfs_idx);
380
+
381
+ // Now traverse all the children in the binary implication
382
+ // graph but keep 'parent' on the stack for 'post-fix' work.
383
+
384
+ for (const auto &w : ws) {
385
+ if (!w.binary ())
386
+ continue;
387
+ const int child = w.blit;
388
+ if (!active (child))
389
+ continue;
390
+ DFS &child_dfs = dfs[vlit (child)];
391
+ if (child_dfs.idx)
392
+ continue;
393
+ work.push_back (child);
394
+ }
395
+ }
396
+ }
397
+ }
398
+ }
399
+ }
400
+
401
+ erase_vector (work);
402
+ erase_vector (scc);
403
+ // delete [] dfs; need to postpone until after changing clauses...
404
+
405
+ // Only keep the representatives 'repr' mapping.
406
+
407
+ PHASE ("decompose", stats.decompositions,
408
+ "%d non-trivial sccs, %d substituted %.2f%%", non_trivial_sccs,
409
+ substituted, percent (substituted, before));
410
+
411
+ bool new_unit = false, new_binary_clause = false;
412
+
413
+ // Finally, mark substituted literals as such and push the equivalences of
414
+ // the substituted literals to their representative on the extension
415
+ // stack to fix an assignment during 'extend'.
416
+ // It is also necessary to do so for proper IDRUP/LIDRUP/Resolution proofs
417
+
418
+ vector<int64_t> decompose_ids;
419
+ const size_t size = 2 * (1 + (size_t) max_var);
420
+ decompose_ids.resize (size);
421
+
422
+ for (auto idx : vars) {
423
+ if (!substituted)
424
+ break;
425
+ if (unsat)
426
+ break;
427
+ if (!active (idx))
428
+ continue;
429
+ int other = reprs[vlit (idx)];
430
+ if (other == idx)
431
+ continue;
432
+ assert (!flags (other).eliminated ());
433
+ assert (!flags (other).substituted ());
434
+
435
+ LOG ("marking equivalence of %d and %d", idx, other);
436
+ assert (clause.empty ());
437
+ assert (lrat_chain.empty ());
438
+ clause.push_back (other);
439
+ clause.push_back (-idx);
440
+ if (lrat) {
441
+ build_lrat_for_clause (dfs_chains);
442
+ assert (!lrat_chain.empty ());
443
+ }
444
+
445
+ const int64_t id1 = ++clause_id;
446
+ if (proof) {
447
+ proof->add_derived_clause (id1, false, clause, lrat_chain);
448
+ proof->weaken_minus (id1, clause);
449
+ }
450
+ external->push_binary_clause_on_extension_stack (id1, -idx, other);
451
+
452
+ decompose_ids[vlit (-idx)] = id1;
453
+
454
+ lrat_chain.clear ();
455
+ clause.clear ();
456
+
457
+ assert (clause.empty ());
458
+ assert (lrat_chain.empty ());
459
+ clause.push_back (idx);
460
+ clause.push_back (-other);
461
+ if (lrat) {
462
+ build_lrat_for_clause (dfs_chains);
463
+ assert (!lrat_chain.empty ());
464
+ }
465
+ const int64_t id2 = ++clause_id;
466
+ if (proof) {
467
+ proof->add_derived_clause (id2, false, clause, lrat_chain);
468
+ proof->weaken_minus (id2, clause);
469
+ }
470
+ external->push_binary_clause_on_extension_stack (id2, idx, -other);
471
+ decompose_ids[vlit (idx)] = id2;
472
+ for (auto &tracer : tracers) {
473
+ const int eidx = externalize (idx);
474
+ const int eother = externalize (other);
475
+ tracer->notify_equivalence (eidx, eother);
476
+ }
477
+
478
+ clause.clear ();
479
+ lrat_chain.clear ();
480
+ }
481
+
482
+ vector<Clause *> postponed_garbage;
483
+
484
+ // Now go over all clauses and find clause which contain literals that
485
+ // should be substituted by their representative.
486
+
487
+ size_t clauses_size = clauses.size ();
488
+ #ifndef QUIET
489
+ size_t garbage = 0, replaced = 0;
490
+ #endif
491
+ for (size_t i = 0; substituted && !unsat && i < clauses_size; i++) {
492
+ Clause *c = clauses[i];
493
+ if (c->garbage)
494
+ continue;
495
+ int j, size = c->size;
496
+ for (j = 0; j < size; j++) {
497
+ const int lit = c->literals[j];
498
+ if (reprs[vlit (lit)] != lit)
499
+ break;
500
+ }
501
+
502
+ if (j == size)
503
+ continue;
504
+
505
+ #ifndef QUIET
506
+ replaced++;
507
+ #endif
508
+ LOG (c, "first substituted literal %d in", substituted);
509
+
510
+ // Now copy the result to 'clause'. Substitute literals if they have a
511
+ // different representative. Skip duplicates and false literals. If a
512
+ // literal occurs in both phases or is assigned to true the clause is
513
+ // satisfied and can be marked as garbage.
514
+
515
+ assert (clause.empty ());
516
+ assert (lrat_chain.empty ());
517
+ assert (analyzed.empty ());
518
+ bool satisfied = false;
519
+
520
+ for (int k = 0; !satisfied && k < size; k++) {
521
+ const int lit = c->literals[k];
522
+ signed char tmp = val (lit);
523
+ if (tmp > 0)
524
+ satisfied = true;
525
+ else if (tmp < 0) {
526
+ if (!lrat)
527
+ continue;
528
+ Flags &f = flags (lit);
529
+ if (f.seen)
530
+ continue;
531
+ f.seen = true;
532
+ analyzed.push_back (lit);
533
+ int64_t id = unit_id (-lit);
534
+ lrat_chain.push_back (id);
535
+ continue;
536
+ } else {
537
+ const int other = reprs[vlit (lit)];
538
+ tmp = val (other);
539
+ if (tmp < 0) {
540
+ if (!lrat)
541
+ continue;
542
+ Flags &f = flags (other);
543
+ if (!f.seen) {
544
+ f.seen = true;
545
+ analyzed.push_back (other);
546
+ int64_t id = unit_id (-other);
547
+ lrat_chain.push_back (id);
548
+ }
549
+ if (other == lit)
550
+ continue;
551
+ int64_t id = decompose_ids[vlit (-lit)];
552
+ assert (id);
553
+ lrat_chain.push_back (id);
554
+ continue;
555
+ } else if (tmp > 0)
556
+ satisfied = true;
557
+ else {
558
+ tmp = marked (other);
559
+ if (tmp < 0)
560
+ satisfied = true;
561
+ else if (!tmp) {
562
+ mark (other);
563
+ clause.push_back (other);
564
+ }
565
+ if (other == lit)
566
+ continue;
567
+ if (!lrat)
568
+ continue;
569
+ int64_t id = decompose_ids[vlit (-lit)];
570
+ assert (id);
571
+ lrat_chain.push_back (id);
572
+ }
573
+ }
574
+ }
575
+ if (lrat)
576
+ lrat_chain.push_back (c->id);
577
+ clear_analyzed_literals ();
578
+ LOG (lrat_chain, "lrat_chain:");
579
+ if (satisfied) {
580
+ LOG (c, "satisfied after substitution (postponed)");
581
+ postponed_garbage.push_back (c);
582
+ #ifndef QUIET
583
+ garbage++;
584
+ #endif
585
+ } else if (!clause.size ()) {
586
+ LOG ("learned empty clause during decompose");
587
+ learn_empty_clause ();
588
+ } else if (clause.size () == 1) {
589
+ LOG (c, "unit %d after substitution", clause[0]);
590
+ assign_unit (clause[0]);
591
+ mark_garbage (c);
592
+ new_unit = true;
593
+ #ifndef QUIET
594
+ garbage++;
595
+ #endif
596
+ } else if (c->literals[0] != clause[0] || c->literals[1] != clause[1]) {
597
+ LOG ("need new clause since at least one watched literal changed");
598
+ if (clause.size () == 2)
599
+ new_binary_clause = true;
600
+ size_t d_clause_idx = clauses.size ();
601
+ Clause *d = new_clause_as (c);
602
+ assert (clauses[d_clause_idx] == d);
603
+ clauses[d_clause_idx] = c;
604
+ clauses[i] = d;
605
+ mark_garbage (c);
606
+ #ifndef QUIET
607
+ garbage++;
608
+ #endif
609
+ } else {
610
+ LOG ("simply shrinking clause since watches did not change");
611
+ assert (c->size > 2);
612
+ if (!c->redundant)
613
+ mark_removed (c);
614
+ if (proof) {
615
+ proof->add_derived_clause (++clause_id, c->redundant, clause,
616
+ lrat_chain);
617
+ proof->delete_clause (c);
618
+ c->id = clause_id;
619
+ }
620
+ size_t l;
621
+ int *literals = c->literals;
622
+ for (l = 2; l < clause.size (); l++)
623
+ literals[l] = clause[l];
624
+ int flushed = c->size - (int) l;
625
+ if (flushed) {
626
+ if (l == 2)
627
+ new_binary_clause = true;
628
+ LOG ("flushed %d literals", flushed);
629
+ (void) shrink_clause (c, l);
630
+ } else if (likely_to_be_kept_clause (c))
631
+ mark_added (c);
632
+ // we have shrunken c->size to l so even though there is an assertion
633
+ // for c->size > 2 at the beginning of this else block, the new size
634
+ // can be 2 now.
635
+ if (c->size == 2) { // cheaper to update only new binary clauses
636
+ assert (new_binary_clause);
637
+ update_watch_size (watches (c->literals[0]), c->literals[1], c);
638
+ update_watch_size (watches (c->literals[1]), c->literals[0], c);
639
+ }
640
+ LOG (c, "substituted");
641
+ }
642
+ while (!clause.empty ()) {
643
+ int lit = clause.back ();
644
+ clause.pop_back ();
645
+ assert (marked (lit) > 0);
646
+ unmark (lit);
647
+ }
648
+ lrat_chain.clear ();
649
+ }
650
+
651
+ if (proof) {
652
+ for (auto idx : vars) {
653
+ if (!substituted)
654
+ break;
655
+ if (!active (idx))
656
+ continue;
657
+ const int64_t id1 = decompose_ids[vlit (-idx)];
658
+ if (!id1)
659
+ continue;
660
+ int other = reprs[vlit (idx)];
661
+ assert (other != idx);
662
+ assert (!flags (other).eliminated ());
663
+ assert (!flags (other).substituted ());
664
+
665
+ clause.push_back (other);
666
+ clause.push_back (-idx);
667
+ proof->delete_clause (id1, false, clause);
668
+ clause.clear ();
669
+
670
+ clause.push_back (idx);
671
+ clause.push_back (-other);
672
+ const int64_t id2 = decompose_ids[vlit (idx)];
673
+ proof->delete_clause (id2, false, clause);
674
+ clause.clear ();
675
+ }
676
+ }
677
+
678
+ if (!unsat && !postponed_garbage.empty ()) {
679
+ LOG ("now marking %zd postponed garbage clauses",
680
+ postponed_garbage.size ());
681
+ for (const auto &c : postponed_garbage)
682
+ mark_garbage (c);
683
+ }
684
+ erase_vector (postponed_garbage);
685
+
686
+ PHASE ("decompose", stats.decompositions,
687
+ "%zd clauses replaced %.2f%% producing %zd garbage clauses %.2f%%",
688
+ replaced, percent (replaced, clauses_size), garbage,
689
+ percent (garbage, replaced));
690
+
691
+ erase_vector (scc);
692
+
693
+ // Propagate found units.
694
+
695
+ if (!unsat && propagated < trail.size () && !propagate ()) {
696
+ LOG ("empty clause after propagating units from substitution");
697
+ learn_empty_clause ();
698
+ }
699
+
700
+ for (auto idx : vars) {
701
+ if (!substituted)
702
+ break;
703
+ if (unsat)
704
+ break;
705
+ if (!active (idx))
706
+ continue;
707
+ int other = reprs[vlit (idx)];
708
+ if (other == idx)
709
+ continue;
710
+ assert (!flags (other).eliminated ());
711
+ assert (!flags (other).substituted ());
712
+ if (!flags (other).fixed ())
713
+ mark_substituted (idx);
714
+ }
715
+
716
+ reprs_delete.free ();
717
+ dfs_delete.free ();
718
+ erase_vector (dfs_chains);
719
+
720
+ if (substituted)
721
+ flush_all_occs_and_watches (); // particularly the 'blit's
722
+
723
+ bool success =
724
+ unsat || (substituted > 0 && (new_unit || new_binary_clause));
725
+ report ('d', !opts.reportall && !success);
726
+
727
+ STOP_SIMPLIFIER (decompose, DECOMP);
728
+
729
+ return success;
730
+ }
731
+
732
+ void Internal::decompose () {
733
+ for (int round = 1; round <= opts.decomposerounds; round++)
734
+ if (!decompose_round ())
735
+ break;
736
+ }
737
+
738
+ } // namespace CaDiCaL