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,738 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
|
|
3
|
+
namespace CaDiCaL {
|
|
4
|
+
|
|
5
|
+
void Internal::decompose_analyze_binary_chain (DFS *dfs, int from) {
|
|
6
|
+
if (!lrat)
|
|
7
|
+
return;
|
|
8
|
+
LOG ("binary chain starting at %d", from);
|
|
9
|
+
DFS &from_dfs = dfs[vlit (from)];
|
|
10
|
+
Clause *reason = from_dfs.parent;
|
|
11
|
+
if (!reason)
|
|
12
|
+
return;
|
|
13
|
+
assert (reason->size == 2);
|
|
14
|
+
mini_chain.push_back (reason->id);
|
|
15
|
+
int other = reason->literals[0];
|
|
16
|
+
other = other == from ? -reason->literals[1] : -other;
|
|
17
|
+
Flags &f = flags (other);
|
|
18
|
+
if (f.seen)
|
|
19
|
+
return;
|
|
20
|
+
f.seen = true;
|
|
21
|
+
analyzed.push_back (other);
|
|
22
|
+
decompose_analyze_binary_chain (dfs, other);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
vector<Clause *> Internal::decompose_analyze_binary_clauses (DFS *dfs,
|
|
26
|
+
int from) {
|
|
27
|
+
vector<Clause *> result;
|
|
28
|
+
LOG ("binary chain starting at %d", from);
|
|
29
|
+
DFS &from_dfs = dfs[vlit (from)];
|
|
30
|
+
Clause *reason = from_dfs.parent;
|
|
31
|
+
while (reason) {
|
|
32
|
+
result.push_back (reason);
|
|
33
|
+
assert (reason->size == 2);
|
|
34
|
+
int other = reason->literals[0];
|
|
35
|
+
other = other == from ? -reason->literals[1] : -other;
|
|
36
|
+
Flags &f = flags (other);
|
|
37
|
+
if (f.seen)
|
|
38
|
+
break;
|
|
39
|
+
f.seen = true;
|
|
40
|
+
analyzed.push_back (other);
|
|
41
|
+
from = other;
|
|
42
|
+
DFS &from_dfs = dfs[vlit (from)];
|
|
43
|
+
reason = from_dfs.parent;
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void Internal::decompose_conflicting_scc_lrat (DFS *dfs, vector<int> &scc) {
|
|
49
|
+
if (!lrat)
|
|
50
|
+
return;
|
|
51
|
+
assert (lrat_chain.empty ());
|
|
52
|
+
assert (mini_chain.empty ());
|
|
53
|
+
for (auto &lit : scc) {
|
|
54
|
+
Flags &f = flags (lit);
|
|
55
|
+
if (f.seen)
|
|
56
|
+
return;
|
|
57
|
+
f.seen = true;
|
|
58
|
+
analyzed.push_back (lit);
|
|
59
|
+
decompose_analyze_binary_chain (dfs, lit);
|
|
60
|
+
for (auto p = mini_chain.rbegin (); p != mini_chain.rend (); p++) {
|
|
61
|
+
lrat_chain.push_back (*p);
|
|
62
|
+
}
|
|
63
|
+
mini_chain.clear ();
|
|
64
|
+
}
|
|
65
|
+
clear_analyzed_literals ();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void Internal::build_lrat_for_clause (
|
|
69
|
+
const vector<vector<Clause *>> &dfs_chains, bool invert) {
|
|
70
|
+
assert (lrat);
|
|
71
|
+
LOG ("building chain for not subsumed clause");
|
|
72
|
+
assert (lrat_chain.empty ());
|
|
73
|
+
assert (sign_marked.empty ());
|
|
74
|
+
// build chain for each replaced literal
|
|
75
|
+
for (const auto lit : clause) {
|
|
76
|
+
auto other = lit;
|
|
77
|
+
if (val (other) > 0) {
|
|
78
|
+
if (marked_decomposed (other))
|
|
79
|
+
continue;
|
|
80
|
+
mark_decomposed (other);
|
|
81
|
+
int64_t id = unit_id (other);
|
|
82
|
+
lrat_chain.push_back (id);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
assert (mini_chain.empty ());
|
|
86
|
+
for (auto p : dfs_chains[vlit (other)]) {
|
|
87
|
+
if (marked_decomposed (other))
|
|
88
|
+
continue;
|
|
89
|
+
mark_decomposed (other);
|
|
90
|
+
int implied = p->literals[0];
|
|
91
|
+
implied = implied == other ? -p->literals[1] : -implied;
|
|
92
|
+
LOG ("ADDED %d -> %d (%" PRId64 ")", implied, other, p->id);
|
|
93
|
+
other = implied;
|
|
94
|
+
mini_chain.push_back (p->id);
|
|
95
|
+
if (val (implied) <= 0)
|
|
96
|
+
continue;
|
|
97
|
+
if (marked_decomposed (implied))
|
|
98
|
+
break;
|
|
99
|
+
mark_decomposed (implied);
|
|
100
|
+
int64_t id = unit_id (implied);
|
|
101
|
+
mini_chain.push_back (id);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
if (invert)
|
|
105
|
+
for (auto p = mini_chain.rbegin (); p != mini_chain.rend (); p++)
|
|
106
|
+
lrat_chain.push_back (*p);
|
|
107
|
+
else
|
|
108
|
+
for (auto p = mini_chain.begin (); p != mini_chain.end (); p++)
|
|
109
|
+
lrat_chain.push_back (*p);
|
|
110
|
+
mini_chain.clear ();
|
|
111
|
+
}
|
|
112
|
+
clear_sign_marked_literals ();
|
|
113
|
+
LOG (lrat_chain, "lrat_chain:");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void Internal::clear_sign_marked_literals () {
|
|
117
|
+
LOG ("clearing %zd marked literals", sign_marked.size ());
|
|
118
|
+
for (const auto &lit : sign_marked) {
|
|
119
|
+
// assert (marked_signed (lit)); violated on purpose in factor
|
|
120
|
+
unmark_decomposed (lit);
|
|
121
|
+
}
|
|
122
|
+
sign_marked.clear ();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// This performs one round of Tarjan's algorithm, e.g., equivalent literal
|
|
126
|
+
// detection and substitution, on the whole formula. We might want to
|
|
127
|
+
// repeat it since its application might produce new binary clauses or
|
|
128
|
+
// units. Such units might even result in an empty clause.
|
|
129
|
+
|
|
130
|
+
bool Internal::decompose_round () {
|
|
131
|
+
|
|
132
|
+
if (!opts.decompose)
|
|
133
|
+
return false;
|
|
134
|
+
if (unsat)
|
|
135
|
+
return false;
|
|
136
|
+
if (terminated_asynchronously ())
|
|
137
|
+
return false;
|
|
138
|
+
|
|
139
|
+
assert (!level);
|
|
140
|
+
|
|
141
|
+
START_SIMPLIFIER (decompose, DECOMP);
|
|
142
|
+
|
|
143
|
+
stats.decompositions++;
|
|
144
|
+
|
|
145
|
+
const size_t size_dfs = 2 * (1 + (size_t) max_var);
|
|
146
|
+
DFS *dfs = new DFS[size_dfs];
|
|
147
|
+
DeferDeleteArray<DFS> dfs_delete (dfs);
|
|
148
|
+
int *reprs = new int[size_dfs];
|
|
149
|
+
DeferDeleteArray<int> reprs_delete (reprs);
|
|
150
|
+
clear_n (reprs, size_dfs);
|
|
151
|
+
vector<vector<Clause *>> dfs_chains;
|
|
152
|
+
dfs_chains.resize (size_dfs);
|
|
153
|
+
if (lrat) {
|
|
154
|
+
for (size_t i = 0; i > size_dfs; i++) {
|
|
155
|
+
vector<Clause *> empty;
|
|
156
|
+
dfs_chains[i] = empty;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
int substituted = 0;
|
|
161
|
+
#ifndef QUIET
|
|
162
|
+
int non_trivial_sccs = 0;
|
|
163
|
+
int before = active ();
|
|
164
|
+
#endif
|
|
165
|
+
unsigned dfs_idx = 0;
|
|
166
|
+
|
|
167
|
+
vector<int> work; // depth first search working stack
|
|
168
|
+
vector<int> scc; // collects members of one SCC
|
|
169
|
+
|
|
170
|
+
// The binary implication graph might have disconnected components and
|
|
171
|
+
// thus we have in general to start several depth first searches.
|
|
172
|
+
|
|
173
|
+
for (auto root_idx : vars) {
|
|
174
|
+
if (unsat)
|
|
175
|
+
break;
|
|
176
|
+
if (!active (root_idx))
|
|
177
|
+
continue;
|
|
178
|
+
for (int root_sign = -1; !unsat && root_sign <= 1; root_sign += 2) {
|
|
179
|
+
int root = root_sign * root_idx;
|
|
180
|
+
if (dfs[vlit (root)].min == TRAVERSED)
|
|
181
|
+
continue; // skip traversed
|
|
182
|
+
LOG ("new dfs search starting at root %d", root);
|
|
183
|
+
assert (work.empty ());
|
|
184
|
+
assert (scc.empty ());
|
|
185
|
+
work.push_back (root);
|
|
186
|
+
while (!unsat && !work.empty ()) {
|
|
187
|
+
int parent = work.back ();
|
|
188
|
+
DFS &parent_dfs = dfs[vlit (parent)];
|
|
189
|
+
if (parent_dfs.min == TRAVERSED) { // skip traversed
|
|
190
|
+
assert (reprs[vlit (parent)]);
|
|
191
|
+
work.pop_back ();
|
|
192
|
+
} else {
|
|
193
|
+
assert (!reprs[vlit (parent)]);
|
|
194
|
+
|
|
195
|
+
// Go over all implied literals, thus need to iterate over all
|
|
196
|
+
// binary watched clauses with the negation of 'parent'.
|
|
197
|
+
|
|
198
|
+
Watches &ws = watches (-parent);
|
|
199
|
+
|
|
200
|
+
// Two cases: Either the node has never been visited before, i.e.,
|
|
201
|
+
// it's depth first search index is zero, then perform the
|
|
202
|
+
// 'pre-fix' work before visiting it's children. Otherwise all
|
|
203
|
+
// it's children and nodes reachable from those children have been
|
|
204
|
+
// visited and their minimum reachable depth first search index
|
|
205
|
+
// has been computed. This second case is the 'post-fix' work.
|
|
206
|
+
|
|
207
|
+
if (parent_dfs.idx) { // post-fix
|
|
208
|
+
|
|
209
|
+
work.pop_back (); // 'parent' done
|
|
210
|
+
|
|
211
|
+
// Get the minimum reachable depth first search index reachable
|
|
212
|
+
// from the children of 'parent'.
|
|
213
|
+
|
|
214
|
+
unsigned new_min = parent_dfs.min;
|
|
215
|
+
|
|
216
|
+
for (const auto &w : ws) {
|
|
217
|
+
if (!w.binary ())
|
|
218
|
+
continue;
|
|
219
|
+
const int child = w.blit;
|
|
220
|
+
if (!active (child))
|
|
221
|
+
continue;
|
|
222
|
+
DFS &child_dfs = dfs[vlit (child)];
|
|
223
|
+
if (new_min > child_dfs.min)
|
|
224
|
+
new_min = child_dfs.min;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
LOG ("post-fix work dfs search %d index %u reaches minimum %u",
|
|
228
|
+
parent, parent_dfs.idx, new_min);
|
|
229
|
+
|
|
230
|
+
if (parent_dfs.idx == new_min) { // entry to SCC
|
|
231
|
+
|
|
232
|
+
// All nodes on the 'scc' stack after and including 'parent'
|
|
233
|
+
// are in the same SCC. Their representative is computed as
|
|
234
|
+
// the smallest literal (index-wise) in the SCC. If the SCC
|
|
235
|
+
// contains both a literal and its negation, then the formula
|
|
236
|
+
// becomes unsatisfiable.
|
|
237
|
+
|
|
238
|
+
if (lrat) {
|
|
239
|
+
assert (analyzed.empty ());
|
|
240
|
+
int other, first = 0;
|
|
241
|
+
bool conflicting = false;
|
|
242
|
+
size_t j = scc.size ();
|
|
243
|
+
do {
|
|
244
|
+
assert (j > 0);
|
|
245
|
+
other = scc[--j];
|
|
246
|
+
if (!first || vlit (other) < vlit (first))
|
|
247
|
+
first = other;
|
|
248
|
+
Flags &f = flags (other);
|
|
249
|
+
if (other == -parent) {
|
|
250
|
+
conflicting = true; // conflicting scc
|
|
251
|
+
}
|
|
252
|
+
if (f.seen) {
|
|
253
|
+
continue; // also conflicting scc
|
|
254
|
+
}
|
|
255
|
+
f.seen = true;
|
|
256
|
+
analyzed.push_back (other);
|
|
257
|
+
} while (other != parent);
|
|
258
|
+
|
|
259
|
+
assert (!conflicting || first > 0);
|
|
260
|
+
vector<int> to_justify;
|
|
261
|
+
if (conflicting) {
|
|
262
|
+
LOG ("conflicting scc simulating up at %d", parent);
|
|
263
|
+
to_justify.push_back (-parent);
|
|
264
|
+
} else
|
|
265
|
+
to_justify.push_back (first);
|
|
266
|
+
while (!to_justify.empty ()) {
|
|
267
|
+
const int next = to_justify.back ();
|
|
268
|
+
to_justify.pop_back ();
|
|
269
|
+
Watches &next_ws = watches (-next);
|
|
270
|
+
for (const auto &w : next_ws) {
|
|
271
|
+
if (!w.binary ())
|
|
272
|
+
continue;
|
|
273
|
+
const int child = w.blit;
|
|
274
|
+
if (!active (child))
|
|
275
|
+
continue;
|
|
276
|
+
if (!flags (child).seen)
|
|
277
|
+
continue;
|
|
278
|
+
DFS &child_dfs = dfs[vlit (child)];
|
|
279
|
+
if (child_dfs.parent)
|
|
280
|
+
continue;
|
|
281
|
+
child_dfs.parent = w.clause;
|
|
282
|
+
to_justify.push_back (child);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
clear_analyzed_literals ();
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
int other, repr = parent;
|
|
290
|
+
#ifndef QUIET
|
|
291
|
+
int size = 0;
|
|
292
|
+
#endif
|
|
293
|
+
assert (!scc.empty ());
|
|
294
|
+
size_t j = scc.size ();
|
|
295
|
+
do {
|
|
296
|
+
assert (j > 0);
|
|
297
|
+
other = scc[--j];
|
|
298
|
+
if (other == -parent) {
|
|
299
|
+
LOG ("both %d and %d in one SCC", parent, -parent);
|
|
300
|
+
if (lrat) {
|
|
301
|
+
Flags &f = flags (-parent);
|
|
302
|
+
f.seen = true;
|
|
303
|
+
analyzed.push_back (-parent);
|
|
304
|
+
decompose_analyze_binary_chain (dfs, parent);
|
|
305
|
+
for (auto p : mini_chain)
|
|
306
|
+
lrat_chain.push_back (p);
|
|
307
|
+
mini_chain.clear ();
|
|
308
|
+
}
|
|
309
|
+
assign_unit (parent);
|
|
310
|
+
#ifndef NDEBUG
|
|
311
|
+
bool ok =
|
|
312
|
+
#endif
|
|
313
|
+
propagate ();
|
|
314
|
+
assert (!ok);
|
|
315
|
+
learn_empty_clause ();
|
|
316
|
+
lrat_chain.clear ();
|
|
317
|
+
} else {
|
|
318
|
+
if (abs (other) < abs (repr))
|
|
319
|
+
repr = other;
|
|
320
|
+
#ifndef QUIET
|
|
321
|
+
size++;
|
|
322
|
+
#endif
|
|
323
|
+
}
|
|
324
|
+
} while (!unsat && other != parent);
|
|
325
|
+
|
|
326
|
+
if (unsat)
|
|
327
|
+
break;
|
|
328
|
+
#ifndef QUIET
|
|
329
|
+
LOG ("SCC of representative %d of size %d", repr, size);
|
|
330
|
+
#endif
|
|
331
|
+
do {
|
|
332
|
+
assert (!scc.empty ());
|
|
333
|
+
other = scc.back ();
|
|
334
|
+
scc.pop_back ();
|
|
335
|
+
dfs[vlit (other)].min = TRAVERSED;
|
|
336
|
+
if (frozen (other)) {
|
|
337
|
+
reprs[vlit (other)] = other;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
reprs[vlit (other)] = repr;
|
|
341
|
+
if (other == repr)
|
|
342
|
+
continue;
|
|
343
|
+
substituted++;
|
|
344
|
+
LOG ("literal %d in SCC of %d", other, repr);
|
|
345
|
+
if (!lrat)
|
|
346
|
+
continue;
|
|
347
|
+
assert (mini_chain.empty ());
|
|
348
|
+
Flags &f = flags (repr);
|
|
349
|
+
f.seen = true;
|
|
350
|
+
analyzed.push_back (repr);
|
|
351
|
+
// no need to reverse dfs_chain because this is handled by
|
|
352
|
+
// build_lrat_for_clause.
|
|
353
|
+
dfs_chains[vlit (other)] =
|
|
354
|
+
decompose_analyze_binary_clauses (dfs, other);
|
|
355
|
+
clear_analyzed_literals ();
|
|
356
|
+
} while (other != parent);
|
|
357
|
+
|
|
358
|
+
#ifndef QUIET
|
|
359
|
+
if (size > 1)
|
|
360
|
+
non_trivial_sccs++;
|
|
361
|
+
#endif
|
|
362
|
+
|
|
363
|
+
} else {
|
|
364
|
+
|
|
365
|
+
// Current node 'parent' is in a non-trivial SCC but is not
|
|
366
|
+
// the entry point of the SCC in this depth first search, so
|
|
367
|
+
// keep it on the SCC stack until the entry point is reached.
|
|
368
|
+
|
|
369
|
+
parent_dfs.min = new_min;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
} else { // pre-fix
|
|
373
|
+
|
|
374
|
+
dfs_idx++;
|
|
375
|
+
assert (dfs_idx < TRAVERSED);
|
|
376
|
+
parent_dfs.idx = parent_dfs.min = dfs_idx;
|
|
377
|
+
scc.push_back (parent);
|
|
378
|
+
|
|
379
|
+
LOG ("pre-fix work dfs search %d index %u", parent, dfs_idx);
|
|
380
|
+
|
|
381
|
+
// Now traverse all the children in the binary implication
|
|
382
|
+
// graph but keep 'parent' on the stack for 'post-fix' work.
|
|
383
|
+
|
|
384
|
+
for (const auto &w : ws) {
|
|
385
|
+
if (!w.binary ())
|
|
386
|
+
continue;
|
|
387
|
+
const int child = w.blit;
|
|
388
|
+
if (!active (child))
|
|
389
|
+
continue;
|
|
390
|
+
DFS &child_dfs = dfs[vlit (child)];
|
|
391
|
+
if (child_dfs.idx)
|
|
392
|
+
continue;
|
|
393
|
+
work.push_back (child);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
erase_vector (work);
|
|
402
|
+
erase_vector (scc);
|
|
403
|
+
// delete [] dfs; need to postpone until after changing clauses...
|
|
404
|
+
|
|
405
|
+
// Only keep the representatives 'repr' mapping.
|
|
406
|
+
|
|
407
|
+
PHASE ("decompose", stats.decompositions,
|
|
408
|
+
"%d non-trivial sccs, %d substituted %.2f%%", non_trivial_sccs,
|
|
409
|
+
substituted, percent (substituted, before));
|
|
410
|
+
|
|
411
|
+
bool new_unit = false, new_binary_clause = false;
|
|
412
|
+
|
|
413
|
+
// Finally, mark substituted literals as such and push the equivalences of
|
|
414
|
+
// the substituted literals to their representative on the extension
|
|
415
|
+
// stack to fix an assignment during 'extend'.
|
|
416
|
+
// It is also necessary to do so for proper IDRUP/LIDRUP/Resolution proofs
|
|
417
|
+
|
|
418
|
+
vector<int64_t> decompose_ids;
|
|
419
|
+
const size_t size = 2 * (1 + (size_t) max_var);
|
|
420
|
+
decompose_ids.resize (size);
|
|
421
|
+
|
|
422
|
+
for (auto idx : vars) {
|
|
423
|
+
if (!substituted)
|
|
424
|
+
break;
|
|
425
|
+
if (unsat)
|
|
426
|
+
break;
|
|
427
|
+
if (!active (idx))
|
|
428
|
+
continue;
|
|
429
|
+
int other = reprs[vlit (idx)];
|
|
430
|
+
if (other == idx)
|
|
431
|
+
continue;
|
|
432
|
+
assert (!flags (other).eliminated ());
|
|
433
|
+
assert (!flags (other).substituted ());
|
|
434
|
+
|
|
435
|
+
LOG ("marking equivalence of %d and %d", idx, other);
|
|
436
|
+
assert (clause.empty ());
|
|
437
|
+
assert (lrat_chain.empty ());
|
|
438
|
+
clause.push_back (other);
|
|
439
|
+
clause.push_back (-idx);
|
|
440
|
+
if (lrat) {
|
|
441
|
+
build_lrat_for_clause (dfs_chains);
|
|
442
|
+
assert (!lrat_chain.empty ());
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const int64_t id1 = ++clause_id;
|
|
446
|
+
if (proof) {
|
|
447
|
+
proof->add_derived_clause (id1, false, clause, lrat_chain);
|
|
448
|
+
proof->weaken_minus (id1, clause);
|
|
449
|
+
}
|
|
450
|
+
external->push_binary_clause_on_extension_stack (id1, -idx, other);
|
|
451
|
+
|
|
452
|
+
decompose_ids[vlit (-idx)] = id1;
|
|
453
|
+
|
|
454
|
+
lrat_chain.clear ();
|
|
455
|
+
clause.clear ();
|
|
456
|
+
|
|
457
|
+
assert (clause.empty ());
|
|
458
|
+
assert (lrat_chain.empty ());
|
|
459
|
+
clause.push_back (idx);
|
|
460
|
+
clause.push_back (-other);
|
|
461
|
+
if (lrat) {
|
|
462
|
+
build_lrat_for_clause (dfs_chains);
|
|
463
|
+
assert (!lrat_chain.empty ());
|
|
464
|
+
}
|
|
465
|
+
const int64_t id2 = ++clause_id;
|
|
466
|
+
if (proof) {
|
|
467
|
+
proof->add_derived_clause (id2, false, clause, lrat_chain);
|
|
468
|
+
proof->weaken_minus (id2, clause);
|
|
469
|
+
}
|
|
470
|
+
external->push_binary_clause_on_extension_stack (id2, idx, -other);
|
|
471
|
+
decompose_ids[vlit (idx)] = id2;
|
|
472
|
+
for (auto &tracer : tracers) {
|
|
473
|
+
const int eidx = externalize (idx);
|
|
474
|
+
const int eother = externalize (other);
|
|
475
|
+
tracer->notify_equivalence (eidx, eother);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
clause.clear ();
|
|
479
|
+
lrat_chain.clear ();
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
vector<Clause *> postponed_garbage;
|
|
483
|
+
|
|
484
|
+
// Now go over all clauses and find clause which contain literals that
|
|
485
|
+
// should be substituted by their representative.
|
|
486
|
+
|
|
487
|
+
size_t clauses_size = clauses.size ();
|
|
488
|
+
#ifndef QUIET
|
|
489
|
+
size_t garbage = 0, replaced = 0;
|
|
490
|
+
#endif
|
|
491
|
+
for (size_t i = 0; substituted && !unsat && i < clauses_size; i++) {
|
|
492
|
+
Clause *c = clauses[i];
|
|
493
|
+
if (c->garbage)
|
|
494
|
+
continue;
|
|
495
|
+
int j, size = c->size;
|
|
496
|
+
for (j = 0; j < size; j++) {
|
|
497
|
+
const int lit = c->literals[j];
|
|
498
|
+
if (reprs[vlit (lit)] != lit)
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (j == size)
|
|
503
|
+
continue;
|
|
504
|
+
|
|
505
|
+
#ifndef QUIET
|
|
506
|
+
replaced++;
|
|
507
|
+
#endif
|
|
508
|
+
LOG (c, "first substituted literal %d in", substituted);
|
|
509
|
+
|
|
510
|
+
// Now copy the result to 'clause'. Substitute literals if they have a
|
|
511
|
+
// different representative. Skip duplicates and false literals. If a
|
|
512
|
+
// literal occurs in both phases or is assigned to true the clause is
|
|
513
|
+
// satisfied and can be marked as garbage.
|
|
514
|
+
|
|
515
|
+
assert (clause.empty ());
|
|
516
|
+
assert (lrat_chain.empty ());
|
|
517
|
+
assert (analyzed.empty ());
|
|
518
|
+
bool satisfied = false;
|
|
519
|
+
|
|
520
|
+
for (int k = 0; !satisfied && k < size; k++) {
|
|
521
|
+
const int lit = c->literals[k];
|
|
522
|
+
signed char tmp = val (lit);
|
|
523
|
+
if (tmp > 0)
|
|
524
|
+
satisfied = true;
|
|
525
|
+
else if (tmp < 0) {
|
|
526
|
+
if (!lrat)
|
|
527
|
+
continue;
|
|
528
|
+
Flags &f = flags (lit);
|
|
529
|
+
if (f.seen)
|
|
530
|
+
continue;
|
|
531
|
+
f.seen = true;
|
|
532
|
+
analyzed.push_back (lit);
|
|
533
|
+
int64_t id = unit_id (-lit);
|
|
534
|
+
lrat_chain.push_back (id);
|
|
535
|
+
continue;
|
|
536
|
+
} else {
|
|
537
|
+
const int other = reprs[vlit (lit)];
|
|
538
|
+
tmp = val (other);
|
|
539
|
+
if (tmp < 0) {
|
|
540
|
+
if (!lrat)
|
|
541
|
+
continue;
|
|
542
|
+
Flags &f = flags (other);
|
|
543
|
+
if (!f.seen) {
|
|
544
|
+
f.seen = true;
|
|
545
|
+
analyzed.push_back (other);
|
|
546
|
+
int64_t id = unit_id (-other);
|
|
547
|
+
lrat_chain.push_back (id);
|
|
548
|
+
}
|
|
549
|
+
if (other == lit)
|
|
550
|
+
continue;
|
|
551
|
+
int64_t id = decompose_ids[vlit (-lit)];
|
|
552
|
+
assert (id);
|
|
553
|
+
lrat_chain.push_back (id);
|
|
554
|
+
continue;
|
|
555
|
+
} else if (tmp > 0)
|
|
556
|
+
satisfied = true;
|
|
557
|
+
else {
|
|
558
|
+
tmp = marked (other);
|
|
559
|
+
if (tmp < 0)
|
|
560
|
+
satisfied = true;
|
|
561
|
+
else if (!tmp) {
|
|
562
|
+
mark (other);
|
|
563
|
+
clause.push_back (other);
|
|
564
|
+
}
|
|
565
|
+
if (other == lit)
|
|
566
|
+
continue;
|
|
567
|
+
if (!lrat)
|
|
568
|
+
continue;
|
|
569
|
+
int64_t id = decompose_ids[vlit (-lit)];
|
|
570
|
+
assert (id);
|
|
571
|
+
lrat_chain.push_back (id);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (lrat)
|
|
576
|
+
lrat_chain.push_back (c->id);
|
|
577
|
+
clear_analyzed_literals ();
|
|
578
|
+
LOG (lrat_chain, "lrat_chain:");
|
|
579
|
+
if (satisfied) {
|
|
580
|
+
LOG (c, "satisfied after substitution (postponed)");
|
|
581
|
+
postponed_garbage.push_back (c);
|
|
582
|
+
#ifndef QUIET
|
|
583
|
+
garbage++;
|
|
584
|
+
#endif
|
|
585
|
+
} else if (!clause.size ()) {
|
|
586
|
+
LOG ("learned empty clause during decompose");
|
|
587
|
+
learn_empty_clause ();
|
|
588
|
+
} else if (clause.size () == 1) {
|
|
589
|
+
LOG (c, "unit %d after substitution", clause[0]);
|
|
590
|
+
assign_unit (clause[0]);
|
|
591
|
+
mark_garbage (c);
|
|
592
|
+
new_unit = true;
|
|
593
|
+
#ifndef QUIET
|
|
594
|
+
garbage++;
|
|
595
|
+
#endif
|
|
596
|
+
} else if (c->literals[0] != clause[0] || c->literals[1] != clause[1]) {
|
|
597
|
+
LOG ("need new clause since at least one watched literal changed");
|
|
598
|
+
if (clause.size () == 2)
|
|
599
|
+
new_binary_clause = true;
|
|
600
|
+
size_t d_clause_idx = clauses.size ();
|
|
601
|
+
Clause *d = new_clause_as (c);
|
|
602
|
+
assert (clauses[d_clause_idx] == d);
|
|
603
|
+
clauses[d_clause_idx] = c;
|
|
604
|
+
clauses[i] = d;
|
|
605
|
+
mark_garbage (c);
|
|
606
|
+
#ifndef QUIET
|
|
607
|
+
garbage++;
|
|
608
|
+
#endif
|
|
609
|
+
} else {
|
|
610
|
+
LOG ("simply shrinking clause since watches did not change");
|
|
611
|
+
assert (c->size > 2);
|
|
612
|
+
if (!c->redundant)
|
|
613
|
+
mark_removed (c);
|
|
614
|
+
if (proof) {
|
|
615
|
+
proof->add_derived_clause (++clause_id, c->redundant, clause,
|
|
616
|
+
lrat_chain);
|
|
617
|
+
proof->delete_clause (c);
|
|
618
|
+
c->id = clause_id;
|
|
619
|
+
}
|
|
620
|
+
size_t l;
|
|
621
|
+
int *literals = c->literals;
|
|
622
|
+
for (l = 2; l < clause.size (); l++)
|
|
623
|
+
literals[l] = clause[l];
|
|
624
|
+
int flushed = c->size - (int) l;
|
|
625
|
+
if (flushed) {
|
|
626
|
+
if (l == 2)
|
|
627
|
+
new_binary_clause = true;
|
|
628
|
+
LOG ("flushed %d literals", flushed);
|
|
629
|
+
(void) shrink_clause (c, l);
|
|
630
|
+
} else if (likely_to_be_kept_clause (c))
|
|
631
|
+
mark_added (c);
|
|
632
|
+
// we have shrunken c->size to l so even though there is an assertion
|
|
633
|
+
// for c->size > 2 at the beginning of this else block, the new size
|
|
634
|
+
// can be 2 now.
|
|
635
|
+
if (c->size == 2) { // cheaper to update only new binary clauses
|
|
636
|
+
assert (new_binary_clause);
|
|
637
|
+
update_watch_size (watches (c->literals[0]), c->literals[1], c);
|
|
638
|
+
update_watch_size (watches (c->literals[1]), c->literals[0], c);
|
|
639
|
+
}
|
|
640
|
+
LOG (c, "substituted");
|
|
641
|
+
}
|
|
642
|
+
while (!clause.empty ()) {
|
|
643
|
+
int lit = clause.back ();
|
|
644
|
+
clause.pop_back ();
|
|
645
|
+
assert (marked (lit) > 0);
|
|
646
|
+
unmark (lit);
|
|
647
|
+
}
|
|
648
|
+
lrat_chain.clear ();
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (proof) {
|
|
652
|
+
for (auto idx : vars) {
|
|
653
|
+
if (!substituted)
|
|
654
|
+
break;
|
|
655
|
+
if (!active (idx))
|
|
656
|
+
continue;
|
|
657
|
+
const int64_t id1 = decompose_ids[vlit (-idx)];
|
|
658
|
+
if (!id1)
|
|
659
|
+
continue;
|
|
660
|
+
int other = reprs[vlit (idx)];
|
|
661
|
+
assert (other != idx);
|
|
662
|
+
assert (!flags (other).eliminated ());
|
|
663
|
+
assert (!flags (other).substituted ());
|
|
664
|
+
|
|
665
|
+
clause.push_back (other);
|
|
666
|
+
clause.push_back (-idx);
|
|
667
|
+
proof->delete_clause (id1, false, clause);
|
|
668
|
+
clause.clear ();
|
|
669
|
+
|
|
670
|
+
clause.push_back (idx);
|
|
671
|
+
clause.push_back (-other);
|
|
672
|
+
const int64_t id2 = decompose_ids[vlit (idx)];
|
|
673
|
+
proof->delete_clause (id2, false, clause);
|
|
674
|
+
clause.clear ();
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (!unsat && !postponed_garbage.empty ()) {
|
|
679
|
+
LOG ("now marking %zd postponed garbage clauses",
|
|
680
|
+
postponed_garbage.size ());
|
|
681
|
+
for (const auto &c : postponed_garbage)
|
|
682
|
+
mark_garbage (c);
|
|
683
|
+
}
|
|
684
|
+
erase_vector (postponed_garbage);
|
|
685
|
+
|
|
686
|
+
PHASE ("decompose", stats.decompositions,
|
|
687
|
+
"%zd clauses replaced %.2f%% producing %zd garbage clauses %.2f%%",
|
|
688
|
+
replaced, percent (replaced, clauses_size), garbage,
|
|
689
|
+
percent (garbage, replaced));
|
|
690
|
+
|
|
691
|
+
erase_vector (scc);
|
|
692
|
+
|
|
693
|
+
// Propagate found units.
|
|
694
|
+
|
|
695
|
+
if (!unsat && propagated < trail.size () && !propagate ()) {
|
|
696
|
+
LOG ("empty clause after propagating units from substitution");
|
|
697
|
+
learn_empty_clause ();
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
for (auto idx : vars) {
|
|
701
|
+
if (!substituted)
|
|
702
|
+
break;
|
|
703
|
+
if (unsat)
|
|
704
|
+
break;
|
|
705
|
+
if (!active (idx))
|
|
706
|
+
continue;
|
|
707
|
+
int other = reprs[vlit (idx)];
|
|
708
|
+
if (other == idx)
|
|
709
|
+
continue;
|
|
710
|
+
assert (!flags (other).eliminated ());
|
|
711
|
+
assert (!flags (other).substituted ());
|
|
712
|
+
if (!flags (other).fixed ())
|
|
713
|
+
mark_substituted (idx);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
reprs_delete.free ();
|
|
717
|
+
dfs_delete.free ();
|
|
718
|
+
erase_vector (dfs_chains);
|
|
719
|
+
|
|
720
|
+
if (substituted)
|
|
721
|
+
flush_all_occs_and_watches (); // particularly the 'blit's
|
|
722
|
+
|
|
723
|
+
bool success =
|
|
724
|
+
unsat || (substituted > 0 && (new_unit || new_binary_clause));
|
|
725
|
+
report ('d', !opts.reportall && !success);
|
|
726
|
+
|
|
727
|
+
STOP_SIMPLIFIER (decompose, DECOMP);
|
|
728
|
+
|
|
729
|
+
return success;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
void Internal::decompose () {
|
|
733
|
+
for (int round = 1; round <= opts.decomposerounds; round++)
|
|
734
|
+
if (!decompose_round ())
|
|
735
|
+
break;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
} // namespace CaDiCaL
|