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