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,1088 @@
1
+ #include "walk.hpp"
2
+ #include "internal.hpp"
3
+ #include "random.hpp"
4
+
5
+ namespace CaDiCaL {
6
+
7
+ /*------------------------------------------------------------------------*/
8
+
9
+ // Random walk local search based on 'ProbSAT' ideas.
10
+
11
+ // We (based on the Master project from Leah Hohl) tried to ticks
12
+ // local search similarly to the other parts of the solver with
13
+ // limited success however.
14
+ //
15
+ // On the problem `ncc_none_5047_6_3_3_3_0_435991723', the broken part
16
+ // of walk_flip is very cheap and should not be counted in ticks, but
17
+ // on various other problems `9pipe_k' it is very important to ticks
18
+ // this part too.
19
+
20
+ // using ClauseOrBinary = std::variant <Clause*, TaggedBinary>;
21
+
22
+ struct Walker {
23
+
24
+ Internal *internal;
25
+
26
+ // for efficiency, storing the model each time an improvement is
27
+ // found is too costly. Instead we store some of the flips since
28
+ // last time and the position of the best model found so far.
29
+ Random random; // local random number generator
30
+ int64_t ticks; // ticks to approximate run time
31
+ int64_t limit; // limit on number of propagations
32
+ vector<ClauseOrBinary> broken; // currently unsatisfied clauses
33
+ double epsilon; // smallest considered score
34
+ vector<double> table; // break value to score table
35
+ vector<double> scores; // scores of candidate literals
36
+ std::vector<int>
37
+ flips; // remember the flips compared to the last best saved model
38
+ int best_trail_pos;
39
+ int64_t minimum = INT64_MAX;
40
+ std::vector<signed char> best_values; // best model stored so far
41
+ double score (unsigned); // compute score from break count
42
+ #ifndef NDEBUG
43
+ std::vector<signed char> current_best_model; // best model found so far
44
+ #endif
45
+ Walker (Internal *, int64_t limit);
46
+ void populate_table (double size);
47
+ void push_flipped (int flipped);
48
+ void save_walker_trail (bool);
49
+ void save_final_minimum (int64_t old_minimum);
50
+ };
51
+
52
+ // These are in essence the CB values from Adrian Balint's thesis. They
53
+ // denote the inverse 'cb' of the base 'b' of the (probability) weight
54
+ // 'b^-i' for picking a literal with the break value 'i' (first column is
55
+ // the 'size', second the 'CB' value).
56
+
57
+ static double cbvals[][2] = {
58
+ {0.0, 2.00}, {3.0, 2.50}, {4.0, 2.85}, {5.0, 3.70},
59
+ {6.0, 5.10}, {7.0, 7.40}, // Adrian has '5.4', but '7.4' looks better.
60
+ };
61
+
62
+ static const int ncbvals = sizeof cbvals / sizeof cbvals[0];
63
+
64
+ // We interpolate the CB values for uniform random SAT formula to the non
65
+ // integer situation of average clause size by piecewise linear functions.
66
+ //
67
+ // y2 - y1
68
+ // ------- * (x - x1) + y1
69
+ // x2 - x1
70
+ //
71
+ // where 'x' is the average size of clauses and 'y' the CB value.
72
+
73
+ inline static double fitcbval (double size) {
74
+ int i = 0;
75
+ while (i + 2 < ncbvals &&
76
+ (cbvals[i][0] > size || cbvals[i + 1][0] < size))
77
+ i++;
78
+ const double x2 = cbvals[i + 1][0], x1 = cbvals[i][0];
79
+ const double y2 = cbvals[i + 1][1], y1 = cbvals[i][1];
80
+ const double dx = x2 - x1, dy = y2 - y1;
81
+ assert (dx);
82
+ const double res = dy * (size - x1) / dx + y1;
83
+ assert (res > 0);
84
+ return res;
85
+ }
86
+
87
+ // Initialize the data structures for one local search round.
88
+
89
+ Walker::Walker (Internal *i, int64_t l)
90
+ : internal (i), random (internal->opts.seed), // global random seed
91
+ ticks (0), limit (l), best_trail_pos (-1) {
92
+ random += internal->stats.walk.count; // different seed every time
93
+ flips.reserve (i->max_var / 4);
94
+ best_values.resize (i->max_var + 1, 0);
95
+ #ifndef NDEBUG
96
+ current_best_model.resize (i->max_var + 1, 0);
97
+ #endif
98
+ }
99
+
100
+ void Walker::populate_table (double size) {
101
+ // This is the magic constant in ProbSAT (also called 'CB'), which we pick
102
+ // according to the average size every second invocation and otherwise
103
+ // just the default '2.0', which turns into the base '0.5'.
104
+ //
105
+ const bool use_size_based_cb = (internal->stats.walk.count & 1);
106
+ const double cb = use_size_based_cb ? fitcbval (size) : 2.0;
107
+ assert (cb);
108
+ const double base = 1 / cb; // scores are 'base^0,base^1,base^2,...
109
+
110
+ double next = 1;
111
+ for (epsilon = next; next; next = epsilon * base)
112
+ table.push_back (epsilon = next);
113
+
114
+ PHASE ("walk", internal->stats.walk.count,
115
+ "CB %.2f with inverse %.2f as base and table size %zd", cb, base,
116
+ table.size ());
117
+ }
118
+
119
+ // Add the literal to flip to the queue
120
+
121
+ void Walker::push_flipped (int flipped) {
122
+ LOG ("push literal %s on the flips", LOGLIT (flipped));
123
+ assert (flipped);
124
+ if (best_trail_pos < 0) {
125
+ LOG ("not pushing flipped %s to already invalid trail",
126
+ LOGLIT (flipped));
127
+ return;
128
+ }
129
+
130
+ const size_t size_trail = flips.size ();
131
+ const size_t limit = internal->max_var / 4 + 1;
132
+ if (size_trail < limit) {
133
+ flips.push_back (flipped);
134
+ LOG ("pushed flipped %s to trail which now has size %zd",
135
+ LOGLIT (flipped), size_trail + 1);
136
+ return;
137
+ }
138
+
139
+ if (best_trail_pos) {
140
+ LOG ("trail reached limit %zd but has best position %d", limit,
141
+ best_trail_pos);
142
+ save_walker_trail (true);
143
+ flips.push_back (flipped);
144
+ LOG ("pushed flipped %s to trail which now has size %zu",
145
+ LOGLIT (flipped), flips.size ());
146
+ return;
147
+ } else {
148
+ LOG ("trail reached limit %zd without best position", limit);
149
+ flips.clear ();
150
+ LOG ("not pushing %s to invalidated trail", LOGLIT (flipped));
151
+ best_trail_pos = -1;
152
+ LOG ("best trail position becomes invalid");
153
+ }
154
+ }
155
+
156
+ void Walker::save_walker_trail (bool keep) {
157
+ assert (best_trail_pos != -1);
158
+ assert ((size_t) best_trail_pos <= flips.size ());
159
+ // assert (!keep || best_trail_pos == flips.size());
160
+ #ifdef LOGGING
161
+ const size_t size_trail = flips.size ();
162
+ #endif
163
+ const int kept = flips.size () - best_trail_pos;
164
+ LOG ("saving %d values of flipped literals on trail of size %zd",
165
+ best_trail_pos, flips.size ());
166
+
167
+ const auto begin = flips.begin ();
168
+ const auto best = flips.begin () + best_trail_pos;
169
+ const auto end = flips.end ();
170
+
171
+ auto it = begin;
172
+ for (; it != best; ++it) {
173
+ const int lit = *it;
174
+ assert (lit);
175
+ const signed char value = sign (lit);
176
+ const int idx = std::abs (lit);
177
+ best_values[idx] = value;
178
+ }
179
+ if (!keep) {
180
+ LOG ("no need to shift and keep remaining %u literals", kept);
181
+ return;
182
+ }
183
+
184
+ #ifndef NDEBUG
185
+ for (auto v : internal->vars) {
186
+ if (internal->active (v))
187
+ assert (best_values[v] == current_best_model[v]);
188
+ }
189
+ #endif
190
+ LOG ("flushed %u literals %.0f%% from trail", best_trail_pos,
191
+ percent (best_trail_pos, size_trail));
192
+ assert (it == best);
193
+ auto jt = begin;
194
+ for (; it != end; ++it, ++jt) {
195
+ assert (jt <= it);
196
+ assert (it < end);
197
+ *jt = *it;
198
+ }
199
+
200
+ assert ((int) (end - jt) == best_trail_pos);
201
+ assert ((int) (jt - begin) == kept);
202
+ flips.resize (kept);
203
+ LOG ("keeping %u literals %.0f%% on trail", kept,
204
+ percent (kept, size_trail));
205
+ LOG ("reset best trail position to 0");
206
+ best_trail_pos = 0;
207
+ }
208
+
209
+ // finally export the final minimum
210
+ void Walker::save_final_minimum (int64_t old_init_minimum) {
211
+ assert (minimum <= old_init_minimum);
212
+ #ifdef NDEBUG
213
+ (void) old_init_minimum;
214
+ #endif
215
+
216
+ if (!best_trail_pos || best_trail_pos == -1)
217
+ LOG ("minimum already saved");
218
+ else
219
+ save_walker_trail (false);
220
+
221
+ ++internal->stats.walk.improved;
222
+ for (auto v : internal->vars) {
223
+ if (best_values[v])
224
+ internal->phases.saved[v] = best_values[v];
225
+ else
226
+ assert (!internal->active (v));
227
+ }
228
+ internal->copy_phases (internal->phases.prev);
229
+ }
230
+ // The scores are tabulated for faster computation (to avoid 'pow').
231
+
232
+ inline double Walker::score (unsigned i) {
233
+ const double res = (i < table.size () ? table[i] : epsilon);
234
+ LOG ("break %u mapped to score %g", i, res);
235
+ return res;
236
+ }
237
+
238
+ /*------------------------------------------------------------------------*/
239
+
240
+ ClauseOrBinary Internal::walk_pick_clause (Walker &walker) {
241
+ require_mode (WALK);
242
+ assert (!walker.broken.empty ());
243
+ int64_t size = walker.broken.size ();
244
+ if (size > INT_MAX)
245
+ size = INT_MAX;
246
+ int pos = walker.random.pick_int (0, size - 1);
247
+ ClauseOrBinary res = walker.broken[pos];
248
+ #ifdef LOGGING
249
+ Clause *c;
250
+ if (!res.is_binary ())
251
+ c = res.clause ();
252
+ else
253
+ c = res.tagged_binary ().d;
254
+ LOG (c, "picking random position %d", pos);
255
+ #endif
256
+ return res;
257
+ }
258
+
259
+ /*------------------------------------------------------------------------*/
260
+
261
+ // Compute the number of clauses which would be become unsatisfied if 'lit'
262
+ // is flipped and set to false. This is called the 'break-count' of 'lit'.
263
+
264
+ unsigned Internal::walk_break_value (int lit, int64_t &ticks) {
265
+ require_mode (WALK);
266
+ START (walkbreak);
267
+ assert (val (lit) > 0);
268
+ const int64_t oldticks = ticks;
269
+
270
+ unsigned res = 0; // The computed break-count of 'lit'.
271
+ ticks += (1 + cache_lines (watches (lit).size (), sizeof (Clause *)));
272
+
273
+ for (auto &w : watches (lit)) {
274
+ assert (w.blit != lit);
275
+ if (val (w.blit) > 0)
276
+ continue;
277
+ if (w.binary ()) {
278
+ res++;
279
+ continue;
280
+ }
281
+
282
+ Clause *c = w.clause;
283
+ #ifdef LOGGING
284
+ assert (c != dummy_binary);
285
+ #endif
286
+ ++ticks;
287
+
288
+ assert (lit == c->literals[0]);
289
+
290
+ // Now try to find a second satisfied literal starting at 'literals[1]'
291
+ // shifting all the traversed literals to right by one position in order
292
+ // to move such a second satisfying literal to 'literals[1]'. This move
293
+ // to front strategy improves the chances to find the second satisfying
294
+ // literal earlier in subsequent break-count computations.
295
+ //
296
+ auto begin = c->begin () + 1;
297
+ const auto end = c->end ();
298
+ auto i = begin;
299
+ int prev = 0;
300
+ while (i != end) {
301
+ const int other = *i;
302
+ *i++ = prev;
303
+ prev = other;
304
+ if (val (other) < 0)
305
+ continue;
306
+
307
+ // Found 'other' as second satisfying literal.
308
+
309
+ w.blit = other; // Update 'blit'
310
+ *begin = other; // and move to front.
311
+
312
+ break;
313
+ }
314
+
315
+ if (i != end)
316
+ continue; // Double satisfied!
317
+
318
+ // Otherwise restore literals (undo shift to the right).
319
+ //
320
+ while (i != begin) {
321
+ const int other = *--i;
322
+ *i = prev;
323
+ prev = other;
324
+ }
325
+ res++; // Literal 'lit' single satisfies clause 'c'.
326
+ }
327
+ stats.ticks.walkbreak += (ticks - oldticks);
328
+ STOP (walkbreak);
329
+
330
+ return res;
331
+ }
332
+
333
+ /*------------------------------------------------------------------------*/
334
+
335
+ // Given an unsatisfied clause 'c', in which we want to flip a literal, we
336
+ // first determine the exponential score based on the break-count of its
337
+ // literals and then sample the literals based on these scores. The CB
338
+ // value is smaller than one and thus the score is exponentially decreasing
339
+ // with the break-count increasing. The sampling works as in 'ProbSAT' and
340
+ // 'YalSAT' by summing up the scores and then picking a random limit in the
341
+ // range of zero to the sum, then summing up the scores again and picking
342
+ // the first literal which reaches the limit. Note, that during incremental
343
+ // SAT solving we can not flip assumed variables. Those are assigned at
344
+ // decision level one, while the other variables are assigned at two.
345
+
346
+ int Internal::walk_pick_lit (Walker &walker, Clause *c) {
347
+ LOG ("picking literal by break-count");
348
+ assert (walker.scores.empty ());
349
+ const int64_t old = walker.ticks;
350
+ walker.ticks += 1;
351
+ double sum = 0;
352
+ int64_t propagations = 0;
353
+ for (const auto lit : *c) {
354
+ assert (active (lit));
355
+ if (var (lit).level == 1) {
356
+ LOG ("skipping assumption %d for scoring", -lit);
357
+ continue;
358
+ }
359
+ assert (active (lit));
360
+ propagations++;
361
+ unsigned tmp = walk_break_value (-lit, walker.ticks);
362
+ double score = walker.score (tmp);
363
+ LOG ("literal %d break-count %u score %g", lit, tmp, score);
364
+ walker.scores.push_back (score);
365
+ sum += score;
366
+ }
367
+ (void) propagations; // TODO actually unused?
368
+ LOG ("scored %zd literals", walker.scores.size ());
369
+ assert (!walker.scores.empty ());
370
+ assert (walker.scores.size () <= (size_t) c->size);
371
+ const double lim = sum * walker.random.generate_double ();
372
+ LOG ("score sum %g limit %g", sum, lim);
373
+ const auto end = c->end ();
374
+ auto i = c->begin ();
375
+ auto j = walker.scores.begin ();
376
+ int res;
377
+ for (;;) {
378
+ assert (i != end);
379
+ res = *i++;
380
+ if (var (res).level > 1)
381
+ break;
382
+ LOG ("skipping assumption %d without score", -res);
383
+ }
384
+ sum = *j++;
385
+ while (sum <= lim && i != end) {
386
+ res = *i++;
387
+ if (var (res).level == 1) {
388
+ LOG ("skipping assumption %d without score", -res);
389
+ continue;
390
+ }
391
+ sum += *j++;
392
+ }
393
+ walker.scores.clear ();
394
+ LOG ("picking literal %d by break-count", res);
395
+ stats.ticks.walkpick += walker.ticks - old;
396
+ return res;
397
+ }
398
+
399
+ int Internal::walk_pick_lit (Walker &walker, ClauseOrBinary c) {
400
+ if (c.is_binary ())
401
+ return walk_pick_lit (walker, c.tagged_binary ());
402
+ return walk_pick_lit (walker, c.clause ());
403
+ }
404
+
405
+ int Internal::walk_pick_lit (Walker &walker, const TaggedBinary c) {
406
+ LOG ("picking literal by break-count on binary clause [%" PRIu64 "]%s %s",
407
+ c.d->id, LOGLIT (c.lit), LOGLIT (c.other));
408
+ assert (walker.scores.empty ());
409
+ const int64_t old = walker.ticks;
410
+ double sum = 0;
411
+ int64_t propagations = 0;
412
+ const std::array<int, 2> clause = {c.lit, c.other};
413
+ for (const auto lit : clause) {
414
+ assert (active (lit));
415
+ if (var (lit).level == 1) {
416
+ LOG ("skipping assumption %d for scoring", -lit);
417
+ continue;
418
+ }
419
+ assert (active (lit));
420
+ assert (val (lit) < 0);
421
+ propagations++;
422
+ unsigned tmp = walk_break_value (-lit, walker.ticks);
423
+ double score = walker.score (tmp);
424
+ LOG ("literal %d break-count %u score %g", lit, tmp, score);
425
+ walker.scores.push_back (score);
426
+ sum += score;
427
+ }
428
+ (void) propagations; // TODO unused?
429
+ LOG ("scored %zd literals", walker.scores.size ());
430
+ assert (!walker.scores.empty ());
431
+ assert (walker.scores.size () <= (size_t) 2);
432
+ const double lim = sum * walker.random.generate_double ();
433
+ LOG ("score sum %g limit %g", sum, lim);
434
+ const auto end = clause.end ();
435
+ auto i = clause.begin ();
436
+ auto j = walker.scores.begin ();
437
+ int res = 0;
438
+ for (;;) {
439
+ assert (i != end);
440
+ res = *i++;
441
+ if (var (res).level > 1)
442
+ break;
443
+ LOG ("skipping assumption %d without score", -res);
444
+ }
445
+ sum = *j++;
446
+ while (sum <= lim && i != end) {
447
+ res = *i++;
448
+ if (var (res).level == 1) {
449
+ LOG ("skipping assumption %d without score", -res);
450
+ continue;
451
+ }
452
+ sum += *j++;
453
+ }
454
+ assert (res);
455
+ walker.scores.clear ();
456
+ LOG ("picking literal %d by break-count", res);
457
+ stats.ticks.walkpick += walker.ticks - old;
458
+ return res;
459
+ }
460
+
461
+ /*------------------------------------------------------------------------*/
462
+
463
+ // flips a literal unless we run out of ticks.
464
+ bool Internal::walk_flip_lit (Walker &walker, int lit) {
465
+ START (walkflip);
466
+ const int64_t old = walker.ticks;
467
+ require_mode (WALK);
468
+ LOG ("flipping assign %d", lit);
469
+ assert (val (lit) < 0);
470
+
471
+ // First flip the literal value.
472
+ //
473
+ const int tmp = sign (lit);
474
+ const int idx = abs (lit);
475
+ set_val (idx, tmp);
476
+ assert (val (lit) > 0);
477
+
478
+ // we are going to need it anyway and it probably still is in memory
479
+ const Watches &ws = watches (-lit);
480
+ if (!ws.empty ()) {
481
+ const Watch &w = ws[0];
482
+ __builtin_prefetch (&w, 0, 1);
483
+ }
484
+
485
+ // Then remove 'c' and all other now satisfied (made) clauses.
486
+ {
487
+ // Simply go over all unsatisfied (broken) clauses.
488
+
489
+ LOG ("trying to make %zd broken clauses", walker.broken.size ());
490
+
491
+ const auto eou = walker.broken.end ();
492
+ // broken is in cache given how central it is... but not always (see the
493
+ // ncc problems). Value was heuristically determined to give reasonnable
494
+ // values.
495
+ walker.ticks +=
496
+ 1 + cache_lines (walker.broken.size (), sizeof (Clause *));
497
+ auto j = walker.broken.begin (), i = j;
498
+ #if defined(LOGGING) || !defined(NDEBUG)
499
+ int64_t made = 0;
500
+ #endif
501
+
502
+ while (i != eou) {
503
+
504
+ ClauseOrBinary tagged = *j++ = *i++;
505
+
506
+ if (tagged.is_binary ()) {
507
+ const TaggedBinary &b = tagged.tagged_binary ();
508
+ const int clit = b.lit;
509
+ const int other = b.other;
510
+ assert (val (clit) < 0 || val (other) < 0);
511
+ #if defined(LOGGING)
512
+ assert (b.d->literals[0] == clit || b.d->literals[1] == clit);
513
+ assert (b.d->literals[0] == other || b.d->literals[1] == other);
514
+ #endif
515
+ if (clit == lit || other == lit) {
516
+ LOG (b.d, "made");
517
+ const int first_lit = lit;
518
+ const int second_lit = clit ^ lit ^ other;
519
+ #ifdef LOGGING
520
+ watch_binary_literal (first_lit, second_lit, b.d);
521
+ #else
522
+ // placeholder for the clause, does not matter
523
+ watch_binary_literal (first_lit, second_lit, dummy_binary);
524
+ #endif
525
+
526
+ ++walker.ticks;
527
+ #if defined(LOGGING) || !defined(NDEBUG)
528
+ made++;
529
+ #endif
530
+ j--;
531
+ } else {
532
+ LOG (b.d, "still broken");
533
+ assert (val (clit) < 0 && val (other) < 0);
534
+ }
535
+ continue;
536
+ }
537
+
538
+ // now the expansive part
539
+ Clause *d = tagged.clause ();
540
+ ++walker.ticks;
541
+ int *literals = d->literals;
542
+ LOG (d, "search for replacement");
543
+ int prev = 0;
544
+ // Find 'lit' in 'd'.
545
+ //
546
+ const int size = d->size;
547
+ for (int i = 0; i < size; i++) {
548
+ const int other = literals[i];
549
+ assert (active (other));
550
+ literals[i] = prev;
551
+ prev = other;
552
+ if (other == lit)
553
+ break;
554
+ assert (val (other) < 0);
555
+ }
556
+ // If 'lit' is in 'd' then move it to the front to watch it.
557
+ //
558
+ if (prev == lit) {
559
+ literals[0] = lit;
560
+ LOG (d, "made");
561
+ watch_literal (literals[0], literals[1], d);
562
+ ++walker.ticks;
563
+ #if defined(LOGGING) || !defined(NDEBUG)
564
+ made++;
565
+ #endif
566
+ j--;
567
+ } else { // Otherwise the clause is not satisfied, undo shift.
568
+
569
+ for (int i = size - 1; i >= 0; i--) {
570
+ int other = literals[i];
571
+ literals[i] = prev;
572
+ prev = other;
573
+ }
574
+ }
575
+ LOG (d, "clause after undoing shift");
576
+ }
577
+ assert ((int64_t) (j - walker.broken.begin ()) + made ==
578
+ (int64_t) walker.broken.size ());
579
+ walker.broken.resize (j - walker.broken.begin ());
580
+ LOG ("made %" PRId64 " clauses by flipping %d, still %zu broken", made,
581
+ lit, walker.broken.size ());
582
+ #ifndef NDEBUG
583
+ for (auto d : walker.broken) {
584
+ if (d.is_binary ()) {
585
+ const TaggedBinary &b = d.tagged_binary ();
586
+ assert (val (b.lit) < 0 && val (b.other) < 0);
587
+ } else {
588
+ for (auto lit : *d.clause ())
589
+ assert (val (lit) < 0);
590
+ }
591
+ }
592
+ #endif
593
+ if (walker.ticks > walker.limit) {
594
+ STOP (walkflip);
595
+ return false;
596
+ }
597
+ }
598
+
599
+ stats.ticks.walkflipbroken += walker.ticks - old;
600
+
601
+ const int64_t old_after_broken = walker.ticks;
602
+
603
+ // Finally add all new unsatisfied (broken) clauses.
604
+ {
605
+ #ifdef LOGGING
606
+ int64_t broken = 0;
607
+ #endif
608
+ Watches &ws = watches (-lit);
609
+ // probably still in cache
610
+ walker.ticks += 1 + cache_lines (ws.size (), sizeof (Clause *));
611
+
612
+ LOG ("trying to break %zd watched clauses", ws.size ());
613
+
614
+ for (const auto &w : ws) {
615
+ Clause *d = w.clause;
616
+ const bool binary = w.binary ();
617
+ if (binary) {
618
+ const int other = w.blit;
619
+ assert (w.blit != -lit);
620
+ if (val (other) > 0) {
621
+ LOG (d, "unwatch %d in", -lit);
622
+ watch_binary_literal (other, -lit, d);
623
+ ++walker.ticks;
624
+ continue;
625
+ }
626
+ LOG (d, "broken");
627
+ #ifdef LOGGING
628
+ assert (d != dummy_binary);
629
+ #endif
630
+ walker.broken.push_back (TaggedBinary (d, -lit, other));
631
+ ++walker.ticks;
632
+ #ifdef LOGGING
633
+ broken++;
634
+ #endif
635
+ continue;
636
+ }
637
+
638
+ if (walker.ticks > walker.limit) {
639
+ STOP (walkflip);
640
+ return false;
641
+ }
642
+ // now the expansive part
643
+ assert (d->size != 2);
644
+ ++walker.ticks;
645
+ int *literals = d->literals, replacement = 0, prev = -lit;
646
+ assert (d->size == w.size);
647
+ const int size = d->size;
648
+ assert (literals[0] == -lit);
649
+
650
+ for (int i = 1; i < size; i++) {
651
+ const int other = literals[i];
652
+ assert (active (other));
653
+ literals[i] = prev; // shift all to right
654
+ prev = other;
655
+ const signed char tmp = val (other);
656
+ if (tmp < 0)
657
+ continue;
658
+ replacement = other; // satisfying literal
659
+ break;
660
+ }
661
+ if (replacement) {
662
+ assert (-lit != replacement);
663
+ literals[1] = -lit;
664
+ literals[0] = replacement;
665
+ watch_literal (replacement, -lit, d);
666
+ ++walker.ticks;
667
+ LOG (d, "found replacement");
668
+ } else {
669
+ for (int i = size - 1; i > 0; i--) { // undo shift
670
+ const int other = literals[i];
671
+ literals[i] = prev;
672
+ prev = other;
673
+ }
674
+
675
+ assert (literals[0] == -lit);
676
+ LOG (d, "broken");
677
+ walker.broken.push_back (d);
678
+ ++walker.ticks;
679
+ #ifdef LOGGING
680
+ broken++;
681
+ #endif
682
+ }
683
+ }
684
+ LOG ("broken %" PRId64 " clauses by flipping %d", broken, lit);
685
+ ws.clear ();
686
+ }
687
+ STOP (walkflip);
688
+ stats.ticks.walkflipWL += walker.ticks - old_after_broken;
689
+ stats.ticks.walkflip += walker.ticks - old;
690
+ return true;
691
+ }
692
+
693
+ /*------------------------------------------------------------------------*/
694
+
695
+ // Check whether to save the current phases as new global minimum.
696
+
697
+ inline void Internal::walk_save_minimum (Walker &walker) {
698
+ int64_t broken = walker.broken.size ();
699
+ if (broken >= walker.minimum)
700
+ return;
701
+ if (broken <= stats.walk.minimum) {
702
+ stats.walk.minimum = broken;
703
+ VERBOSE (3, "new global minimum %" PRId64 "", broken);
704
+ } else {
705
+ VERBOSE (3, "new walk minimum %" PRId64 "", broken);
706
+ }
707
+
708
+ walker.minimum = broken;
709
+
710
+ #ifndef NDEBUG
711
+ for (auto i : vars) {
712
+ const signed char tmp = vals[i];
713
+ if (tmp)
714
+ walker.current_best_model[i] = tmp;
715
+ }
716
+ if (walker.minimum == 0) {
717
+ for (auto c : clauses) {
718
+ if (c->garbage)
719
+ continue;
720
+ if (c->redundant)
721
+ continue;
722
+ int satisfied = 0;
723
+ for (const auto &lit : *c) {
724
+ const int tmp = internal->val (lit);
725
+ if (tmp > 0) {
726
+ LOG (c, "satisfied literal %d in", lit);
727
+ satisfied++;
728
+ }
729
+ }
730
+ assert (satisfied);
731
+ }
732
+ }
733
+ #endif
734
+ if (walker.best_trail_pos == -1) {
735
+ VERBOSE (3, "saving the new walk minimum %" PRId64 "", broken);
736
+ for (auto i : vars) {
737
+ const signed char tmp = vals[i];
738
+ if (tmp) {
739
+ walker.best_values[i] = tmp;
740
+ #ifndef NDEBUG
741
+ assert (tmp == walker.current_best_model[i]);
742
+ #endif
743
+ } else {
744
+ assert (!active (i));
745
+ }
746
+ }
747
+ walker.best_trail_pos = 0;
748
+ } else {
749
+ walker.best_trail_pos = walker.flips.size ();
750
+ LOG ("new best trail position %u", walker.best_trail_pos);
751
+ }
752
+ }
753
+
754
+ /*------------------------------------------------------------------------*/
755
+
756
+ int Internal::walk_round (int64_t limit, bool prev) {
757
+
758
+ stats.walk.count++;
759
+
760
+ clear_watches ();
761
+
762
+ // Remove all fixed variables first (assigned at decision level zero).
763
+ //
764
+ if (last.collect.fixed < stats.all.fixed)
765
+ garbage_collection ();
766
+
767
+ #ifndef QUIET
768
+ // We want to see more messages during initial local search.
769
+ //
770
+ if (localsearching) {
771
+ assert (!force_phase_messages);
772
+ force_phase_messages = true;
773
+ }
774
+ #endif
775
+
776
+ PHASE ("walk", stats.walk.count, "random walk limit of %" PRId64 " ticks",
777
+ limit);
778
+
779
+ // Instantiate data structures for this local search round.
780
+ //
781
+ Walker walker (internal, limit);
782
+ #ifndef QUIET
783
+ int old_global_minimum = stats.walk.minimum;
784
+ #endif
785
+
786
+ bool failed = false; // Inconsistent assumptions?
787
+
788
+ level = 1; // Assumed variables assigned at level 1.
789
+
790
+ if (assumptions.empty ()) {
791
+ LOG ("no assumptions so assigning all variables to decision phase");
792
+ } else {
793
+ LOG ("assigning assumptions to their forced phase first");
794
+ for (const auto lit : assumptions) {
795
+ signed char tmp = val (lit);
796
+ if (tmp > 0)
797
+ continue;
798
+ if (tmp < 0) {
799
+ LOG ("inconsistent assumption %d", lit);
800
+ failed = true;
801
+ break;
802
+ }
803
+ if (!active (lit))
804
+ continue;
805
+ tmp = sign (lit);
806
+ const int idx = abs (lit);
807
+ LOG ("initial assign %d to assumption phase", tmp < 0 ? -idx : idx);
808
+ set_val (idx, tmp);
809
+ assert (level == 1);
810
+ var (idx).level = 1;
811
+ }
812
+ if (!failed)
813
+ LOG ("now assigning remaining variables to their decision phase");
814
+ }
815
+
816
+ level = 2; // All other non assumed variables assigned at level 2.
817
+
818
+ if (!failed) {
819
+
820
+ // warmup stores the result in phases, not in target
821
+ const bool target = opts.warmup ? false : stable || opts.target == 2;
822
+ for (auto idx : vars) {
823
+ if (!active (idx)) {
824
+ LOG ("skipping inactive variable %d", idx);
825
+ continue;
826
+ }
827
+ if (vals[idx]) {
828
+ assert (var (idx).level == 1);
829
+ LOG ("skipping assumed variable %d", idx);
830
+ continue;
831
+ }
832
+ int tmp = 0;
833
+ if (prev)
834
+ tmp = phases.prev[idx];
835
+ if (!tmp)
836
+ tmp = sign (decide_phase (idx, target));
837
+ assert (tmp == 1 || tmp == -1);
838
+ set_val (idx, tmp);
839
+ assert (level == 2);
840
+ var (idx).level = 2;
841
+ LOG ("initial assign %d to decision phase", tmp < 0 ? -idx : idx);
842
+ }
843
+
844
+ LOG ("watching satisfied and registering broken clauses");
845
+ #ifdef LOGGING
846
+ int64_t watched = 0;
847
+ #endif
848
+
849
+ double size = 0;
850
+ int64_t n = 0;
851
+ for (const auto c : clauses) {
852
+
853
+ if (c->garbage)
854
+ continue;
855
+ if (c->redundant) {
856
+ if (!opts.walkredundant)
857
+ continue;
858
+ if (!likely_to_be_kept_clause (c))
859
+ continue;
860
+ }
861
+
862
+ bool satisfiable = false; // contains not only assumptions
863
+ int satisfied = 0; // clause satisfied?
864
+
865
+ int *lits = c->literals;
866
+ size += c->size;
867
+ n++;
868
+ const int size = c->size;
869
+
870
+ // Move to front satisfied literals and determine whether there
871
+ // is at least one (non-assumed) literal that can be flipped.
872
+ //
873
+ for (int i = 0; satisfied < 2 && i < size; i++) {
874
+ const int lit = lits[i];
875
+ assert (active (lit)); // Due to garbage collection.
876
+ if (val (lit) > 0) {
877
+ swap (lits[satisfied], lits[i]);
878
+ if (!satisfied++)
879
+ LOG ("first satisfying literal %d", lit);
880
+ } else if (!satisfiable && var (lit).level > 1) {
881
+ LOG ("non-assumption potentially satisfying literal %d", lit);
882
+ satisfiable = true;
883
+ }
884
+ }
885
+
886
+ if (!satisfied && !satisfiable) {
887
+ LOG (c, "due to assumptions unsatisfiable");
888
+ LOG ("stopping local search since assumptions falsify a clause");
889
+ failed = true;
890
+ break;
891
+ }
892
+
893
+ if (satisfied) {
894
+ LOG (c, "pushing to satisfied");
895
+ if (c->size == 2)
896
+ watch_binary_literal (lits[0], lits[1], c);
897
+ else
898
+ watch_literal (lits[0], lits[1], c);
899
+ #ifdef LOGGING
900
+ watched++;
901
+ #endif
902
+ } else {
903
+ assert (satisfiable); // at least one non-assumed variable ...
904
+ LOG (c, "broken");
905
+ assert (c->size == size);
906
+ if (size == 2)
907
+ walker.broken.push_back (TaggedBinary (c));
908
+ else
909
+ walker.broken.push_back (c);
910
+ }
911
+ }
912
+
913
+ double average_size = relative (size, n);
914
+ walker.populate_table (average_size);
915
+ PHASE ("walk", stats.walk.count,
916
+ "%" PRId64 " clauses average size %.2f over %d variables", n,
917
+ average_size, active ());
918
+
919
+ #ifdef LOGGING
920
+ if (!failed) {
921
+ int64_t broken = walker.broken.size ();
922
+ int64_t total = watched + broken;
923
+ LOG ("watching %" PRId64 " clauses %.0f%% "
924
+ "out of %" PRId64 " (watched and broken)",
925
+ watched, percent (watched, total), total);
926
+ }
927
+ #endif
928
+ }
929
+
930
+ assert (failed || walker.table.size ());
931
+
932
+ int res; // Tells caller to continue with local search.
933
+
934
+ if (!failed) {
935
+
936
+ int64_t broken = walker.broken.size ();
937
+ int64_t initial_minimum = broken;
938
+
939
+ PHASE ("walk", stats.walk.count,
940
+ "starting with %" PRId64 " unsatisfied clauses "
941
+ "(%.0f%% out of %" PRId64 ")",
942
+ broken, percent (broken, stats.current.irredundant),
943
+ stats.current.irredundant);
944
+
945
+ walk_save_minimum (walker);
946
+ assert (stats.walk.minimum <= walker.minimum);
947
+
948
+ int64_t minimum = broken;
949
+ #ifndef QUIET
950
+ int64_t flips = 0;
951
+ #endif
952
+ while (!terminated_asynchronously () && !walker.broken.empty () &&
953
+ walker.ticks < walker.limit) {
954
+ #ifndef QUIET
955
+ flips++;
956
+ #endif
957
+ stats.walk.flips++;
958
+ stats.walk.broken += broken;
959
+ ClauseOrBinary c = walk_pick_clause (walker);
960
+ const int lit = walk_pick_lit (walker, c);
961
+ bool finished = walk_flip_lit (walker, lit);
962
+ if (!finished)
963
+ break;
964
+ walker.push_flipped (lit);
965
+ broken = walker.broken.size ();
966
+ LOG ("now have %" PRId64 " broken clauses in total", broken);
967
+ if (broken >= minimum)
968
+ continue;
969
+ minimum = broken;
970
+ VERBOSE (3, "new phase minimum %" PRId64 " after %" PRId64 " flips",
971
+ minimum, flips);
972
+ walk_save_minimum (walker);
973
+ }
974
+
975
+ walker.save_final_minimum (initial_minimum);
976
+
977
+ #ifndef QUIET
978
+ if (minimum == initial_minimum) {
979
+ PHASE ("walk", internal->stats.walk.count,
980
+ "%sno improvement %" PRId64 "%s in %" PRId64 " flips and "
981
+ "%" PRId64 " ticks",
982
+ tout.bright_yellow_code (), minimum, tout.normal_code (),
983
+ flips, walker.ticks);
984
+ } else if (minimum < old_global_minimum)
985
+ PHASE ("walk", stats.walk.count,
986
+ "%snew global minimum %" PRId64 "%s in %" PRId64 " flips and "
987
+ "%" PRId64 " ticks",
988
+ tout.bright_yellow_code (), minimum, tout.normal_code (),
989
+ flips, walker.ticks);
990
+ else
991
+ PHASE ("walk", stats.walk.count,
992
+ "best phase minimum %" PRId64 " in %" PRId64 " flips and "
993
+ "%" PRId64 " ticks",
994
+ minimum, flips, walker.ticks);
995
+
996
+ if (opts.profile >= 2) {
997
+ PHASE ("walk", stats.walk.count, "%.2f million ticks per second",
998
+ 1e-6 *
999
+ relative (walker.ticks, time () - profiles.walk.started));
1000
+
1001
+ PHASE ("walk", stats.walk.count, "%.2f thousand flips per second",
1002
+ relative (1e-3 * flips, time () - profiles.walk.started));
1003
+
1004
+ } else {
1005
+ PHASE ("walk", stats.walk.count, "%.2f ticks", 1e-6 * walker.ticks);
1006
+
1007
+ PHASE ("walk", stats.walk.count, "%.2f thousand flips", 1e-3 * flips);
1008
+ }
1009
+ #endif
1010
+
1011
+ if (minimum > 0) {
1012
+ LOG ("minimum %" PRId64 " non-zero thus potentially continue",
1013
+ minimum);
1014
+ res = 0;
1015
+ } else {
1016
+ LOG ("minimum is zero thus stop local search");
1017
+ res = 10;
1018
+ }
1019
+
1020
+ } else {
1021
+
1022
+ res = 20;
1023
+
1024
+ PHASE ("walk", stats.walk.count,
1025
+ "aborted due to inconsistent assumptions");
1026
+ }
1027
+
1028
+ for (auto idx : vars)
1029
+ if (active (idx))
1030
+ set_val (idx, 0);
1031
+
1032
+ assert (level == 2);
1033
+ level = 0;
1034
+
1035
+ clear_watches ();
1036
+ connect_watches ();
1037
+
1038
+ #ifndef QUIET
1039
+ if (localsearching) {
1040
+ assert (force_phase_messages);
1041
+ force_phase_messages = false;
1042
+ }
1043
+ #endif
1044
+ stats.ticks.walk += walker.ticks;
1045
+ return res;
1046
+ }
1047
+
1048
+ void Internal::walk () {
1049
+ START_INNER_WALK ();
1050
+
1051
+ backtrack ();
1052
+ if (propagated < trail.size () && !propagate ()) {
1053
+ LOG ("empty clause after root level propagation");
1054
+ learn_empty_clause ();
1055
+ STOP_INNER_WALK ();
1056
+ return;
1057
+ }
1058
+
1059
+ int res = 0;
1060
+ if (opts.warmup)
1061
+ res = warmup ();
1062
+ if (res) {
1063
+ LOG ("stopping walk due to warmup");
1064
+ STOP_INNER_WALK ();
1065
+ return;
1066
+ }
1067
+ const int64_t ticks = stats.ticks.search[0] + stats.ticks.search[1];
1068
+ int64_t limit = ticks - last.walk.ticks;
1069
+ VERBOSE (2,
1070
+ "walk scheduling: last %" PRId64 " current %" PRId64
1071
+ " delta %" PRId64,
1072
+ last.walk.ticks, ticks, limit);
1073
+ last.walk.ticks = ticks;
1074
+ limit *= 1e-3 * opts.walkeffort;
1075
+ if (limit < opts.walkmineff)
1076
+ limit = opts.walkmineff;
1077
+ // local search is very cache friendly, so we actually really go over a
1078
+ // lot of ticks
1079
+ if (limit > 1e3 * opts.walkmaxeff) {
1080
+ MSG ("reached maximum efficiency %" PRId64, limit);
1081
+ limit = 1e3 * opts.walkmaxeff;
1082
+ }
1083
+ (void) walk_round (limit, false);
1084
+ STOP_INNER_WALK ();
1085
+ assert (!unsat);
1086
+ }
1087
+
1088
+ } // namespace CaDiCaL