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