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.
- checksums.yaml +7 -0
- data/LICENSE.txt +26 -0
- data/README.md +101 -0
- data/ext/cadical/cadical/LICENSE +28 -0
- data/ext/cadical/cadical/README.md +65 -0
- data/ext/cadical/cadical/VERSION +1 -0
- data/ext/cadical/cadical/src/analyze.cpp +1360 -0
- data/ext/cadical/cadical/src/arena.cpp +30 -0
- data/ext/cadical/cadical/src/arena.hpp +105 -0
- data/ext/cadical/cadical/src/assume.cpp +616 -0
- data/ext/cadical/cadical/src/averages.cpp +34 -0
- data/ext/cadical/cadical/src/averages.hpp +37 -0
- data/ext/cadical/cadical/src/backbone.cpp +631 -0
- data/ext/cadical/cadical/src/backtrack.cpp +177 -0
- data/ext/cadical/cadical/src/backward.cpp +231 -0
- data/ext/cadical/cadical/src/bins.cpp +22 -0
- data/ext/cadical/cadical/src/bins.hpp +22 -0
- data/ext/cadical/cadical/src/block.cpp +824 -0
- data/ext/cadical/cadical/src/block.hpp +37 -0
- data/ext/cadical/cadical/src/cadical.cpp +1026 -0
- data/ext/cadical/cadical/src/cadical.hpp +1419 -0
- data/ext/cadical/cadical/src/ccadical.cpp +208 -0
- data/ext/cadical/cadical/src/ccadical.h +74 -0
- data/ext/cadical/cadical/src/checker.cpp +649 -0
- data/ext/cadical/cadical/src/checker.hpp +173 -0
- data/ext/cadical/cadical/src/clause.cpp +689 -0
- data/ext/cadical/cadical/src/clause.hpp +190 -0
- data/ext/cadical/cadical/src/collect.cpp +545 -0
- data/ext/cadical/cadical/src/compact.cpp +550 -0
- data/ext/cadical/cadical/src/condition.cpp +940 -0
- data/ext/cadical/cadical/src/config.cpp +101 -0
- data/ext/cadical/cadical/src/config.hpp +20 -0
- data/ext/cadical/cadical/src/congruence.cpp +7880 -0
- data/ext/cadical/cadical/src/congruence.hpp +757 -0
- data/ext/cadical/cadical/src/constrain.cpp +64 -0
- data/ext/cadical/cadical/src/contract.cpp +27 -0
- data/ext/cadical/cadical/src/contract.hpp +139 -0
- data/ext/cadical/cadical/src/cover.cpp +704 -0
- data/ext/cadical/cadical/src/cover.hpp +34 -0
- data/ext/cadical/cadical/src/decide.cpp +347 -0
- data/ext/cadical/cadical/src/decompose.cpp +738 -0
- data/ext/cadical/cadical/src/decompose.hpp +23 -0
- data/ext/cadical/cadical/src/deduplicate.cpp +275 -0
- data/ext/cadical/cadical/src/definition.cpp +283 -0
- data/ext/cadical/cadical/src/delay.hpp +38 -0
- data/ext/cadical/cadical/src/drattracer.cpp +153 -0
- data/ext/cadical/cadical/src/drattracer.hpp +55 -0
- data/ext/cadical/cadical/src/elim.cpp +1171 -0
- data/ext/cadical/cadical/src/elim.hpp +53 -0
- data/ext/cadical/cadical/src/elimfast.cpp +570 -0
- data/ext/cadical/cadical/src/ema.cpp +95 -0
- data/ext/cadical/cadical/src/ema.hpp +68 -0
- data/ext/cadical/cadical/src/extend.cpp +289 -0
- data/ext/cadical/cadical/src/external.cpp +1034 -0
- data/ext/cadical/cadical/src/external.hpp +487 -0
- data/ext/cadical/cadical/src/external_propagate.cpp +1316 -0
- data/ext/cadical/cadical/src/factor.cpp +1011 -0
- data/ext/cadical/cadical/src/factor.hpp +54 -0
- data/ext/cadical/cadical/src/file.cpp +506 -0
- data/ext/cadical/cadical/src/file.hpp +210 -0
- data/ext/cadical/cadical/src/flags.cpp +135 -0
- data/ext/cadical/cadical/src/flags.hpp +93 -0
- data/ext/cadical/cadical/src/flip.cpp +269 -0
- data/ext/cadical/cadical/src/format.cpp +89 -0
- data/ext/cadical/cadical/src/format.hpp +36 -0
- data/ext/cadical/cadical/src/frattracer.cpp +277 -0
- data/ext/cadical/cadical/src/frattracer.hpp +67 -0
- data/ext/cadical/cadical/src/gates.cpp +766 -0
- data/ext/cadical/cadical/src/heap.hpp +212 -0
- data/ext/cadical/cadical/src/idruptracer.cpp +566 -0
- data/ext/cadical/cadical/src/idruptracer.hpp +112 -0
- data/ext/cadical/cadical/src/instantiate.cpp +365 -0
- data/ext/cadical/cadical/src/instantiate.hpp +45 -0
- data/ext/cadical/cadical/src/internal.cpp +1265 -0
- data/ext/cadical/cadical/src/internal.hpp +1941 -0
- data/ext/cadical/cadical/src/inttypes.hpp +34 -0
- data/ext/cadical/cadical/src/ipasir.cpp +47 -0
- data/ext/cadical/cadical/src/ipasir.h +37 -0
- data/ext/cadical/cadical/src/kitten.c +2599 -0
- data/ext/cadical/cadical/src/kitten.h +97 -0
- data/ext/cadical/cadical/src/level.hpp +33 -0
- data/ext/cadical/cadical/src/lidruptracer.cpp +657 -0
- data/ext/cadical/cadical/src/lidruptracer.hpp +122 -0
- data/ext/cadical/cadical/src/limit.cpp +146 -0
- data/ext/cadical/cadical/src/limit.hpp +168 -0
- data/ext/cadical/cadical/src/logging.cpp +214 -0
- data/ext/cadical/cadical/src/logging.hpp +98 -0
- data/ext/cadical/cadical/src/lookahead.cpp +520 -0
- data/ext/cadical/cadical/src/lratchecker.cpp +833 -0
- data/ext/cadical/cadical/src/lratchecker.hpp +168 -0
- data/ext/cadical/cadical/src/lrattracer.cpp +200 -0
- data/ext/cadical/cadical/src/lrattracer.hpp +61 -0
- data/ext/cadical/cadical/src/lucky.cpp +506 -0
- data/ext/cadical/cadical/src/message.cpp +218 -0
- data/ext/cadical/cadical/src/message.hpp +65 -0
- data/ext/cadical/cadical/src/minimize.cpp +224 -0
- data/ext/cadical/cadical/src/mobical.cpp +5588 -0
- data/ext/cadical/cadical/src/occs.cpp +52 -0
- data/ext/cadical/cadical/src/occs.hpp +36 -0
- data/ext/cadical/cadical/src/options.cpp +359 -0
- data/ext/cadical/cadical/src/options.hpp +442 -0
- data/ext/cadical/cadical/src/parse.cpp +471 -0
- data/ext/cadical/cadical/src/parse.hpp +75 -0
- data/ext/cadical/cadical/src/phases.cpp +56 -0
- data/ext/cadical/cadical/src/phases.hpp +19 -0
- data/ext/cadical/cadical/src/probe.cpp +990 -0
- data/ext/cadical/cadical/src/profile.cpp +107 -0
- data/ext/cadical/cadical/src/profile.hpp +283 -0
- data/ext/cadical/cadical/src/proof.cpp +691 -0
- data/ext/cadical/cadical/src/proof.hpp +125 -0
- data/ext/cadical/cadical/src/propagate.cpp +584 -0
- data/ext/cadical/cadical/src/queue.cpp +90 -0
- data/ext/cadical/cadical/src/queue.hpp +74 -0
- data/ext/cadical/cadical/src/radix.hpp +180 -0
- data/ext/cadical/cadical/src/random.cpp +207 -0
- data/ext/cadical/cadical/src/random.h +44 -0
- data/ext/cadical/cadical/src/random.hpp +98 -0
- data/ext/cadical/cadical/src/range.hpp +125 -0
- data/ext/cadical/cadical/src/reap.cpp +127 -0
- data/ext/cadical/cadical/src/reap.hpp +28 -0
- data/ext/cadical/cadical/src/reduce.cpp +278 -0
- data/ext/cadical/cadical/src/reluctant.hpp +82 -0
- data/ext/cadical/cadical/src/rephase.cpp +402 -0
- data/ext/cadical/cadical/src/report.cpp +313 -0
- data/ext/cadical/cadical/src/resources.cpp +160 -0
- data/ext/cadical/cadical/src/resources.hpp +16 -0
- data/ext/cadical/cadical/src/restart.cpp +178 -0
- data/ext/cadical/cadical/src/restore.cpp +267 -0
- data/ext/cadical/cadical/src/score.cpp +51 -0
- data/ext/cadical/cadical/src/score.hpp +16 -0
- data/ext/cadical/cadical/src/shrink.cpp +507 -0
- data/ext/cadical/cadical/src/signal.cpp +136 -0
- data/ext/cadical/cadical/src/signal.hpp +33 -0
- data/ext/cadical/cadical/src/solution.cpp +50 -0
- data/ext/cadical/cadical/src/solver.cpp +1871 -0
- data/ext/cadical/cadical/src/stable.cpp +31 -0
- data/ext/cadical/cadical/src/stack.h +110 -0
- data/ext/cadical/cadical/src/stats.cpp +920 -0
- data/ext/cadical/cadical/src/stats.hpp +418 -0
- data/ext/cadical/cadical/src/subsume.cpp +645 -0
- data/ext/cadical/cadical/src/sweep.cpp +1960 -0
- data/ext/cadical/cadical/src/sweep.hpp +61 -0
- data/ext/cadical/cadical/src/terminal.cpp +38 -0
- data/ext/cadical/cadical/src/terminal.hpp +96 -0
- data/ext/cadical/cadical/src/ternary.cpp +450 -0
- data/ext/cadical/cadical/src/testing.hpp +24 -0
- data/ext/cadical/cadical/src/tier.cpp +189 -0
- data/ext/cadical/cadical/src/tracer.hpp +186 -0
- data/ext/cadical/cadical/src/transred.cpp +253 -0
- data/ext/cadical/cadical/src/unstable.cpp +29 -0
- data/ext/cadical/cadical/src/util.cpp +129 -0
- data/ext/cadical/cadical/src/util.hpp +181 -0
- data/ext/cadical/cadical/src/var.cpp +39 -0
- data/ext/cadical/cadical/src/var.hpp +22 -0
- data/ext/cadical/cadical/src/veripbtracer.cpp +427 -0
- data/ext/cadical/cadical/src/veripbtracer.hpp +106 -0
- data/ext/cadical/cadical/src/version.cpp +107 -0
- data/ext/cadical/cadical/src/version.hpp +13 -0
- data/ext/cadical/cadical/src/vivify.cpp +1893 -0
- data/ext/cadical/cadical/src/vivify.hpp +50 -0
- data/ext/cadical/cadical/src/walk.cpp +1088 -0
- data/ext/cadical/cadical/src/walk.hpp +91 -0
- data/ext/cadical/cadical/src/walk_full_occs.cpp +966 -0
- data/ext/cadical/cadical/src/warmup.cpp +403 -0
- data/ext/cadical/cadical/src/watch.cpp +126 -0
- data/ext/cadical/cadical/src/watch.hpp +77 -0
- data/ext/cadical/cadical_ext.c +778 -0
- data/ext/cadical/extconf.rb +26 -0
- data/lib/cadical/version.rb +3 -0
- data/lib/cadical.rb +12 -0
- 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
|