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,403 @@
|
|
|
1
|
+
#include "cadical.hpp"
|
|
2
|
+
#include "internal.hpp"
|
|
3
|
+
|
|
4
|
+
namespace CaDiCaL {
|
|
5
|
+
|
|
6
|
+
// The idea of warmup is to reuse the strength of CDCL, namely
|
|
7
|
+
// propagating, before calling random walk that is not good at
|
|
8
|
+
// propagating long chains. Therefore, we propagate (ignoring all conflicts)
|
|
9
|
+
// discovered along the way.
|
|
10
|
+
// The asignmend is the same as the normal assignment however, it updates
|
|
11
|
+
// the target phases so that local search can pick them up later
|
|
12
|
+
|
|
13
|
+
// specific warmup version with saving of the target.
|
|
14
|
+
inline void Internal::warmup_assign (int lit, Clause *reason) {
|
|
15
|
+
|
|
16
|
+
assert (level); // no need to learn unit clauses here
|
|
17
|
+
require_mode (SEARCH);
|
|
18
|
+
|
|
19
|
+
const int idx = vidx (lit);
|
|
20
|
+
assert (reason != external_reason);
|
|
21
|
+
assert (!vals[idx]);
|
|
22
|
+
assert (!flags (idx).eliminated () || reason == decision_reason);
|
|
23
|
+
assert (!searching_lucky_phases);
|
|
24
|
+
assert (lrat_chain.empty ());
|
|
25
|
+
Var &v = var (idx);
|
|
26
|
+
int lit_level;
|
|
27
|
+
assert (
|
|
28
|
+
!(reason == external_reason &&
|
|
29
|
+
((size_t) level <= assumptions.size () + (!!constraint.size ()))));
|
|
30
|
+
assert (reason);
|
|
31
|
+
assert (level || reason == decision_reason);
|
|
32
|
+
// we purely assign in order here
|
|
33
|
+
lit_level = level;
|
|
34
|
+
|
|
35
|
+
v.level = lit_level;
|
|
36
|
+
v.trail = trail.size ();
|
|
37
|
+
v.reason = reason;
|
|
38
|
+
assert ((int) num_assigned < max_var);
|
|
39
|
+
assert (num_assigned == trail.size ());
|
|
40
|
+
num_assigned++;
|
|
41
|
+
const signed char tmp = sign (lit);
|
|
42
|
+
phases.saved[idx] = tmp;
|
|
43
|
+
set_val (idx, tmp);
|
|
44
|
+
assert (val (lit) > 0);
|
|
45
|
+
assert (val (-lit) < 0);
|
|
46
|
+
|
|
47
|
+
trail.push_back (lit);
|
|
48
|
+
#ifdef LOGGING
|
|
49
|
+
if (!lit_level)
|
|
50
|
+
LOG ("root-level unit assign %d @ 0", lit);
|
|
51
|
+
else
|
|
52
|
+
LOG (reason, "search assign %d @ %d", lit, lit_level);
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
assert (watching ());
|
|
56
|
+
const Watches &ws = watches (-lit);
|
|
57
|
+
if (!ws.empty ()) {
|
|
58
|
+
const Watch &w = ws[0];
|
|
59
|
+
__builtin_prefetch (&w, 0, 1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void Internal::warmup_propagate_beyond_conflict () {
|
|
64
|
+
|
|
65
|
+
assert (!unsat);
|
|
66
|
+
|
|
67
|
+
START (propagate);
|
|
68
|
+
assert (!ignore);
|
|
69
|
+
|
|
70
|
+
int64_t before = propagated;
|
|
71
|
+
|
|
72
|
+
while (propagated != trail.size ()) {
|
|
73
|
+
|
|
74
|
+
const int lit = -trail[propagated++];
|
|
75
|
+
LOG ("propagating %d", -lit);
|
|
76
|
+
Watches &ws = watches (lit);
|
|
77
|
+
|
|
78
|
+
const const_watch_iterator eow = ws.end ();
|
|
79
|
+
watch_iterator j = ws.begin ();
|
|
80
|
+
const_watch_iterator i = j;
|
|
81
|
+
|
|
82
|
+
while (i != eow) {
|
|
83
|
+
|
|
84
|
+
const Watch w = *j++ = *i++;
|
|
85
|
+
const signed char b = val (w.blit);
|
|
86
|
+
|
|
87
|
+
if (b > 0)
|
|
88
|
+
continue; // blocking literal satisfied
|
|
89
|
+
|
|
90
|
+
if (w.binary ()) {
|
|
91
|
+
|
|
92
|
+
// In principle we can ignore garbage binary clauses too, but that
|
|
93
|
+
// would require to dereference the clause pointer all the time with
|
|
94
|
+
//
|
|
95
|
+
// if (w.clause->garbage) { j--; continue; } // (*)
|
|
96
|
+
//
|
|
97
|
+
// This is too costly. It is however necessary to produce correct
|
|
98
|
+
// proof traces if binary clauses are traced to be deleted ('d ...'
|
|
99
|
+
// line) immediately as soon they are marked as garbage. Actually
|
|
100
|
+
// finding instances where this happens is pretty difficult (six
|
|
101
|
+
// parallel fuzzing jobs in parallel took an hour), but it does
|
|
102
|
+
// occur. Our strategy to avoid generating incorrect proofs now is
|
|
103
|
+
// to delay tracing the deletion of binary clauses marked as garbage
|
|
104
|
+
// until they are really deleted from memory. For large clauses
|
|
105
|
+
// this is not necessary since we have to access the clause anyhow.
|
|
106
|
+
//
|
|
107
|
+
// Thanks go to Mathias Fleury, who wanted me to explain why the
|
|
108
|
+
// line '(*)' above was in the code. Removing it actually really
|
|
109
|
+
// improved running times and thus I tried to find concrete
|
|
110
|
+
// instances where this happens (which I found), and then
|
|
111
|
+
// implemented the described fix.
|
|
112
|
+
|
|
113
|
+
// Binary clauses are treated separately since they do not require
|
|
114
|
+
// to access the clause at all (only during conflict analysis, and
|
|
115
|
+
// there also only to simplify the code).
|
|
116
|
+
|
|
117
|
+
if (b < 0)
|
|
118
|
+
// ignoring conflict
|
|
119
|
+
++stats.warmup.conflicts;
|
|
120
|
+
else {
|
|
121
|
+
warmup_assign (w.blit, w.clause);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
} else {
|
|
125
|
+
assert (w.clause->size > 2);
|
|
126
|
+
|
|
127
|
+
// The cache line with the clause data is forced to be loaded here
|
|
128
|
+
// and thus this first memory access below is the real hot-spot of
|
|
129
|
+
// the solver. Note, that this check is positive very rarely and
|
|
130
|
+
// thus branch prediction should be almost perfect here.
|
|
131
|
+
|
|
132
|
+
if (w.clause->garbage) {
|
|
133
|
+
j--;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
literal_iterator lits = w.clause->begin ();
|
|
137
|
+
const int other = lits[0] ^ lits[1] ^ lit;
|
|
138
|
+
const signed char u = val (other);
|
|
139
|
+
if (u > 0)
|
|
140
|
+
j[-1].blit = other;
|
|
141
|
+
else {
|
|
142
|
+
const int size = w.clause->size;
|
|
143
|
+
const const_literal_iterator end = lits + size;
|
|
144
|
+
const literal_iterator middle = lits + w.clause->pos;
|
|
145
|
+
literal_iterator k = middle;
|
|
146
|
+
signed char v = -1;
|
|
147
|
+
int r = 0;
|
|
148
|
+
while (k != end && (v = val (r = *k)) < 0)
|
|
149
|
+
k++;
|
|
150
|
+
if (v < 0) {
|
|
151
|
+
k = lits + 2;
|
|
152
|
+
assert (w.clause->pos <= size);
|
|
153
|
+
while (k != middle && (v = val (r = *k)) < 0)
|
|
154
|
+
k++;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
w.clause->pos = k - lits; // always save position
|
|
158
|
+
|
|
159
|
+
assert (lits + 2 <= k), assert (k <= w.clause->end ());
|
|
160
|
+
|
|
161
|
+
if (v > 0) {
|
|
162
|
+
|
|
163
|
+
// Replacement satisfied, so just replace 'blit'.
|
|
164
|
+
|
|
165
|
+
j[-1].blit = r;
|
|
166
|
+
|
|
167
|
+
} else if (!v) {
|
|
168
|
+
|
|
169
|
+
// Found new unassigned replacement literal to be watched.
|
|
170
|
+
|
|
171
|
+
LOG (w.clause, "unwatch %d in", lit);
|
|
172
|
+
|
|
173
|
+
lits[0] = other;
|
|
174
|
+
lits[1] = r;
|
|
175
|
+
*k = lit;
|
|
176
|
+
|
|
177
|
+
watch_literal (r, lit, w.clause);
|
|
178
|
+
|
|
179
|
+
j--; // Drop this watch from the watch list of 'lit'.
|
|
180
|
+
|
|
181
|
+
} else if (!u) {
|
|
182
|
+
|
|
183
|
+
assert (v < 0);
|
|
184
|
+
|
|
185
|
+
// The other watch is unassigned ('!u') and all other literals
|
|
186
|
+
// assigned to false (still 'v < 0'), thus we found a unit.
|
|
187
|
+
//
|
|
188
|
+
build_chain_for_units (other, w.clause, 0);
|
|
189
|
+
warmup_assign (other, w.clause);
|
|
190
|
+
} else {
|
|
191
|
+
assert (u < 0);
|
|
192
|
+
assert (v < 0);
|
|
193
|
+
|
|
194
|
+
// ignoring conflict
|
|
195
|
+
++stats.warmup.conflicts;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (j != i) {
|
|
202
|
+
ws.resize (j - ws.begin ());
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
assert (propagated == trail.size ());
|
|
207
|
+
|
|
208
|
+
stats.warmup.propagated += (trail.size () - before);
|
|
209
|
+
STOP (propagate);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
int Internal::warmup_decide () {
|
|
213
|
+
assert (!satisfied ());
|
|
214
|
+
START (decide);
|
|
215
|
+
int res = 0;
|
|
216
|
+
if ((size_t) level < assumptions.size ()) {
|
|
217
|
+
const int lit = assumptions[level];
|
|
218
|
+
assert (assumed (lit));
|
|
219
|
+
const signed char tmp = val (lit);
|
|
220
|
+
if (tmp < 0) {
|
|
221
|
+
LOG ("assumption %d falsified", lit);
|
|
222
|
+
res = 20;
|
|
223
|
+
} else if (tmp > 0) {
|
|
224
|
+
LOG ("assumption %d already satisfied", lit);
|
|
225
|
+
new_trail_level (0);
|
|
226
|
+
LOG ("added pseudo decision level");
|
|
227
|
+
} else {
|
|
228
|
+
LOG ("deciding assumption %d", lit);
|
|
229
|
+
search_assume_decision (lit);
|
|
230
|
+
}
|
|
231
|
+
} else if ((size_t) level == assumptions.size () && constraint.size ()) {
|
|
232
|
+
|
|
233
|
+
int satisfied_lit = 0; // The literal satisfying the constrain.
|
|
234
|
+
int unassigned_lit = 0; // Highest score unassigned literal.
|
|
235
|
+
int previous_lit = 0; // Move satisfied literals to the front.
|
|
236
|
+
|
|
237
|
+
const size_t size_constraint = constraint.size ();
|
|
238
|
+
|
|
239
|
+
#ifndef NDEBUG
|
|
240
|
+
unsigned sum = 0;
|
|
241
|
+
for (auto lit : constraint)
|
|
242
|
+
sum += lit;
|
|
243
|
+
#endif
|
|
244
|
+
for (size_t i = 0; i != size_constraint; i++) {
|
|
245
|
+
|
|
246
|
+
// Get literal and move 'constraint[i] = constraint[i-1]'.
|
|
247
|
+
|
|
248
|
+
int lit = constraint[i];
|
|
249
|
+
constraint[i] = previous_lit;
|
|
250
|
+
previous_lit = lit;
|
|
251
|
+
|
|
252
|
+
const signed char tmp = val (lit);
|
|
253
|
+
if (tmp < 0) {
|
|
254
|
+
LOG ("constraint literal %d falsified", lit);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (tmp > 0) {
|
|
259
|
+
LOG ("constraint literal %d satisfied", lit);
|
|
260
|
+
satisfied_lit = lit;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
assert (!tmp);
|
|
265
|
+
LOG ("constraint literal %d unassigned", lit);
|
|
266
|
+
|
|
267
|
+
if (!unassigned_lit || better_decision (lit, unassigned_lit))
|
|
268
|
+
unassigned_lit = lit;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (satisfied_lit) {
|
|
272
|
+
|
|
273
|
+
constraint[0] = satisfied_lit; // Move satisfied to the front.
|
|
274
|
+
|
|
275
|
+
LOG ("literal %d satisfies constraint and "
|
|
276
|
+
"is implied by assumptions",
|
|
277
|
+
satisfied_lit);
|
|
278
|
+
|
|
279
|
+
new_trail_level (0);
|
|
280
|
+
LOG ("added pseudo decision level for constraint");
|
|
281
|
+
notify_decision ();
|
|
282
|
+
|
|
283
|
+
} else {
|
|
284
|
+
|
|
285
|
+
// Just move all the literals back. If we found an unsatisfied
|
|
286
|
+
// literal then it will be satisfied (most likely) at the next
|
|
287
|
+
// decision and moved then to the first position.
|
|
288
|
+
|
|
289
|
+
if (size_constraint) {
|
|
290
|
+
|
|
291
|
+
for (size_t i = 0; i + 1 != size_constraint; i++)
|
|
292
|
+
constraint[i] = constraint[i + 1];
|
|
293
|
+
|
|
294
|
+
constraint[size_constraint - 1] = previous_lit;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (unassigned_lit) {
|
|
298
|
+
|
|
299
|
+
LOG ("deciding %d to satisfy constraint", unassigned_lit);
|
|
300
|
+
search_assume_decision (unassigned_lit);
|
|
301
|
+
|
|
302
|
+
} else {
|
|
303
|
+
|
|
304
|
+
LOG ("failing constraint");
|
|
305
|
+
unsat_constraint = true;
|
|
306
|
+
res = 20;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
#ifndef NDEBUG
|
|
311
|
+
for (auto lit : constraint)
|
|
312
|
+
sum -= lit;
|
|
313
|
+
assert (!sum); // Checksum of literal should not change!
|
|
314
|
+
#endif
|
|
315
|
+
|
|
316
|
+
} else {
|
|
317
|
+
const bool target = (stable || opts.target == 2);
|
|
318
|
+
stats.warmup.decision++;
|
|
319
|
+
int idx = next_decision_variable ();
|
|
320
|
+
if (flags (idx).eliminated ())
|
|
321
|
+
++stats.warmup.dummydecision;
|
|
322
|
+
int decision = decide_phase (idx, target);
|
|
323
|
+
new_trail_level (decision);
|
|
324
|
+
warmup_assign (decision, decision_reason);
|
|
325
|
+
}
|
|
326
|
+
if (res)
|
|
327
|
+
marked_failed = false;
|
|
328
|
+
STOP (decide);
|
|
329
|
+
return res;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
int Internal::warmup () {
|
|
333
|
+
assert (!unsat);
|
|
334
|
+
assert (!level);
|
|
335
|
+
if (!opts.warmup)
|
|
336
|
+
return 0;
|
|
337
|
+
require_mode (WALK);
|
|
338
|
+
START (warmup);
|
|
339
|
+
++stats.warmup.count;
|
|
340
|
+
int res = 0;
|
|
341
|
+
|
|
342
|
+
#ifndef QUIET
|
|
343
|
+
const int64_t warmup_propagated = stats.warmup.propagated;
|
|
344
|
+
const int64_t decision = stats.warmup.decision;
|
|
345
|
+
const int64_t dummydecision = stats.warmup.dummydecision;
|
|
346
|
+
#endif
|
|
347
|
+
// first propagate assumptions in case we find a conflict. One subtle
|
|
348
|
+
// thing, if we find a conflict in the assumption, then we actually do
|
|
349
|
+
// need the notifications. Otherwise, we there should be no notification
|
|
350
|
+
// at all (not even the `backtrack ()` at the end). Also, we cannot not
|
|
351
|
+
// ignore conflicts at all, meaning that we cannot use our special
|
|
352
|
+
// propagation function, even if it could counts ticks.
|
|
353
|
+
const size_t assms_contraint_level =
|
|
354
|
+
assumptions.size () + !constraint.empty ();
|
|
355
|
+
while (!res && (size_t) level < assms_contraint_level &&
|
|
356
|
+
num_assigned < (size_t) max_var) {
|
|
357
|
+
assert (num_assigned < (size_t) max_var);
|
|
358
|
+
res = warmup_decide ();
|
|
359
|
+
if (!propagate ()) {
|
|
360
|
+
res = 20;
|
|
361
|
+
marked_failed = false;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const bool no_backtrack_notification = (level == 0);
|
|
366
|
+
|
|
367
|
+
// now we do not need any notification and can simply propagate
|
|
368
|
+
assert (res || propagated == trail.size ());
|
|
369
|
+
assert (!private_steps);
|
|
370
|
+
private_steps = true;
|
|
371
|
+
|
|
372
|
+
LOG ("propagating beyond conflicts to warm-up walk");
|
|
373
|
+
while (!res && num_assigned < (size_t) max_var) {
|
|
374
|
+
assert (propagated == trail.size ());
|
|
375
|
+
res = warmup_decide ();
|
|
376
|
+
warmup_propagate_beyond_conflict ();
|
|
377
|
+
LOG (lrat_chain, "during warmup with lrat chain:");
|
|
378
|
+
}
|
|
379
|
+
assert (res || num_assigned == (size_t) max_var);
|
|
380
|
+
#ifndef QUIET
|
|
381
|
+
// constrains with empty levels break this
|
|
382
|
+
// assert (res || stats.warmup.propagated - warmup_propagated ==
|
|
383
|
+
// (int64_t)num_assigned);
|
|
384
|
+
VERBOSE (3,
|
|
385
|
+
"warming-up needed %" PRIu64 " propagations including %" PRIu64
|
|
386
|
+
" decisions (with %" PRIu64 " dummy ones)",
|
|
387
|
+
stats.warmup.propagated - warmup_propagated,
|
|
388
|
+
stats.warmup.decision - decision,
|
|
389
|
+
stats.warmup.dummydecision - dummydecision);
|
|
390
|
+
#endif
|
|
391
|
+
|
|
392
|
+
// now we backtrack, notifying only if there was something to
|
|
393
|
+
// notify.
|
|
394
|
+
private_steps = no_backtrack_notification;
|
|
395
|
+
if (!res)
|
|
396
|
+
backtrack_without_updating_phases ();
|
|
397
|
+
private_steps = false;
|
|
398
|
+
STOP (warmup);
|
|
399
|
+
require_mode (WALK);
|
|
400
|
+
return res;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
} // namespace CaDiCaL
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
void Internal::init_watches () {
|
|
6
|
+
assert (wtab.empty ());
|
|
7
|
+
if (wtab.size () < 2 * vsize)
|
|
8
|
+
wtab.resize (2 * vsize, Watches ());
|
|
9
|
+
LOG ("initialized watcher tables");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
void Internal::clear_watches () {
|
|
13
|
+
for (auto lit : lits)
|
|
14
|
+
watches (lit).clear ();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
void Internal::reset_watches () {
|
|
18
|
+
assert (!wtab.empty ());
|
|
19
|
+
erase_vector (wtab);
|
|
20
|
+
LOG ("reset watcher tables");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// This can be quite costly since lots of memory is accessed in a rather
|
|
24
|
+
// random fashion, and thus we optionally profile it.
|
|
25
|
+
|
|
26
|
+
void Internal::connect_watches (bool irredundant_only) {
|
|
27
|
+
START (connect);
|
|
28
|
+
assert (watching ());
|
|
29
|
+
|
|
30
|
+
LOG ("watching all %sclauses", irredundant_only ? "irredundant " : "");
|
|
31
|
+
|
|
32
|
+
// First connect binary clauses.
|
|
33
|
+
//
|
|
34
|
+
for (const auto &c : clauses) {
|
|
35
|
+
if (irredundant_only && c->redundant)
|
|
36
|
+
continue;
|
|
37
|
+
if (c->garbage || c->size > 2)
|
|
38
|
+
continue;
|
|
39
|
+
watch_clause (c);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Then connect non-binary clauses.
|
|
43
|
+
//
|
|
44
|
+
for (const auto &c : clauses) {
|
|
45
|
+
if (irredundant_only && c->redundant)
|
|
46
|
+
continue;
|
|
47
|
+
if (c->garbage || c->size == 2)
|
|
48
|
+
continue;
|
|
49
|
+
watch_clause (c);
|
|
50
|
+
if (!level) {
|
|
51
|
+
const int lit0 = c->literals[0];
|
|
52
|
+
const int lit1 = c->literals[1];
|
|
53
|
+
const signed char tmp0 = val (lit0);
|
|
54
|
+
const signed char tmp1 = val (lit1);
|
|
55
|
+
if (tmp0 > 0)
|
|
56
|
+
continue;
|
|
57
|
+
if (tmp1 > 0)
|
|
58
|
+
continue;
|
|
59
|
+
if (tmp0 < 0) {
|
|
60
|
+
const size_t pos0 = var (lit0).trail;
|
|
61
|
+
if (pos0 < propagated) {
|
|
62
|
+
propagated = pos0;
|
|
63
|
+
LOG ("literal %d resets propagated to %zd", lit0, pos0);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (tmp1 < 0) {
|
|
67
|
+
const size_t pos1 = var (lit1).trail;
|
|
68
|
+
if (pos1 < propagated) {
|
|
69
|
+
propagated = pos1;
|
|
70
|
+
LOG ("literal %d resets propagated to %zd", lit1, pos1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
STOP (connect);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// This can be quite costly since lots of memory is accessed in a rather
|
|
80
|
+
// random fashion, and thus we optionally profile it.
|
|
81
|
+
|
|
82
|
+
void Internal::connect_binary_watches () {
|
|
83
|
+
START (connect);
|
|
84
|
+
assert (watching ());
|
|
85
|
+
|
|
86
|
+
LOG ("watching binary clauses");
|
|
87
|
+
|
|
88
|
+
// First connect binary clauses.
|
|
89
|
+
//
|
|
90
|
+
for (const auto &c : clauses) {
|
|
91
|
+
if (c->garbage || c->size > 2)
|
|
92
|
+
continue;
|
|
93
|
+
watch_clause (c);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
STOP (connect);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
void Internal::sort_watches () {
|
|
100
|
+
assert (watching ());
|
|
101
|
+
LOG ("sorting watches");
|
|
102
|
+
Watches saved;
|
|
103
|
+
for (auto lit : lits) {
|
|
104
|
+
Watches &ws = watches (lit);
|
|
105
|
+
|
|
106
|
+
const const_watch_iterator end = ws.end ();
|
|
107
|
+
watch_iterator j = ws.begin ();
|
|
108
|
+
const_watch_iterator i;
|
|
109
|
+
|
|
110
|
+
assert (saved.empty ());
|
|
111
|
+
|
|
112
|
+
for (i = j; i != end; i++) {
|
|
113
|
+
const Watch w = *i;
|
|
114
|
+
if (w.binary ())
|
|
115
|
+
*j++ = w;
|
|
116
|
+
else
|
|
117
|
+
saved.push_back (w);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
std::copy (saved.cbegin (), saved.cend (), j);
|
|
121
|
+
|
|
122
|
+
saved.clear ();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} // namespace CaDiCaL
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#ifndef _watch_hpp_INCLUDED
|
|
2
|
+
#define _watch_hpp_INCLUDED
|
|
3
|
+
|
|
4
|
+
#include <cassert>
|
|
5
|
+
#include <vector>
|
|
6
|
+
|
|
7
|
+
#include "clause.hpp"
|
|
8
|
+
|
|
9
|
+
namespace CaDiCaL {
|
|
10
|
+
|
|
11
|
+
// Watch lists for CDCL search. The blocking literal (see also comments
|
|
12
|
+
// related to 'propagate') is a must and thus combining that with a 64 bit
|
|
13
|
+
// pointer will give a 16 byte (8 byte aligned) structure anyhow, which
|
|
14
|
+
// means the additional 4 bytes for the size come for free. As alternative
|
|
15
|
+
// one could use a 32-bit reference instead of the pointer which would
|
|
16
|
+
// however limit the number of clauses to '2^32 - 1'. One would also need
|
|
17
|
+
// to use at least one more bit (either taken away from the variable space
|
|
18
|
+
// or the clauses) to denote whether the watch is binary.
|
|
19
|
+
|
|
20
|
+
// in fashion of Intel Sat 10.4230/LIPIcs.SAT.2022.8 we try to
|
|
21
|
+
// guarantee the following invariant:
|
|
22
|
+
// For both watches:
|
|
23
|
+
// if the watched literal is negatively assigned
|
|
24
|
+
// either it will be propagated in the future
|
|
25
|
+
// or the corresponding blocking literal is positively assigned
|
|
26
|
+
// and its level is smaller than the level of the watched literal
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
struct Clause;
|
|
30
|
+
|
|
31
|
+
struct Watch {
|
|
32
|
+
|
|
33
|
+
Clause *clause;
|
|
34
|
+
int blit;
|
|
35
|
+
int size;
|
|
36
|
+
|
|
37
|
+
Watch (int b, Clause *c) : clause (c), blit (b), size (c->size) {}
|
|
38
|
+
Watch (bool, int b, Clause *c) : clause (c), blit (b), size (2) {
|
|
39
|
+
assert (c->size == 2);
|
|
40
|
+
}
|
|
41
|
+
Watch () {}
|
|
42
|
+
|
|
43
|
+
bool binary () const { return size == 2; }
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
typedef vector<Watch> Watches; // of one literal
|
|
47
|
+
|
|
48
|
+
typedef Watches::iterator watch_iterator;
|
|
49
|
+
typedef Watches::const_iterator const_watch_iterator;
|
|
50
|
+
|
|
51
|
+
inline void remove_watch (Watches &ws, Clause *clause) {
|
|
52
|
+
const auto end = ws.end ();
|
|
53
|
+
auto i = ws.begin ();
|
|
54
|
+
for (auto j = i; j != end; j++) {
|
|
55
|
+
const Watch &w = *i++ = *j;
|
|
56
|
+
if (w.clause == clause)
|
|
57
|
+
i--;
|
|
58
|
+
}
|
|
59
|
+
assert (i + 1 == end);
|
|
60
|
+
ws.resize (i - ws.begin ());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// search for the clause and updates the size marked in the watch lists
|
|
64
|
+
inline void update_watch_size (Watches &ws, int blit, Clause *conflict) {
|
|
65
|
+
bool found = false;
|
|
66
|
+
const int size = conflict->size;
|
|
67
|
+
for (Watch &w : ws) {
|
|
68
|
+
if (w.clause == conflict)
|
|
69
|
+
w.size = size, w.blit = blit, found = true;
|
|
70
|
+
assert (w.clause->garbage || w.size == 2 || w.clause->size != 2);
|
|
71
|
+
}
|
|
72
|
+
assert (found), (void) found;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} // namespace CaDiCaL
|
|
76
|
+
|
|
77
|
+
#endif
|