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,990 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
/*------------------------------------------------------------------------*/
|
|
6
|
+
|
|
7
|
+
// Failed literal probing uses its own propagation and assignment
|
|
8
|
+
// functions. It further provides on-the-fly generation of hyper binary
|
|
9
|
+
// resolvents but only probes on roots of the binary implication graph. The
|
|
10
|
+
// search for failed literals is limited, but untried roots are kept until
|
|
11
|
+
// the next time 'probe' is called. Left over probes from the last attempt
|
|
12
|
+
// and new probes are tried until the limit is hit or all are tried.
|
|
13
|
+
|
|
14
|
+
/*------------------------------------------------------------------------*/
|
|
15
|
+
|
|
16
|
+
bool Internal::inprobing () {
|
|
17
|
+
if (!opts.inprobing)
|
|
18
|
+
return false;
|
|
19
|
+
if (!preprocessing && !opts.inprocessing)
|
|
20
|
+
return false;
|
|
21
|
+
if (preprocessing)
|
|
22
|
+
assert (lim.preprocessing);
|
|
23
|
+
if (stats.inprobingphases && last.inprobe.reductions == stats.reductions)
|
|
24
|
+
return false;
|
|
25
|
+
return lim.inprobe <= stats.conflicts;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/*------------------------------------------------------------------------*/
|
|
29
|
+
|
|
30
|
+
inline int Internal::get_parent_reason_literal (int lit) {
|
|
31
|
+
const int idx = vidx (lit);
|
|
32
|
+
int res = parents[idx];
|
|
33
|
+
if (lit < 0)
|
|
34
|
+
res = -res;
|
|
35
|
+
return res;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
inline void Internal::set_parent_reason_literal (int lit, int reason) {
|
|
39
|
+
const int idx = vidx (lit);
|
|
40
|
+
if (lit < 0)
|
|
41
|
+
reason = -reason;
|
|
42
|
+
parents[idx] = reason;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/*-----------------------------------------------------------------------*/
|
|
46
|
+
|
|
47
|
+
// for opts.probehbr=false we need to do a lot of extra work to remember the
|
|
48
|
+
// correct lrat_chains... This solution is also memory intensive I think
|
|
49
|
+
// all corresponding functions are guarded to only work with the right
|
|
50
|
+
// options so they can be called without checking for options
|
|
51
|
+
//
|
|
52
|
+
// call locally after failed_literal or backtracking
|
|
53
|
+
//
|
|
54
|
+
void Internal::clean_probehbr_lrat () {
|
|
55
|
+
if (!lrat || opts.probehbr)
|
|
56
|
+
return;
|
|
57
|
+
for (auto &field : probehbr_chains) {
|
|
58
|
+
for (auto &chain : field) {
|
|
59
|
+
chain.clear ();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// call globally before a probe round (or a lookahead round)
|
|
65
|
+
//
|
|
66
|
+
void Internal::init_probehbr_lrat () {
|
|
67
|
+
if (!lrat || opts.probehbr)
|
|
68
|
+
return;
|
|
69
|
+
const size_t size = 2 * (1 + (size_t) max_var);
|
|
70
|
+
probehbr_chains.resize (size);
|
|
71
|
+
for (size_t i = 0; i < size; i++) {
|
|
72
|
+
probehbr_chains[i].resize (size);
|
|
73
|
+
// commented because not needed... should be empty already
|
|
74
|
+
/*
|
|
75
|
+
for (size_t j = 0; j < size; j++) {
|
|
76
|
+
vector<int64_t> empty;
|
|
77
|
+
probehbr_chains[i][j] = empty;
|
|
78
|
+
}
|
|
79
|
+
*/
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// sets lrat_chain to the stored chain in probehbr_chains.
|
|
84
|
+
// this leads to conflict with unit reason uip
|
|
85
|
+
//
|
|
86
|
+
void Internal::get_probehbr_lrat (int lit, int uip) {
|
|
87
|
+
if (!lrat || opts.probehbr)
|
|
88
|
+
return;
|
|
89
|
+
assert (lit);
|
|
90
|
+
assert (lrat_chain.empty ());
|
|
91
|
+
assert (val (uip) < 0);
|
|
92
|
+
lrat_chain = probehbr_chains[vlit (lit)][vlit (uip)];
|
|
93
|
+
int64_t id = unit_id (-uip);
|
|
94
|
+
lrat_chain.push_back (id);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// sets the corresponding probehbr_chain to what is currently stored in
|
|
98
|
+
// lrat_chain. also clears lrat_chain.
|
|
99
|
+
//
|
|
100
|
+
void Internal::set_probehbr_lrat (int lit, int uip) {
|
|
101
|
+
if (!lrat || opts.probehbr)
|
|
102
|
+
return;
|
|
103
|
+
assert (lit);
|
|
104
|
+
assert (lrat_chain.size ());
|
|
105
|
+
assert (probehbr_chains[vlit (lit)][vlit (uip)].empty ());
|
|
106
|
+
probehbr_chains[vlit (lit)][vlit (uip)] = lrat_chain;
|
|
107
|
+
lrat_chain.clear ();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// compute lrat_chain for the part of the tree from lit to dom
|
|
111
|
+
// use mini_chain because it needs to be reversed
|
|
112
|
+
//
|
|
113
|
+
void Internal::probe_dominator_lrat (int dom, Clause *reason) {
|
|
114
|
+
if (!lrat || !dom)
|
|
115
|
+
return;
|
|
116
|
+
LOG (reason, "probe dominator LRAT for %d from", dom);
|
|
117
|
+
for (const auto lit : *reason) {
|
|
118
|
+
if (val (lit) >= 0)
|
|
119
|
+
continue;
|
|
120
|
+
const auto other = -lit;
|
|
121
|
+
if (other == dom)
|
|
122
|
+
continue;
|
|
123
|
+
Flags &f = flags (other);
|
|
124
|
+
if (f.seen)
|
|
125
|
+
continue;
|
|
126
|
+
f.seen = true;
|
|
127
|
+
analyzed.push_back (other);
|
|
128
|
+
Var u = var (other);
|
|
129
|
+
if (u.level) {
|
|
130
|
+
if (!u.reason) {
|
|
131
|
+
LOG ("this may be a problem %d", other);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
probe_dominator_lrat (dom, u.reason);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
int64_t id = unit_id (other);
|
|
138
|
+
lrat_chain.push_back (id);
|
|
139
|
+
}
|
|
140
|
+
lrat_chain.push_back (reason->id);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/*------------------------------------------------------------------------*/
|
|
144
|
+
|
|
145
|
+
// On-the-fly (dynamic) hyper binary resolution on decision level one can
|
|
146
|
+
// make use of the fact that the implication graph is actually a tree.
|
|
147
|
+
|
|
148
|
+
// Compute a dominator of two literals in the binary implication tree.
|
|
149
|
+
|
|
150
|
+
int Internal::probe_dominator (int a, int b) {
|
|
151
|
+
require_mode (PROBE);
|
|
152
|
+
int l = a, k = b;
|
|
153
|
+
Var *u = &var (l), *v = &var (k);
|
|
154
|
+
assert (val (l) > 0), assert (val (k) > 0);
|
|
155
|
+
assert (u->level == 1), assert (v->level == 1);
|
|
156
|
+
while (l != k) {
|
|
157
|
+
if (u->trail > v->trail)
|
|
158
|
+
swap (l, k), swap (u, v);
|
|
159
|
+
if (!get_parent_reason_literal (l))
|
|
160
|
+
return l;
|
|
161
|
+
int parent = get_parent_reason_literal (k);
|
|
162
|
+
assert (parent), assert (val (parent) > 0);
|
|
163
|
+
v = &var (k = parent);
|
|
164
|
+
assert (v->level == 1);
|
|
165
|
+
}
|
|
166
|
+
LOG ("dominator %d of %d and %d", l, a, b);
|
|
167
|
+
assert (val (l) > 0);
|
|
168
|
+
return l;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// The idea of dynamic on-the-fly hyper-binary resolution came up in the
|
|
172
|
+
// PrecoSAT solver, where it originally was used on all decision levels.
|
|
173
|
+
|
|
174
|
+
// It turned out, that most of the hyper-binary resolvents were generated
|
|
175
|
+
// during probing on decision level one anyhow. Thus this version is
|
|
176
|
+
// specialized to decision level one, where actually all long (non-binary)
|
|
177
|
+
// forcing clauses can be resolved to become binary. So if we find a clause
|
|
178
|
+
// which would force a new assignment at decision level one during probing
|
|
179
|
+
// we resolve it (the 'reason' argument) to obtain a hyper binary resolvent.
|
|
180
|
+
// It consists of the still unassigned literal (the new unit) and the
|
|
181
|
+
// negation of the unique closest dominator of the negation of all (false)
|
|
182
|
+
// literals in the clause (which has to exist on decision level one).
|
|
183
|
+
|
|
184
|
+
// There are two special cases which should be mentioned:
|
|
185
|
+
//
|
|
186
|
+
// (A) The reason is already a binary clause in a certain sense, since all
|
|
187
|
+
// its unwatched literals are root level fixed to false. In this
|
|
188
|
+
// situation it would be better to shrink the clause immediately instead
|
|
189
|
+
// of adding a new clause consisting only of the watched literals.
|
|
190
|
+
// However, this would happen during the next garbage collection anyhow.
|
|
191
|
+
//
|
|
192
|
+
// (B) The resolvent subsumes the original reason clause. This is
|
|
193
|
+
// equivalent to the property that the negated dominator is contained in
|
|
194
|
+
// the original reason. Again one could in principle shrink the clause.
|
|
195
|
+
//
|
|
196
|
+
// Note that (A) is actually subsumed by (B). The possible optimization to
|
|
197
|
+
// shrink the clause on-the-fly is difficult (need to update 'blit' and
|
|
198
|
+
// 'binary' of the other watch at least) and also not really that important.
|
|
199
|
+
// For (B) we simply add the new binary resolvent and mark the old subsumed
|
|
200
|
+
// clause as garbage instead. And since in the situation of (A) the
|
|
201
|
+
// shrinking will be performed at the next garbage collection anyhow, we
|
|
202
|
+
// do not change clauses in (A).
|
|
203
|
+
|
|
204
|
+
// The hyper binary resolvent clause is redundant unless it subsumes the
|
|
205
|
+
// original reason and that one is irredundant.
|
|
206
|
+
|
|
207
|
+
// If the option 'opts.probehbr' is 'false', we actually do not add the new
|
|
208
|
+
// hyper binary resolvent, but simply pretend we would have added it and
|
|
209
|
+
// still return the dominator as new reason / parent for the new unit.
|
|
210
|
+
|
|
211
|
+
// Finally note that adding clauses changes the watches of the propagated
|
|
212
|
+
// literal and thus we can not use standard iterators during probing but
|
|
213
|
+
// need to fall back to indices. One watch for the hyper binary resolvent
|
|
214
|
+
// clause is added at the end of the currently propagated watches, but its
|
|
215
|
+
// watch is a binary watch and will be skipped during propagating long
|
|
216
|
+
// clauses anyhow.
|
|
217
|
+
|
|
218
|
+
inline int Internal::hyper_binary_resolve (Clause *reason) {
|
|
219
|
+
require_mode (PROBE);
|
|
220
|
+
assert (level == 1);
|
|
221
|
+
assert (reason->size > 2);
|
|
222
|
+
const const_literal_iterator end = reason->end ();
|
|
223
|
+
const int *lits = reason->literals;
|
|
224
|
+
const_literal_iterator k;
|
|
225
|
+
#ifndef NDEBUG
|
|
226
|
+
// First literal unassigned, all others false.
|
|
227
|
+
assert (!val (lits[0]));
|
|
228
|
+
for (k = lits + 1; k != end; k++)
|
|
229
|
+
assert (val (*k) < 0);
|
|
230
|
+
assert (var (lits[1]).level == 1);
|
|
231
|
+
#endif
|
|
232
|
+
LOG (reason, "hyper binary resolving");
|
|
233
|
+
stats.hbrs++;
|
|
234
|
+
stats.hbrsizes += reason->size;
|
|
235
|
+
const int lit = lits[1];
|
|
236
|
+
int dom = -lit, non_root_level_literals = 0;
|
|
237
|
+
for (k = lits + 2; k != end; k++) {
|
|
238
|
+
const int other = -*k;
|
|
239
|
+
assert (val (other) > 0);
|
|
240
|
+
if (!var (other).level)
|
|
241
|
+
continue;
|
|
242
|
+
dom = probe_dominator (dom, other);
|
|
243
|
+
non_root_level_literals++;
|
|
244
|
+
}
|
|
245
|
+
probe_reason = reason;
|
|
246
|
+
if (non_root_level_literals && opts.probehbr) { // !(A)
|
|
247
|
+
bool contained = false;
|
|
248
|
+
for (k = lits + 1; !contained && k != end; k++)
|
|
249
|
+
contained = (*k == -dom);
|
|
250
|
+
const bool red = !contained || reason->redundant;
|
|
251
|
+
if (red)
|
|
252
|
+
stats.hbreds++;
|
|
253
|
+
LOG ("new %s hyper binary resolvent %d %d",
|
|
254
|
+
(red ? "redundant" : "irredundant"), -dom, lits[0]);
|
|
255
|
+
assert (clause.empty ());
|
|
256
|
+
clause.push_back (-dom);
|
|
257
|
+
clause.push_back (lits[0]);
|
|
258
|
+
probe_dominator_lrat (dom, reason);
|
|
259
|
+
if (lrat)
|
|
260
|
+
clear_analyzed_literals ();
|
|
261
|
+
Clause *c = new_hyper_binary_resolved_clause (red, 2);
|
|
262
|
+
probe_reason = c;
|
|
263
|
+
if (red)
|
|
264
|
+
c->hyper = true;
|
|
265
|
+
clause.clear ();
|
|
266
|
+
lrat_chain.clear ();
|
|
267
|
+
if (contained) {
|
|
268
|
+
stats.hbrsubs++;
|
|
269
|
+
LOG (reason, "subsumed original");
|
|
270
|
+
mark_garbage (reason);
|
|
271
|
+
}
|
|
272
|
+
} else if (non_root_level_literals && lrat) {
|
|
273
|
+
// still calculate LRAT and remember for later
|
|
274
|
+
assert (!opts.probehbr);
|
|
275
|
+
probe_dominator_lrat (dom, reason);
|
|
276
|
+
clear_analyzed_literals ();
|
|
277
|
+
set_probehbr_lrat (dom, lits[0]);
|
|
278
|
+
}
|
|
279
|
+
return dom;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/*------------------------------------------------------------------------*/
|
|
283
|
+
|
|
284
|
+
// The following functions 'probe_assign' and 'probe_propagate' are used for
|
|
285
|
+
// propagating during failed literal probing in simplification mode, as
|
|
286
|
+
// replacement of the generic propagation routine 'propagate' and
|
|
287
|
+
// 'search_assign'.
|
|
288
|
+
|
|
289
|
+
// The code is mostly copied from 'propagate.cpp' and specialized. We only
|
|
290
|
+
// comment on the differences. More explanations are in 'propagate.cpp'.
|
|
291
|
+
|
|
292
|
+
inline void Internal::probe_assign (int lit, int parent) {
|
|
293
|
+
require_mode (PROBE);
|
|
294
|
+
int idx = vidx (lit);
|
|
295
|
+
assert (!val (idx));
|
|
296
|
+
assert (!flags (idx).eliminated () || !parent);
|
|
297
|
+
assert (!parent || val (parent) > 0);
|
|
298
|
+
Var &v = var (idx);
|
|
299
|
+
v.level = level;
|
|
300
|
+
v.trail = (int) trail.size ();
|
|
301
|
+
assert ((int) num_assigned < max_var);
|
|
302
|
+
num_assigned++;
|
|
303
|
+
v.reason = level ? probe_reason : 0;
|
|
304
|
+
probe_reason = 0;
|
|
305
|
+
set_parent_reason_literal (lit, parent);
|
|
306
|
+
if (!level)
|
|
307
|
+
learn_unit_clause (lit);
|
|
308
|
+
else
|
|
309
|
+
assert (level == 1);
|
|
310
|
+
const signed char tmp = sign (lit);
|
|
311
|
+
set_val (idx, tmp);
|
|
312
|
+
assert (val (lit) > 0);
|
|
313
|
+
assert (val (-lit) < 0);
|
|
314
|
+
trail.push_back (lit);
|
|
315
|
+
|
|
316
|
+
// Do not save the current phase during inprocessing but remember the
|
|
317
|
+
// number of units on the trail of the last time this literal was
|
|
318
|
+
// assigned. This allows us to avoid some redundant failed literal
|
|
319
|
+
// probing attempts. Search for 'propfixed' in 'probe.cpp' for details.
|
|
320
|
+
//
|
|
321
|
+
if (level)
|
|
322
|
+
propfixed (lit) = stats.all.fixed;
|
|
323
|
+
|
|
324
|
+
if (parent)
|
|
325
|
+
LOG ("probe assign %d parent %d", lit, parent);
|
|
326
|
+
else if (level)
|
|
327
|
+
LOG ("probe assign %d probe", lit);
|
|
328
|
+
else
|
|
329
|
+
LOG ("probe assign %d negated failed literal UIP", lit);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
void Internal::probe_assign_decision (int lit) {
|
|
333
|
+
require_mode (PROBE);
|
|
334
|
+
assert (!level);
|
|
335
|
+
assert (propagated == trail.size ());
|
|
336
|
+
level++;
|
|
337
|
+
control.push_back (Level (lit, trail.size ()));
|
|
338
|
+
probe_assign (lit, 0);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
void Internal::probe_assign_unit (int lit) {
|
|
342
|
+
require_mode (PROBE);
|
|
343
|
+
assert (!level);
|
|
344
|
+
assert (active (lit));
|
|
345
|
+
probe_assign (lit, 0);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/*------------------------------------------------------------------------*/
|
|
349
|
+
|
|
350
|
+
// same as in propagate but inlined here
|
|
351
|
+
//
|
|
352
|
+
inline void Internal::probe_lrat_for_units (int lit) {
|
|
353
|
+
if (!lrat)
|
|
354
|
+
return;
|
|
355
|
+
if (level)
|
|
356
|
+
return; // not decision level 0
|
|
357
|
+
LOG ("building chain for units");
|
|
358
|
+
assert (lrat_chain.empty ());
|
|
359
|
+
assert (probe_reason);
|
|
360
|
+
for (auto &reason_lit : *probe_reason) {
|
|
361
|
+
if (lit == reason_lit)
|
|
362
|
+
continue;
|
|
363
|
+
assert (val (reason_lit));
|
|
364
|
+
if (!val (reason_lit))
|
|
365
|
+
continue;
|
|
366
|
+
const int signed_reason_lit = val (reason_lit) * reason_lit;
|
|
367
|
+
int64_t id = unit_id (signed_reason_lit);
|
|
368
|
+
lrat_chain.push_back (id);
|
|
369
|
+
}
|
|
370
|
+
lrat_chain.push_back (probe_reason->id);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/*------------------------------------------------------------------------*/
|
|
374
|
+
|
|
375
|
+
// This is essentially the same as 'propagate' except that we prioritize and
|
|
376
|
+
// always propagate binary clauses first (see our CPAIOR'13 paper on tree
|
|
377
|
+
// based look ahead), then immediately stop at a conflict and of course use
|
|
378
|
+
// 'probe_assign' instead of 'search_assign'. The binary propagation part
|
|
379
|
+
// is factored out too. If a new unit on decision level one is found we
|
|
380
|
+
// perform hyper binary resolution and thus actually build an implication
|
|
381
|
+
// tree instead of a DAG. Statistics counters are also different.
|
|
382
|
+
|
|
383
|
+
inline void Internal::probe_propagate2 () {
|
|
384
|
+
require_mode (PROBE);
|
|
385
|
+
int64_t &ticks = stats.ticks.probe;
|
|
386
|
+
while (propagated2 != trail.size ()) {
|
|
387
|
+
const int lit = -trail[propagated2++];
|
|
388
|
+
LOG ("probe propagating %d over binary clauses", -lit);
|
|
389
|
+
Watches &ws = watches (lit);
|
|
390
|
+
ticks += 1 + cache_lines (ws.size (), sizeof (const_watch_iterator *));
|
|
391
|
+
for (const auto &w : ws) {
|
|
392
|
+
if (!w.binary ())
|
|
393
|
+
continue;
|
|
394
|
+
const signed char b = val (w.blit);
|
|
395
|
+
if (b > 0)
|
|
396
|
+
continue;
|
|
397
|
+
ticks++;
|
|
398
|
+
if (b < 0)
|
|
399
|
+
conflict = w.clause; // but continue
|
|
400
|
+
else {
|
|
401
|
+
assert (lrat_chain.empty ());
|
|
402
|
+
assert (!probe_reason);
|
|
403
|
+
probe_reason = w.clause;
|
|
404
|
+
probe_lrat_for_units (w.blit);
|
|
405
|
+
probe_assign (w.blit, -lit);
|
|
406
|
+
lrat_chain.clear ();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
bool Internal::probe_propagate () {
|
|
413
|
+
require_mode (PROBE);
|
|
414
|
+
assert (!unsat);
|
|
415
|
+
START (propagate);
|
|
416
|
+
int64_t before = propagated2 = propagated;
|
|
417
|
+
int64_t &ticks = stats.ticks.probe;
|
|
418
|
+
while (!conflict) {
|
|
419
|
+
if (propagated2 != trail.size ())
|
|
420
|
+
probe_propagate2 ();
|
|
421
|
+
else if (propagated != trail.size ()) {
|
|
422
|
+
const int lit = -trail[propagated++];
|
|
423
|
+
LOG ("probe propagating %d over large clauses", -lit);
|
|
424
|
+
Watches &ws = watches (lit);
|
|
425
|
+
ticks +=
|
|
426
|
+
1 + cache_lines (ws.size (), sizeof (const_watch_iterator *));
|
|
427
|
+
size_t i = 0, j = 0;
|
|
428
|
+
while (i != ws.size ()) {
|
|
429
|
+
const Watch w = ws[j++] = ws[i++];
|
|
430
|
+
if (w.binary ())
|
|
431
|
+
continue;
|
|
432
|
+
const signed char b = val (w.blit);
|
|
433
|
+
if (b > 0)
|
|
434
|
+
continue;
|
|
435
|
+
ticks++;
|
|
436
|
+
if (w.clause->garbage)
|
|
437
|
+
continue;
|
|
438
|
+
const literal_iterator lits = w.clause->begin ();
|
|
439
|
+
const int other = lits[0] ^ lits[1] ^ lit;
|
|
440
|
+
// lits[0] = other, lits[1] = lit;
|
|
441
|
+
const signed char u = val (other);
|
|
442
|
+
if (u > 0)
|
|
443
|
+
ws[j - 1].blit = other;
|
|
444
|
+
else {
|
|
445
|
+
const int size = w.clause->size;
|
|
446
|
+
const const_literal_iterator end = lits + size;
|
|
447
|
+
const literal_iterator middle = lits + w.clause->pos;
|
|
448
|
+
literal_iterator k = middle;
|
|
449
|
+
int r = 0;
|
|
450
|
+
signed char v = -1;
|
|
451
|
+
while (k != end && (v = val (r = *k)) < 0)
|
|
452
|
+
k++;
|
|
453
|
+
if (v < 0) {
|
|
454
|
+
k = lits + 2;
|
|
455
|
+
assert (w.clause->pos <= size);
|
|
456
|
+
while (k != middle && (v = val (r = *k)) < 0)
|
|
457
|
+
k++;
|
|
458
|
+
}
|
|
459
|
+
w.clause->pos = k - lits;
|
|
460
|
+
assert (lits + 2 <= k), assert (k <= w.clause->end ());
|
|
461
|
+
if (v > 0)
|
|
462
|
+
ws[j - 1].blit = r;
|
|
463
|
+
else if (!v) {
|
|
464
|
+
ticks++;
|
|
465
|
+
LOG (w.clause, "unwatch %d in", r);
|
|
466
|
+
*k = lit;
|
|
467
|
+
lits[0] = other;
|
|
468
|
+
lits[1] = r;
|
|
469
|
+
watch_literal (r, lit, w.clause);
|
|
470
|
+
j--;
|
|
471
|
+
} else if (!u) {
|
|
472
|
+
ticks++;
|
|
473
|
+
if (level == 1) {
|
|
474
|
+
lits[0] = other, lits[1] = lit;
|
|
475
|
+
assert (lrat_chain.empty ());
|
|
476
|
+
assert (!probe_reason);
|
|
477
|
+
int dom = hyper_binary_resolve (w.clause);
|
|
478
|
+
probe_assign (other, dom);
|
|
479
|
+
} else {
|
|
480
|
+
ticks++;
|
|
481
|
+
assert (lrat_chain.empty ());
|
|
482
|
+
assert (!probe_reason);
|
|
483
|
+
probe_reason = w.clause;
|
|
484
|
+
probe_lrat_for_units (other);
|
|
485
|
+
probe_assign_unit (other);
|
|
486
|
+
lrat_chain.clear ();
|
|
487
|
+
}
|
|
488
|
+
probe_propagate2 ();
|
|
489
|
+
} else
|
|
490
|
+
conflict = w.clause;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (j != i) {
|
|
494
|
+
while (i != ws.size ())
|
|
495
|
+
ws[j++] = ws[i++];
|
|
496
|
+
ws.resize (j);
|
|
497
|
+
}
|
|
498
|
+
} else
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
int64_t delta = propagated2 - before;
|
|
502
|
+
stats.propagations.probe += delta;
|
|
503
|
+
if (conflict)
|
|
504
|
+
LOG (conflict, "conflict");
|
|
505
|
+
STOP (propagate);
|
|
506
|
+
return !conflict;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/*------------------------------------------------------------------------*/
|
|
510
|
+
|
|
511
|
+
// This a specialized instance of 'analyze'.
|
|
512
|
+
|
|
513
|
+
void Internal::failed_literal (int failed) {
|
|
514
|
+
|
|
515
|
+
LOG ("analyzing failed literal probe %d", failed);
|
|
516
|
+
stats.failed++;
|
|
517
|
+
stats.probefailed++;
|
|
518
|
+
|
|
519
|
+
assert (!unsat);
|
|
520
|
+
assert (conflict);
|
|
521
|
+
assert (level == 1);
|
|
522
|
+
assert (analyzed.empty ());
|
|
523
|
+
assert (lrat_chain.empty ());
|
|
524
|
+
|
|
525
|
+
START (analyze);
|
|
526
|
+
|
|
527
|
+
LOG (conflict, "analyzing failed literal conflict");
|
|
528
|
+
|
|
529
|
+
int uip = 0;
|
|
530
|
+
for (const auto &lit : *conflict) {
|
|
531
|
+
const int other = -lit;
|
|
532
|
+
if (!var (other).level) {
|
|
533
|
+
assert (val (other) > 0);
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
uip = uip ? probe_dominator (uip, other) : other;
|
|
537
|
+
}
|
|
538
|
+
probe_dominator_lrat (uip, conflict);
|
|
539
|
+
if (lrat)
|
|
540
|
+
clear_analyzed_literals ();
|
|
541
|
+
|
|
542
|
+
LOG ("found probing UIP %d", uip);
|
|
543
|
+
assert (uip);
|
|
544
|
+
|
|
545
|
+
vector<int> work;
|
|
546
|
+
|
|
547
|
+
int parent = uip;
|
|
548
|
+
while (parent != failed) {
|
|
549
|
+
const int next = get_parent_reason_literal (parent);
|
|
550
|
+
parent = next;
|
|
551
|
+
assert (parent);
|
|
552
|
+
work.push_back (parent);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
backtrack ();
|
|
556
|
+
conflict = 0;
|
|
557
|
+
|
|
558
|
+
assert (!val (uip));
|
|
559
|
+
probe_assign_unit (-uip);
|
|
560
|
+
lrat_chain.clear ();
|
|
561
|
+
|
|
562
|
+
if (!probe_propagate ())
|
|
563
|
+
learn_empty_clause ();
|
|
564
|
+
|
|
565
|
+
size_t j = 0;
|
|
566
|
+
while (!unsat && j < work.size ()) {
|
|
567
|
+
// assert (!opts.probehbr); assertion fails ...
|
|
568
|
+
const int parent = work[j++];
|
|
569
|
+
const signed char tmp = val (parent);
|
|
570
|
+
if (tmp > 0) {
|
|
571
|
+
assert (!opts.probehbr); // ... assertion should hold here
|
|
572
|
+
get_probehbr_lrat (parent, uip);
|
|
573
|
+
LOG ("clashing failed parent %d", parent);
|
|
574
|
+
learn_empty_clause ();
|
|
575
|
+
} else if (tmp == 0) {
|
|
576
|
+
assert (!opts.probehbr); // ... and here
|
|
577
|
+
LOG ("found unassigned failed parent %d", parent);
|
|
578
|
+
get_probehbr_lrat (parent, uip); // this is computed during
|
|
579
|
+
probe_assign_unit (-parent); // propagation and can include
|
|
580
|
+
lrat_chain.clear (); // multiple chains where only one
|
|
581
|
+
if (!probe_propagate ())
|
|
582
|
+
learn_empty_clause (); // is needed!
|
|
583
|
+
}
|
|
584
|
+
uip = parent;
|
|
585
|
+
}
|
|
586
|
+
work.clear ();
|
|
587
|
+
erase_vector (work);
|
|
588
|
+
|
|
589
|
+
STOP (analyze);
|
|
590
|
+
|
|
591
|
+
assert (unsat || val (failed) < 0);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/*------------------------------------------------------------------------*/
|
|
595
|
+
|
|
596
|
+
bool Internal::is_binary_clause (Clause *c, int &a, int &b) {
|
|
597
|
+
assert (!level);
|
|
598
|
+
if (c->garbage)
|
|
599
|
+
return false;
|
|
600
|
+
int first = 0, second = 0;
|
|
601
|
+
for (const auto &lit : *c) {
|
|
602
|
+
const signed char tmp = val (lit);
|
|
603
|
+
if (tmp > 0)
|
|
604
|
+
return false;
|
|
605
|
+
if (tmp < 0)
|
|
606
|
+
continue;
|
|
607
|
+
if (second)
|
|
608
|
+
return false;
|
|
609
|
+
if (first)
|
|
610
|
+
second = lit;
|
|
611
|
+
else
|
|
612
|
+
first = lit;
|
|
613
|
+
}
|
|
614
|
+
if (!second)
|
|
615
|
+
return false;
|
|
616
|
+
a = first, b = second;
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// We probe on literals first, which occur more often negated and thus we
|
|
621
|
+
// sort the 'probes' stack in such a way that literals which occur negated
|
|
622
|
+
// less frequently come first. Probes are taken from the back of the stack.
|
|
623
|
+
|
|
624
|
+
struct probe_negated_noccs_rank {
|
|
625
|
+
Internal *internal;
|
|
626
|
+
probe_negated_noccs_rank (Internal *i) : internal (i) {}
|
|
627
|
+
typedef size_t Type;
|
|
628
|
+
Type operator() (int a) const { return internal->noccs (-a); }
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
// Fill the 'probes' schedule.
|
|
632
|
+
|
|
633
|
+
void Internal::generate_probes () {
|
|
634
|
+
|
|
635
|
+
assert (probes.empty ());
|
|
636
|
+
|
|
637
|
+
int64_t &ticks = stats.ticks.probe;
|
|
638
|
+
|
|
639
|
+
// First determine all the literals which occur in binary clauses. It is
|
|
640
|
+
// way faster to go over the clauses once, instead of walking the watch
|
|
641
|
+
// lists for each literal.
|
|
642
|
+
//
|
|
643
|
+
init_noccs ();
|
|
644
|
+
ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *));
|
|
645
|
+
for (const auto &c : clauses) {
|
|
646
|
+
int a, b;
|
|
647
|
+
ticks++;
|
|
648
|
+
if (!is_binary_clause (c, a, b))
|
|
649
|
+
continue;
|
|
650
|
+
noccs (a)++;
|
|
651
|
+
noccs (b)++;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
for (auto idx : vars) {
|
|
655
|
+
|
|
656
|
+
// Then focus on roots of the binary implication graph, which are
|
|
657
|
+
// literals occurring negatively in a binary clause, but not positively.
|
|
658
|
+
// If neither 'idx' nor '-idx' is a root it makes less sense to probe
|
|
659
|
+
// this variable.
|
|
660
|
+
|
|
661
|
+
// This argument requires that equivalent literal substitution through
|
|
662
|
+
// 'decompose' is performed, because otherwise there might be 'cyclic
|
|
663
|
+
// roots' which are not tried, i.e., -1 2 0, 1 -2 0, 1 2 3 0, 1 2 -3 0.
|
|
664
|
+
|
|
665
|
+
ticks += 2;
|
|
666
|
+
|
|
667
|
+
const bool have_pos_bin_occs = noccs (idx) > 0;
|
|
668
|
+
const bool have_neg_bin_occs = noccs (-idx) > 0;
|
|
669
|
+
|
|
670
|
+
if (have_pos_bin_occs == have_neg_bin_occs)
|
|
671
|
+
continue;
|
|
672
|
+
|
|
673
|
+
int probe = have_neg_bin_occs ? idx : -idx;
|
|
674
|
+
|
|
675
|
+
// See the discussion where 'propfixed' is used below.
|
|
676
|
+
//
|
|
677
|
+
if (propfixed (probe) >= stats.all.fixed)
|
|
678
|
+
continue;
|
|
679
|
+
|
|
680
|
+
LOG ("scheduling probe %d negated occs %" PRId64 "", probe,
|
|
681
|
+
noccs (-probe));
|
|
682
|
+
probes.push_back (probe);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this));
|
|
686
|
+
|
|
687
|
+
reset_noccs ();
|
|
688
|
+
shrink_vector (probes);
|
|
689
|
+
|
|
690
|
+
PHASE ("probe-round", stats.probingrounds,
|
|
691
|
+
"scheduled %zd literals %.0f%%", probes.size (),
|
|
692
|
+
percent (probes.size (), 2u * max_var));
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Follow the ideas in 'generate_probes' but flush non root probes and
|
|
696
|
+
// reorder remaining probes.
|
|
697
|
+
|
|
698
|
+
void Internal::flush_probes () {
|
|
699
|
+
|
|
700
|
+
assert (!probes.empty ());
|
|
701
|
+
int64_t &ticks = stats.ticks.probe;
|
|
702
|
+
|
|
703
|
+
init_noccs ();
|
|
704
|
+
ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *));
|
|
705
|
+
for (const auto &c : clauses) {
|
|
706
|
+
int a, b;
|
|
707
|
+
ticks++;
|
|
708
|
+
if (!is_binary_clause (c, a, b))
|
|
709
|
+
continue;
|
|
710
|
+
noccs (a)++;
|
|
711
|
+
noccs (b)++;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const auto eop = probes.end ();
|
|
715
|
+
auto j = probes.begin ();
|
|
716
|
+
for (auto i = j; i != eop; i++) {
|
|
717
|
+
int lit = *i;
|
|
718
|
+
if (!active (lit))
|
|
719
|
+
continue;
|
|
720
|
+
ticks += 2;
|
|
721
|
+
const bool have_pos_bin_occs = noccs (lit) > 0;
|
|
722
|
+
const bool have_neg_bin_occs = noccs (-lit) > 0;
|
|
723
|
+
if (have_pos_bin_occs == have_neg_bin_occs)
|
|
724
|
+
continue;
|
|
725
|
+
if (have_pos_bin_occs)
|
|
726
|
+
lit = -lit;
|
|
727
|
+
assert (!noccs (lit)), assert (noccs (-lit) > 0);
|
|
728
|
+
if (propfixed (lit) >= stats.all.fixed)
|
|
729
|
+
continue;
|
|
730
|
+
LOG ("keeping probe %d negated occs %" PRId64 "", lit, noccs (-lit));
|
|
731
|
+
*j++ = lit;
|
|
732
|
+
}
|
|
733
|
+
size_t remain = j - probes.begin ();
|
|
734
|
+
#ifndef QUIET
|
|
735
|
+
size_t flushed = probes.size () - remain;
|
|
736
|
+
#endif
|
|
737
|
+
probes.resize (remain);
|
|
738
|
+
|
|
739
|
+
rsort (probes.begin (), probes.end (), probe_negated_noccs_rank (this));
|
|
740
|
+
|
|
741
|
+
reset_noccs ();
|
|
742
|
+
shrink_vector (probes);
|
|
743
|
+
|
|
744
|
+
PHASE ("probe-round", stats.probingrounds,
|
|
745
|
+
"flushed %zd literals %.0f%% remaining %zd", flushed,
|
|
746
|
+
percent (flushed, remain + flushed), remain);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
int Internal::next_probe () {
|
|
750
|
+
|
|
751
|
+
int generated = 0;
|
|
752
|
+
|
|
753
|
+
for (;;) {
|
|
754
|
+
|
|
755
|
+
if (probes.empty ()) {
|
|
756
|
+
if (generated++)
|
|
757
|
+
return 0;
|
|
758
|
+
generate_probes ();
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
while (!probes.empty ()) {
|
|
762
|
+
|
|
763
|
+
int probe = probes.back ();
|
|
764
|
+
probes.pop_back ();
|
|
765
|
+
|
|
766
|
+
// Eliminated or assigned.
|
|
767
|
+
//
|
|
768
|
+
if (!active (probe))
|
|
769
|
+
continue;
|
|
770
|
+
|
|
771
|
+
// There is now new unit since the last time we propagated this probe,
|
|
772
|
+
// thus we propagated it before without obtaining a conflict and
|
|
773
|
+
// nothing changed since then. Thus there is no need to propagate it
|
|
774
|
+
// again. This observation was independently made by Partik Simons
|
|
775
|
+
// et.al. in the context of implementing 'smodels' (see for instance
|
|
776
|
+
// Alg. 4 in his JAIR article from 2002) and it has also been
|
|
777
|
+
// contributed to the thesis work of Yacine Boufkhad.
|
|
778
|
+
//
|
|
779
|
+
if (propfixed (probe) >= stats.all.fixed)
|
|
780
|
+
continue;
|
|
781
|
+
|
|
782
|
+
return probe;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
bool Internal::probe () {
|
|
788
|
+
|
|
789
|
+
if (!opts.probe)
|
|
790
|
+
return false;
|
|
791
|
+
if (unsat)
|
|
792
|
+
return false;
|
|
793
|
+
if (terminated_asynchronously ())
|
|
794
|
+
return false;
|
|
795
|
+
|
|
796
|
+
SET_EFFORT_LIMIT (limit, probe, true);
|
|
797
|
+
|
|
798
|
+
START_SIMPLIFIER (probe, PROBE);
|
|
799
|
+
stats.probingrounds++;
|
|
800
|
+
|
|
801
|
+
// Probing is limited in terms of non-probing propagations
|
|
802
|
+
// 'stats.propagations'. We allow a certain percentage 'opts.probeeffort'
|
|
803
|
+
// (say %5) of probing propagations in each probing with a lower bound of
|
|
804
|
+
// 'opts.probmineff'.
|
|
805
|
+
//
|
|
806
|
+
|
|
807
|
+
PHASE ("probe-round", stats.probingrounds,
|
|
808
|
+
"probing limit of %" PRId64 " propagations ", limit);
|
|
809
|
+
|
|
810
|
+
int old_failed = stats.failed;
|
|
811
|
+
#ifndef QUIET
|
|
812
|
+
int64_t old_probed = stats.probed;
|
|
813
|
+
#endif
|
|
814
|
+
int64_t old_hbrs = stats.hbrs;
|
|
815
|
+
|
|
816
|
+
if (!probes.empty ())
|
|
817
|
+
flush_probes ();
|
|
818
|
+
|
|
819
|
+
// We reset 'propfixed' since there was at least another conflict thus
|
|
820
|
+
// a new learned clause, which might produce new propagations (and hyper
|
|
821
|
+
// binary resolvents). During 'generate_probes' we keep the old value.
|
|
822
|
+
//
|
|
823
|
+
for (auto idx : vars)
|
|
824
|
+
propfixed (idx) = propfixed (-idx) = -1;
|
|
825
|
+
|
|
826
|
+
assert (unsat || propagated == trail.size ());
|
|
827
|
+
propagated = propagated2 = trail.size ();
|
|
828
|
+
|
|
829
|
+
int probe;
|
|
830
|
+
init_probehbr_lrat ();
|
|
831
|
+
while (!unsat && !terminated_asynchronously () &&
|
|
832
|
+
stats.ticks.probe < limit && (probe = next_probe ())) {
|
|
833
|
+
stats.probed++;
|
|
834
|
+
LOG ("probing %d", probe);
|
|
835
|
+
probe_assign_decision (probe);
|
|
836
|
+
if (probe_propagate ())
|
|
837
|
+
backtrack_without_updating_phases ();
|
|
838
|
+
else
|
|
839
|
+
failed_literal (probe);
|
|
840
|
+
clean_probehbr_lrat ();
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if (unsat)
|
|
844
|
+
LOG ("probing derived empty clause");
|
|
845
|
+
else if (propagated < trail.size ()) {
|
|
846
|
+
LOG ("probing produced %zd units",
|
|
847
|
+
(size_t) (trail.size () - propagated));
|
|
848
|
+
if (!propagate ()) {
|
|
849
|
+
LOG ("propagating units after probing results in empty clause");
|
|
850
|
+
learn_empty_clause ();
|
|
851
|
+
} else
|
|
852
|
+
sort_watches ();
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
int failed = stats.failed - old_failed;
|
|
856
|
+
#ifndef QUIET
|
|
857
|
+
int64_t probed = stats.probed - old_probed;
|
|
858
|
+
#endif
|
|
859
|
+
int64_t hbrs = stats.hbrs - old_hbrs;
|
|
860
|
+
|
|
861
|
+
PHASE ("probe-round", stats.probingrounds,
|
|
862
|
+
"probed %" PRId64 " and found %d failed literals", probed, failed);
|
|
863
|
+
|
|
864
|
+
if (hbrs)
|
|
865
|
+
PHASE ("probe-round", stats.probingrounds,
|
|
866
|
+
"found %" PRId64 " hyper binary resolvents", hbrs);
|
|
867
|
+
|
|
868
|
+
STOP_SIMPLIFIER (probe, PROBE);
|
|
869
|
+
|
|
870
|
+
report ('p', !opts.reportall && !(unsat + failed + hbrs));
|
|
871
|
+
|
|
872
|
+
return !unsat && failed;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
/*------------------------------------------------------------------------*/
|
|
876
|
+
|
|
877
|
+
// This schedules a number of inprocessing techniques.
|
|
878
|
+
// These range from very cheap and beneficial (decompose) to
|
|
879
|
+
// more expensive and sometimes less beneficial. We want to limit
|
|
880
|
+
// expensive techniques to some fraction of total time or search time.
|
|
881
|
+
// this is done using 'ticks'.
|
|
882
|
+
// Generally, there are options for each of the techniques to set the
|
|
883
|
+
// efficiency, i.e., the fraction of ticks they are allowed as budget.
|
|
884
|
+
// Whenever e.g. vivify is called, the budget is calculated from the
|
|
885
|
+
// search ticks that have passed since the last vivify round and this
|
|
886
|
+
// efficiency.
|
|
887
|
+
// We want to be able to run inprocessing frequently, without it dominating
|
|
888
|
+
// runtimes. This entire inprocessing scheme is scheduled after a certain
|
|
889
|
+
// amount of conflicts were found, the gap between two inprocessing rounds
|
|
890
|
+
// increasing by a constant number each time. In effect, the number of
|
|
891
|
+
// inprocessing rounds is allways the square root of the number of conflicts
|
|
892
|
+
// with some constant factor.
|
|
893
|
+
// This factor can also be with the option 'inprobeint'
|
|
894
|
+
// Some of the techniques are not run always, for different reasons.
|
|
895
|
+
// 'factor' or BVA depends on certain structures of the irredundant clauses
|
|
896
|
+
// and as such will only be run when new irredundant clauses are derived or
|
|
897
|
+
// it was not able to finish with the entire search space.
|
|
898
|
+
// 'sweeping' is especially usefull on certain classes of formulas, and uses
|
|
899
|
+
// a increasing or decreasing delay that depends on how usefull it was.
|
|
900
|
+
// In cases where it is less usefull, we obviously want to reset the budged,
|
|
901
|
+
// even if the routine was delayed.
|
|
902
|
+
// Additionally 'vivify', 'sweep' and 'factor' can also have a big initial
|
|
903
|
+
// overhead in setting up the datastructures. This has to be accounted for
|
|
904
|
+
// with the 'ticks', however, since inprocessing is done frequently, this
|
|
905
|
+
// overhead is too expensive to pay. So instead, we accumulate the budget
|
|
906
|
+
// of 'ticks' and delay the technique until it passes a certain threshhold,
|
|
907
|
+
// which depends on the the cost of initialization. Note that in the case of
|
|
908
|
+
// sweeping, we have two different delays, one which resets the budged, and
|
|
909
|
+
// one which passes it to the next round. In this case the former takes
|
|
910
|
+
// precendent, until we would run sweeping once, at which point the focus
|
|
911
|
+
// switches to the latter delay until the budget is big enough, such that
|
|
912
|
+
// sweeping can be run. Then we switch back to the other delay.
|
|
913
|
+
|
|
914
|
+
void CaDiCaL::Internal::inprobe (bool update_limits) {
|
|
915
|
+
|
|
916
|
+
if (unsat)
|
|
917
|
+
return;
|
|
918
|
+
if (level)
|
|
919
|
+
backtrack ();
|
|
920
|
+
if (!propagate ()) {
|
|
921
|
+
learn_empty_clause ();
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
stats.inprobingphases++;
|
|
926
|
+
if (external_prop) {
|
|
927
|
+
assert (!level);
|
|
928
|
+
private_steps = true;
|
|
929
|
+
}
|
|
930
|
+
const int before = active ();
|
|
931
|
+
const int before_extended = stats.variables_extension;
|
|
932
|
+
|
|
933
|
+
// schedule of inprobing techniques.
|
|
934
|
+
//
|
|
935
|
+
{
|
|
936
|
+
mark_duplicated_binary_clauses_as_garbage ();
|
|
937
|
+
decompose ();
|
|
938
|
+
if (ternary ())
|
|
939
|
+
decompose (); // If we derived a binary clause
|
|
940
|
+
if (probe ())
|
|
941
|
+
decompose ();
|
|
942
|
+
|
|
943
|
+
if (extract_gates (preprocessing))
|
|
944
|
+
decompose ();
|
|
945
|
+
binary_clauses_backbone ();
|
|
946
|
+
mark_duplicated_binary_clauses_as_garbage ();
|
|
947
|
+
if (sweep ()) // full occurrence list
|
|
948
|
+
decompose (); // ... and (ELS) afterwards.
|
|
949
|
+
(void) vivify (); // resets watches
|
|
950
|
+
transred (); // builds big.
|
|
951
|
+
binary_clauses_backbone ();
|
|
952
|
+
factor (); // resets watches, partial occurrence list
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (external_prop) {
|
|
956
|
+
assert (!level);
|
|
957
|
+
private_steps = false;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
if (!update_limits)
|
|
961
|
+
return;
|
|
962
|
+
|
|
963
|
+
const int after = active ();
|
|
964
|
+
const int after_extended = stats.variables_extension;
|
|
965
|
+
const int diff_extended = after_extended - before_extended;
|
|
966
|
+
assert (diff_extended >= 0);
|
|
967
|
+
const int removed = before - after + diff_extended;
|
|
968
|
+
assert (removed >= 0);
|
|
969
|
+
|
|
970
|
+
if (removed) {
|
|
971
|
+
stats.inprobesuccess++;
|
|
972
|
+
PHASE ("probe-phase", stats.inprobingphases,
|
|
973
|
+
"successfully removed %d active variables %.0f%%", removed,
|
|
974
|
+
percent (removed, before));
|
|
975
|
+
} else
|
|
976
|
+
PHASE ("probe-phase", stats.inprobingphases,
|
|
977
|
+
"could not remove any active variable");
|
|
978
|
+
|
|
979
|
+
const int64_t delta =
|
|
980
|
+
25 * (int64_t) opts.inprobeint * log10 (stats.inprobingphases + 9);
|
|
981
|
+
lim.inprobe = stats.conflicts + delta;
|
|
982
|
+
|
|
983
|
+
PHASE ("probe-phase", stats.inprobingphases,
|
|
984
|
+
"new limit at %" PRId64 " conflicts after %" PRId64 " conflicts",
|
|
985
|
+
lim.inprobe, delta);
|
|
986
|
+
|
|
987
|
+
last.inprobe.reductions = stats.reductions;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
} // namespace CaDiCaL
|