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,1960 @@
1
+ #include "internal.hpp"
2
+
3
+ namespace CaDiCaL {
4
+
5
+ Sweeper::Sweeper (Internal *i)
6
+ : internal (i), random (internal->opts.seed) {
7
+ random += internal->stats.sweep; // different seed every time
8
+ internal->init_sweeper (*this);
9
+ }
10
+
11
+ Sweeper::~Sweeper () {
12
+ // this is already called actively
13
+ // internal->release_sweeper (this);
14
+ return;
15
+ }
16
+
17
+ #define INVALID64 INT64_MAX
18
+ #define INVALID UINT_MAX
19
+
20
+ int Internal::sweep_solve () {
21
+ START (sweepsolve);
22
+ kitten_randomize_phases (citten);
23
+ stats.sweep_solved++;
24
+ int res = kitten_solve (citten);
25
+ if (res == 10)
26
+ stats.sweep_sat++;
27
+ if (res == 20)
28
+ stats.sweep_unsat++;
29
+ STOP (sweepsolve);
30
+ return res;
31
+ }
32
+
33
+ bool Internal::sweep_flip (int lit) {
34
+ START (sweepflip);
35
+ bool res = kitten_flip_signed_literal (citten, lit);
36
+ STOP (sweepflip);
37
+ return res;
38
+ }
39
+
40
+ int Internal::sweep_flip_and_implicant (int lit) {
41
+ START (sweepimplicant);
42
+ int res = kitten_flip_and_implicant_for_signed_literal (citten, lit);
43
+ STOP (sweepimplicant);
44
+ return res;
45
+ }
46
+
47
+ void Internal::sweep_set_kitten_ticks_limit (Sweeper &sweeper) {
48
+ uint64_t remaining = 0;
49
+ const uint64_t current = sweeper.current_ticks;
50
+ if (current < sweeper.limit.ticks)
51
+ remaining = sweeper.limit.ticks - current;
52
+ LOG ("'kitten_ticks' remaining %" PRIu64, remaining);
53
+ kitten_set_ticks_limit (citten, remaining);
54
+ }
55
+
56
+ void Internal::sweep_update_noccs (Clause *c) {
57
+ if (c->redundant)
58
+ return;
59
+ for (const auto &lit : *c) {
60
+ noccs (lit)--;
61
+ }
62
+ }
63
+
64
+ bool Internal::can_sweep_clause (Clause *c) {
65
+ if (c->garbage)
66
+ return false;
67
+ if (!c->redundant)
68
+ return true;
69
+ return c->size == 2; // && !c->hyper; // could ignore hyper
70
+ }
71
+
72
+ // essentially do full occurence list as in elim.cpp
73
+ void Internal::sweep_dense_mode_and_watch_irredundant () {
74
+ reset_watches ();
75
+
76
+ init_noccs ();
77
+
78
+ // mark satisfied irredundant clauses as garbage
79
+ for (const auto &c : clauses) {
80
+ if (!can_sweep_clause (c))
81
+ continue;
82
+ bool satisfied = false;
83
+ for (const auto &lit : *c) {
84
+ const signed char tmp = val (lit);
85
+ if (tmp <= 0)
86
+ continue;
87
+ if (tmp > 0) {
88
+ satisfied = true;
89
+ break;
90
+ }
91
+ }
92
+ if (satisfied)
93
+ mark_garbage (c); // forces more precise counts
94
+ else {
95
+ for (const auto &lit : *c)
96
+ noccs (lit)++;
97
+ }
98
+ }
99
+
100
+ init_occs ();
101
+
102
+ // Connect irredundant clauses.
103
+ //
104
+ for (const auto &c : clauses) {
105
+ if (!c->garbage) {
106
+ for (const auto &lit : *c)
107
+ if (active (lit))
108
+ occs (lit).push_back (c);
109
+ } else if (c->size == 2) {
110
+ if (!c->flushed) {
111
+ if (proof) {
112
+ c->flushed = true;
113
+ proof->delete_clause (c);
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ // go back to two watch scheme
121
+ void Internal::sweep_sparse_mode () {
122
+ reset_occs ();
123
+ reset_noccs ();
124
+ init_watches ();
125
+ connect_watches ();
126
+ }
127
+
128
+ // propagate without watches but full occurence list
129
+ void Internal::sweep_dense_propagate (Sweeper &sweeper) {
130
+ vector<int> &work = sweeper.propagate;
131
+ size_t i = 0;
132
+ uint64_t &ticks = sweeper.current_ticks;
133
+ while (i < work.size ()) {
134
+ int lit = work[i++];
135
+ LOG ("sweeping propagation of %d", lit);
136
+ assert (val (lit) > 0);
137
+ ticks += 1 + cache_lines (occs (-lit).size (), sizeof (Clause *));
138
+ const Occs &ns = occs (-lit);
139
+ for (const auto &c : ns) {
140
+ ticks++;
141
+ if (!can_sweep_clause (c))
142
+ continue;
143
+ int unit = 0, satisfied = 0;
144
+ for (const auto &other : *c) {
145
+ const signed char tmp = val (other);
146
+ if (tmp < 0)
147
+ continue;
148
+ if (tmp > 0) {
149
+ satisfied = other;
150
+ break;
151
+ }
152
+ if (unit)
153
+ unit = INT_MIN;
154
+ else
155
+ unit = other;
156
+ }
157
+ if (satisfied) {
158
+ LOG (c, "sweeping propagation of %d finds %d satisfied", lit,
159
+ satisfied);
160
+ mark_garbage (c);
161
+ sweep_update_noccs (c);
162
+ } else if (!unit) {
163
+ LOG ("empty clause during sweeping propagation of %d", lit);
164
+ // need to set conflict = c for lrat
165
+ conflict = c;
166
+ learn_empty_clause ();
167
+ conflict = 0;
168
+ break;
169
+ } else if (unit != INT_MIN) {
170
+ LOG ("new unit %d during sweeping propagation of %d", unit, lit);
171
+ build_chain_for_units (unit, c, 0);
172
+ assign_unit (unit);
173
+ work.push_back (unit);
174
+ ticks++;
175
+ }
176
+ }
177
+ if (unsat)
178
+ break;
179
+
180
+ // not necessary but should help
181
+ ticks += 1 + cache_lines (occs (lit).size (), sizeof (Clause *));
182
+ const Occs &ps = occs (lit);
183
+ for (const auto &c : ps) {
184
+ ticks++;
185
+ if (c->garbage)
186
+ continue;
187
+ // if (c->redundant) // TODO I assume it does not hurt to mark
188
+ // everything here continue;
189
+ LOG (c, "sweeping propagation of %d produces satisfied", lit);
190
+ mark_garbage (c);
191
+ sweep_update_noccs (c);
192
+ }
193
+ }
194
+ work.clear ();
195
+ }
196
+
197
+ bool Internal::kitten_ticks_limit_hit (Sweeper &sweeper, const char *when) {
198
+ const uint64_t current =
199
+ kitten_current_ticks (citten) + sweeper.current_ticks;
200
+ if (current >= sweeper.limit.ticks) {
201
+ LOG ("'kitten_ticks' limit of %" PRIu64 " ticks hit after %" PRIu64
202
+ " ticks during %s",
203
+ sweeper.limit.ticks, current, when);
204
+ return true;
205
+ }
206
+ #ifndef LOGGING
207
+ (void) when;
208
+ #endif
209
+ return false;
210
+ }
211
+
212
+ void Internal::init_sweeper (Sweeper &sweeper) {
213
+ sweeper.encoded = 0;
214
+ enlarge_zero (sweeper.depths, max_var + 1);
215
+ sweeper.reprs = new int[2 * max_var + 1];
216
+ sweeper.reprs += max_var;
217
+ enlarge_zero (sweeper.prev, max_var + 1);
218
+ enlarge_zero (sweeper.next, max_var + 1);
219
+ for (const auto &lit : lits)
220
+ sweeper.reprs[lit] = lit;
221
+ sweeper.first = sweeper.last = 0;
222
+ sweeper.current_ticks =
223
+ 2 *
224
+ clauses
225
+ .size (); // initialize with the cost of building full occ list.
226
+ sweeper.current_ticks +=
227
+ 2 + 2 * cache_lines (clauses.size (), sizeof (Clause *));
228
+ assert (!citten);
229
+ citten = kitten_init ();
230
+ citten_clear_track_log_terminate ();
231
+
232
+ sweep_dense_mode_and_watch_irredundant (); // full occurence list
233
+
234
+ if (lrat) {
235
+ sweeper.prev_units.push_back (0);
236
+ for (const auto &idx : vars) {
237
+ sweeper.prev_units.push_back (val (idx) != 0);
238
+ }
239
+ }
240
+
241
+ unsigned completed = stats.sweep_completed;
242
+ const unsigned max_completed = 32;
243
+ if (completed > max_completed)
244
+ completed = max_completed;
245
+
246
+ uint64_t vars_limit = opts.sweepvars;
247
+ vars_limit <<= completed;
248
+ const unsigned max_vars_limit = opts.sweepmaxvars;
249
+ if (vars_limit > max_vars_limit)
250
+ vars_limit = max_vars_limit;
251
+ sweeper.limit.vars = vars_limit;
252
+ VERBOSE (3, "sweeper variable limit %u", sweeper.limit.vars);
253
+
254
+ uint64_t depth_limit = stats.sweep_completed;
255
+ depth_limit += opts.sweepdepth;
256
+ const unsigned max_depth = opts.sweepmaxdepth;
257
+ if (depth_limit > max_depth)
258
+ depth_limit = max_depth;
259
+ sweeper.limit.depth = depth_limit;
260
+ VERBOSE (3, "sweeper depth limit %u", sweeper.limit.depth);
261
+
262
+ uint64_t clause_limit = opts.sweepclauses;
263
+ clause_limit <<= completed;
264
+ const unsigned max_clause_limit = opts.sweepmaxclauses;
265
+ if (clause_limit > max_clause_limit)
266
+ clause_limit = max_clause_limit;
267
+ sweeper.limit.clauses = clause_limit;
268
+ VERBOSE (3, "sweeper clause limit %u", sweeper.limit.clauses);
269
+ }
270
+
271
+ void Internal::release_sweeper (Sweeper &sweeper) {
272
+
273
+ sweeper.reprs -= max_var;
274
+ delete[] sweeper.reprs;
275
+
276
+ erase_vector (sweeper.depths);
277
+ erase_vector (sweeper.prev);
278
+ erase_vector (sweeper.next);
279
+ erase_vector (sweeper.vars);
280
+ erase_vector (sweeper.clause);
281
+ erase_vector (sweeper.backbone);
282
+ erase_vector (sweeper.partition);
283
+ erase_vector (sweeper.prev_units);
284
+ for (unsigned i = 0; i < 2; i++)
285
+ erase_vector (sweeper.core[i]);
286
+
287
+ kitten_release (citten);
288
+ citten = 0;
289
+ stats.ticks.sweep += sweeper.current_ticks;
290
+ sweep_sparse_mode ();
291
+ return;
292
+ }
293
+
294
+ void Internal::clear_sweeper (Sweeper &sweeper) {
295
+ LOG ("clearing sweeping environment");
296
+ sweeper.current_ticks += kitten_current_ticks (citten);
297
+
298
+ citten_clear_track_log_terminate ();
299
+ for (auto &idx : sweeper.vars) {
300
+ assert (sweeper.depths[idx]);
301
+ sweeper.depths[idx] = 0;
302
+ }
303
+ sweeper.vars.clear ();
304
+ for (auto c : sweeper.clauses) {
305
+ assert (c->swept);
306
+ c->swept = false;
307
+ }
308
+ sweeper.clauses.clear ();
309
+ sweeper.backbone.clear ();
310
+ sweeper.partition.clear ();
311
+ sweeper.encoded = 0;
312
+ sweep_set_kitten_ticks_limit (sweeper);
313
+ }
314
+
315
+ int Internal::sweep_repr (Sweeper &sweeper, int lit) {
316
+ int res;
317
+ {
318
+ int prev = lit;
319
+ while ((res = sweeper.reprs[prev]) != prev)
320
+ prev = res;
321
+ }
322
+ if (res == lit)
323
+ return res;
324
+ LOG ("sweeping repr[%d] = %d", lit, res);
325
+ {
326
+ const int not_res = -res;
327
+ int next, prev = lit;
328
+ while ((next = sweeper.reprs[prev]) != res) {
329
+ const int not_prev = -prev;
330
+ sweeper.reprs[not_prev] = not_res;
331
+ sweeper.reprs[prev] = res;
332
+ prev = next;
333
+ }
334
+ assert (sweeper.reprs[-prev] == not_res);
335
+ }
336
+ return res;
337
+ }
338
+
339
+ void Internal::add_literal_to_environment (Sweeper &sweeper, unsigned depth,
340
+ int lit) {
341
+ const int repr = sweep_repr (sweeper, lit);
342
+ if (repr != lit)
343
+ return;
344
+ const int idx = abs (lit);
345
+ if (sweeper.depths[idx])
346
+ return;
347
+ assert (depth < UINT_MAX);
348
+ sweeper.depths[idx] = depth + 1;
349
+ assert (idx);
350
+ sweeper.vars.push_back (idx);
351
+ LOG ("sweeping[%u] adding literal %d", depth, lit);
352
+ }
353
+
354
+ void Internal::sweep_add_clause (Sweeper &sweeper, unsigned depth) {
355
+ // TODO: assertion fails, check if this an issue or can be avoided
356
+ // assert (sweeper.clause.size () > 1);
357
+ for (const auto &lit : sweeper.clause)
358
+ add_literal_to_environment (sweeper, depth, lit);
359
+ citten_clause_with_id (citten, sweeper.clauses.size (),
360
+ sweeper.clause.size (), sweeper.clause.data ());
361
+ sweeper.clause.clear ();
362
+ if (opts.sweepcountbinary || sweeper.clause.size () > 2)
363
+ sweeper.encoded++;
364
+ }
365
+
366
+ void Internal::sweep_clause (Sweeper &sweeper, unsigned depth, Clause *c) {
367
+ if (c->swept)
368
+ return;
369
+ assert (can_sweep_clause (c));
370
+ LOG (c, "sweeping[%u]", depth);
371
+ assert (sweeper.clause.empty ());
372
+ for (const auto &lit : *c) {
373
+ const signed char tmp = val (lit);
374
+ if (tmp > 0) {
375
+ mark_garbage (c);
376
+ sweep_update_noccs (c);
377
+ sweeper.clause.clear ();
378
+ return;
379
+ }
380
+ if (tmp < 0) {
381
+ if (lrat)
382
+ sweeper.prev_units[abs (lit)] = true;
383
+ continue;
384
+ }
385
+ sweeper.clause.push_back (lit);
386
+ }
387
+ c->swept = true;
388
+ sweep_add_clause (sweeper, depth);
389
+ sweeper.clauses.push_back (c);
390
+ }
391
+
392
+ extern "C" {
393
+ static void save_core_clause (void *state, unsigned id, bool learned,
394
+ size_t size, const unsigned *lits) {
395
+ Sweeper *sweeper = (Sweeper *) state;
396
+ Internal *internal = sweeper->internal;
397
+ if (internal->unsat)
398
+ return;
399
+ vector<sweep_proof_clause> &core = sweeper->core[sweeper->save];
400
+ sweep_proof_clause pc;
401
+ if (learned) {
402
+ pc.sweep_id = INVALID; // necessary
403
+ pc.cad_id = INVALID64; // delay giving ids
404
+ } else {
405
+ pc.sweep_id = id; // necessary
406
+ assert (id < sweeper->clauses.size ());
407
+ pc.cad_id = sweeper->clauses[id]->id;
408
+ }
409
+ pc.kit_id = 0;
410
+ pc.learned = learned;
411
+ const unsigned *end = lits + size;
412
+ for (const unsigned *p = lits; p != end; p++) {
413
+ pc.literals.push_back (internal->citten2lit (*p)); // conversion
414
+ }
415
+ #ifdef LOGGING
416
+ LOG (pc.literals, "traced %s",
417
+ pc.learned == true ? "learned" : "original");
418
+ #endif
419
+ core.push_back (pc);
420
+ }
421
+
422
+ static void save_core_clause_with_lrat (void *state, unsigned cid,
423
+ unsigned id, bool learned,
424
+ size_t size, const unsigned *lits,
425
+ size_t chain_size,
426
+ const unsigned *chain) {
427
+ Sweeper *sweeper = (Sweeper *) state;
428
+ Internal *internal = sweeper->internal;
429
+ if (internal->unsat)
430
+ return;
431
+ vector<sweep_proof_clause> &core = sweeper->core[sweeper->save];
432
+ vector<Clause *> &clauses = sweeper->clauses;
433
+ sweep_proof_clause pc;
434
+ pc.kit_id = cid;
435
+ pc.learned = learned;
436
+ pc.sweep_id = INVALID;
437
+ pc.cad_id = INVALID64;
438
+ if (!learned) {
439
+ assert (size);
440
+ assert (!chain_size);
441
+ assert (id < clauses.size ());
442
+ pc.sweep_id = id;
443
+ assert (id < clauses.size ());
444
+ pc.cad_id = clauses[id]->id;
445
+ for (const auto &lit : *clauses[id]) {
446
+ pc.literals.push_back (lit);
447
+ }
448
+ } else {
449
+ assert (chain_size);
450
+ pc.sweep_id = INVALID;
451
+ pc.cad_id = INVALID64; // delay giving ids
452
+ const unsigned *end = lits + size;
453
+ for (const unsigned *p = lits; p != end; p++) {
454
+ pc.literals.push_back (internal->citten2lit (*p)); // conversion
455
+ }
456
+ for (const unsigned *p = chain + chain_size; p != chain; p--) {
457
+ pc.chain.push_back (*(p - 1));
458
+ }
459
+ }
460
+ #ifdef LOGGING
461
+ if (learned)
462
+ LOG (pc.literals, "traced %s",
463
+ pc.learned == true ? "learned" : "original");
464
+ else {
465
+ assert (id < clauses.size ());
466
+ LOG (clauses[id], "traced");
467
+ }
468
+ #endif
469
+ core.push_back (pc);
470
+ }
471
+
472
+ static int citten_terminate (void *data) {
473
+ return ((Internal *) data)->terminated_asynchronously ();
474
+ }
475
+
476
+ } // end extern C
477
+
478
+ void Internal::citten_clear_track_log_terminate () {
479
+ assert (citten);
480
+ kitten_clear (citten);
481
+ kitten_track_antecedents (citten);
482
+ if (external->terminator)
483
+ kitten_set_terminator (citten, internal, citten_terminate);
484
+ #ifdef LOGGING
485
+ if (opts.log)
486
+ kitten_set_logging (citten);
487
+ #endif
488
+ }
489
+
490
+ void Internal::add_core (Sweeper &sweeper, unsigned core_idx) {
491
+ if (unsat)
492
+ return;
493
+ LOG ("check and add extracted core[%u] lemmas to proof", core_idx);
494
+ assert (core_idx == 0 || core_idx == 1);
495
+ vector<sweep_proof_clause> &core = sweeper.core[core_idx];
496
+
497
+ assert (!lrat || proof);
498
+
499
+ unsigned unsat_size = 0;
500
+ for (auto &pc : core) {
501
+ unsat_size++;
502
+
503
+ if (!pc.learned) {
504
+ LOG (pc.literals,
505
+ "not adding already present core[%u] kitten[%u] clause",
506
+ core_idx, pc.kit_id);
507
+ continue;
508
+ }
509
+
510
+ LOG (pc.literals, "adding extracted core[%u] kitten[%u] lemma",
511
+ core_idx, pc.kit_id);
512
+
513
+ const unsigned new_size = pc.literals.size ();
514
+
515
+ if (lrat) {
516
+ assert (pc.cad_id == INVALID64);
517
+ for (auto &cid : pc.chain) {
518
+ int64_t id = 0;
519
+ for (const auto &cpc : core) {
520
+ if (cpc.kit_id == cid) {
521
+ if (cpc.learned)
522
+ id = cpc.cad_id;
523
+ else {
524
+ id = cpc.cad_id;
525
+ assert (cpc.cad_id == sweeper.clauses[cpc.sweep_id]->id);
526
+ assert (!sweeper.clauses[cpc.sweep_id]->garbage);
527
+ // avoid duplicate ids of units with seen flags
528
+ for (const auto &lit : cpc.literals) {
529
+ if (val (lit) >= 0)
530
+ continue;
531
+ if (flags (lit).seen)
532
+ continue;
533
+ const int idx = abs (lit);
534
+ if (sweeper.prev_units[idx]) {
535
+ int64_t uid = unit_id (-lit);
536
+ lrat_chain.push_back (uid);
537
+ analyzed.push_back (lit);
538
+ flags (lit).seen = true;
539
+ }
540
+ }
541
+ }
542
+ break;
543
+ }
544
+ }
545
+ assert (id);
546
+ if (id != INVALID64)
547
+ lrat_chain.push_back (id);
548
+ }
549
+ clear_analyzed_literals ();
550
+ }
551
+
552
+ if (!new_size) {
553
+ LOG ("sweeping produced empty clause");
554
+ learn_empty_clause ();
555
+ core.resize (unsat_size);
556
+ return;
557
+ }
558
+
559
+ if (new_size == 1) {
560
+ int unit = pc.literals[0];
561
+ if (val (unit) > 0) {
562
+ LOG ("already assigned sweeping unit %d", unit);
563
+ lrat_chain.clear ();
564
+ } else if (val (unit) < 0) {
565
+ LOG ("falsified sweeping unit %d leads to empty clause", unit);
566
+ if (lrat) {
567
+ int64_t id = unit_id (-unit);
568
+ lrat_chain.push_back (id);
569
+ }
570
+ learn_empty_clause ();
571
+ core.resize (unsat_size);
572
+ return;
573
+ } else {
574
+ LOG ("sweeping produced unit %d", unit);
575
+ assign_unit (unit);
576
+ stats.sweep_units++;
577
+ sweeper.propagate.push_back (unit);
578
+ }
579
+ if (proof && lrat)
580
+ pc.cad_id = unit_id (unit);
581
+ continue;
582
+ }
583
+
584
+ assert (new_size > 1);
585
+ assert (pc.learned);
586
+
587
+ if (proof) {
588
+ pc.cad_id = ++clause_id;
589
+ proof->add_derived_clause (pc.cad_id, true, pc.literals, lrat_chain);
590
+ lrat_chain.clear ();
591
+ }
592
+ }
593
+ }
594
+
595
+ void Internal::save_core (Sweeper &sweeper, unsigned core) {
596
+ LOG ("saving extracted core[%u] lemmas", core);
597
+ assert (core == 0 || core == 1);
598
+ assert (sweeper.core[core].empty ());
599
+ sweeper.save = core;
600
+ kitten_compute_clausal_core (citten, 0);
601
+ if (lrat)
602
+ kitten_trace_core (citten, &sweeper, save_core_clause_with_lrat);
603
+ else
604
+ kitten_traverse_core_clauses_with_id (citten, &sweeper,
605
+ save_core_clause);
606
+ }
607
+
608
+ void Internal::clear_core (Sweeper &sweeper, unsigned core_idx) {
609
+ assert (core_idx == 0 || core_idx == 1);
610
+ LOG ("clearing core[%u] lemmas", core_idx);
611
+ vector<sweep_proof_clause> &core = sweeper.core[core_idx];
612
+ if (proof) {
613
+ LOG ("deleting sub-solver core clauses");
614
+ for (auto &pc : core) {
615
+ if (pc.learned && pc.literals.size () > 1)
616
+ proof->delete_clause (pc.cad_id, true, pc.literals);
617
+ }
618
+ }
619
+ core.clear ();
620
+ }
621
+
622
+ void Internal::save_add_clear_core (Sweeper &sweeper) {
623
+ save_core (sweeper, 0);
624
+ add_core (sweeper, 0);
625
+ clear_core (sweeper, 0);
626
+ }
627
+
628
+ void Internal::init_backbone_and_partition (Sweeper &sweeper) {
629
+ LOG ("initializing backbone and equivalent literals candidates");
630
+ sweeper.backbone.clear ();
631
+ sweeper.partition.clear ();
632
+ for (const auto &idx : sweeper.vars) {
633
+ if (!active (idx))
634
+ continue;
635
+ assert (idx > 0);
636
+ const int lit = idx;
637
+ const int not_lit = -lit;
638
+ const signed char tmp = kitten_signed_value (citten, lit);
639
+ const int candidate = (tmp < 0) ? not_lit : lit;
640
+ LOG ("sweeping candidate %d", candidate);
641
+ sweeper.backbone.push_back (candidate);
642
+ sweeper.partition.push_back (candidate);
643
+ }
644
+ sweeper.partition.push_back (0);
645
+
646
+ LOG (sweeper.backbone, "initialized backbone candidates");
647
+ LOG (sweeper.partition, "initialized equivalence candidates");
648
+ }
649
+
650
+ void Internal::sweep_empty_clause (Sweeper &sweeper) {
651
+ assert (!unsat);
652
+ save_add_clear_core (sweeper);
653
+ assert (unsat);
654
+ }
655
+
656
+ void Internal::sweep_refine_partition (Sweeper &sweeper) {
657
+ LOG ("refining partition");
658
+ vector<int> &old_partition = sweeper.partition;
659
+ vector<int> new_partition;
660
+ auto old_begin = old_partition.begin ();
661
+ const auto old_end = old_partition.end ();
662
+ #ifdef LOGGING
663
+ unsigned old_classes = 0;
664
+ unsigned new_classes = 0;
665
+ #endif
666
+ for (auto p = old_begin, q = p; p != old_end; p = q + 1) {
667
+ unsigned assigned_true = 0;
668
+ int other;
669
+ for (q = p; (other = *q) != 0; q++) {
670
+ if (sweep_repr (sweeper, other) != other)
671
+ continue;
672
+ if (val (other))
673
+ continue;
674
+ signed char value = kitten_signed_value (citten, other);
675
+ if (!value)
676
+ LOG ("dropping sub-solver unassigned %d", other);
677
+ else if (value > 0) {
678
+ new_partition.push_back (other);
679
+ assigned_true++;
680
+ }
681
+ }
682
+ #ifdef LOGGING
683
+ LOG ("refining class %u of size %zu", old_classes, (size_t) (q - p));
684
+ old_classes++;
685
+ #endif
686
+ if (assigned_true == 0)
687
+ LOG ("no positive literal in class");
688
+ else if (assigned_true == 1) {
689
+ #ifdef LOGGING
690
+ other =
691
+ #else
692
+ (void)
693
+ #endif
694
+ new_partition.back ();
695
+ new_partition.pop_back ();
696
+ LOG ("dropping singleton class %d", other);
697
+ } else {
698
+ LOG ("%u positive literal in class", assigned_true);
699
+ new_partition.push_back (0);
700
+ #ifdef LOGGING
701
+ new_classes++;
702
+ #endif
703
+ }
704
+
705
+ unsigned assigned_false = 0;
706
+ for (q = p; (other = *q) != 0; q++) {
707
+ if (sweep_repr (sweeper, other) != other)
708
+ continue;
709
+ if (val (other))
710
+ continue;
711
+ signed char value = kitten_signed_value (citten, other);
712
+ if (value < 0) {
713
+ new_partition.push_back (other);
714
+ assigned_false++;
715
+ }
716
+ }
717
+
718
+ if (assigned_false == 0)
719
+ LOG ("no negative literal in class");
720
+ else if (assigned_false == 1) {
721
+ #ifdef LOGGING
722
+ other =
723
+ #else
724
+ (void)
725
+ #endif
726
+ new_partition.back ();
727
+ new_partition.pop_back ();
728
+ LOG ("dropping singleton class %d", other);
729
+ } else {
730
+ LOG ("%u negative literal in class", assigned_false);
731
+ new_partition.push_back (0);
732
+ #ifdef LOGGING
733
+ new_classes++;
734
+ #endif
735
+ }
736
+ }
737
+ old_partition.swap (new_partition);
738
+ LOG ("refined %u classes into %u", old_classes, new_classes);
739
+ }
740
+
741
+ void Internal::sweep_refine_backbone (Sweeper &sweeper) {
742
+ LOG ("refining backbone candidates");
743
+ const auto end = sweeper.backbone.end ();
744
+ auto q = sweeper.backbone.begin ();
745
+ for (auto p = q; p != end; p++) {
746
+ const int lit = *p;
747
+ if (val (lit))
748
+ continue;
749
+ signed char value = kitten_signed_value (citten, lit);
750
+ if (!value)
751
+ LOG ("dropping sub-solver unassigned %d", lit);
752
+ else if (value > 0)
753
+ *q++ = lit;
754
+ }
755
+ sweeper.backbone.resize (q - sweeper.backbone.begin ());
756
+ }
757
+
758
+ void Internal::sweep_refine (Sweeper &sweeper) {
759
+ assert (kitten_status (citten) == 10);
760
+ if (sweeper.backbone.empty ())
761
+ LOG ("no need to refine empty backbone candidates");
762
+ else
763
+ sweep_refine_backbone (sweeper);
764
+ if (sweeper.partition.empty ())
765
+ LOG ("no need to refine empty partition candidates");
766
+ else
767
+ sweep_refine_partition (sweeper);
768
+ }
769
+
770
+ void Internal::flip_backbone_literals (Sweeper &sweeper) {
771
+ const unsigned max_rounds = opts.sweepfliprounds;
772
+ if (!max_rounds)
773
+ return;
774
+ assert (sweeper.backbone.size ());
775
+ if (kitten_status (citten) != 10)
776
+ return;
777
+ #ifdef LOGGING
778
+ unsigned total_flipped = 0;
779
+ #endif
780
+ unsigned flipped, round = 0;
781
+ do {
782
+ round++;
783
+ flipped = 0;
784
+ bool refine = false;
785
+ auto begin = sweeper.backbone.begin (), q = begin, p = q;
786
+ const auto end = sweeper.backbone.end ();
787
+ bool limit_hit = false;
788
+ while (p != end) {
789
+ const int lit = *p++;
790
+ stats.sweep_flip_backbone++;
791
+ if (limit_hit || terminated_asynchronously ()) {
792
+ break;
793
+ } else if (sweep_flip (lit)) {
794
+ LOG ("flipping backbone candidate %d succeeded", lit);
795
+ #ifdef LOGGING
796
+ total_flipped++;
797
+ #endif
798
+ stats.sweep_flipped_backbone++;
799
+ flipped++;
800
+ } else {
801
+ LOG ("flipping backbone candidate %d failed", lit);
802
+ *q++ = lit;
803
+ }
804
+ }
805
+ while (p != end)
806
+ *q++ = *p++;
807
+ sweeper.backbone.resize (q - sweeper.backbone.begin ());
808
+ LOG ("flipped %u backbone candidates in round %u", flipped, round);
809
+
810
+ if (limit_hit)
811
+ break;
812
+ if (terminated_asynchronously ())
813
+ break;
814
+ if (kitten_ticks_limit_hit (sweeper, "backbone flipping"))
815
+ break;
816
+ if (refine)
817
+ sweep_refine (sweeper);
818
+ } while (flipped && round < max_rounds);
819
+ LOG ("flipped %u backbone candidates in total in %u rounds",
820
+ total_flipped, round);
821
+ }
822
+
823
+ bool Internal::sweep_extract_fixed (Sweeper &sweeper, int lit) {
824
+ const int not_lit = -lit;
825
+ stats.sweep_solved_backbone++;
826
+ kitten_assume_signed (citten, not_lit);
827
+ int res = sweep_solve ();
828
+ if (!res) {
829
+ stats.sweep_unknown_backbone++;
830
+ return false;
831
+ }
832
+ assert (res == 20);
833
+ LOG ("sweep unit %d", lit);
834
+ save_add_clear_core (sweeper);
835
+ stats.sweep_unsat_backbone++;
836
+ return true;
837
+ }
838
+
839
+ bool Internal::sweep_backbone_candidate (Sweeper &sweeper, int lit) {
840
+ LOG ("trying backbone candidate %d", lit);
841
+ signed char value = kitten_fixed_signed (citten, lit);
842
+ if (value) {
843
+ stats.sweep_fixed_backbone++;
844
+ assert (value > 0);
845
+ if (val (lit) <= 0) {
846
+ return sweep_extract_fixed (sweeper, lit);
847
+ } else
848
+ LOG ("literal %d already fixed", lit);
849
+ return false;
850
+ }
851
+
852
+ int res = kitten_status (citten);
853
+ if (res != 10) {
854
+ LOG ("not flipping due to status %d != 10", res);
855
+ }
856
+ stats.sweep_flip_backbone++;
857
+ if (res == 10 && sweep_flip (lit)) {
858
+ stats.sweep_flipped_backbone++;
859
+ LOG ("flipping %d succeeded", lit);
860
+ // LOGBACKBONE ("refined backbone candidates");
861
+ return false;
862
+ }
863
+
864
+ LOG ("flipping %d failed", lit);
865
+ const int not_lit = -lit;
866
+ stats.sweep_solved_backbone++;
867
+ kitten_assume_signed (citten, not_lit);
868
+ res = sweep_solve ();
869
+ if (res == 10) {
870
+ LOG ("sweeping backbone candidate %d failed", lit);
871
+ sweep_refine (sweeper);
872
+ stats.sweep_sat_backbone++;
873
+ return false;
874
+ }
875
+
876
+ if (res == 20) {
877
+ LOG ("sweep unit %d", lit);
878
+ save_add_clear_core (sweeper);
879
+ assert (val (lit));
880
+ stats.sweep_unsat_backbone++;
881
+ return true;
882
+ }
883
+
884
+ stats.sweep_unknown_backbone++;
885
+
886
+ LOG ("sweeping backbone candidate %d failed", lit);
887
+ return false;
888
+ }
889
+
890
+ // at this point the binary (lit or other) is already present
891
+ // in the proof via 'add_core'.
892
+ // We just copy it as an irredundant clause, call weaken minus
893
+ // and push it on the extension stack.
894
+ //
895
+ int64_t Internal::add_sweep_binary (sweep_proof_clause pc, int lit,
896
+ int other) {
897
+ assert (!unsat);
898
+ if (unsat)
899
+ return 0; // sanity check, should be fuzzed
900
+
901
+ assert (!val (lit) && !val (other));
902
+ if (val (lit) || val (other))
903
+ return 0;
904
+
905
+ if (lrat) {
906
+ for (const auto &plit : pc.literals) {
907
+ if (val (plit)) {
908
+ int64_t id = unit_id (-plit);
909
+ lrat_chain.push_back (id);
910
+ }
911
+ }
912
+ lrat_chain.push_back (pc.cad_id);
913
+ }
914
+ clause.push_back (lit);
915
+ clause.push_back (other);
916
+ const int64_t id = ++clause_id;
917
+ if (proof) {
918
+ proof->add_derived_clause (id, false, clause, lrat_chain);
919
+ proof->weaken_minus (id, clause);
920
+ }
921
+ external->push_binary_clause_on_extension_stack (id, lit, other);
922
+ for (auto &tracer : tracers) {
923
+ if (externalize (lit) < 0)
924
+ break;
925
+ const int elit = externalize (lit);
926
+ const int eother = externalize (other);
927
+ tracer->notify_equivalence (elit, -eother);
928
+ }
929
+ clause.clear ();
930
+ lrat_chain.clear ();
931
+ return id;
932
+ }
933
+
934
+ void Internal::delete_sweep_binary (const sweep_binary &sb) {
935
+ if (unsat)
936
+ return;
937
+ if (!proof)
938
+ return;
939
+ vector<int> bin;
940
+ bin.push_back (sb.lit);
941
+ bin.push_back (sb.other);
942
+ proof->delete_clause (sb.id, false, bin);
943
+ }
944
+
945
+ bool Internal::scheduled_variable (Sweeper &sweeper, int idx) {
946
+ return sweeper.prev[idx] != 0 || sweeper.first == idx;
947
+ }
948
+
949
+ void Internal::schedule_inner (Sweeper &sweeper, int idx) {
950
+ assert (idx);
951
+ if (!active (idx))
952
+ return;
953
+ const int next = sweeper.next[idx];
954
+ if (next != 0) {
955
+ LOG ("rescheduling inner %d as last", idx);
956
+ const unsigned prev = sweeper.prev[idx];
957
+ assert (sweeper.prev[next] == idx);
958
+ sweeper.prev[next] = prev;
959
+ if (prev == 0) {
960
+ assert (sweeper.first == idx);
961
+ sweeper.first = next;
962
+ } else {
963
+ assert (sweeper.next[prev] == idx);
964
+ sweeper.next[prev] = next;
965
+ }
966
+ const unsigned last = sweeper.last;
967
+ if (last == 0) {
968
+ assert (sweeper.first == 0);
969
+ sweeper.first = idx;
970
+ } else {
971
+ assert (sweeper.next[last] == 0);
972
+ sweeper.next[last] = idx;
973
+ }
974
+ sweeper.prev[idx] = last;
975
+ sweeper.next[idx] = 0;
976
+ sweeper.last = idx;
977
+ } else if (sweeper.last != idx) {
978
+ LOG ("scheduling inner %d as last", idx);
979
+ const unsigned last = sweeper.last;
980
+ if (last == 0) {
981
+ assert (sweeper.first == 0);
982
+ sweeper.first = idx;
983
+ } else {
984
+ assert (sweeper.next[last] == 0);
985
+ sweeper.next[last] = idx;
986
+ }
987
+ assert (sweeper.next[idx] == 0);
988
+ sweeper.prev[idx] = last;
989
+ sweeper.last = idx;
990
+ } else
991
+ LOG ("keeping inner %d scheduled as last", idx);
992
+ }
993
+
994
+ void Internal::schedule_outer (Sweeper &sweeper, int idx) {
995
+ assert (!scheduled_variable (sweeper, idx));
996
+ assert (active (idx));
997
+ const int first = sweeper.first;
998
+ if (first == 0) {
999
+ assert (sweeper.last == 0);
1000
+ sweeper.last = idx;
1001
+ } else {
1002
+ assert (sweeper.prev[first] == 0);
1003
+ sweeper.prev[first] = idx;
1004
+ }
1005
+ assert (sweeper.prev[idx] == 0);
1006
+ sweeper.next[idx] = first;
1007
+ sweeper.first = idx;
1008
+ LOG ("scheduling outer %d as first", idx);
1009
+ }
1010
+
1011
+ int Internal::next_scheduled (Sweeper &sweeper) {
1012
+ int res = sweeper.last;
1013
+ if (res == 0) {
1014
+ LOG ("no more scheduled variables left");
1015
+ return 0;
1016
+ }
1017
+ assert (res > 0);
1018
+ LOG ("dequeuing next scheduled %d", res);
1019
+ const unsigned prev = sweeper.prev[res];
1020
+ assert (sweeper.next[res] == 0);
1021
+ sweeper.prev[res] = 0;
1022
+ if (prev == 0) {
1023
+ assert (sweeper.first == res);
1024
+ sweeper.first = 0;
1025
+ } else {
1026
+ assert (sweeper.next[prev] == res);
1027
+ sweeper.next[prev] = 0;
1028
+ }
1029
+ sweeper.last = prev;
1030
+ return res;
1031
+ }
1032
+
1033
+ void Internal::sweep_substitute_lrat (Clause *c, int64_t id) {
1034
+ if (!lrat)
1035
+ return;
1036
+ for (const auto &lit : *c) {
1037
+ assert (val (lit) <= 0);
1038
+ if (val (lit) < 0) {
1039
+ int64_t id = unit_id (-lit);
1040
+ lrat_chain.push_back (id);
1041
+ }
1042
+ }
1043
+ lrat_chain.push_back (id);
1044
+ lrat_chain.push_back (c->id);
1045
+ }
1046
+
1047
+ #define all_scheduled(IDX) \
1048
+ int IDX = sweeper.first, NEXT_##IDX; \
1049
+ IDX != 0 && (NEXT_##IDX = sweeper.next[IDX], true); \
1050
+ IDX = NEXT_##IDX
1051
+
1052
+ // Substitute equivalences in clauses (see
1053
+ // 'sweep_substitute_new_equivalences' for explanation)
1054
+ void Internal::substitute_connected_clauses (Sweeper &sweeper, int lit,
1055
+ int repr, int64_t id) {
1056
+ if (unsat)
1057
+ return;
1058
+ if (val (lit))
1059
+ return;
1060
+ if (val (repr))
1061
+ return;
1062
+ LOG ("substituting %d with %d in all irredundant clauses", lit, repr);
1063
+
1064
+ assert (lit != repr);
1065
+ assert (lit != -repr);
1066
+
1067
+ assert (active (lit));
1068
+ assert (active (repr));
1069
+
1070
+ uint64_t &ticks = sweeper.current_ticks;
1071
+
1072
+ {
1073
+ ticks += 1 + cache_lines (occs (lit).size (), sizeof (Clause *));
1074
+ Occs &ns = occs (lit);
1075
+ auto const begin = ns.begin ();
1076
+ const auto end = ns.end ();
1077
+ auto q = begin;
1078
+ auto p = q;
1079
+ while (p != end) {
1080
+ Clause *c = *q++ = *p++;
1081
+ ticks++;
1082
+ if (c->garbage)
1083
+ continue;
1084
+ assert (clause.empty ());
1085
+ bool satisfied = false;
1086
+ bool repr_already_watched = false;
1087
+ const int not_repr = -repr;
1088
+ #ifndef NDEBUG
1089
+ bool found = false;
1090
+ #endif
1091
+ for (const auto &other : *c) {
1092
+ if (other == lit) {
1093
+ #ifndef NDEBUG
1094
+ assert (!found);
1095
+ found = true;
1096
+ #endif
1097
+ clause.push_back (repr);
1098
+ continue;
1099
+ }
1100
+ assert (other != -lit);
1101
+ if (other == repr) {
1102
+ assert (!repr_already_watched);
1103
+ repr_already_watched = true;
1104
+ continue;
1105
+ }
1106
+ if (other == not_repr) {
1107
+ satisfied = true;
1108
+ break;
1109
+ }
1110
+ const signed char tmp = val (other);
1111
+ if (tmp < 0)
1112
+ continue;
1113
+ if (tmp > 0) {
1114
+ satisfied = true;
1115
+ break;
1116
+ }
1117
+ clause.push_back (other);
1118
+ }
1119
+ if (satisfied) {
1120
+ clause.clear ();
1121
+ mark_garbage (c);
1122
+ sweep_update_noccs (c);
1123
+ continue;
1124
+ }
1125
+ assert (found);
1126
+ const unsigned new_size = clause.size ();
1127
+ sweep_substitute_lrat (c, id);
1128
+ if (new_size == 0) {
1129
+ LOG (c, "substituted empty clause");
1130
+ assert (!unsat);
1131
+ learn_empty_clause ();
1132
+ break;
1133
+ }
1134
+ ticks++;
1135
+ if (new_size == 1) {
1136
+ LOG (c, "reduces to unit");
1137
+ const int unit = clause[0];
1138
+ clause.clear ();
1139
+ assign_unit (unit);
1140
+ sweeper.propagate.push_back (unit);
1141
+ mark_garbage (c);
1142
+ sweep_update_noccs (c);
1143
+ stats.sweep_units++;
1144
+ break;
1145
+ }
1146
+ assert (c->size >= 2);
1147
+ if (!c->redundant)
1148
+ mark_removed (c);
1149
+ uint64_t new_id = ++clause_id;
1150
+ if (proof) {
1151
+ proof->add_derived_clause (new_id, c->redundant, clause,
1152
+ lrat_chain);
1153
+ proof->delete_clause (c);
1154
+ }
1155
+ c->id = new_id;
1156
+ lrat_chain.clear ();
1157
+ size_t l;
1158
+ int *literals = c->literals;
1159
+ for (l = 0; l < clause.size (); l++)
1160
+ literals[l] = clause[l];
1161
+ int flushed = c->size - (int) l;
1162
+ if (flushed) {
1163
+ LOG ("flushed %d literals", flushed);
1164
+ (void) shrink_clause (c, l);
1165
+ } else if (likely_to_be_kept_clause (c))
1166
+ mark_added (c);
1167
+ LOG (c, "substituted");
1168
+ if (!repr_already_watched) {
1169
+ occs (repr).push_back (c);
1170
+ noccs (repr)++;
1171
+ }
1172
+ clause.clear ();
1173
+ q--;
1174
+ }
1175
+ while (p != end)
1176
+ *q++ = *p++;
1177
+ ns.resize (q - ns.begin ());
1178
+ }
1179
+ }
1180
+
1181
+ // In contrast to kissat we substitute the equivalences explicitely after
1182
+ // every successful round of sweeping. This is necessary in order to extract
1183
+ // valid LRAT proofs for subsequent rounds of sweeping.
1184
+ void Internal::sweep_substitute_new_equivalences (Sweeper &sweeper) {
1185
+ if (unsat)
1186
+ return;
1187
+
1188
+ unsigned count = 0;
1189
+ assert (lrat_chain.empty ());
1190
+
1191
+ for (const auto &sb : sweeper.binaries) {
1192
+ count++;
1193
+ const auto lit = sb.lit;
1194
+ const auto other = sb.other;
1195
+ if (abs (lit) < abs (other)) {
1196
+ substitute_connected_clauses (sweeper, -other, lit, sb.id);
1197
+ } else {
1198
+ substitute_connected_clauses (sweeper, -lit, other, sb.id);
1199
+ }
1200
+ assert (lrat_chain.empty ());
1201
+ if (val (lit) < 0) {
1202
+ if (lrat) {
1203
+ const int64_t lid = unit_id (-lit);
1204
+ lrat_chain.push_back (lid);
1205
+ }
1206
+ if (!val (other)) {
1207
+ if (lrat)
1208
+ lrat_chain.push_back (sb.id);
1209
+ assign_unit (other);
1210
+ } else if (val (other) < 0) {
1211
+ if (lrat) {
1212
+ const int64_t oid = unit_id (-other);
1213
+ lrat_chain.push_back (oid);
1214
+ lrat_chain.push_back (sb.id);
1215
+ }
1216
+ learn_empty_clause ();
1217
+ return;
1218
+ }
1219
+ } else if (val (other) < 0) {
1220
+ if (!val (lit)) {
1221
+ if (lrat) {
1222
+ const int64_t oid = unit_id (-other);
1223
+ lrat_chain.push_back (oid);
1224
+ lrat_chain.push_back (sb.id);
1225
+ }
1226
+ assign_unit (lit);
1227
+ } else
1228
+ assert (val (lit) > 0);
1229
+ }
1230
+ lrat_chain.clear ();
1231
+ delete_sweep_binary (sb);
1232
+ if (count == 2) {
1233
+ if (!val (lit) && !val (other)) {
1234
+ const auto idx = abs (lit) < abs (other) ? abs (other) : abs (lit);
1235
+ if (!flags (idx).fixed ())
1236
+ mark_substituted (idx);
1237
+ }
1238
+ count = 0;
1239
+ }
1240
+ assert (lrat_chain.empty ());
1241
+ }
1242
+ sweeper.binaries.clear ();
1243
+ }
1244
+
1245
+ void Internal::sweep_remove (Sweeper &sweeper, int lit) {
1246
+ assert (sweeper.reprs[lit] != lit);
1247
+ vector<int> &partition = sweeper.partition;
1248
+ const auto begin_partition = partition.begin ();
1249
+ auto p = begin_partition;
1250
+ const auto end_partition = partition.end ();
1251
+ for (; *p != lit; p++)
1252
+ assert (p + 1 != end_partition);
1253
+ auto begin_class = p;
1254
+ while (begin_class != begin_partition && begin_class[-1] != 0)
1255
+ begin_class--;
1256
+ auto end_class = p;
1257
+ while (*end_class != 0)
1258
+ end_class++;
1259
+ const unsigned size = end_class - begin_class;
1260
+ LOG ("removing non-representative %d from equivalence class of size %u",
1261
+ lit, size);
1262
+ assert (size > 1);
1263
+ auto q = begin_class;
1264
+ if (size == 2) {
1265
+ LOG ("completely squashing equivalence class of %d", lit);
1266
+ for (auto r = end_class + 1; r != end_partition; r++)
1267
+ *q++ = *r;
1268
+ } else {
1269
+ for (auto r = begin_class; r != end_partition; r++)
1270
+ if (r != p)
1271
+ *q++ = *r;
1272
+ }
1273
+ partition.resize (q - partition.begin ());
1274
+ }
1275
+
1276
+ void Internal::flip_partition_literals (Sweeper &sweeper) {
1277
+ const unsigned max_rounds = opts.sweepfliprounds;
1278
+ if (!max_rounds)
1279
+ return;
1280
+ assert (sweeper.partition.size ());
1281
+ if (kitten_status (citten) != 10)
1282
+ return;
1283
+ #ifdef LOGGING
1284
+ unsigned total_flipped = 0;
1285
+ #endif
1286
+ unsigned flipped, round = 0;
1287
+ do {
1288
+ round++;
1289
+ flipped = 0;
1290
+ bool refine = false;
1291
+ bool limit_hit = false;
1292
+ auto begin = sweeper.partition.begin (), dst = begin, src = dst;
1293
+ const auto end = sweeper.partition.end ();
1294
+ while (src != end) {
1295
+ auto end_src = src;
1296
+ while (assert (end_src != end), *end_src != 0)
1297
+ end_src++;
1298
+ unsigned size = end_src - src;
1299
+ assert (size > 1);
1300
+ auto q = dst;
1301
+ for (auto p = src; p != end_src; p++) {
1302
+ const int lit = *p;
1303
+ if (limit_hit) {
1304
+ *q++ = lit;
1305
+ continue;
1306
+ } else if (kitten_ticks_limit_hit (sweeper, "partition flipping")) {
1307
+ *q++ = lit;
1308
+ limit_hit = true;
1309
+ continue;
1310
+ } else if (sweep_flip (lit)) {
1311
+ LOG ("flipping equivalence candidate %d succeeded", lit);
1312
+ #ifdef LOGGING
1313
+ total_flipped++;
1314
+ #endif
1315
+ flipped++;
1316
+ if (--size < 2)
1317
+ break;
1318
+ } else {
1319
+ LOG ("flipping equivalence candidate %d failed", lit);
1320
+ *q++ = lit;
1321
+ }
1322
+ stats.sweep_flip_equivalences++;
1323
+ }
1324
+ if (size > 1) {
1325
+ *q++ = 0;
1326
+ dst = q;
1327
+ }
1328
+ src = end_src + 1;
1329
+ }
1330
+ stats.sweep_flipped_equivalences += flipped;
1331
+ sweeper.partition.resize (dst - sweeper.partition.begin ());
1332
+ LOG ("flipped %u equivalence candidates in round %u", flipped, round);
1333
+ if (terminated_asynchronously ())
1334
+ break;
1335
+ if (kitten_ticks_limit_hit (sweeper, "partition flipping"))
1336
+ break;
1337
+ if (refine)
1338
+ sweep_refine (sweeper);
1339
+ } while (flipped && round < max_rounds);
1340
+ LOG ("flipped %u equivalence candidates in total in %u rounds",
1341
+ total_flipped, round);
1342
+ }
1343
+
1344
+ bool Internal::sweep_equivalence_candidates (Sweeper &sweeper, int lit,
1345
+ int other) {
1346
+ LOG ("trying equivalence candidates %d = %d", lit, other);
1347
+ const auto begin = sweeper.partition.begin ();
1348
+ auto const end = sweeper.partition.end ();
1349
+ assert (begin + 3 <= end);
1350
+ assert (end[-3] == lit);
1351
+ assert (end[-2] == other);
1352
+ const int third = (end - begin == 3) ? 0 : end[-4];
1353
+ int res = kitten_status (citten);
1354
+ if (res == 10) {
1355
+ stats.sweep_flip_equivalences++;
1356
+ if (sweep_flip (lit)) {
1357
+ stats.sweep_flipped_equivalences++;
1358
+ LOG ("flipping %d succeeded", lit);
1359
+ if (third == 0) {
1360
+ LOG ("squashing equivalence class of %d", lit);
1361
+ sweeper.partition.resize (sweeper.partition.size () - 3);
1362
+ } else {
1363
+ LOG ("removing %d from equivalence class of %d", lit, other);
1364
+ end[-3] = other;
1365
+ end[-2] = 0;
1366
+ sweeper.partition.resize (sweeper.partition.size () - 1);
1367
+ }
1368
+ return false;
1369
+ }
1370
+ stats.sweep_flip_equivalences++;
1371
+ if (sweep_flip (other)) {
1372
+ stats.sweep_flipped_equivalences++;
1373
+ LOG ("flipping %d succeeded", other);
1374
+ if (third == 0) {
1375
+ LOG ("squashing equivalence class of %d", lit);
1376
+ sweeper.partition.resize (sweeper.partition.size () - 3);
1377
+ } else {
1378
+ LOG ("removing %d from equivalence class of %d", other, lit);
1379
+ end[-2] = 0;
1380
+ sweeper.partition.resize (sweeper.partition.size () - 1);
1381
+ }
1382
+ return false;
1383
+ }
1384
+ }
1385
+ // frozen variables are not allowed to be eliminated.
1386
+ // It might still be beneficial to learn the binaries, if they
1387
+ // really are equivalent, but we avoid the issue by not trying
1388
+ // for equivalence at all if the non-representative is frozen.
1389
+ // i.e., the higher absolute value
1390
+ if (abs (lit) > abs (other) && frozen (lit)) {
1391
+ if (third == 0) {
1392
+ LOG ("squashing equivalence class of %d", lit);
1393
+ sweeper.partition.resize (sweeper.partition.size () - 3);
1394
+ } else {
1395
+ LOG ("removing %d from equivalence class of %d", lit, other);
1396
+ end[-3] = other;
1397
+ end[-2] = 0;
1398
+ sweeper.partition.resize (sweeper.partition.size () - 1);
1399
+ }
1400
+ return false;
1401
+ } else if (abs (other) > abs (lit) && frozen (other)) {
1402
+ if (third == 0) {
1403
+ LOG ("squashing equivalence class of %d", lit);
1404
+ sweeper.partition.resize (sweeper.partition.size () - 3);
1405
+ } else {
1406
+ LOG ("removing %d from equivalence class of %d", lit, other);
1407
+ end[-2] = 0;
1408
+ sweeper.partition.resize (sweeper.partition.size () - 1);
1409
+ }
1410
+ return false;
1411
+ }
1412
+
1413
+ const int not_other = -other;
1414
+ const int not_lit = -lit;
1415
+ LOG ("flipping %d and %d both failed", lit, other);
1416
+ kitten_assume_signed (citten, not_lit);
1417
+ kitten_assume_signed (citten, other);
1418
+ stats.sweep_solved_equivalences++;
1419
+ res = sweep_solve ();
1420
+ if (res == 10) {
1421
+ stats.sweep_sat_equivalences++;
1422
+ LOG ("first sweeping implication %d -> %d failed", other, lit);
1423
+ sweep_refine (sweeper);
1424
+ } else if (!res) {
1425
+ stats.sweep_unknown_equivalences++;
1426
+ LOG ("first sweeping implication %d -> %d hit ticks limit", other, lit);
1427
+ }
1428
+
1429
+ if (res != 20)
1430
+ return false;
1431
+
1432
+ stats.sweep_unsat_equivalences++;
1433
+ LOG ("first sweeping implication %d -> %d succeeded", other, lit);
1434
+
1435
+ save_core (sweeper, 0);
1436
+
1437
+ kitten_assume_signed (citten, lit);
1438
+ kitten_assume_signed (citten, not_other);
1439
+ res = sweep_solve ();
1440
+ stats.sweep_solved_equivalences++;
1441
+ if (res == 10) {
1442
+ stats.sweep_sat_equivalences++;
1443
+ LOG ("second sweeping implication %d <- %d failed", other, lit);
1444
+ sweep_refine (sweeper);
1445
+ } else if (!res) {
1446
+ stats.sweep_unknown_equivalences++;
1447
+ LOG ("second sweeping implication %d <- %d hit ticks limit", other,
1448
+ lit);
1449
+ }
1450
+
1451
+ if (res != 20) {
1452
+ sweeper.core[0].clear ();
1453
+ return false;
1454
+ }
1455
+
1456
+ assert (res == 20);
1457
+
1458
+ stats.sweep_unsat_equivalences++;
1459
+ LOG ("second sweeping implication %d <- %d succeeded too", other, lit);
1460
+
1461
+ save_core (sweeper, 1);
1462
+
1463
+ LOG ("sweep equivalence %d = %d", lit, other);
1464
+
1465
+ // If kitten behaves as expected, the two binaries of the equivalence
1466
+ // should be stored at sweeper.core[i].back () for i in {0, 1}.
1467
+ // We pick the smaller absolute valued literal as representative and
1468
+ // store the equivalence .
1469
+ add_core (sweeper, 0);
1470
+ add_core (sweeper, 1);
1471
+ if (!val (lit) && !val (other)) {
1472
+ assert (sweeper.core[0].size ());
1473
+ assert (sweeper.core[1].size ());
1474
+ stats.sweep_equivalences++;
1475
+ sweep_binary bin1;
1476
+ sweep_binary bin2;
1477
+ if (abs (lit) > abs (other)) {
1478
+ bin1.lit = lit;
1479
+ bin1.other = not_other;
1480
+ bin2.lit = not_lit;
1481
+ bin2.other = other;
1482
+ bin1.id = add_sweep_binary (sweeper.core[0].back (), lit, not_other);
1483
+ bin2.id = add_sweep_binary (sweeper.core[1].back (), not_lit, other);
1484
+ } else {
1485
+ bin1.lit = not_other;
1486
+ bin1.other = lit;
1487
+ bin2.lit = other;
1488
+ bin2.other = not_lit;
1489
+ bin1.id = add_sweep_binary (sweeper.core[0].back (), not_other, lit);
1490
+ bin2.id = add_sweep_binary (sweeper.core[1].back (), other, not_lit);
1491
+ }
1492
+ if (bin1.id && bin2.id) {
1493
+ sweeper.binaries.push_back (bin1);
1494
+ sweeper.binaries.push_back (bin2);
1495
+ }
1496
+ }
1497
+
1498
+ int repr;
1499
+ if (abs (lit) < abs (other)) {
1500
+ repr = sweeper.reprs[other] = lit;
1501
+ sweeper.reprs[not_other] = not_lit;
1502
+ sweep_remove (sweeper, other);
1503
+ } else {
1504
+ repr = sweeper.reprs[lit] = other;
1505
+ sweeper.reprs[not_lit] = not_other;
1506
+ sweep_remove (sweeper, lit);
1507
+ }
1508
+ clear_core (sweeper, 0);
1509
+ clear_core (sweeper, 1);
1510
+
1511
+ const int repr_idx = abs (repr);
1512
+ schedule_inner (sweeper, repr_idx);
1513
+
1514
+ return true;
1515
+ }
1516
+
1517
+ const char *Internal::sweep_variable (Sweeper &sweeper, int idx) {
1518
+ assert (!unsat);
1519
+ if (!active (idx))
1520
+ return "inactive variable";
1521
+ const int start = idx;
1522
+ if (sweeper.reprs[start] != start)
1523
+ return "non-representative variable";
1524
+ assert (sweeper.vars.empty ());
1525
+ assert (sweeper.clauses.empty ());
1526
+ assert (sweeper.backbone.empty ());
1527
+ assert (sweeper.partition.empty ());
1528
+ assert (!sweeper.encoded);
1529
+
1530
+ stats.sweep_variables++;
1531
+
1532
+ LOG ("sweeping %d", idx);
1533
+ assert (!val (start));
1534
+ LOG ("starting sweeping[0]");
1535
+ add_literal_to_environment (sweeper, 0, start);
1536
+ LOG ("finished sweeping[0]");
1537
+ LOG ("starting sweeping[1]");
1538
+
1539
+ bool limit_reached = false;
1540
+ size_t expand = 0, next = 1;
1541
+ bool success = false;
1542
+ unsigned depth = 1;
1543
+
1544
+ uint64_t &ticks = sweeper.current_ticks;
1545
+ while (!limit_reached) {
1546
+ if (sweeper.encoded >= sweeper.limit.clauses) {
1547
+ LOG ("environment clause limit reached");
1548
+ limit_reached = true;
1549
+ break;
1550
+ }
1551
+ if (expand == next) {
1552
+ LOG ("finished sweeping[%u]", depth);
1553
+ if (depth >= sweeper.limit.depth) {
1554
+ LOG ("environment depth limit reached");
1555
+ break;
1556
+ }
1557
+ next = sweeper.vars.size ();
1558
+ if (expand == next) {
1559
+ LOG ("completely copied all clauses");
1560
+ break;
1561
+ }
1562
+ depth++;
1563
+ LOG ("starting sweeping[%u]", depth);
1564
+ }
1565
+ const unsigned choices = next - expand;
1566
+ if (opts.sweeprand && choices > 1) {
1567
+ const unsigned swaps = sweeper.random.pick_int (0, choices - 1);
1568
+ if (swaps) {
1569
+ assert (expand + swaps < sweeper.vars.size ());
1570
+ swap (sweeper.vars[expand], sweeper.vars[expand + swaps]);
1571
+ }
1572
+ }
1573
+ const int idx = sweeper.vars[expand];
1574
+ LOG ("traversing and adding clauses of %d", idx);
1575
+ for (unsigned sign = 0; sign < 2; sign++) {
1576
+ const int lit = sign ? -idx : idx;
1577
+ ticks += 1 + cache_lines (occs (lit).size (), sizeof (Clause *));
1578
+ Occs &ns = occs (lit);
1579
+ for (auto c : ns) {
1580
+ ticks++;
1581
+ if (!can_sweep_clause (c))
1582
+ continue;
1583
+ sweep_clause (sweeper, depth, c);
1584
+ if (sweeper.vars.size () >= sweeper.limit.vars) {
1585
+ LOG ("environment variable limit reached");
1586
+ limit_reached = true;
1587
+ break;
1588
+ }
1589
+ }
1590
+ if (limit_reached)
1591
+ break;
1592
+ }
1593
+ expand++;
1594
+ }
1595
+ stats.sweep_depth += depth;
1596
+ stats.sweep_clauses += sweeper.encoded;
1597
+ stats.sweep_environment += sweeper.vars.size ();
1598
+ VERBOSE (3,
1599
+ "sweeping variable %d environment of "
1600
+ "%zu variables %u clauses depth %u",
1601
+ externalize (idx), sweeper.vars.size (), sweeper.encoded, depth);
1602
+
1603
+ int res;
1604
+ if (sweeper.vars.size () == 1) {
1605
+ LOG ("not sweeping literal %d with environment size 1", idx);
1606
+ goto DONE;
1607
+ }
1608
+ res = sweep_solve ();
1609
+ LOG ("sub-solver returns '%d'", res);
1610
+ if (res == 10) {
1611
+ init_backbone_and_partition (sweeper);
1612
+ #ifndef QUIET
1613
+ uint64_t units = stats.sweep_units;
1614
+ uint64_t solved = stats.sweep_solved;
1615
+ #endif
1616
+ START (sweepbackbone);
1617
+ while (sweeper.backbone.size ()) {
1618
+ if (unsat || terminated_asynchronously () ||
1619
+ kitten_ticks_limit_hit (sweeper, "backbone refinement")) {
1620
+ limit_reached = true;
1621
+ STOP_SWEEP_BACKBONE:
1622
+ STOP (sweepbackbone);
1623
+ goto DONE;
1624
+ }
1625
+ flip_backbone_literals (sweeper);
1626
+ if (terminated_asynchronously () ||
1627
+ kitten_ticks_limit_hit (sweeper, "backbone refinement")) {
1628
+ limit_reached = true;
1629
+ goto STOP_SWEEP_BACKBONE;
1630
+ }
1631
+ if (sweeper.backbone.empty ())
1632
+ break;
1633
+ const int lit = sweeper.backbone.back ();
1634
+ sweeper.backbone.pop_back ();
1635
+ if (!active (lit))
1636
+ continue;
1637
+ if (sweep_backbone_candidate (sweeper, lit))
1638
+ success = true;
1639
+ }
1640
+ STOP (sweepbackbone);
1641
+ #ifndef QUIET
1642
+ units = stats.sweep_units - units;
1643
+ solved = stats.sweep_solved - solved;
1644
+ #endif
1645
+ VERBOSE (4,
1646
+ "complete swept variable %d backbone with %" PRIu64
1647
+ " units in %" PRIu64 " solver calls",
1648
+ externalize (idx), units, solved);
1649
+ assert (sweeper.backbone.empty ());
1650
+ #ifndef QUIET
1651
+ uint64_t equivalences = stats.sweep_equivalences;
1652
+ solved = stats.sweep_solved;
1653
+ #endif
1654
+ START (sweepequivalences);
1655
+ while (sweeper.partition.size ()) {
1656
+ if (unsat || terminated_asynchronously () ||
1657
+ kitten_ticks_limit_hit (sweeper, "partition refinement")) {
1658
+ limit_reached = true;
1659
+ STOP_SWEEP_EQUIVALENCES:
1660
+ STOP (sweepequivalences);
1661
+ goto DONE;
1662
+ }
1663
+ flip_partition_literals (sweeper);
1664
+ if (terminated_asynchronously () ||
1665
+ kitten_ticks_limit_hit (sweeper, "backbone refinement")) {
1666
+ limit_reached = true;
1667
+ goto STOP_SWEEP_EQUIVALENCES;
1668
+ }
1669
+ if (sweeper.partition.empty ())
1670
+ break;
1671
+ if (sweeper.partition.size () > 2) {
1672
+ const auto end = sweeper.partition.end ();
1673
+ assert (end[-1] == 0);
1674
+ int lit = end[-3];
1675
+ int other = end[-2];
1676
+ if (sweep_equivalence_candidates (sweeper, lit, other))
1677
+ success = true;
1678
+ } else
1679
+ sweeper.partition.clear ();
1680
+ }
1681
+ STOP (sweepequivalences);
1682
+ #ifndef QUIET
1683
+ equivalences = stats.sweep_equivalences - equivalences;
1684
+ solved = stats.sweep_solved - solved;
1685
+ if (equivalences)
1686
+ VERBOSE (3,
1687
+ "complete swept variable %d partition with %" PRIu64
1688
+ " equivalences in %" PRIu64 " solver calls",
1689
+ externalize (idx), equivalences, solved);
1690
+ #endif
1691
+ } else if (res == 20)
1692
+ sweep_empty_clause (sweeper);
1693
+
1694
+ DONE:
1695
+ clear_sweeper (sweeper);
1696
+
1697
+ if (!unsat)
1698
+ sweep_substitute_new_equivalences (sweeper);
1699
+ if (!unsat)
1700
+ sweep_dense_propagate (sweeper);
1701
+
1702
+ if (success && limit_reached)
1703
+ return "successfully despite reaching limit";
1704
+ if (!success && !limit_reached)
1705
+ return "unsuccessfully without reaching limit";
1706
+ else if (success && !limit_reached)
1707
+ return "successfully without reaching limit";
1708
+ assert (!success && limit_reached);
1709
+ return "unsuccessfully and reached limit";
1710
+ }
1711
+
1712
+ struct sweep_candidate {
1713
+ unsigned rank;
1714
+ int idx;
1715
+ };
1716
+
1717
+ struct rank_sweep_candidate {
1718
+ bool operator() (sweep_candidate a, sweep_candidate b) const {
1719
+ assert (a.rank && b.rank);
1720
+ assert (a.idx > 0 && b.idx > 0);
1721
+ if (a.rank < b.rank)
1722
+ return true;
1723
+ if (b.rank < a.rank)
1724
+ return false;
1725
+ return a.idx < b.idx;
1726
+ }
1727
+ };
1728
+
1729
+ bool Internal::scheduable_variable (Sweeper &sweeper, int idx,
1730
+ size_t *occ_ptr) {
1731
+ const int lit = idx;
1732
+ const size_t pos = noccs (lit);
1733
+ if (!pos)
1734
+ return false;
1735
+ const unsigned max_occurrences = sweeper.limit.clauses;
1736
+ if (pos > max_occurrences)
1737
+ return false;
1738
+ const int not_lit = -lit;
1739
+ const size_t neg = noccs (not_lit);
1740
+ if (!neg)
1741
+ return false;
1742
+ if (neg > max_occurrences)
1743
+ return false;
1744
+ *occ_ptr = pos + neg;
1745
+ return true;
1746
+ }
1747
+
1748
+ unsigned Internal::schedule_all_other_not_scheduled_yet (Sweeper &sweeper) {
1749
+ vector<sweep_candidate> fresh;
1750
+ for (const auto &idx : vars) {
1751
+ Flags &f = flags (idx);
1752
+ if (!f.active ())
1753
+ continue;
1754
+ if (sweep_incomplete && !f.sweep)
1755
+ continue;
1756
+ if (scheduled_variable (sweeper, idx))
1757
+ continue;
1758
+ size_t occ;
1759
+ if (!scheduable_variable (sweeper, idx, &occ)) {
1760
+ f.sweep = false;
1761
+ continue;
1762
+ }
1763
+ sweep_candidate cand;
1764
+ cand.rank = occ;
1765
+ cand.idx = idx;
1766
+ fresh.push_back (cand);
1767
+ }
1768
+ const size_t size = fresh.size ();
1769
+ assert (size <= UINT_MAX);
1770
+ sort (fresh.begin (), fresh.end (), rank_sweep_candidate ());
1771
+ for (auto &cand : fresh)
1772
+ schedule_outer (sweeper, cand.idx);
1773
+ return size;
1774
+ }
1775
+
1776
+ unsigned Internal::reschedule_previously_remaining (Sweeper &sweeper) {
1777
+ unsigned rescheduled = 0;
1778
+ for (const auto &idx : sweep_schedule) {
1779
+ Flags &f = flags (idx);
1780
+ if (!f.active ())
1781
+ continue;
1782
+ if (scheduled_variable (sweeper, idx))
1783
+ continue;
1784
+ size_t occ;
1785
+ if (!scheduable_variable (sweeper, idx, &occ)) {
1786
+ f.sweep = false;
1787
+ continue;
1788
+ }
1789
+ schedule_inner (sweeper, idx);
1790
+ rescheduled++;
1791
+ }
1792
+ sweep_schedule.clear ();
1793
+ return rescheduled;
1794
+ }
1795
+
1796
+ unsigned Internal::incomplete_variables () {
1797
+ unsigned res = 0;
1798
+ for (const auto &idx : vars) {
1799
+ Flags &f = flags (idx);
1800
+ if (!f.active ())
1801
+ continue;
1802
+ if (f.sweep)
1803
+ res++;
1804
+ }
1805
+ return res;
1806
+ }
1807
+
1808
+ void Internal::mark_incomplete (Sweeper &sweeper) {
1809
+ unsigned marked = 0;
1810
+ for (all_scheduled (idx)) {
1811
+ if (!flags (idx).sweep) {
1812
+ flags (idx).sweep = true;
1813
+ marked++;
1814
+ }
1815
+ }
1816
+ sweep_incomplete = true;
1817
+ #ifndef QUIET
1818
+ VERBOSE (2, "marked %u scheduled sweeping variables as incomplete",
1819
+ marked);
1820
+ #else
1821
+ (void) marked;
1822
+ #endif
1823
+ }
1824
+
1825
+ unsigned Internal::schedule_sweeping (Sweeper &sweeper) {
1826
+ const unsigned rescheduled = reschedule_previously_remaining (sweeper);
1827
+ const unsigned fresh = schedule_all_other_not_scheduled_yet (sweeper);
1828
+ const unsigned scheduled = fresh + rescheduled;
1829
+ const unsigned incomplete = incomplete_variables ();
1830
+ #ifndef QUIET
1831
+ PHASE ("sweep", stats.sweep,
1832
+ "scheduled %u variables %.0f%% "
1833
+ "(%u rescheduled %.0f%%, %u incomplete %.0f%%)",
1834
+ scheduled, percent (scheduled, active ()), rescheduled,
1835
+ percent (rescheduled, scheduled), incomplete,
1836
+ percent (incomplete, scheduled));
1837
+ #endif
1838
+ if (incomplete)
1839
+ assert (sweep_incomplete);
1840
+ else {
1841
+ if (sweep_incomplete)
1842
+ stats.sweep_completed++;
1843
+ mark_incomplete (sweeper);
1844
+ }
1845
+ return scheduled;
1846
+ }
1847
+
1848
+ void Internal::unschedule_sweeping (Sweeper &sweeper, unsigned swept,
1849
+ unsigned scheduled) {
1850
+ #ifdef QUIET
1851
+ (void) scheduled, (void) swept;
1852
+ #endif
1853
+ assert (sweep_schedule.empty ());
1854
+ assert (sweep_incomplete);
1855
+ for (all_scheduled (idx))
1856
+ if (active (idx)) {
1857
+ sweep_schedule.push_back (idx);
1858
+ LOG ("untried scheduled %d", idx);
1859
+ }
1860
+ #ifndef QUIET
1861
+ const unsigned retained = sweep_schedule.size ();
1862
+ #endif
1863
+ VERBOSE (3, "retained %u variables %.0f%% to be swept next time",
1864
+ retained, percent (retained, active ()));
1865
+ const unsigned incomplete = incomplete_variables ();
1866
+ if (incomplete)
1867
+ VERBOSE (3, "need to sweep %u more variables %.0f%% for completion",
1868
+ incomplete, percent (incomplete, active ()));
1869
+ else {
1870
+ VERBOSE (3, "no more variables needed to complete sweep");
1871
+ sweep_incomplete = false;
1872
+ stats.sweep_completed++;
1873
+ }
1874
+ PHASE ("sweep", stats.sweep, "swept %u variables (%u remain %.0f%%)",
1875
+ swept, incomplete, percent (incomplete, scheduled));
1876
+ }
1877
+
1878
+ bool Internal::sweep () {
1879
+ if (!opts.sweep)
1880
+ return false;
1881
+ if (unsat)
1882
+ return false;
1883
+ if (terminated_asynchronously ())
1884
+ return false;
1885
+ if (delaying_sweep.bumpreasons.delay ()) { // TODO need to fix Delay
1886
+ last.sweep.ticks = stats.ticks.search[0] + stats.ticks.search[1];
1887
+ return false;
1888
+ }
1889
+ delaying_sweep.bumpreasons.bypass_delay ();
1890
+ SET_EFFORT_LIMIT (tickslimit, sweep, !opts.sweepcomplete);
1891
+ delaying_sweep.bumpreasons.unbypass_delay ();
1892
+
1893
+ assert (!level);
1894
+ START_SIMPLIFIER (sweep, SWEEP);
1895
+ stats.sweep++;
1896
+ uint64_t equivalences = stats.sweep_equivalences;
1897
+ uint64_t units = stats.sweep_units;
1898
+ Sweeper sweeper = Sweeper (this);
1899
+ if (opts.sweepcomplete)
1900
+ sweeper.limit.ticks = INT64_MAX;
1901
+ else
1902
+ sweeper.limit.ticks = tickslimit - stats.ticks.sweep;
1903
+ sweep_set_kitten_ticks_limit (sweeper);
1904
+ const unsigned scheduled = schedule_sweeping (sweeper);
1905
+ uint64_t swept = 0, limit = 10;
1906
+ for (;;) {
1907
+ if (unsat)
1908
+ break;
1909
+ if (terminated_asynchronously ())
1910
+ break;
1911
+ if (kitten_ticks_limit_hit (sweeper, "sweeping loop"))
1912
+ break;
1913
+ int idx = next_scheduled (sweeper);
1914
+ if (idx == 0)
1915
+ break;
1916
+ flags (idx).sweep = false;
1917
+ #ifndef QUIET
1918
+ const char *res =
1919
+ #endif
1920
+ sweep_variable (sweeper, idx);
1921
+ VERBOSE (3, "swept[%" PRIu64 "] external variable %d %s", swept,
1922
+ externalize (idx), res);
1923
+ if (++swept == limit) {
1924
+ VERBOSE (2,
1925
+ "found %" PRIu64 " equivalences and %" PRIu64
1926
+ " units after sweeping %" PRIu64 " variables ",
1927
+ stats.sweep_equivalences - equivalences,
1928
+ stats.sweep_units - units, swept);
1929
+ limit *= 10;
1930
+ }
1931
+ }
1932
+ VERBOSE (2, "swept %" PRIu64 " variables", swept);
1933
+ equivalences = stats.sweep_equivalences - equivalences,
1934
+ units = stats.sweep_units - units;
1935
+ PHASE ("sweep", stats.sweep,
1936
+ "found %" PRIu64 " equivalences and %" PRIu64 " units",
1937
+ equivalences, units);
1938
+ unschedule_sweeping (sweeper, swept, scheduled);
1939
+ release_sweeper (sweeper);
1940
+
1941
+ if (!unsat) {
1942
+ propagated = 0;
1943
+ if (!propagate ()) {
1944
+ learn_empty_clause ();
1945
+ }
1946
+ }
1947
+
1948
+ uint64_t eliminated = equivalences + units;
1949
+ report ('=', !eliminated);
1950
+
1951
+ if (relative (eliminated, swept) < 0.001) {
1952
+ delaying_sweep.bumpreasons.bump_delay ();
1953
+ } else {
1954
+ delaying_sweep.bumpreasons.reduce_delay ();
1955
+ }
1956
+ STOP_SIMPLIFIER (sweep, SWEEP);
1957
+ return eliminated;
1958
+ }
1959
+
1960
+ } // namespace CaDiCaL