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,645 @@
1
+ #include "internal.hpp"
2
+
3
+ namespace CaDiCaL {
4
+
5
+ /*------------------------------------------------------------------------*/
6
+
7
+ // This file implements a global forward subsumption algorithm, which is run
8
+ // frequently during search. It works both on original (irredundant)
9
+ // clauses and on 'sticky' learned clauses which are likely to be kept.
10
+ // This is abstracted away in the 'likely_to_be_kept_clause' function, which
11
+ // implicitly relies on 'opts.reducetier1glue' (glucose level of clauses
12
+ // which are not reduced) as well as dynamically determined size and glucose
13
+ // level ('lim.keptglue' and 'lim.keptsize') of clauses kept in 'reduce'.
14
+ //
15
+ // Note, that 'forward' means that the clause from which the subsumption
16
+ // check is started is checked for being subsumed by other (smaller or equal
17
+ // size) clauses. Since 'vivification' is an extended version of subsume,
18
+ // more powerful, but also slower, we schedule 'vivify' right after
19
+ // 'subsume', which in contrast to 'subsume' is not run until to completion.
20
+ //
21
+ // This implementation is inspired by Bayardo's SDM'11 analysis of our
22
+ // subsumption algorithm in our SATeLite preprocessor in the context of
23
+ // finding extremal sets in data mining and his suggested improvements.
24
+
25
+ // Our original subsumption algorithm in 'Quantor' and 'SATeLite' (and in
26
+ // MiniSAT and descendants) is based on backward subsumption. It uses the
27
+ // observation that only the occurrence list of one literal of a clause has
28
+ // to be traversed in order to find all potential clauses which are subsumed
29
+ // by the candidate. Thus the literal with the smallest number of
30
+ // occurrences is used. However, that scheme requires to connect all
31
+ // literals of surviving clauses, while forward algorithms only need to
32
+ // connect one literal. On the other hand forward checking requires to
33
+ // traverse the occurrence lists of all literals of the candidate clause to
34
+ // find subsuming clauses. During connecting the single literal (similar to
35
+ // the one-watch scheme by Lintao Zhang) one can connect a literal with a
36
+ // minimal number of occurrence so far, which implicitly also reduces future
37
+ // occurrence list traversal time.
38
+
39
+ // Also the actual subsumption check is cheaper since during backward
40
+ // checking the short subsuming candidate clause is marked and all the
41
+ // literals in the larger subsume candidate clauses have to be traversed,
42
+ // while for our forward approach the long subsumed candidate clause is only
43
+ // marked once, while the literals of the shorter subsuming clauses have to
44
+ // be checked. We also use a fixed special more cache friendly data
45
+ // structure for binary clauses, to avoid traversing them directly.
46
+
47
+ // In our forward scheme it is still possible to skip occurrence lists of
48
+ // literals which were not added since the last subsumption round, since
49
+ // only those can contain subsuming candidates. Actually, clauses which
50
+ // contain at least one literal, which was not added since the last
51
+ // subsumption round do not have to be connected at all, even though they
52
+ // might still be subsumed them self.
53
+
54
+ // Bayardo suggests to sort the literals in clauses and perform some kind of
55
+ // partial merge-sort, while we mark literals, but do sort literals during
56
+ // connecting a clause w.r.t. the number of occurrences, in order to find
57
+ // literals which do not occur in the subsumed candidate fast with high
58
+ // probability (less occurring literals have a higher chance).
59
+
60
+ // This is the actual subsumption and strengthening check. We assume that
61
+ // all the literals of the candidate clause to be subsumed or strengthened
62
+ // are marked, so we only have to check that all the literals of the
63
+ // argument clause 'subsuming', which is checked for subsuming the candidate
64
+ // clause 'subsumed', has all its literals marked (in the correct phase).
65
+ // If exactly one is in the opposite phase we can still strengthen the
66
+ // candidate clause by this single literal which occurs in opposite phase.
67
+ //
68
+ // The result is INT_MIN if all literals are marked and thus the candidate
69
+ // clause can be subsumed. It is zero if neither subsumption nor
70
+ // strengthening is possible. Otherwise the candidate clause can be
71
+ // strengthened and as a result the negation of the literal which can be
72
+ // removed is returned.
73
+
74
+ inline int Internal::subsume_check (Clause *subsuming, Clause *subsumed) {
75
+ #ifdef NDEBUG
76
+ (void) subsumed;
77
+ #endif
78
+ // Only use 'subsumed' for these following assertion checks. Otherwise we
79
+ // only require that 'subsumed' has all its literals marked.
80
+ //
81
+ assert (!subsumed->garbage);
82
+ assert (!subsuming->garbage);
83
+ assert (subsuming != subsumed);
84
+ assert (subsuming->size <= subsumed->size);
85
+
86
+ stats.subchecks++;
87
+ if (subsuming->size == 2)
88
+ stats.subchecks2++;
89
+
90
+ int flipped = 0, prev = 0;
91
+ bool failed = false;
92
+ const auto eoc = subsuming->end ();
93
+ for (auto i = subsuming->begin (); !failed && i != eoc; i++) {
94
+ int lit = *i;
95
+ *i = prev;
96
+ prev = lit;
97
+ const int tmp = marked (lit);
98
+ if (!tmp)
99
+ failed = true;
100
+ else if (tmp > 0)
101
+ continue;
102
+ else if (flipped)
103
+ failed = true;
104
+ else
105
+ flipped = lit;
106
+ }
107
+ assert (prev);
108
+ assert (!subsuming->literals[0]);
109
+ subsuming->literals[0] = prev;
110
+ if (failed)
111
+ return 0;
112
+
113
+ if (!flipped)
114
+ return INT_MIN; // subsumed!!
115
+ else if (!opts.subsumestr)
116
+ return 0;
117
+ else
118
+ return flipped; // strengthen!!
119
+ }
120
+
121
+ /*------------------------------------------------------------------------*/
122
+
123
+ // Candidate clause 'subsumed' is subsumed by 'subsuming'.
124
+
125
+ inline void Internal::subsume_clause (Clause *subsuming, Clause *subsumed) {
126
+ stats.subsumed++;
127
+ assert (subsuming->size <= subsumed->size);
128
+ LOG (subsumed, "subsumed");
129
+ if (subsumed->redundant)
130
+ stats.subred++;
131
+ else
132
+ stats.subirr++;
133
+ if (subsumed->redundant || !subsuming->redundant) {
134
+ mark_garbage (subsumed);
135
+ return;
136
+ }
137
+ LOG ("turning redundant subsuming clause into irredundant clause");
138
+ subsuming->redundant = false;
139
+ if (proof)
140
+ proof->strengthen (subsuming->id);
141
+ mark_garbage (subsumed);
142
+ stats.current.irredundant++;
143
+ stats.added.irredundant++;
144
+ stats.irrlits += subsuming->size;
145
+ assert (stats.current.redundant > 0);
146
+ stats.current.redundant--;
147
+ assert (stats.added.redundant > 0);
148
+ stats.added.redundant--;
149
+ // ... and keep 'stats.added.total'.
150
+ }
151
+
152
+ /*------------------------------------------------------------------------*/
153
+
154
+ // Candidate clause 'c' is strengthened by removing 'lit'.
155
+
156
+ void Internal::strengthen_clause (Clause *c, int lit) {
157
+ if (opts.check && is_external_forgettable (c->id))
158
+ mark_garbage_external_forgettable (c->id);
159
+ stats.strengthened++;
160
+ assert (c->size > 2);
161
+ LOG (c, "removing %d in", lit);
162
+ if (proof) {
163
+ LOG (lrat_chain, "strengthening clause with chain");
164
+ proof->strengthen_clause (c, lit, lrat_chain);
165
+ }
166
+ if (!c->redundant)
167
+ mark_removed (lit);
168
+ auto new_end = remove (c->begin (), c->end (), lit);
169
+ assert (new_end + 1 == c->end ()), (void) new_end;
170
+ (void) shrink_clause (c, c->size - 1);
171
+ // bump_clause2 (c);
172
+ LOG (c, "strengthened");
173
+ external->check_shrunken_clause (c);
174
+ }
175
+
176
+ /*------------------------------------------------------------------------*/
177
+
178
+ // Find clauses connected in the occurrence lists 'occs' which subsume the
179
+ // candidate clause 'c' given as first argument. If this is the case the
180
+ // clause is subsumed and the result is positive. If the clause was
181
+ // strengthened the result is negative. Otherwise the candidate clause
182
+ // can not be subsumed nor strengthened and zero is returned.
183
+
184
+ inline int Internal::try_to_subsume_clause (Clause *c,
185
+ vector<Clause *> &shrunken) {
186
+
187
+ stats.subtried++;
188
+ assert (!level);
189
+ LOG (c, "trying to subsume");
190
+
191
+ mark (c); // signed!
192
+
193
+ Clause *d = 0;
194
+ int flipped = 0;
195
+
196
+ for (const auto &lit : *c) {
197
+
198
+ // Only clauses which have a variable which has recently been added are
199
+ // checked for being subsumed. The idea is that all these newly added
200
+ // clauses are candidates for subsuming the clause. Then we also only
201
+ // need to check occurrences of these variables. The occurrence lists
202
+ // of other literal do not have to be checked.
203
+ //
204
+ if (!flags (lit).subsume)
205
+ continue;
206
+
207
+ for (int sign = -1; !d && sign <= 1; sign += 2) {
208
+
209
+ // First we check against all binary clauses. The other literals of
210
+ // all binary clauses of 'sign*lit' are stored in one consecutive
211
+ // array, which is way faster than storing clause pointers and
212
+ // dereferencing them. Since this binary clause array is also not
213
+ // shrunken, we also can bail out earlier if subsumption or
214
+ // strengthening is determined.
215
+
216
+ // In both cases the (self-)subsuming clause is stored in 'd', which
217
+ // makes it nonzero and forces aborting both the outer and inner loop.
218
+ // If the binary clause can strengthen the candidate clause 'c'
219
+ // (through self-subsuming resolution), then 'filled' is set to the
220
+ // literal which can be removed in 'c', otherwise to 'INT_MIN' which
221
+ // is a non-valid literal.
222
+
223
+ for (const auto &bin : bins (sign * lit)) {
224
+ const auto &other = bin.lit;
225
+ const int tmp = marked (other);
226
+ if (!tmp)
227
+ continue;
228
+ if (tmp < 0 && sign < 0)
229
+ continue;
230
+ if (tmp < 0) {
231
+ if (sign < 0)
232
+ continue; // tautological resolvent
233
+ dummy_binary->literals[0] = lit;
234
+ dummy_binary->literals[1] = other;
235
+ flipped = other;
236
+ } else {
237
+ dummy_binary->literals[0] = sign * lit;
238
+ dummy_binary->literals[1] = other;
239
+ flipped = (sign < 0) ? -lit : INT_MIN;
240
+ }
241
+
242
+ // This dummy binary clauses is initialized in 'Internal::Internal'
243
+ // and only changes it literals in the lines above. By using such
244
+ // a faked binary clause we can simply reuse 'subsume_clause' as
245
+ // well as the code around 'strengthen_clause' uniform for both real
246
+ // clauses and this special case for binary clauses
247
+
248
+ dummy_binary->id = bin.id;
249
+ d = dummy_binary;
250
+
251
+ break;
252
+ }
253
+
254
+ if (d)
255
+ break;
256
+
257
+ // In this second loop we check for larger than binary clauses to
258
+ // subsume or strengthen the candidate clause. This is more costly,
259
+ // and needs a call to 'subsume_check'. Otherwise the same contract
260
+ // as above for communicating 'subsumption' or 'strengthening' to the
261
+ // code after the loop is used.
262
+ //
263
+ const Occs &os = occs (sign * lit);
264
+ for (const auto &e : os) {
265
+ assert (!e->garbage); // sanity check
266
+ if (e->garbage)
267
+ continue; // defensive: not needed
268
+ flipped = subsume_check (e, c);
269
+ if (!flipped)
270
+ continue;
271
+ d = e; // leave also outer loop
272
+ break;
273
+ }
274
+ }
275
+
276
+ if (d)
277
+ break;
278
+ }
279
+
280
+ unmark (c);
281
+
282
+ if (flipped == INT_MIN) {
283
+ LOG (d, "subsuming");
284
+ subsume_clause (d, c);
285
+ return 1;
286
+ }
287
+
288
+ if (flipped) {
289
+ LOG (d, "strengthening");
290
+ if (lrat) {
291
+ assert (lrat_chain.empty ());
292
+ lrat_chain.push_back (c->id);
293
+ lrat_chain.push_back (d->id);
294
+ }
295
+ if (d->used > c->used)
296
+ c->used = d->used;
297
+ strengthen_clause (c, -flipped);
298
+ lrat_chain.clear ();
299
+ assert (likely_to_be_kept_clause (c));
300
+ shrunken.push_back (c);
301
+ return -1;
302
+ }
303
+
304
+ return 0;
305
+ }
306
+
307
+ struct subsume_less_noccs {
308
+ Internal *internal;
309
+ subsume_less_noccs (Internal *i) : internal (i) {}
310
+ bool operator() (int a, int b) {
311
+ const signed char u = internal->val (a), v = internal->val (b);
312
+ if (!u && v)
313
+ return true;
314
+ if (u && !v)
315
+ return false;
316
+ const int64_t m = internal->noccs (a), n = internal->noccs (b);
317
+ if (m < n)
318
+ return true;
319
+ if (m > n)
320
+ return false;
321
+ return abs (a) < abs (b);
322
+ }
323
+ };
324
+
325
+ /*------------------------------------------------------------------------*/
326
+
327
+ // Usually called from 'subsume' below if 'subsuming' triggered it. Then
328
+ // the idea is to subsume both redundant and irredundant clauses. It is also
329
+ // called in the elimination loop in 'elim' in which case we focus on
330
+ // irredundant clauses only to help bounded variable elimination. The
331
+ // function returns true of an irredundant clause was removed or
332
+ // strengthened, which might then in the second usage scenario trigger new
333
+ // variable eliminations.
334
+
335
+ bool Internal::subsume_round () {
336
+
337
+ if (!opts.subsume)
338
+ return false;
339
+ if (unsat)
340
+ return false;
341
+ if (terminated_asynchronously ())
342
+ return false;
343
+ if (!stats.current.redundant && !stats.current.irredundant)
344
+ return false;
345
+
346
+ START_SIMPLIFIER (subsume, SUBSUME);
347
+ stats.subsumerounds++;
348
+
349
+ int64_t check_limit;
350
+ if (opts.subsumelimited) {
351
+ int64_t delta = stats.propagations.search;
352
+ delta *= 1e-3 * opts.subsumeeffort;
353
+ if (delta < opts.subsumemineff)
354
+ delta = opts.subsumemineff;
355
+ if (delta > opts.subsumemaxeff)
356
+ delta = opts.subsumemaxeff;
357
+ delta = max (delta, (int64_t) 2l * active ());
358
+
359
+ PHASE ("subsume-round", stats.subsumerounds,
360
+ "limit of %" PRId64 " subsumption checks", delta);
361
+
362
+ check_limit = stats.subchecks + delta;
363
+ } else {
364
+ PHASE ("subsume-round", stats.subsumerounds,
365
+ "unlimited subsumption checks");
366
+ check_limit = LONG_MAX;
367
+ }
368
+
369
+ int old_marked_candidate_variables_for_elimination = stats.mark.elim;
370
+
371
+ assert (!level);
372
+
373
+ // Allocate schedule and occurrence lists.
374
+ //
375
+ vector<ClauseSize> schedule;
376
+ init_noccs ();
377
+
378
+ // Determine candidate clauses and sort them by size.
379
+ //
380
+ int64_t left_over_from_last_subsumption_round = 0;
381
+
382
+ for (auto c : clauses) {
383
+
384
+ if (c->garbage)
385
+ continue;
386
+ if (c->size > opts.subsumeclslim)
387
+ continue;
388
+ if (!likely_to_be_kept_clause (c))
389
+ continue;
390
+
391
+ bool fixed = false;
392
+ int subsume = 0;
393
+ for (const auto &lit : *c)
394
+ if (val (lit))
395
+ fixed = true;
396
+ else if (flags (lit).subsume)
397
+ subsume++;
398
+
399
+ // If the clause contains a root level assigned (fixed) literal we will
400
+ // not work on it. This simplifies the code substantially since we do
401
+ // not have to care about assignments at all. Strengthening becomes
402
+ // much simpler too.
403
+ //
404
+ if (fixed) {
405
+ LOG (c, "skipping (fixed literal)");
406
+ continue;
407
+ }
408
+
409
+ // Further, if less than two variables in the clause were added since
410
+ // the last subsumption round, the clause is ignored too.
411
+ //
412
+ if (subsume < 2) {
413
+ LOG (c, "skipping (only %d added literals)", subsume);
414
+ continue;
415
+ }
416
+
417
+ if (c->subsume)
418
+ left_over_from_last_subsumption_round++;
419
+ schedule.push_back (ClauseSize (c->size, c));
420
+ for (const auto &lit : *c)
421
+ noccs (lit)++;
422
+ }
423
+ shrink_vector (schedule);
424
+
425
+ // Smaller clauses are checked and connected first.
426
+ //
427
+ rsort (schedule.begin (), schedule.end (), smaller_clause_size_rank ());
428
+
429
+ if (!left_over_from_last_subsumption_round)
430
+ for (auto cs : schedule)
431
+ if (cs.clause->size > 2)
432
+ cs.clause->subsume = true;
433
+
434
+ #ifndef QUIET
435
+ int64_t scheduled = schedule.size ();
436
+ int64_t total = stats.current.irredundant + stats.current.redundant;
437
+ PHASE ("subsume-round", stats.subsumerounds,
438
+ "scheduled %" PRId64 " clauses %.0f%% out of %" PRId64 " clauses",
439
+ scheduled, percent (scheduled, total), total);
440
+ #endif
441
+
442
+ // Now go over the scheduled clauses in the order of increasing size and
443
+ // try to forward subsume and strengthen them. Forward subsumption tries
444
+ // to find smaller or same size clauses which subsume or might strengthen
445
+ // the candidate. After the candidate has been processed connect one
446
+ // of its literals (with smallest number of occurrences at this point) in
447
+ // a one-watched scheme.
448
+
449
+ int64_t subsumed = 0, strengthened = 0, checked = 0;
450
+
451
+ vector<Clause *> shrunken;
452
+ init_occs ();
453
+ init_bins ();
454
+
455
+ for (const auto &s : schedule) {
456
+
457
+ if (terminated_asynchronously ())
458
+ break;
459
+ if (stats.subchecks >= check_limit)
460
+ break;
461
+
462
+ Clause *c = s.clause;
463
+ assert (!c->garbage);
464
+
465
+ checked++;
466
+
467
+ // First try to subsume or strengthen this candidate clause. For binary
468
+ // clauses this could be done much faster by hashing and is costly due
469
+ // to a usually large number of binary clauses. There is further the
470
+ // issue, that strengthening binary clauses (through double
471
+ // self-subsuming resolution) would produce units, which needs much more
472
+ // care. In the same (lazy) spirit we also ignore clauses with fixed
473
+ // literals (false or true).
474
+ //
475
+ if (c->size > 2 && c->subsume) {
476
+ c->subsume = false;
477
+ const int tmp = try_to_subsume_clause (c, shrunken);
478
+ if (tmp > 0) {
479
+ subsumed++;
480
+ continue;
481
+ }
482
+ if (tmp < 0)
483
+ strengthened++;
484
+ }
485
+
486
+ // If not subsumed connect smallest occurring literal, where occurring
487
+ // means the number of times it was used to connect (as a one-watch) a
488
+ // previous smaller or equal sized clause. This minimizes the length of
489
+ // the occurrence lists traversed during 'try_to_subsume_clause'. Also
490
+ // note that this number is usually way smaller than the number of
491
+ // occurrences computed before and stored in 'noccs'.
492
+ //
493
+ int minlit = 0;
494
+ int64_t minoccs = 0;
495
+ size_t minsize = 0;
496
+ bool subsume = true;
497
+ bool binary = (c->size == 2 && !c->redundant);
498
+
499
+ for (const auto &lit : *c) {
500
+
501
+ if (!flags (lit).subsume)
502
+ subsume = false;
503
+ const size_t size = binary ? bins (lit).size () : occs (lit).size ();
504
+ if (minlit && minsize <= size)
505
+ continue;
506
+ const int64_t tmp = noccs (lit);
507
+ if (minlit && minsize == size && tmp <= minoccs)
508
+ continue;
509
+ minlit = lit, minsize = size, minoccs = tmp;
510
+ }
511
+
512
+ // If there is a variable in a clause different from is not 'subsume'
513
+ // (has been added since the last subsumption round), then this clause
514
+ // can not serve to strengthen or subsume another clause, since all
515
+ // shrunken or added clauses mark all their variables as 'subsume'.
516
+ //
517
+ if (!subsume)
518
+ continue;
519
+
520
+ if (!binary) {
521
+
522
+ // If smallest occurring literal occurs too often do not connect.
523
+ //
524
+ if (minsize > (size_t) opts.subsumeocclim)
525
+ continue;
526
+
527
+ LOG (c,
528
+ "watching %d with %zd current and total %" PRId64 " occurrences",
529
+ minlit, minsize, minoccs);
530
+
531
+ occs (minlit).push_back (c);
532
+
533
+ // This sorting should give faster failures for assumption checks
534
+ // since the less occurring variables are put first in a clause and
535
+ // thus will make it more likely to be found as witness for a clause
536
+ // not to be subsuming. One could in principle (see also the
537
+ // discussion on 'subsumption' in our 'Splatz' solver) replace marking
538
+ // by a kind of merge sort, as also suggested by Bayardo. It would
539
+ // avoid 'marked' calls and thus might be slightly faster but could
540
+ // not take benefit of this sorting optimization.
541
+ //
542
+ sort (c->begin (), c->end (), subsume_less_noccs (this));
543
+
544
+ } else {
545
+
546
+ // If smallest occurring literal occurs too often do not connect.
547
+ //
548
+ if (minsize > (size_t) opts.subsumebinlim)
549
+ continue;
550
+
551
+ LOG (c,
552
+ "watching %d with %zd current binary and total %" PRId64
553
+ " occurrences",
554
+ minlit, minsize, minoccs);
555
+
556
+ const int minlit_pos = (c->literals[1] == minlit);
557
+ const int other = c->literals[!minlit_pos];
558
+ bins (minlit).push_back (Bin{other, c->id});
559
+ }
560
+ }
561
+
562
+ PHASE ("subsume-round", stats.subsumerounds,
563
+ "subsumed %" PRId64 " and strengthened %" PRId64 " out of %" PRId64
564
+ " clauses %.0f%%",
565
+ subsumed, strengthened, scheduled,
566
+ percent (subsumed + strengthened, scheduled));
567
+
568
+ const int64_t remain = schedule.size () - checked;
569
+ const bool completed = !remain;
570
+
571
+ if (completed)
572
+ PHASE ("subsume-round", stats.subsumerounds,
573
+ "checked all %" PRId64 " scheduled clauses", checked);
574
+ else
575
+ PHASE ("subsume-round", stats.subsumerounds,
576
+ "checked %" PRId64 " clauses %.0f%% of scheduled (%" PRId64
577
+ " remain)",
578
+ checked, percent (checked, scheduled), remain);
579
+
580
+ // Release occurrence lists and schedule.
581
+ //
582
+ erase_vector (schedule);
583
+ reset_noccs ();
584
+ reset_occs ();
585
+ reset_bins ();
586
+
587
+ // Reset all old 'added' flags and mark variables in shrunken
588
+ // clauses as 'added' for the next subsumption round.
589
+ //
590
+ if (completed)
591
+ reset_subsume_bits ();
592
+
593
+ for (const auto &c : shrunken)
594
+ mark_added (c);
595
+ erase_vector (shrunken);
596
+
597
+ report ('s', !opts.reportall && !(subsumed + strengthened));
598
+
599
+ STOP_SIMPLIFIER (subsume, SUBSUME);
600
+
601
+ return old_marked_candidate_variables_for_elimination < stats.mark.elim;
602
+ }
603
+
604
+ /*------------------------------------------------------------------------*/
605
+
606
+ void Internal::subsume () {
607
+
608
+ if (!stats.current.redundant && !stats.current.irredundant)
609
+ return;
610
+
611
+ if (unsat)
612
+ return;
613
+
614
+ backtrack ();
615
+ if (!propagate ()) {
616
+ learn_empty_clause ();
617
+ return;
618
+ }
619
+
620
+ stats.subsumephases++;
621
+
622
+ if (external_prop) {
623
+ assert (!level);
624
+ private_steps = true;
625
+ }
626
+
627
+ if (opts.subsume) {
628
+ reset_watches ();
629
+ subsume_round ();
630
+ init_watches ();
631
+ connect_watches ();
632
+ if (!unsat && !propagate ()) {
633
+ LOG ("propagation after subsume rounds results in inconsistency");
634
+ learn_empty_clause ();
635
+ }
636
+ }
637
+
638
+ transred ();
639
+ if (external_prop) {
640
+ assert (!level);
641
+ private_steps = false;
642
+ }
643
+ }
644
+
645
+ } // namespace CaDiCaL