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,1171 @@
1
+ #include "internal.hpp"
2
+
3
+ namespace CaDiCaL {
4
+
5
+ /*------------------------------------------------------------------------*/
6
+
7
+ // Implements a variant of bounded variable elimination as originally
8
+ // described in our SAT'05 paper introducing 'SATeLite'. This is an
9
+ // inprocessing version, i.e., it is interleaved with search and triggers
10
+ // subsumption and strengthening, blocked and covered clause elimination
11
+ // during elimination rounds. It focuses only those variables which
12
+ // occurred in removed irredundant clauses since the last time an
13
+ // elimination round was run. By bounding the maximum resolvent size we can
14
+ // run each elimination round until completion. See the code of 'elim' for
15
+ // how elimination rounds are interleaved with blocked clause elimination
16
+ // and subsumption (which in turn also calls vivification and transitive
17
+ // reduction of the binary implication graph).
18
+
19
+ /*------------------------------------------------------------------------*/
20
+
21
+ inline double Internal::compute_elim_score (unsigned lit) {
22
+ assert (1 <= lit), assert (lit <= (unsigned) max_var);
23
+ const double pos = noccs (lit);
24
+ const double neg = noccs (-lit);
25
+ if (!pos)
26
+ return -neg;
27
+ if (!neg)
28
+ return -pos;
29
+ double sum = 0, prod = 0;
30
+ if (opts.elimsum)
31
+ sum = opts.elimsum * (pos + neg);
32
+ if (opts.elimprod)
33
+ prod = opts.elimprod * (pos * neg);
34
+ return prod + sum;
35
+ }
36
+
37
+ /*------------------------------------------------------------------------*/
38
+
39
+ bool elim_more::operator() (unsigned a, unsigned b) {
40
+ const auto s = internal->compute_elim_score (a);
41
+ const auto t = internal->compute_elim_score (b);
42
+ if (s > t)
43
+ return true;
44
+ if (s < t)
45
+ return false;
46
+ return a > b;
47
+ }
48
+
49
+ /*------------------------------------------------------------------------*/
50
+
51
+ // Note that the new fast subsumption algorithm implemented in 'subsume'
52
+ // does not distinguish between irredundant and redundant clauses and is
53
+ // also run during search to strengthen and remove 'sticky' redundant
54
+ // clauses but also irredundant ones. So beside learned units during search
55
+ // or as consequence of other preprocessors, these subsumption rounds during
56
+ // search can remove (irredundant) clauses (and literals), which in turn
57
+ // might make new bounded variable elimination possible. This is tested
58
+ // in the 'bool ineliminating ()' guard.
59
+
60
+ bool Internal::ineliminating () {
61
+
62
+ if (!opts.elim)
63
+ return false;
64
+ if (!preprocessing && !opts.inprocessing)
65
+ return false;
66
+ if (preprocessing)
67
+ assert (lim.preprocessing);
68
+
69
+ // Respect (increasing) conflict limit.
70
+ //
71
+ if (lim.elim >= stats.conflicts)
72
+ return false;
73
+
74
+ // Wait until there are new units or new removed variables
75
+ // (in removed or shrunken irredundant clauses and thus marked).
76
+ //
77
+ if (last.elim.fixed < stats.all.fixed)
78
+ return true;
79
+ if (last.elim.marked < stats.mark.elim)
80
+ return true;
81
+
82
+ // VERBOSE (3, "elim not scheduled due to fixpoint");
83
+ return false;
84
+ }
85
+
86
+ /*------------------------------------------------------------------------*/
87
+
88
+ // Update the global elimination schedule after adding or removing a clause.
89
+
90
+ void Internal::elim_update_added_clause (Eliminator &eliminator,
91
+ Clause *c) {
92
+ assert (!c->redundant);
93
+ ElimSchedule &schedule = eliminator.schedule;
94
+ for (const auto &lit : *c) {
95
+ if (!active (lit))
96
+ continue;
97
+ occs (lit).push_back (c);
98
+ if (frozen (lit))
99
+ continue;
100
+ noccs (lit)++;
101
+ const int idx = abs (lit);
102
+ if (schedule.contains (idx))
103
+ schedule.update (idx);
104
+ }
105
+ }
106
+
107
+ void Internal::elim_update_removed_lit (Eliminator &eliminator, int lit) {
108
+ if (!active (lit))
109
+ return;
110
+ if (frozen (lit))
111
+ return;
112
+ int64_t &score = noccs (lit);
113
+ assert (score > 0);
114
+ score--;
115
+ const int idx = abs (lit);
116
+ ElimSchedule &schedule = eliminator.schedule;
117
+ if (schedule.contains (idx))
118
+ schedule.update (idx);
119
+ else {
120
+ LOG ("rescheduling %d for elimination after removing clause", idx);
121
+ schedule.push_back (idx);
122
+ }
123
+ }
124
+
125
+ void Internal::elim_update_removed_clause (Eliminator &eliminator,
126
+ Clause *c, int except) {
127
+ assert (!c->redundant);
128
+ for (const auto &lit : *c) {
129
+ if (lit == except)
130
+ continue;
131
+ assert (lit != -except);
132
+ elim_update_removed_lit (eliminator, lit);
133
+ }
134
+ }
135
+
136
+ /*------------------------------------------------------------------------*/
137
+
138
+ // Since we do not have watches we have to do our own unit propagation
139
+ // during elimination as soon we find a unit clause. This finds new units
140
+ // and also marks clauses satisfied by those units as garbage immediately.
141
+
142
+ void Internal::elim_propagate (Eliminator &eliminator, int root) {
143
+ assert (val (root) > 0);
144
+ vector<int> work;
145
+ size_t i = 0;
146
+ work.push_back (root);
147
+ while (i < work.size ()) {
148
+ int lit = work[i++];
149
+ LOG ("elimination propagation of %d", lit);
150
+ assert (val (lit) > 0);
151
+ const Occs &ns = occs (-lit);
152
+ for (const auto &c : ns) {
153
+ if (c->garbage)
154
+ continue;
155
+ int unit = 0, satisfied = 0;
156
+ for (const auto &other : *c) {
157
+ const signed char tmp = val (other);
158
+ if (tmp < 0)
159
+ continue;
160
+ if (tmp > 0) {
161
+ satisfied = other;
162
+ break;
163
+ }
164
+ if (unit)
165
+ unit = INT_MIN;
166
+ else
167
+ unit = other;
168
+ }
169
+ if (satisfied) {
170
+ LOG (c, "elimination propagation of %d finds %d satisfied", lit,
171
+ satisfied);
172
+ elim_update_removed_clause (eliminator, c, satisfied);
173
+ mark_garbage (c);
174
+ } else if (!unit) {
175
+ LOG ("empty clause during elimination propagation of %d", lit);
176
+ // need to set conflict = c for lrat
177
+ conflict = c;
178
+ learn_empty_clause ();
179
+ conflict = 0;
180
+ break;
181
+ } else if (unit != INT_MIN) {
182
+ LOG ("new unit %d during elimination propagation of %d", unit, lit);
183
+ build_chain_for_units (unit, c, 0);
184
+ assign_unit (unit);
185
+ work.push_back (unit);
186
+ }
187
+ }
188
+ if (unsat)
189
+ break;
190
+ const Occs &ps = occs (lit);
191
+ for (const auto &c : ps) {
192
+ if (c->garbage)
193
+ continue;
194
+ LOG (c, "elimination propagation of %d produces satisfied", lit);
195
+ elim_update_removed_clause (eliminator, c, lit);
196
+ mark_garbage (c);
197
+ }
198
+ }
199
+ }
200
+
201
+ /*------------------------------------------------------------------------*/
202
+
203
+ // On-the-fly self-subsuming resolution during variable elimination is due
204
+ // to HyoJung Han, Fabio Somenzi, SAT'09. Basically while resolving two
205
+ // clauses we test the resolvent to be smaller than one of the antecedents.
206
+ // If this is the case the pivot can be removed from the antecedent
207
+ // on-the-fly and the resolution can be skipped during elimination.
208
+
209
+ void Internal::elim_on_the_fly_self_subsumption (Eliminator &eliminator,
210
+ Clause *c, int pivot) {
211
+ LOG (c, "pivot %d on-the-fly self-subsuming resolution", pivot);
212
+ stats.elimotfstr++;
213
+ stats.strengthened++;
214
+ assert (clause.empty ());
215
+ for (const auto &lit : *c) {
216
+ if (lit == pivot)
217
+ continue;
218
+ const signed char tmp = val (lit);
219
+ assert (tmp <= 0);
220
+ if (tmp < 0)
221
+ continue;
222
+ clause.push_back (lit);
223
+ }
224
+ Clause *r = new_resolved_irredundant_clause ();
225
+ elim_update_added_clause (eliminator, r);
226
+ clause.clear ();
227
+ lrat_chain.clear ();
228
+ elim_update_removed_clause (eliminator, c, pivot);
229
+ mark_garbage (c);
230
+ }
231
+
232
+ /*------------------------------------------------------------------------*/
233
+
234
+ // Resolve two clauses on the pivot literal 'pivot', which is assumed to
235
+ // occur in opposite phases in 'c' and 'd'. The actual resolvent is stored
236
+ // in the temporary global 'clause' if it is not redundant. It is
237
+ // considered redundant if one of the clauses is already marked as garbage
238
+ // it is root level satisfied, the resolvent is empty, a unit, or produces a
239
+ // self-subsuming resolution, which results in the pivot to be removed from
240
+ // at least one of the antecedents.
241
+
242
+ // Note that current root level assignments are taken into account, i.e., by
243
+ // removing root level falsified literals. The function returns true if the
244
+ // resolvent is not redundant and for instance has to be taken into account
245
+ // during bounded variable elimination.
246
+
247
+ // Detected units are immediately assigned and in case the last argument is
248
+ // true also propagated eagerly in a elimination specific propagation
249
+ // routine, which not only finds units but also updates the schedule.
250
+
251
+ // When this function is called during computation of the number of
252
+ // non-trivial (or non-satisfied) resolvents we can eagerly propagate units.
253
+ // But during actually adding the resolvents this results in problems as we
254
+ // found one rare test case '../test/trace/reg0056.trace' (out of billions),
255
+ // where the pivot itself was assigned during such a propagation while
256
+ // adding resolvents and lead to pushing a clause to the reconstruction
257
+ // stack that later flipped the value of the pivot (while all other literals
258
+ // in that clause were unit implied too). Not pushing the pivot clauses to
259
+ // the reconstruction stack produced a wrong model too. Our fix is to only
260
+ // eagerly propagate during computation of the number of resolvents and
261
+ // otherwise delay propagation until the end of elimination (which is less
262
+ // precise regarding scheduling but very rarely happens).
263
+
264
+ bool Internal::resolve_clauses (Eliminator &eliminator, Clause *c,
265
+ int pivot, Clause *d,
266
+ const bool propagate_eagerly) {
267
+
268
+ assert (!c->redundant);
269
+ assert (!d->redundant);
270
+
271
+ stats.elimres++;
272
+
273
+ if (c->garbage || d->garbage)
274
+ return false;
275
+ if (c->size > d->size) {
276
+ pivot = -pivot;
277
+ swap (c, d);
278
+ }
279
+
280
+ assert (!level);
281
+ assert (clause.empty ());
282
+
283
+ int satisfied = 0; // Contains this satisfying literal.
284
+ int tautological = 0; // Clashing literal if tautological.
285
+
286
+ int s = 0; // Actual literals from 'c'.
287
+ int t = 0; // Actual literals from 'd'.
288
+
289
+ // First determine whether the first antecedent is satisfied, add its
290
+ // literals to 'clause' and mark them (except for 'pivot').
291
+ //
292
+ for (const auto &lit : *c) {
293
+ if (lit == pivot) {
294
+ s++;
295
+ continue;
296
+ }
297
+ assert (lit != -pivot);
298
+ const signed char tmp = val (lit);
299
+ if (tmp > 0) {
300
+ satisfied = lit;
301
+ break;
302
+ } else if (tmp < 0) {
303
+ if (!lrat)
304
+ continue;
305
+ Flags &f = flags (lit);
306
+ if (f.seen)
307
+ continue;
308
+ analyzed.push_back (lit);
309
+ f.seen = true;
310
+ int64_t id = unit_id (-lit);
311
+ lrat_chain.push_back (id);
312
+ continue;
313
+ } else
314
+ mark (lit), clause.push_back (lit), s++;
315
+ }
316
+ if (satisfied) {
317
+ LOG (c, "satisfied by %d antecedent", satisfied);
318
+ elim_update_removed_clause (eliminator, c, satisfied);
319
+ mark_garbage (c);
320
+ clause.clear ();
321
+ lrat_chain.clear ();
322
+ clear_analyzed_literals ();
323
+ unmark (c);
324
+ return false;
325
+ }
326
+
327
+ // Then determine whether the second antecedent is satisfied, add its
328
+ // literal to 'clause' and check whether a clashing literal is found, such
329
+ // that the resolvent would be tautological.
330
+ //
331
+ for (const auto &lit : *d) {
332
+ if (lit == -pivot) {
333
+ t++;
334
+ continue;
335
+ }
336
+ assert (lit != pivot);
337
+ signed char tmp = val (lit);
338
+ if (tmp > 0) {
339
+ satisfied = lit;
340
+ break;
341
+ } else if (tmp < 0) {
342
+ if (!lrat)
343
+ continue;
344
+ Flags &f = flags (lit);
345
+ if (f.seen)
346
+ continue;
347
+ analyzed.push_back (lit);
348
+ f.seen = true;
349
+ int64_t id = unit_id (-lit);
350
+ lrat_chain.push_back (id);
351
+ continue;
352
+ } else if ((tmp = marked (lit)) < 0) {
353
+ tautological = lit;
354
+ break;
355
+ } else if (!tmp)
356
+ clause.push_back (lit), t++;
357
+ else
358
+ assert (tmp > 0), t++;
359
+ }
360
+
361
+ clear_analyzed_literals ();
362
+ unmark (c);
363
+ const int64_t size = clause.size ();
364
+
365
+ if (lrat) {
366
+ lrat_chain.push_back (d->id);
367
+ lrat_chain.push_back (c->id);
368
+ }
369
+
370
+ if (satisfied) {
371
+ LOG (d, "satisfied by %d antecedent", satisfied);
372
+ elim_update_removed_clause (eliminator, d, satisfied);
373
+ mark_garbage (d);
374
+ clause.clear ();
375
+ lrat_chain.clear ();
376
+ return false;
377
+ }
378
+
379
+ LOG (c, "first antecedent");
380
+ LOG (d, "second antecedent");
381
+
382
+ if (tautological) {
383
+ clause.clear ();
384
+ LOG ("resolvent tautological on %d", tautological);
385
+ lrat_chain.clear ();
386
+ return false;
387
+ }
388
+
389
+ if (!size) {
390
+ clause.clear ();
391
+ LOG ("empty resolvent");
392
+ learn_empty_clause (); // already clears lrat_chain.
393
+ return false;
394
+ }
395
+
396
+ if (size == 1) {
397
+ int unit = clause[0];
398
+ LOG ("unit resolvent %d", unit);
399
+ clause.clear ();
400
+ assign_unit (unit); // already clears lrat_chain.
401
+ if (propagate_eagerly)
402
+ elim_propagate (eliminator, unit);
403
+ return false;
404
+ }
405
+
406
+ LOG (clause, "resolvent");
407
+ assert (!lrat || !lrat_chain.empty ());
408
+
409
+ // Double self-subsuming resolution. The clauses 'c' and 'd' are
410
+ // identical except for the pivot which occurs in different phase. The
411
+ // resolvent subsumes both antecedents.
412
+
413
+ if (s > size && t > size) {
414
+ assert (s == size + 1);
415
+ assert (t == size + 1);
416
+ clause.clear ();
417
+ // LRAT is c + d (+ eventual units)
418
+ elim_on_the_fly_self_subsumption (eliminator, c, pivot);
419
+ LOG (d, "double pivot %d on-the-fly self-subsuming resolution", -pivot);
420
+ stats.elimotfsub++;
421
+ stats.subsumed++;
422
+ elim_update_removed_clause (eliminator, d, -pivot);
423
+ mark_garbage (d);
424
+ return false;
425
+ }
426
+
427
+ // Single self-subsuming resolution: The pivot can be removed from 'c',
428
+ // which is implemented by adding a clause which is the same as 'c' but
429
+ // with 'pivot' removed and then marking 'c' as garbage.
430
+
431
+ if (s > size) {
432
+ assert (s == size + 1);
433
+ clause.clear ();
434
+ // LRAT is c + d (+ eventual units)
435
+ elim_on_the_fly_self_subsumption (eliminator, c, pivot);
436
+ return false;
437
+ }
438
+
439
+ // Same single self-subsuming resolution situation, but only for 'd'.
440
+
441
+ if (t > size) {
442
+ assert (t == size + 1);
443
+ clause.clear ();
444
+ // LRAT is c + d (+ eventual units) -> same.
445
+ elim_on_the_fly_self_subsumption (eliminator, d, -pivot);
446
+ return false;
447
+ }
448
+ if (propagate_eagerly)
449
+ lrat_chain.clear ();
450
+ return true;
451
+ }
452
+
453
+ /*------------------------------------------------------------------------*/
454
+
455
+ // Check whether the number of non-tautological resolvents on 'pivot' is
456
+ // smaller or equal to the number of clauses with 'pivot' or '-pivot'. This
457
+ // is the main criteria of bounded variable elimination. As a side effect
458
+ // it flushes garbage clauses with that variable, sorts its occurrence lists
459
+ // (smallest clauses first) and also negates pivot if it has more positive
460
+ // than negative occurrences.
461
+
462
+ bool Internal::elim_resolvents_are_bounded (Eliminator &eliminator,
463
+ int pivot) {
464
+ const bool substitute = !eliminator.gates.empty ();
465
+ const bool resolve_gates = eliminator.definition_unit;
466
+ if (substitute)
467
+ LOG ("trying to substitute %d", pivot);
468
+
469
+ stats.elimtried++;
470
+
471
+ assert (!unsat);
472
+ assert (active (pivot));
473
+
474
+ const Occs &ps = occs (pivot);
475
+ const Occs &ns = occs (-pivot);
476
+ const int64_t pos = ps.size ();
477
+ const int64_t neg = ns.size ();
478
+ if (!pos || !neg)
479
+ return lim.elimbound >= 0;
480
+ const int64_t bound = pos + neg + lim.elimbound;
481
+
482
+ LOG ("checking number resolvents on %d bounded by "
483
+ "%" PRId64 " = %" PRId64 " + %" PRId64 " + %" PRId64,
484
+ pivot, bound, pos, neg, lim.elimbound);
485
+
486
+ // Try all resolutions between a positive occurrence (outer loop) of
487
+ // 'pivot' and a negative occurrence of 'pivot' (inner loop) as long the
488
+ // bound on non-tautological resolvents is not hit and the size of the
489
+ // generated resolvents does not exceed the resolvent clause size limit.
490
+
491
+ int64_t resolvents = 0; // Non-tautological resolvents.
492
+
493
+ for (const auto &c : ps) {
494
+ assert (!c->redundant);
495
+ if (c->garbage)
496
+ continue;
497
+ for (const auto &d : ns) {
498
+ assert (!d->redundant);
499
+ if (d->garbage)
500
+ continue;
501
+ if (!resolve_gates && substitute && c->gate == d->gate)
502
+ continue;
503
+ stats.elimrestried++;
504
+ if (resolve_clauses (eliminator, c, pivot, d, true)) {
505
+ resolvents++;
506
+ int size = clause.size ();
507
+ clause.clear ();
508
+ LOG ("now at least %" PRId64
509
+ " non-tautological resolvents on pivot %d",
510
+ resolvents, pivot);
511
+ if (size > opts.elimclslim) {
512
+ LOG ("resolvent size %d too big after %" PRId64
513
+ " resolvents on %d",
514
+ size, resolvents, pivot);
515
+ return false;
516
+ }
517
+ if (resolvents > bound) {
518
+ LOG ("too many non-tautological resolvents on %d", pivot);
519
+ return false;
520
+ }
521
+ } else if (unsat)
522
+ return false;
523
+ else if (val (pivot))
524
+ return false;
525
+ }
526
+ }
527
+
528
+ LOG ("need %" PRId64 " <= %" PRId64 " non-tautological resolvents",
529
+ resolvents, bound);
530
+
531
+ return true;
532
+ }
533
+
534
+ /*------------------------------------------------------------------------*/
535
+ // Add all resolvents on 'pivot' and connect them.
536
+
537
+ inline void Internal::elim_add_resolvents (Eliminator &eliminator,
538
+ int pivot) {
539
+
540
+ const bool substitute = !eliminator.gates.empty ();
541
+ const bool resolve_gates = eliminator.definition_unit;
542
+ if (substitute) {
543
+ LOG ("substituting pivot %d by resolving with %zd gate clauses", pivot,
544
+ eliminator.gates.size ());
545
+ stats.elimsubst++;
546
+ }
547
+ switch (eliminator.gatetype) {
548
+ case EQUI:
549
+ stats.eliminated_equi++;
550
+ break;
551
+ case AND:
552
+ stats.eliminated_and++;
553
+ break;
554
+ case ITE:
555
+ stats.eliminated_ite++;
556
+ break;
557
+ case XOR:
558
+ stats.eliminated_xor++;
559
+ break;
560
+ case DEF:
561
+ stats.eliminated_def++;
562
+ break;
563
+ case NO:
564
+ break;
565
+ }
566
+
567
+ LOG ("adding all resolvents on %d", pivot);
568
+
569
+ assert (!val (pivot));
570
+ assert (!flags (pivot).eliminated ());
571
+
572
+ const Occs &ps = occs (pivot);
573
+ const Occs &ns = occs (-pivot);
574
+ #ifdef LOGGING
575
+ int64_t resolvents = 0;
576
+ #endif
577
+ for (auto &c : ps) {
578
+ if (unsat)
579
+ break;
580
+ if (c->garbage)
581
+ continue;
582
+ for (auto &d : ns) {
583
+ if (unsat)
584
+ break;
585
+ if (d->garbage)
586
+ continue;
587
+ if (!resolve_gates && substitute && c->gate == d->gate)
588
+ continue;
589
+ if (!resolve_clauses (eliminator, c, pivot, d, false))
590
+ continue;
591
+ assert (!lrat || !lrat_chain.empty ());
592
+ Clause *r = new_resolved_irredundant_clause ();
593
+ elim_update_added_clause (eliminator, r);
594
+ eliminator.enqueue (r);
595
+ lrat_chain.clear ();
596
+ clause.clear ();
597
+ #ifdef LOGGING
598
+ resolvents++;
599
+ #endif
600
+ }
601
+ }
602
+
603
+ LOG ("added %" PRId64 " resolvents to eliminate %d", resolvents, pivot);
604
+ }
605
+
606
+ /*------------------------------------------------------------------------*/
607
+
608
+ // Remove clauses with 'pivot' and '-pivot' by marking them as garbage and
609
+ // push them on the extension stack.
610
+
611
+ void Internal::mark_eliminated_clauses_as_garbage (
612
+ Eliminator &eliminator, int pivot, bool &deleted_binary_clause) {
613
+ assert (!unsat);
614
+
615
+ LOG ("marking irredundant clauses with %d as garbage", pivot);
616
+
617
+ const int64_t substitute = eliminator.gates.size ();
618
+ if (substitute)
619
+ LOG ("pushing %" PRId64 " gate clauses on extension stack", substitute);
620
+ #ifndef NDEBUG
621
+ int64_t pushed = 0;
622
+ #endif
623
+ Occs &ps = occs (pivot);
624
+ for (const auto &c : ps) {
625
+ if (c->garbage)
626
+ continue;
627
+ assert (!c->redundant);
628
+ if (!substitute || c->gate) {
629
+ if (proof)
630
+ proof->weaken_minus (c);
631
+ if (c->size == 2)
632
+ deleted_binary_clause = true;
633
+ external->push_clause_on_extension_stack (c, pivot);
634
+ #ifndef NDEBUG
635
+ pushed++;
636
+ #endif
637
+ }
638
+ mark_garbage (c);
639
+ elim_update_removed_clause (eliminator, c, pivot);
640
+ }
641
+ erase_occs (ps);
642
+
643
+ LOG ("marking irredundant clauses with %d as garbage", -pivot);
644
+
645
+ Occs &ns = occs (-pivot);
646
+ for (const auto &d : ns) {
647
+ if (d->garbage)
648
+ continue;
649
+ assert (!d->redundant);
650
+ if (!substitute || d->gate) {
651
+ if (proof)
652
+ proof->weaken_minus (d);
653
+ if (d->size == 2)
654
+ deleted_binary_clause = true;
655
+ external->push_clause_on_extension_stack (d, -pivot);
656
+ #ifndef NDEBUG
657
+ pushed++;
658
+ #endif
659
+ }
660
+ mark_garbage (d);
661
+ elim_update_removed_clause (eliminator, d, -pivot);
662
+ }
663
+ erase_occs (ns);
664
+
665
+ if (substitute)
666
+ assert (pushed <= substitute);
667
+
668
+ // Unfortunately, we can not use the trick by Niklas Soerensson anymore,
669
+ // which avoids saving all clauses on the extension stack. This would
670
+ // break our new incremental 'restore' logic.
671
+ }
672
+
673
+ /*------------------------------------------------------------------------*/
674
+
675
+ // Try to eliminate 'pivot' by bounded variable elimination.
676
+ void Internal::try_to_eliminate_variable (Eliminator &eliminator, int pivot,
677
+ bool &deleted_binary_clause) {
678
+
679
+ if (!active (pivot))
680
+ return;
681
+ assert (!frozen (pivot));
682
+
683
+ // First flush garbage clauses.
684
+ //
685
+ int64_t pos = flush_occs (pivot);
686
+ int64_t neg = flush_occs (-pivot);
687
+
688
+ if (pos > neg) {
689
+ pivot = -pivot;
690
+ swap (pos, neg);
691
+ }
692
+ LOG ("pivot %d occurs positively %" PRId64
693
+ " times and negatively %" PRId64 " times",
694
+ pivot, pos, neg);
695
+ assert (!eliminator.schedule.contains (abs (pivot)));
696
+ assert (pos <= neg);
697
+
698
+ if (pos && neg > opts.elimocclim) {
699
+ LOG ("too many occurrences thus not eliminated %d", pivot);
700
+ assert (!eliminator.schedule.contains (abs (pivot)));
701
+ return;
702
+ }
703
+
704
+ LOG ("trying to eliminate %d", pivot);
705
+ assert (!flags (pivot).eliminated ());
706
+
707
+ // Sort occurrence lists, such that shorter clauses come first.
708
+ Occs &ps = occs (pivot);
709
+ stable_sort (ps.begin (), ps.end (), clause_smaller_size ());
710
+ Occs &ns = occs (-pivot);
711
+ stable_sort (ns.begin (), ns.end (), clause_smaller_size ());
712
+
713
+ if (pos)
714
+ find_gate_clauses (eliminator, pivot);
715
+
716
+ if (!unsat && !val (pivot)) {
717
+ if (elim_resolvents_are_bounded (eliminator, pivot)) {
718
+ LOG ("number of resolvents on %d are bounded", pivot);
719
+ elim_add_resolvents (eliminator, pivot);
720
+ if (!unsat)
721
+ mark_eliminated_clauses_as_garbage (eliminator, pivot,
722
+ deleted_binary_clause);
723
+ if (active (pivot))
724
+ mark_eliminated (pivot);
725
+ } else {
726
+ LOG ("too many resolvents on %d so not eliminated", pivot);
727
+ }
728
+ }
729
+
730
+ unmark_gate_clauses (eliminator);
731
+ elim_backward_clauses (eliminator);
732
+ }
733
+
734
+ /*------------------------------------------------------------------------*/
735
+
736
+ void Internal::
737
+ mark_redundant_clauses_with_eliminated_variables_as_garbage () {
738
+ for (const auto &c : clauses) {
739
+ if (c->garbage || !c->redundant)
740
+ continue;
741
+ bool clean = true;
742
+ for (const auto &lit : *c) {
743
+ Flags &f = flags (lit);
744
+ if (f.eliminated ()) {
745
+ clean = false;
746
+ break;
747
+ }
748
+ if (f.pure ()) {
749
+ clean = false;
750
+ break;
751
+ }
752
+ }
753
+ if (!clean)
754
+ mark_garbage (c);
755
+ }
756
+ }
757
+
758
+ /*------------------------------------------------------------------------*/
759
+
760
+ // This function performs one round of bounded variable elimination and
761
+ // returns the number of eliminated variables. The additional result
762
+ // 'completed' is true if this elimination round ran to completion (all
763
+ // variables have been tried). Otherwise it was asynchronously terminated
764
+ // or the resolution limit was hit.
765
+
766
+ int Internal::elim_round (bool &completed, bool &deleted_binary_clause) {
767
+
768
+ assert (opts.elim);
769
+ assert (!unsat);
770
+
771
+ START_SIMPLIFIER (elim, ELIM);
772
+ stats.elimrounds++;
773
+
774
+ int64_t marked_before = last.elim.marked;
775
+ last.elim.marked = stats.mark.elim;
776
+ assert (!level);
777
+
778
+ int64_t resolution_limit;
779
+
780
+ if (opts.elimlimited) {
781
+ int64_t delta = stats.propagations.search;
782
+ delta *= 1e-3 * opts.elimeffort;
783
+ if (delta < opts.elimmineff)
784
+ delta = opts.elimmineff;
785
+ if (delta > opts.elimmaxeff)
786
+ delta = opts.elimmaxeff;
787
+ delta = max (delta, (int64_t) 2l * active ());
788
+
789
+ PHASE ("elim-round", stats.elimrounds,
790
+ "limit of %" PRId64 " resolutions", delta);
791
+
792
+ resolution_limit = stats.elimres + delta;
793
+ } else {
794
+ PHASE ("elim-round", stats.elimrounds, "resolutions unlimited");
795
+ resolution_limit = LONG_MAX;
796
+ }
797
+
798
+ init_noccs ();
799
+
800
+ // First compute the number of occurrences of each literal and at the same
801
+ // time mark satisfied clauses and update 'elim' flags of variables in
802
+ // clauses with root level assigned literals (both false and true).
803
+ //
804
+ for (const auto &c : clauses) {
805
+ if (c->garbage || c->redundant)
806
+ continue;
807
+ bool satisfied = false, falsified = false;
808
+ for (const auto &lit : *c) {
809
+ const signed char tmp = val (lit);
810
+ if (tmp > 0)
811
+ satisfied = true;
812
+ else if (tmp < 0)
813
+ falsified = true;
814
+ else
815
+ assert (active (lit));
816
+ }
817
+ if (satisfied)
818
+ mark_garbage (c); // forces more precise counts
819
+ else {
820
+ for (const auto &lit : *c) {
821
+ if (!active (lit))
822
+ continue;
823
+ if (falsified)
824
+ mark_elim (lit); // simulate unit propagation
825
+ noccs (lit)++;
826
+ }
827
+ }
828
+ }
829
+
830
+ init_occs ();
831
+
832
+ Eliminator eliminator (this);
833
+ ElimSchedule &schedule = eliminator.schedule;
834
+ assert (schedule.empty ());
835
+
836
+ // Now find elimination candidates which occurred in clauses removed since
837
+ // the last time we ran bounded variable elimination, which in turned
838
+ // triggered their 'elim' bit to be set.
839
+ //
840
+ for (auto idx : vars) {
841
+ if (!active (idx))
842
+ continue;
843
+ if (frozen (idx))
844
+ continue;
845
+ if (!flags (idx).elim)
846
+ continue;
847
+ LOG ("scheduling %d for elimination initially", idx);
848
+ schedule.push_back (idx);
849
+ }
850
+
851
+ schedule.shrink ();
852
+
853
+ #ifndef QUIET
854
+ int64_t scheduled = schedule.size ();
855
+ #endif
856
+
857
+ PHASE ("elim-round", stats.elimrounds,
858
+ "scheduled %" PRId64 " variables %.0f%% for elimination",
859
+ scheduled, percent (scheduled, active ()));
860
+
861
+ // Connect irredundant clauses.
862
+ //
863
+ for (const auto &c : clauses)
864
+ if (!c->garbage && !c->redundant)
865
+ for (const auto &lit : *c)
866
+ if (active (lit))
867
+ occs (lit).push_back (c);
868
+
869
+ #ifndef QUIET
870
+ const int64_t old_resolutions = stats.elimres;
871
+ #endif
872
+ const int old_eliminated = stats.all.eliminated;
873
+ const int old_fixed = stats.all.fixed;
874
+
875
+ // Limit on garbage literals during variable elimination. If the limit is
876
+ // hit a garbage collection is performed.
877
+ //
878
+ const int64_t garbage_limit = (2 * stats.irrlits / 3) + (1 << 20);
879
+
880
+ // Main loops tries to eliminate variables according to the schedule. The
881
+ // schedule is updated dynamically and variables are potentially
882
+ // rescheduled to be tried again if they occur in a removed clause.
883
+ //
884
+ #ifndef QUIET
885
+ int64_t tried = 0;
886
+ #endif
887
+ while (!unsat && !terminated_asynchronously () &&
888
+ stats.elimres <= resolution_limit && !schedule.empty ()) {
889
+ int idx = schedule.front ();
890
+ schedule.pop_front ();
891
+ flags (idx).elim = false;
892
+ try_to_eliminate_variable (eliminator, idx, deleted_binary_clause);
893
+ #ifndef QUIET
894
+ tried++;
895
+ #endif
896
+ if (stats.garbage.literals <= garbage_limit)
897
+ continue;
898
+ mark_redundant_clauses_with_eliminated_variables_as_garbage ();
899
+ garbage_collection ();
900
+ }
901
+
902
+ // If the schedule is empty all variables have been tried (even
903
+ // rescheduled ones). Otherwise asynchronous termination happened or we
904
+ // ran into the resolution limit (or derived unsatisfiability).
905
+ //
906
+ completed = !schedule.size ();
907
+
908
+ if (!completed)
909
+ last.elim.marked = marked_before;
910
+
911
+ PHASE ("elim-round", stats.elimrounds,
912
+ "tried to eliminate %" PRId64 " variables %.0f%% (%zd remain)",
913
+ tried, percent (tried, scheduled), schedule.size ());
914
+
915
+ schedule.erase ();
916
+
917
+ // Collect potential literal clause instantiation pairs, which needs full
918
+ // occurrence lists and thus we have it here before resetting them.
919
+ //
920
+ Instantiator instantiator;
921
+ if (!unsat && !terminated_asynchronously () && opts.instantiate)
922
+ collect_instantiation_candidates (instantiator);
923
+
924
+ reset_occs ();
925
+ reset_noccs ();
926
+
927
+ // Mark all redundant clauses with eliminated variables as garbage.
928
+ //
929
+ if (!unsat)
930
+ mark_redundant_clauses_with_eliminated_variables_as_garbage ();
931
+
932
+ int eliminated = stats.all.eliminated - old_eliminated;
933
+ #ifndef QUIET
934
+ int64_t resolutions = stats.elimres - old_resolutions;
935
+ PHASE ("elim-round", stats.elimrounds,
936
+ "eliminated %d variables %.0f%% in %" PRId64 " resolutions",
937
+ eliminated, percent (eliminated, scheduled), resolutions);
938
+ #endif
939
+
940
+ last.elim.subsumephases = stats.subsumephases;
941
+ const int units = stats.all.fixed - old_fixed;
942
+ report ('e', !opts.reportall && !(eliminated + units));
943
+ STOP_SIMPLIFIER (elim, ELIM);
944
+
945
+ if (!unsat && !terminated_asynchronously () &&
946
+ instantiator) // Do we have candidate pairs?
947
+ instantiate (instantiator);
948
+
949
+ return eliminated; // non-zero if successful
950
+ }
951
+
952
+ /*------------------------------------------------------------------------*/
953
+
954
+ // Increase elimination bound (additional clauses allowed during variable
955
+ // elimination), which is triggered if elimination with last bound completed
956
+ // (including no new subsumptions). This was pioneered by GlueMiniSAT in
957
+ // the SAT Race 2015 and then picked up Chanseok Oh in his COMinisatPS
958
+ // solver, which in turn is used in the Maple series of SAT solvers.
959
+ // The bound is no increased if the maximum bound is reached.
960
+
961
+ void Internal::increase_elimination_bound () {
962
+
963
+ if (lim.elimbound >= opts.elimboundmax)
964
+ return;
965
+
966
+ if (lim.elimbound < 0)
967
+ lim.elimbound = 0;
968
+ else if (!lim.elimbound)
969
+ lim.elimbound = 1;
970
+ else
971
+ lim.elimbound *= 2;
972
+
973
+ if (lim.elimbound > opts.elimboundmax)
974
+ lim.elimbound = opts.elimboundmax;
975
+
976
+ PHASE ("elim-phase", stats.elimphases,
977
+ "new elimination bound %" PRId64 "", lim.elimbound);
978
+
979
+ // Now reschedule all active variables for elimination again.
980
+ //
981
+ #ifdef LOGGING
982
+ int count = 0;
983
+ #endif
984
+ for (auto idx : vars) {
985
+ if (!active (idx))
986
+ continue;
987
+ if (flags (idx).elim)
988
+ continue;
989
+ mark_elim (idx);
990
+ #ifdef LOGGING
991
+ count++;
992
+ #endif
993
+ }
994
+ LOG ("marked %d variables as elimination candidates", count);
995
+
996
+ report ('^');
997
+ }
998
+
999
+ void Internal::init_citten () {
1000
+ if (!opts.elimdef)
1001
+ return;
1002
+ assert (!citten);
1003
+ citten = kitten_init ();
1004
+ }
1005
+
1006
+ void Internal::reset_citten () {
1007
+ if (citten) {
1008
+ kitten_release (citten);
1009
+ citten = 0;
1010
+ }
1011
+ }
1012
+
1013
+ /*------------------------------------------------------------------------*/
1014
+
1015
+ void Internal::elim (bool update_limits) {
1016
+
1017
+ if (unsat)
1018
+ return;
1019
+ if (level)
1020
+ backtrack ();
1021
+ if (!propagate ()) {
1022
+ learn_empty_clause ();
1023
+ return;
1024
+ }
1025
+
1026
+ stats.elimphases++;
1027
+ PHASE ("elim-phase", stats.elimphases,
1028
+ "starting at most %d elimination rounds", opts.elimrounds);
1029
+
1030
+ if (external_prop) {
1031
+ assert (!level);
1032
+ private_steps = true;
1033
+ }
1034
+
1035
+ #ifndef QUIET
1036
+ int old_active_variables = active ();
1037
+ int old_eliminated = stats.all.eliminated;
1038
+ #endif
1039
+
1040
+ // Make sure there was a complete subsumption phase since last
1041
+ // elimination
1042
+ //
1043
+ if (last.elim.subsumephases == stats.subsumephases)
1044
+ subsume ();
1045
+
1046
+ reset_watches (); // saves lots of memory
1047
+
1048
+ init_citten ();
1049
+
1050
+ // Alternate one round of bounded variable elimination ('elim_round') and
1051
+ // subsumption ('subsume_round'), blocked ('block') and covered clause
1052
+ // elimination ('cover') until nothing changes, or the round limit is hit.
1053
+ // The loop also aborts early if no variable could be eliminated, the
1054
+ // empty clause is resolved, it is asynchronously terminated or a
1055
+ // resolution limit is hit.
1056
+
1057
+ // This variable determines whether the whole loop of this bounded
1058
+ // variable elimination phase ('elim') ran until completion. This
1059
+ // potentially triggers an incremental increase of the elimination bound.
1060
+ //
1061
+ bool phase_complete = false, deleted_binary_clause = false;
1062
+
1063
+ int round = 1;
1064
+ #ifndef QUIET
1065
+ int eliminated = 0;
1066
+ #endif
1067
+
1068
+ bool round_complete = false;
1069
+ while (!unsat && !phase_complete && !terminated_asynchronously ()) {
1070
+ #ifndef QUIET
1071
+ int eliminated =
1072
+ #endif
1073
+ elim_round (round_complete, deleted_binary_clause);
1074
+
1075
+ if (!round_complete) {
1076
+ PHASE ("elim-phase", stats.elimphases, "last round %d incomplete %s",
1077
+ round, eliminated ? "but successful" : "and unsuccessful");
1078
+ assert (!phase_complete);
1079
+ break;
1080
+ }
1081
+
1082
+ if (round++ >= opts.elimrounds) {
1083
+ PHASE ("elim-phase", stats.elimphases, "round limit %d hit (%s)",
1084
+ round - 1,
1085
+ eliminated ? "though last round successful"
1086
+ : "last round unsuccessful anyhow");
1087
+ assert (!phase_complete);
1088
+ break;
1089
+ }
1090
+
1091
+ // Prioritize 'subsumption' over blocked and covered clause elimination.
1092
+
1093
+ if (subsume_round ())
1094
+ continue;
1095
+ if (block ())
1096
+ continue;
1097
+ if (cover ())
1098
+ continue;
1099
+
1100
+ // Was not able to generate new variable elimination candidates after
1101
+ // variable elimination round, neither through subsumption, nor blocked,
1102
+ // nor covered clause elimination.
1103
+ //
1104
+ PHASE ("elim-phase", stats.elimphases,
1105
+ "no new variable elimination candidates");
1106
+
1107
+ assert (round_complete);
1108
+ phase_complete = true;
1109
+ }
1110
+
1111
+ if (phase_complete) {
1112
+ stats.elimcompleted++;
1113
+ PHASE ("elim-phase", stats.elimphases,
1114
+ "fully completed elimination %" PRId64
1115
+ " at elimination bound %" PRId64 "",
1116
+ stats.elimcompleted, lim.elimbound);
1117
+ } else {
1118
+ PHASE ("elim-phase", stats.elimphases,
1119
+ "incomplete elimination %" PRId64
1120
+ " at elimination bound %" PRId64 "",
1121
+ stats.elimcompleted + 1, lim.elimbound);
1122
+ }
1123
+
1124
+ reset_citten ();
1125
+ if (deleted_binary_clause)
1126
+ delete_garbage_clauses ();
1127
+ init_watches ();
1128
+ connect_watches ();
1129
+
1130
+ if (unsat)
1131
+ LOG ("elimination derived empty clause");
1132
+ else if (propagated < trail.size ()) {
1133
+ LOG ("elimination produced %zd units",
1134
+ (size_t) (trail.size () - propagated));
1135
+ if (!propagate ()) {
1136
+ LOG ("propagating units after elimination results in empty clause");
1137
+ learn_empty_clause ();
1138
+ }
1139
+ }
1140
+
1141
+ // If we ran variable elimination until completion we increase the
1142
+ // variable elimination bound and reschedule elimination of all variables.
1143
+ //
1144
+ if (phase_complete)
1145
+ increase_elimination_bound ();
1146
+
1147
+ #ifndef QUIET
1148
+ eliminated = stats.all.eliminated - old_eliminated;
1149
+ PHASE ("elim-phase", stats.elimphases, "eliminated %d variables %.2f%%",
1150
+ eliminated, percent (eliminated, old_active_variables));
1151
+ #endif
1152
+
1153
+ if (external_prop) {
1154
+ assert (!level);
1155
+ private_steps = false;
1156
+ }
1157
+
1158
+ if (!update_limits)
1159
+ return;
1160
+
1161
+ int64_t delta = scale (opts.elimint * (stats.elimphases + 1));
1162
+ lim.elim = stats.conflicts + delta;
1163
+
1164
+ PHASE ("elim-phase", stats.elimphases,
1165
+ "new limit at %" PRId64 " conflicts after %" PRId64 " conflicts",
1166
+ lim.elim, delta);
1167
+
1168
+ last.elim.fixed = stats.all.fixed;
1169
+ }
1170
+
1171
+ } // namespace CaDiCaL