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,1034 @@
|
|
|
1
|
+
#include "internal.hpp"
|
|
2
|
+
#include "util.hpp"
|
|
3
|
+
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
|
|
6
|
+
namespace CaDiCaL {
|
|
7
|
+
|
|
8
|
+
External::External (Internal *i)
|
|
9
|
+
: internal (i), max_var (0), vsize (0), extended (false),
|
|
10
|
+
concluded (false), terminator (0), learner (0), fixed_listener (0),
|
|
11
|
+
propagator (0), solution (0), vars (max_var) {
|
|
12
|
+
assert (internal);
|
|
13
|
+
assert (!internal->external);
|
|
14
|
+
internal->external = this;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
External::~External () {
|
|
18
|
+
if (solution)
|
|
19
|
+
delete[] solution;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void External::enlarge (int new_max_var) {
|
|
23
|
+
|
|
24
|
+
assert (!extended);
|
|
25
|
+
|
|
26
|
+
size_t new_vsize = vsize ? 2 * vsize : 1 + (size_t) new_max_var;
|
|
27
|
+
while (new_vsize <= (size_t) new_max_var)
|
|
28
|
+
new_vsize *= 2;
|
|
29
|
+
LOG ("enlarge external size from %zd to new size %zd", vsize, new_vsize);
|
|
30
|
+
vsize = new_vsize;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void External::init (int new_max_var, bool extension) {
|
|
34
|
+
assert (!extended);
|
|
35
|
+
if (new_max_var <= max_var)
|
|
36
|
+
return;
|
|
37
|
+
int new_vars = new_max_var - max_var;
|
|
38
|
+
int old_internal_max_var = internal->max_var;
|
|
39
|
+
int new_internal_max_var = old_internal_max_var + new_vars;
|
|
40
|
+
internal->init_vars (new_internal_max_var);
|
|
41
|
+
if ((size_t) new_max_var >= vsize)
|
|
42
|
+
enlarge (new_max_var);
|
|
43
|
+
LOG ("initialized %d external variables", new_vars);
|
|
44
|
+
reserve_at_least (ext_units, 2 * new_max_var + 2);
|
|
45
|
+
reserve_at_least (e2i, new_max_var + 1);
|
|
46
|
+
reserve_at_least (ervars, new_max_var + 1);
|
|
47
|
+
reserve_at_least (ext_flags, new_max_var + 1);
|
|
48
|
+
reserve_at_least (internal->i2e, new_max_var + 1);
|
|
49
|
+
if (!max_var) {
|
|
50
|
+
assert (e2i.empty ());
|
|
51
|
+
e2i.push_back (0);
|
|
52
|
+
ext_units.push_back (0);
|
|
53
|
+
ext_units.push_back (0);
|
|
54
|
+
ext_flags.push_back (0);
|
|
55
|
+
ervars.push_back (0);
|
|
56
|
+
assert (internal->i2e.empty ());
|
|
57
|
+
internal->i2e.push_back (0);
|
|
58
|
+
} else {
|
|
59
|
+
assert (e2i.size () == (size_t) max_var + 1);
|
|
60
|
+
assert (internal->i2e.size () == (size_t) old_internal_max_var + 1);
|
|
61
|
+
}
|
|
62
|
+
unsigned iidx = old_internal_max_var + 1, eidx;
|
|
63
|
+
for (eidx = max_var + 1u; eidx <= (unsigned) new_max_var;
|
|
64
|
+
eidx++, iidx++) {
|
|
65
|
+
LOG ("mapping external %u to internal %u", eidx, iidx);
|
|
66
|
+
assert (e2i.size () == eidx);
|
|
67
|
+
e2i.push_back (iidx);
|
|
68
|
+
ext_units.push_back (0);
|
|
69
|
+
ext_units.push_back (0);
|
|
70
|
+
ext_flags.push_back (0);
|
|
71
|
+
ervars.push_back (0);
|
|
72
|
+
internal->i2e.push_back (eidx);
|
|
73
|
+
assert (internal->i2e[iidx] == (int) eidx);
|
|
74
|
+
assert (e2i[eidx] == (int) iidx);
|
|
75
|
+
}
|
|
76
|
+
if (extension)
|
|
77
|
+
internal->stats.variables_extension += new_vars;
|
|
78
|
+
else
|
|
79
|
+
internal->stats.variables_original += new_vars;
|
|
80
|
+
if (internal->opts.checkfrozen)
|
|
81
|
+
if (new_max_var >= (int64_t) moltentab.size ())
|
|
82
|
+
moltentab.resize (1 + (size_t) new_max_var, false);
|
|
83
|
+
assert (iidx == (size_t) new_internal_max_var + 1);
|
|
84
|
+
assert (eidx == (size_t) new_max_var + 1);
|
|
85
|
+
assert (ext_units.size () == (size_t) new_max_var * 2 + 2);
|
|
86
|
+
max_var = new_max_var;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*------------------------------------------------------------------------*/
|
|
90
|
+
|
|
91
|
+
void External::reset_assumptions () {
|
|
92
|
+
assumptions.clear ();
|
|
93
|
+
internal->reset_assumptions ();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void External::reset_concluded () {
|
|
97
|
+
concluded = false;
|
|
98
|
+
internal->reset_concluded ();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void External::reset_constraint () {
|
|
102
|
+
constraint.clear ();
|
|
103
|
+
internal->reset_constraint ();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
void External::reset_extended () {
|
|
107
|
+
if (!extended)
|
|
108
|
+
return;
|
|
109
|
+
LOG ("reset extended");
|
|
110
|
+
extended = false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void External::reset_limits () { internal->reset_limits (); }
|
|
114
|
+
|
|
115
|
+
/*------------------------------------------------------------------------*/
|
|
116
|
+
|
|
117
|
+
// when extension is true, elit should be a fresh variable and
|
|
118
|
+
// we can set a flag that it is an extension variable.
|
|
119
|
+
// This is then used in the API contracts, that extension variables are
|
|
120
|
+
// never part of the input
|
|
121
|
+
int External::internalize (int elit, bool extension) {
|
|
122
|
+
int ilit;
|
|
123
|
+
if (elit) {
|
|
124
|
+
assert (elit != INT_MIN);
|
|
125
|
+
const int eidx = abs (elit);
|
|
126
|
+
if (extension && eidx <= max_var)
|
|
127
|
+
FATAL ("can not add a definition for an already used variable %d",
|
|
128
|
+
eidx);
|
|
129
|
+
if (eidx > max_var) {
|
|
130
|
+
init (eidx, extension);
|
|
131
|
+
}
|
|
132
|
+
if (extension) {
|
|
133
|
+
assert (ervars.size () > (size_t) eidx);
|
|
134
|
+
ervars[eidx] = true;
|
|
135
|
+
}
|
|
136
|
+
ilit = e2i[eidx];
|
|
137
|
+
if (elit < 0)
|
|
138
|
+
ilit = -ilit;
|
|
139
|
+
if (!ilit) {
|
|
140
|
+
assert (internal->max_var < INT_MAX);
|
|
141
|
+
ilit = internal->max_var + 1u;
|
|
142
|
+
internal->init_vars (ilit);
|
|
143
|
+
e2i[eidx] = ilit;
|
|
144
|
+
LOG ("mapping external %d to internal %d", eidx, ilit);
|
|
145
|
+
e2i[eidx] = ilit;
|
|
146
|
+
internal->i2e.push_back (eidx);
|
|
147
|
+
assert (internal->i2e[ilit] == eidx);
|
|
148
|
+
assert (e2i[eidx] == ilit);
|
|
149
|
+
if (elit < 0)
|
|
150
|
+
ilit = -ilit;
|
|
151
|
+
}
|
|
152
|
+
if (internal->opts.checkfrozen) {
|
|
153
|
+
assert (eidx < (int64_t) moltentab.size ());
|
|
154
|
+
if (moltentab[eidx])
|
|
155
|
+
FATAL ("can not reuse molten literal %d", eidx);
|
|
156
|
+
}
|
|
157
|
+
Flags &f = internal->flags (ilit);
|
|
158
|
+
if (f.status == Flags::UNUSED)
|
|
159
|
+
internal->mark_active (ilit);
|
|
160
|
+
else if (f.status != Flags::ACTIVE && f.status != Flags::FIXED)
|
|
161
|
+
internal->reactivate (ilit);
|
|
162
|
+
if (!marked (tainted, elit) && marked (witness, -elit)) {
|
|
163
|
+
assert (!internal->opts.checkfrozen);
|
|
164
|
+
LOG ("marking tainted %d", elit);
|
|
165
|
+
mark (tainted, elit);
|
|
166
|
+
}
|
|
167
|
+
} else
|
|
168
|
+
ilit = 0;
|
|
169
|
+
return ilit;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
void External::add (int elit) {
|
|
173
|
+
assert (elit != INT_MIN);
|
|
174
|
+
|
|
175
|
+
if (elit)
|
|
176
|
+
REQUIRE (is_valid_input ((int) elit),
|
|
177
|
+
"extension variable '%d' defined by the solver internally "
|
|
178
|
+
"(all user variables have to be declared explicitly "
|
|
179
|
+
"if 'factor' is enabled)", // TODO only reason?
|
|
180
|
+
(int) abs(elit));
|
|
181
|
+
reset_extended ();
|
|
182
|
+
|
|
183
|
+
bool forgettable = false;
|
|
184
|
+
|
|
185
|
+
if (internal->opts.check &&
|
|
186
|
+
(internal->opts.checkwitness || internal->opts.checkfailed)) {
|
|
187
|
+
|
|
188
|
+
forgettable =
|
|
189
|
+
internal->from_propagator && internal->ext_clause_forgettable;
|
|
190
|
+
|
|
191
|
+
// Forgettable clauses (coming from the external propagator) are not
|
|
192
|
+
// saved into the external 'original' stack. They are stored separately
|
|
193
|
+
// in external 'forgettable_original', from where they are deleted when
|
|
194
|
+
// the corresponding clause is deleted (actually deleted, not just
|
|
195
|
+
// marked as garbage).
|
|
196
|
+
if (!forgettable)
|
|
197
|
+
original.push_back (elit);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const int ilit = internalize (elit);
|
|
201
|
+
assert (!elit == !ilit);
|
|
202
|
+
|
|
203
|
+
// The external literals of the new clause must be saved for later
|
|
204
|
+
// when the proof is printed during add_original_lit (0)
|
|
205
|
+
if (elit && (internal->proof || forgettable)) {
|
|
206
|
+
eclause.push_back (elit);
|
|
207
|
+
if (internal->lrat) {
|
|
208
|
+
// actually find unit of -elit (flips elit < 0)
|
|
209
|
+
unsigned eidx = (elit > 0) + 2u * (unsigned) abs (elit);
|
|
210
|
+
assert ((size_t) eidx < ext_units.size ());
|
|
211
|
+
const int64_t id = ext_units[eidx];
|
|
212
|
+
bool added = ext_flags[abs (elit)];
|
|
213
|
+
if (id && !added) {
|
|
214
|
+
ext_flags[abs (elit)] = true;
|
|
215
|
+
internal->lrat_chain.push_back (id);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!elit && internal->proof && internal->lrat) {
|
|
221
|
+
for (const auto &elit : eclause) {
|
|
222
|
+
ext_flags[abs (elit)] = false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (elit)
|
|
227
|
+
LOG ("adding external %d as internal %d", elit, ilit);
|
|
228
|
+
internal->add_original_lit (ilit);
|
|
229
|
+
|
|
230
|
+
// Clean-up saved external literals once proof line is printed
|
|
231
|
+
if (!elit && (internal->proof || forgettable))
|
|
232
|
+
eclause.clear ();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
void External::assume (int elit) {
|
|
236
|
+
assert (elit);
|
|
237
|
+
reset_extended ();
|
|
238
|
+
if (internal->proof)
|
|
239
|
+
internal->proof->add_assumption (elit);
|
|
240
|
+
assumptions.push_back (elit);
|
|
241
|
+
const int ilit = internalize (elit);
|
|
242
|
+
assert (ilit);
|
|
243
|
+
LOG ("assuming external %d as internal %d", elit, ilit);
|
|
244
|
+
internal->assume (ilit);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
bool External::flip (int elit) {
|
|
248
|
+
assert (elit);
|
|
249
|
+
assert (elit != INT_MIN);
|
|
250
|
+
assert (!propagator);
|
|
251
|
+
|
|
252
|
+
int eidx = abs (elit);
|
|
253
|
+
if (eidx > max_var)
|
|
254
|
+
return false;
|
|
255
|
+
if (marked (witness, elit))
|
|
256
|
+
return false;
|
|
257
|
+
int ilit = e2i[eidx];
|
|
258
|
+
if (!ilit)
|
|
259
|
+
return false;
|
|
260
|
+
bool res = internal->flip (ilit);
|
|
261
|
+
if (res && extended)
|
|
262
|
+
reset_extended ();
|
|
263
|
+
return res;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
bool External::flippable (int elit) {
|
|
267
|
+
assert (elit);
|
|
268
|
+
assert (elit != INT_MIN);
|
|
269
|
+
assert (!propagator);
|
|
270
|
+
|
|
271
|
+
int eidx = abs (elit);
|
|
272
|
+
if (eidx > max_var)
|
|
273
|
+
return false;
|
|
274
|
+
if (marked (witness, elit))
|
|
275
|
+
return false;
|
|
276
|
+
int ilit = e2i[eidx];
|
|
277
|
+
if (!ilit)
|
|
278
|
+
return false;
|
|
279
|
+
return internal->flippable (ilit);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
bool External::failed (int elit) {
|
|
283
|
+
assert (elit);
|
|
284
|
+
assert (elit != INT_MIN);
|
|
285
|
+
int eidx = abs (elit);
|
|
286
|
+
if (eidx > max_var)
|
|
287
|
+
return 0;
|
|
288
|
+
int ilit = e2i[eidx];
|
|
289
|
+
if (!ilit)
|
|
290
|
+
return 0;
|
|
291
|
+
if (elit < 0)
|
|
292
|
+
ilit = -ilit;
|
|
293
|
+
return internal->failed (ilit);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
void External::constrain (int elit) {
|
|
297
|
+
if (constraint.size () && !constraint.back ()) {
|
|
298
|
+
LOG (constraint, "replacing previous constraint");
|
|
299
|
+
reset_constraint ();
|
|
300
|
+
}
|
|
301
|
+
assert (elit != INT_MIN);
|
|
302
|
+
reset_extended ();
|
|
303
|
+
const int ilit = internalize (elit);
|
|
304
|
+
assert (!elit == !ilit);
|
|
305
|
+
if (elit)
|
|
306
|
+
LOG ("adding external %d as internal %d to constraint", elit, ilit);
|
|
307
|
+
else if (!elit && internal->proof) {
|
|
308
|
+
internal->proof->add_constraint (constraint);
|
|
309
|
+
}
|
|
310
|
+
constraint.push_back (elit);
|
|
311
|
+
internal->constrain (ilit);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
bool External::failed_constraint () {
|
|
315
|
+
return internal->failed_constraint ();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
void External::phase (int elit) {
|
|
319
|
+
assert (elit);
|
|
320
|
+
assert (elit != INT_MIN);
|
|
321
|
+
const int ilit = internalize (elit);
|
|
322
|
+
internal->phase (ilit);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
void External::unphase (int elit) {
|
|
326
|
+
assert (elit);
|
|
327
|
+
assert (elit != INT_MIN);
|
|
328
|
+
int eidx = abs (elit);
|
|
329
|
+
if (eidx > max_var) {
|
|
330
|
+
UNUSED:
|
|
331
|
+
LOG ("resetting forced phase of unused external %d ignored", elit);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
int ilit = e2i[eidx];
|
|
335
|
+
if (!ilit)
|
|
336
|
+
goto UNUSED;
|
|
337
|
+
if (elit < 0)
|
|
338
|
+
ilit = -ilit;
|
|
339
|
+
internal->unphase (ilit);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/*------------------------------------------------------------------------*/
|
|
343
|
+
|
|
344
|
+
// External propagation related functions
|
|
345
|
+
//
|
|
346
|
+
// Note that when an already assigned variable is added as observed, the
|
|
347
|
+
// solver will backtrack to undo this assignment.
|
|
348
|
+
//
|
|
349
|
+
void External::add_observed_var (int elit) {
|
|
350
|
+
assert (propagator); // REQ is in Solver::add_observed_var
|
|
351
|
+
|
|
352
|
+
assert (elit);
|
|
353
|
+
assert (elit != INT_MIN);
|
|
354
|
+
reset_extended (); // tainting!
|
|
355
|
+
|
|
356
|
+
int eidx = abs (elit);
|
|
357
|
+
|
|
358
|
+
REQUIRE (eidx > max_var ||
|
|
359
|
+
(!marked (witness, elit) && !marked (witness, -elit)),
|
|
360
|
+
"Only clean variables are allowed to be observed.");
|
|
361
|
+
// if (eidx <= max_var &&
|
|
362
|
+
// (marked (witness, elit) || marked (witness, -elit))) {
|
|
363
|
+
// LOG ("Error, only clean variables are allowed to become observed.");
|
|
364
|
+
// assert (false);
|
|
365
|
+
|
|
366
|
+
// // TODO: here needs to come the taint and restore of the newly
|
|
367
|
+
// // observed variable. Restore_clauses must be called before continue.
|
|
368
|
+
// // LOG ("marking tainted %d", elit);
|
|
369
|
+
// // mark (tainted, elit);
|
|
370
|
+
// // mark (tainted, -elit);
|
|
371
|
+
// // restore_clauses ...
|
|
372
|
+
// }
|
|
373
|
+
|
|
374
|
+
if (eidx >= (int64_t) is_observed.size ())
|
|
375
|
+
is_observed.resize (1 + (size_t) eidx, false);
|
|
376
|
+
|
|
377
|
+
if (is_observed[eidx])
|
|
378
|
+
return;
|
|
379
|
+
|
|
380
|
+
LOG ("marking %d as externally watched", eidx);
|
|
381
|
+
|
|
382
|
+
// Will do the necessary internalization
|
|
383
|
+
freeze (elit);
|
|
384
|
+
is_observed[eidx] = true;
|
|
385
|
+
|
|
386
|
+
int ilit = internalize (elit);
|
|
387
|
+
// internal add-observed-var backtracks to a lower decision level to
|
|
388
|
+
// unassign the variable in case it was already assigned previously (but
|
|
389
|
+
// not on the current level)
|
|
390
|
+
internal->add_observed_var (ilit);
|
|
391
|
+
|
|
392
|
+
if (propagator->is_lazy)
|
|
393
|
+
return;
|
|
394
|
+
|
|
395
|
+
// In case this variable was already assigned (e.g. via unit clause) and
|
|
396
|
+
// got compacted to map to another (not observed) variable, it can not be
|
|
397
|
+
// unnasigned so it must be notified explicitly now. (-> Can lead to
|
|
398
|
+
// repeated fixed assignment notifications, in case it was unobserved and
|
|
399
|
+
// observed again. But a repeated notification is less error-prone than
|
|
400
|
+
// never notifying an assignment.)
|
|
401
|
+
const int tmp = fixed (elit);
|
|
402
|
+
if (!tmp)
|
|
403
|
+
return;
|
|
404
|
+
int unit = tmp < 0 ? -elit : elit;
|
|
405
|
+
|
|
406
|
+
LOG ("notify propagator about fixed assignment upon observe for %d",
|
|
407
|
+
unit);
|
|
408
|
+
|
|
409
|
+
// internal add-observed-var had to backtrack to root-level already
|
|
410
|
+
assert (!internal->level);
|
|
411
|
+
|
|
412
|
+
std::vector<int> assigned = {unit};
|
|
413
|
+
propagator->notify_assignment (assigned);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
void External::remove_observed_var (int elit) {
|
|
417
|
+
assert (propagator); // REQ is in Solver::remove_observed_var
|
|
418
|
+
|
|
419
|
+
int eidx = abs (elit);
|
|
420
|
+
|
|
421
|
+
if (eidx > max_var) // Ignore call if variable does not exist
|
|
422
|
+
return;
|
|
423
|
+
|
|
424
|
+
// Ignore call if variable is not observed
|
|
425
|
+
if ((size_t) eidx >= is_observed.size ())
|
|
426
|
+
return;
|
|
427
|
+
if (is_observed[eidx]) {
|
|
428
|
+
// Follow opposite order of add_observed_var, first remove internal
|
|
429
|
+
// is_observed
|
|
430
|
+
int ilit = e2i[eidx]; // internalize (elit);
|
|
431
|
+
internal->remove_observed_var (ilit);
|
|
432
|
+
|
|
433
|
+
is_observed[eidx] = false;
|
|
434
|
+
melt (elit);
|
|
435
|
+
LOG ("unmarking %d as externally watched", eidx);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
void External::reset_observed_vars () {
|
|
440
|
+
// Shouldn't be called if there is no connected propagator
|
|
441
|
+
assert (propagator); // REQ is in Solver::reset_observed_vars
|
|
442
|
+
reset_extended ();
|
|
443
|
+
|
|
444
|
+
internal->notified = 0;
|
|
445
|
+
LOG ("reset notified counter to 0");
|
|
446
|
+
|
|
447
|
+
if (!is_observed.size ())
|
|
448
|
+
return;
|
|
449
|
+
|
|
450
|
+
for (auto elit : vars) {
|
|
451
|
+
int eidx = abs (elit);
|
|
452
|
+
assert (eidx <= max_var);
|
|
453
|
+
if ((size_t) eidx >= is_observed.size ())
|
|
454
|
+
break;
|
|
455
|
+
if (is_observed[eidx]) {
|
|
456
|
+
int ilit = internalize (elit);
|
|
457
|
+
internal->remove_observed_var (ilit);
|
|
458
|
+
LOG ("unmarking %d as externally watched", eidx);
|
|
459
|
+
is_observed[eidx] = false;
|
|
460
|
+
melt (elit);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
bool External::observed (int elit) {
|
|
466
|
+
assert (elit);
|
|
467
|
+
assert (elit != INT_MIN);
|
|
468
|
+
int eidx = abs (elit);
|
|
469
|
+
if (eidx > max_var)
|
|
470
|
+
return false;
|
|
471
|
+
if (eidx >= (int) is_observed.size ())
|
|
472
|
+
return false;
|
|
473
|
+
|
|
474
|
+
return is_observed[eidx];
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
bool External::is_witness (int elit) {
|
|
478
|
+
assert (elit);
|
|
479
|
+
assert (elit != INT_MIN);
|
|
480
|
+
int eidx = abs (elit);
|
|
481
|
+
if (eidx > max_var)
|
|
482
|
+
return false;
|
|
483
|
+
return (marked (witness, elit) || marked (witness, -elit));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
bool External::is_decision (int elit) {
|
|
487
|
+
assert (elit);
|
|
488
|
+
assert (elit != INT_MIN);
|
|
489
|
+
int eidx = abs (elit);
|
|
490
|
+
if (eidx > max_var)
|
|
491
|
+
return false;
|
|
492
|
+
|
|
493
|
+
int ilit = internalize (elit);
|
|
494
|
+
return internal->is_decision (ilit);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
void External::force_backtrack (int new_level) {
|
|
498
|
+
assert (propagator); // REQ is is in Solver::force_backtrack
|
|
499
|
+
|
|
500
|
+
LOG ("force backtrack to level %d", new_level);
|
|
501
|
+
internal->force_backtrack (new_level);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/*------------------------------------------------------------------------*/
|
|
505
|
+
|
|
506
|
+
int External::propagate_assumptions () {
|
|
507
|
+
int res = internal->propagate_assumptions ();
|
|
508
|
+
if (res == 10 && !extended)
|
|
509
|
+
extend (); // Call solution reconstruction
|
|
510
|
+
check_solve_result (res);
|
|
511
|
+
reset_limits ();
|
|
512
|
+
return res;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
void External::implied (std::vector<int> &trailed) {
|
|
516
|
+
std::vector<int> ilit_implicants;
|
|
517
|
+
internal->implied (ilit_implicants);
|
|
518
|
+
|
|
519
|
+
// Those implied literals must be filtered out that are witnesses
|
|
520
|
+
// on the reconstruction stack -> no inplace externalize is possible.
|
|
521
|
+
// (Internal does not see these marks, so no earlier filter is
|
|
522
|
+
// possible.)
|
|
523
|
+
|
|
524
|
+
trailed.clear ();
|
|
525
|
+
|
|
526
|
+
for (const auto &ilit : ilit_implicants) {
|
|
527
|
+
assert (ilit);
|
|
528
|
+
const int elit = internal->externalize (ilit);
|
|
529
|
+
const int eidx = abs (elit);
|
|
530
|
+
const bool is_extension_var = ervars[eidx];
|
|
531
|
+
if (!marked (tainted, elit) && !is_extension_var) {
|
|
532
|
+
trailed.push_back (elit);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
void External::conclude_unknown () {
|
|
538
|
+
if (!internal->proof || concluded)
|
|
539
|
+
return;
|
|
540
|
+
concluded = true;
|
|
541
|
+
|
|
542
|
+
vector<int> trail;
|
|
543
|
+
implied (trail);
|
|
544
|
+
internal->proof->conclude_unknown (trail);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/*------------------------------------------------------------------------*/
|
|
548
|
+
|
|
549
|
+
// Internal checker if 'solve' claims the formula to be satisfiable.
|
|
550
|
+
|
|
551
|
+
void External::check_satisfiable () {
|
|
552
|
+
LOG ("checking satisfiable");
|
|
553
|
+
if (!extended)
|
|
554
|
+
extend ();
|
|
555
|
+
if (internal->opts.checkwitness)
|
|
556
|
+
check_assignment (&External::ival);
|
|
557
|
+
if (internal->opts.checkassumptions && !assumptions.empty ())
|
|
558
|
+
check_assumptions_satisfied ();
|
|
559
|
+
if (internal->opts.checkconstraint && !constraint.empty ())
|
|
560
|
+
check_constraint_satisfied ();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Internal checker if 'solve' claims formula to be unsatisfiable.
|
|
564
|
+
|
|
565
|
+
void External::check_unsatisfiable () {
|
|
566
|
+
LOG ("checking unsatisfiable");
|
|
567
|
+
if (!internal->opts.checkfailed)
|
|
568
|
+
return;
|
|
569
|
+
if (!assumptions.empty () || !constraint.empty ())
|
|
570
|
+
check_failing ();
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// Check result of 'solve' to be correct.
|
|
574
|
+
|
|
575
|
+
void External::check_solve_result (int res) {
|
|
576
|
+
if (!internal->opts.check)
|
|
577
|
+
return;
|
|
578
|
+
if (res == 10)
|
|
579
|
+
check_satisfiable ();
|
|
580
|
+
if (res == 20)
|
|
581
|
+
check_unsatisfiable ();
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Prepare checking that completely molten literals are not used as argument
|
|
585
|
+
// of 'add' or 'assume', which is invalid under freezing semantics. This
|
|
586
|
+
// case would be caught by our 'restore' implementation so is only needed
|
|
587
|
+
// for checking the deprecated 'freeze' semantics.
|
|
588
|
+
|
|
589
|
+
void External::update_molten_literals () {
|
|
590
|
+
if (!internal->opts.checkfrozen)
|
|
591
|
+
return;
|
|
592
|
+
assert ((size_t) max_var + 1 == moltentab.size ());
|
|
593
|
+
#ifdef LOGGING
|
|
594
|
+
int registered = 0, molten = 0;
|
|
595
|
+
#endif
|
|
596
|
+
for (auto lit : vars) {
|
|
597
|
+
if (moltentab[lit]) {
|
|
598
|
+
LOG ("skipping already molten literal %d", lit);
|
|
599
|
+
#ifdef LOGGING
|
|
600
|
+
molten++;
|
|
601
|
+
#endif
|
|
602
|
+
} else if (frozen (lit))
|
|
603
|
+
LOG ("skipping currently frozen literal %d", lit);
|
|
604
|
+
else {
|
|
605
|
+
LOG ("new molten literal %d", lit);
|
|
606
|
+
moltentab[lit] = true;
|
|
607
|
+
#ifdef LOGGING
|
|
608
|
+
registered++;
|
|
609
|
+
molten++;
|
|
610
|
+
#endif
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
LOG ("registered %d new molten literals", registered);
|
|
614
|
+
LOG ("reached in total %d molten literals", molten);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
int External::solve (bool preprocess_only) {
|
|
618
|
+
reset_extended ();
|
|
619
|
+
update_molten_literals ();
|
|
620
|
+
int res = internal->solve (preprocess_only);
|
|
621
|
+
check_solve_result (res);
|
|
622
|
+
reset_limits ();
|
|
623
|
+
return res;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
void External::terminate () { internal->terminate (); }
|
|
627
|
+
|
|
628
|
+
int External::lookahead () {
|
|
629
|
+
reset_extended ();
|
|
630
|
+
update_molten_literals ();
|
|
631
|
+
int ilit = internal->lookahead ();
|
|
632
|
+
const int elit =
|
|
633
|
+
(ilit && ilit != INT_MIN) ? internal->externalize (ilit) : 0;
|
|
634
|
+
LOG ("lookahead internal %d external %d", ilit, elit);
|
|
635
|
+
return elit;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
CaDiCaL::CubesWithStatus External::generate_cubes (int depth,
|
|
639
|
+
int min_depth = 0) {
|
|
640
|
+
reset_extended ();
|
|
641
|
+
update_molten_literals ();
|
|
642
|
+
reset_limits ();
|
|
643
|
+
auto cubes = internal->generate_cubes (depth, min_depth);
|
|
644
|
+
auto externalize = [this] (int ilit) {
|
|
645
|
+
const int elit = ilit ? internal->externalize (ilit) : 0;
|
|
646
|
+
MSG ("lookahead internal %d external %d", ilit, elit);
|
|
647
|
+
return elit;
|
|
648
|
+
};
|
|
649
|
+
auto externalize_map = [this, externalize] (std::vector<int> cube) {
|
|
650
|
+
(void) this;
|
|
651
|
+
MSG ("Cube : ");
|
|
652
|
+
std::for_each (begin (cube), end (cube), externalize);
|
|
653
|
+
};
|
|
654
|
+
std::for_each (begin (cubes.cubes), end (cubes.cubes), externalize_map);
|
|
655
|
+
|
|
656
|
+
return cubes;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/*------------------------------------------------------------------------*/
|
|
660
|
+
|
|
661
|
+
void External::freeze (int elit) {
|
|
662
|
+
reset_extended ();
|
|
663
|
+
int ilit = internalize (elit);
|
|
664
|
+
unsigned eidx = vidx (elit);
|
|
665
|
+
if (eidx >= frozentab.size ())
|
|
666
|
+
frozentab.resize (eidx + 1, 0);
|
|
667
|
+
unsigned &ref = frozentab[eidx];
|
|
668
|
+
if (ref < UINT_MAX) {
|
|
669
|
+
ref++;
|
|
670
|
+
LOG ("external variable %d frozen once and now frozen %u times", eidx,
|
|
671
|
+
ref);
|
|
672
|
+
} else
|
|
673
|
+
LOG ("external variable %d frozen but remains frozen forever", eidx);
|
|
674
|
+
internal->freeze (ilit);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
void External::melt (int elit) {
|
|
678
|
+
reset_extended ();
|
|
679
|
+
int ilit = internalize (elit);
|
|
680
|
+
unsigned eidx = vidx (elit);
|
|
681
|
+
assert (eidx < frozentab.size ());
|
|
682
|
+
unsigned &ref = frozentab[eidx];
|
|
683
|
+
assert (ref > 0);
|
|
684
|
+
if (ref < UINT_MAX) {
|
|
685
|
+
if (!--ref) {
|
|
686
|
+
if (observed (elit)) {
|
|
687
|
+
ref++;
|
|
688
|
+
LOG ("external variable %d is observed, can not be completely "
|
|
689
|
+
"molten",
|
|
690
|
+
eidx);
|
|
691
|
+
} else
|
|
692
|
+
LOG ("external variable %d melted once and now completely melted",
|
|
693
|
+
eidx);
|
|
694
|
+
} else
|
|
695
|
+
LOG ("external variable %d melted once but remains frozen %u times",
|
|
696
|
+
eidx, ref);
|
|
697
|
+
} else
|
|
698
|
+
LOG ("external variable %d melted but remains frozen forever", eidx);
|
|
699
|
+
internal->melt (ilit);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/*------------------------------------------------------------------------*/
|
|
703
|
+
|
|
704
|
+
void External::check_assignment (int (External::*a) (int) const) {
|
|
705
|
+
|
|
706
|
+
// First check all assigned and consistent.
|
|
707
|
+
//
|
|
708
|
+
for (auto idx : vars) {
|
|
709
|
+
if (!(this->*a) (idx))
|
|
710
|
+
FATAL ("unassigned variable: %d", idx);
|
|
711
|
+
int value_idx = (this->*a) (idx);
|
|
712
|
+
int value_neg_idx = (this->*a) (-idx);
|
|
713
|
+
if (value_idx == idx)
|
|
714
|
+
assert (value_neg_idx == idx);
|
|
715
|
+
else {
|
|
716
|
+
assert (value_idx == -idx);
|
|
717
|
+
assert (value_neg_idx == -idx);
|
|
718
|
+
}
|
|
719
|
+
if (value_idx != value_neg_idx)
|
|
720
|
+
FATAL ("inconsistently assigned literals %d and %d", idx, -idx);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Then check that all (saved) original clauses are satisfied.
|
|
724
|
+
//
|
|
725
|
+
bool satisfied = false;
|
|
726
|
+
const auto end = original.end ();
|
|
727
|
+
auto start = original.begin (), i = start;
|
|
728
|
+
#ifndef QUIET
|
|
729
|
+
int64_t count = 0;
|
|
730
|
+
#endif
|
|
731
|
+
for (; i != end; i++) {
|
|
732
|
+
int lit = *i;
|
|
733
|
+
if (!lit) {
|
|
734
|
+
if (!satisfied) {
|
|
735
|
+
fatal_message_start ();
|
|
736
|
+
fputs ("unsatisfied clause:\n", stderr);
|
|
737
|
+
for (auto j = start; j != i; j++)
|
|
738
|
+
fprintf (stderr, "%d ", *j);
|
|
739
|
+
fputc ('0', stderr);
|
|
740
|
+
fatal_message_end ();
|
|
741
|
+
}
|
|
742
|
+
satisfied = false;
|
|
743
|
+
start = i + 1;
|
|
744
|
+
#ifndef QUIET
|
|
745
|
+
count++;
|
|
746
|
+
#endif
|
|
747
|
+
} else if (!satisfied && (this->*a) (lit) == lit)
|
|
748
|
+
satisfied = true;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
bool presence_flag;
|
|
752
|
+
// Check those forgettable external clauses that are still present, but
|
|
753
|
+
// only if the external propagator is still connected (otherwise solution
|
|
754
|
+
// reconstruction is allowed to touch the previously observed variables so
|
|
755
|
+
// there is no guarantee that the final model will satisfy these clauses.)
|
|
756
|
+
for (const auto &forgettables : forgettable_original) {
|
|
757
|
+
if (!propagator)
|
|
758
|
+
break;
|
|
759
|
+
presence_flag = true;
|
|
760
|
+
satisfied = false;
|
|
761
|
+
#ifndef QUIET
|
|
762
|
+
count++;
|
|
763
|
+
#endif
|
|
764
|
+
std::vector<int> literals;
|
|
765
|
+
for (const auto lit : forgettables.second) {
|
|
766
|
+
if (presence_flag) {
|
|
767
|
+
// First integer is a Boolean flag, not a literal
|
|
768
|
+
if (!lit) {
|
|
769
|
+
// Deleted clauses can be ignored, they count as satisfied
|
|
770
|
+
satisfied = true;
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
presence_flag = false;
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if ((this->*a) (lit) == lit) {
|
|
778
|
+
satisfied = true;
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
if (!satisfied) {
|
|
784
|
+
fatal_message_start ();
|
|
785
|
+
fputs ("unsatisfied external forgettable clause:\n", stderr);
|
|
786
|
+
for (size_t j = 1; j < forgettables.second.size (); j++)
|
|
787
|
+
fprintf (stderr, "%d ", forgettables.second[j]);
|
|
788
|
+
fputc ('0', stderr);
|
|
789
|
+
fatal_message_end ();
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
#ifndef QUIET
|
|
793
|
+
VERBOSE (1, "satisfying assignment checked on %" PRId64 " clauses",
|
|
794
|
+
count);
|
|
795
|
+
#endif
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/*------------------------------------------------------------------------*/
|
|
799
|
+
|
|
800
|
+
void External::check_assumptions_satisfied () {
|
|
801
|
+
for (const auto &lit : assumptions) {
|
|
802
|
+
// Not 'signed char' !!!!
|
|
803
|
+
const int tmp = ival (lit);
|
|
804
|
+
if (tmp != lit)
|
|
805
|
+
FATAL ("assumption %d falsified", lit);
|
|
806
|
+
if (!tmp)
|
|
807
|
+
FATAL ("assumption %d unassigned", lit);
|
|
808
|
+
}
|
|
809
|
+
VERBOSE (1, "checked that %zd assumptions are satisfied",
|
|
810
|
+
assumptions.size ());
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
void External::check_constraint_satisfied () {
|
|
814
|
+
for (const auto lit : constraint) {
|
|
815
|
+
if (ival (lit) == lit) {
|
|
816
|
+
VERBOSE (1, "checked that constraint is satisfied");
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
FATAL ("constraint not satisfied");
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
void External::check_failing () {
|
|
824
|
+
Solver *checker = new Solver ();
|
|
825
|
+
DeferDeletePtr<Solver> delete_checker (checker);
|
|
826
|
+
checker->prefix ("checker ");
|
|
827
|
+
#ifdef LOGGING
|
|
828
|
+
if (internal->opts.log)
|
|
829
|
+
checker->set ("log", true);
|
|
830
|
+
#endif
|
|
831
|
+
checker->set ("factorcheck", false);
|
|
832
|
+
|
|
833
|
+
for (const auto lit : assumptions) {
|
|
834
|
+
if (!failed (lit))
|
|
835
|
+
continue;
|
|
836
|
+
LOG ("checking failed literal %d in core", lit);
|
|
837
|
+
checker->add (lit);
|
|
838
|
+
checker->add (0);
|
|
839
|
+
}
|
|
840
|
+
if (failed_constraint ()) {
|
|
841
|
+
LOG (constraint, "checking failed constraint");
|
|
842
|
+
for (const auto lit : constraint)
|
|
843
|
+
checker->add (lit);
|
|
844
|
+
} else if (constraint.size ())
|
|
845
|
+
LOG (constraint, "constraint satisfied and ignored");
|
|
846
|
+
|
|
847
|
+
// Add original clauses as last step, failing () and failed_constraint ()
|
|
848
|
+
// might add more external clauses (due to lazy explanation)
|
|
849
|
+
for (const auto lit : original)
|
|
850
|
+
checker->add (lit);
|
|
851
|
+
|
|
852
|
+
// Add every forgettable external clauses
|
|
853
|
+
for (const auto &forgettables : forgettable_original) {
|
|
854
|
+
bool presence_flag = true;
|
|
855
|
+
for (const auto lit : forgettables.second) {
|
|
856
|
+
if (presence_flag) {
|
|
857
|
+
// First integer is a Boolean flag, not a literal, ignore it here
|
|
858
|
+
presence_flag = false;
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
checker->add (lit);
|
|
862
|
+
}
|
|
863
|
+
checker->add (0);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
int res = checker->solve ();
|
|
867
|
+
if (res != 20)
|
|
868
|
+
FATAL ("failed assumptions do not form a core");
|
|
869
|
+
delete_checker.free ();
|
|
870
|
+
VERBOSE (1, "checked that %zd failing assumptions form a core",
|
|
871
|
+
assumptions.size ());
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/*------------------------------------------------------------------------*/
|
|
875
|
+
|
|
876
|
+
// Traversal of unit clauses is implemented here.
|
|
877
|
+
|
|
878
|
+
// In principle we want to traverse the clauses of the simplified formula
|
|
879
|
+
// only, particularly eliminated variables should be completely removed.
|
|
880
|
+
// This poses the question what to do with unit clauses. Should they be
|
|
881
|
+
// considered part of the simplified formula or of the witness to construct
|
|
882
|
+
// solutions for the original formula? Ideally they should be considered
|
|
883
|
+
// to be part of the witness only, i.e., as they have been simplified away.
|
|
884
|
+
|
|
885
|
+
// Therefore we distinguish frozen and non-frozen units during clause
|
|
886
|
+
// traversal. Frozen units are treated as unit clauses while non-frozen
|
|
887
|
+
// units are treated as if they were already eliminated and put on the
|
|
888
|
+
// extension stack as witness clauses.
|
|
889
|
+
|
|
890
|
+
// Furthermore, eliminating units during 'compact' could be interpreted as
|
|
891
|
+
// variable elimination, i.e., just add the resolvents (remove falsified
|
|
892
|
+
// literals), then drop the clauses with the unit, and push the unit on the
|
|
893
|
+
// extension stack. This is of course only OK if the user did not freeze
|
|
894
|
+
// that variable (even implicitly during assumptions).
|
|
895
|
+
|
|
896
|
+
// Thanks go to Fahiem Bacchus for asking why there is a necessity to
|
|
897
|
+
// distinguish these two cases (frozen and non-frozen units). The answer is
|
|
898
|
+
// that it is not strictly necessary, and this distinction could be avoided
|
|
899
|
+
// by always treating units as remaining unit clauses, thus only using the
|
|
900
|
+
// first of the two following functions and dropping the 'if (!frozen (idx))
|
|
901
|
+
// continue;' check in it. This has however the down-side that those units
|
|
902
|
+
// are still in the simplified formula and only as units. I would not
|
|
903
|
+
// consider such a formula as really being 'simplified'. On the other hand
|
|
904
|
+
// if the user explicitly freezes a literal, then it should continue to be
|
|
905
|
+
// in the simplified formula during traversal. So also only using the
|
|
906
|
+
// second function is not ideal.
|
|
907
|
+
|
|
908
|
+
// There is however a catch where this solution breaks down (in the sense of
|
|
909
|
+
// producing less optimal results - that is keeping units in the formula
|
|
910
|
+
// which better would be witness clauses). The problem is with compact
|
|
911
|
+
// preprocessing which removes eliminated but also fixed internal variables.
|
|
912
|
+
// One internal unit (fixed) variable is kept and all the other external
|
|
913
|
+
// literals which became unit are mapped to that internal literal (negated
|
|
914
|
+
// or positively). Compact is called non-deterministically from the point
|
|
915
|
+
// of the user and thus there is no control on when this happens. If
|
|
916
|
+
// compact happens those external units are mapped to a single internal
|
|
917
|
+
// literal now and then all share the same 'frozen' counter. So if the
|
|
918
|
+
// user freezes one of them all in essence get frozen, which in turn then
|
|
919
|
+
// makes a difference in terms of traversing such a unit as unit clause or
|
|
920
|
+
// as unit witness.
|
|
921
|
+
|
|
922
|
+
bool External::traverse_all_frozen_units_as_clauses (ClauseIterator &it) {
|
|
923
|
+
if (internal->unsat)
|
|
924
|
+
return true;
|
|
925
|
+
|
|
926
|
+
vector<int> clause;
|
|
927
|
+
|
|
928
|
+
for (auto idx : vars) {
|
|
929
|
+
if (!frozen (idx))
|
|
930
|
+
continue;
|
|
931
|
+
const int tmp = fixed (idx);
|
|
932
|
+
if (!tmp)
|
|
933
|
+
continue;
|
|
934
|
+
int unit = tmp < 0 ? -idx : idx;
|
|
935
|
+
clause.push_back (unit);
|
|
936
|
+
if (!it.clause (clause))
|
|
937
|
+
return false;
|
|
938
|
+
clause.clear ();
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
bool External::traverse_all_non_frozen_units_as_witnesses (
|
|
945
|
+
WitnessIterator &it) {
|
|
946
|
+
if (internal->unsat)
|
|
947
|
+
return true;
|
|
948
|
+
|
|
949
|
+
vector<int> clause_and_witness;
|
|
950
|
+
for (auto idx : vars) {
|
|
951
|
+
if (frozen (idx))
|
|
952
|
+
continue;
|
|
953
|
+
const int tmp = fixed (idx);
|
|
954
|
+
if (!tmp)
|
|
955
|
+
continue;
|
|
956
|
+
int unit = tmp < 0 ? -idx : idx;
|
|
957
|
+
const int ilit = e2i[idx] * (tmp < 0 ? -1 : 1);
|
|
958
|
+
// heurstically add + max_var to the id to avoid reusing ids
|
|
959
|
+
const int64_t id = internal->lrat ? internal->unit_id (ilit) : 1;
|
|
960
|
+
assert (id);
|
|
961
|
+
clause_and_witness.push_back (unit);
|
|
962
|
+
if (!it.witness (clause_and_witness, clause_and_witness, id + max_var))
|
|
963
|
+
return false;
|
|
964
|
+
clause_and_witness.clear ();
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
return true;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/*------------------------------------------------------------------------*/
|
|
971
|
+
|
|
972
|
+
void External::copy_flags (External &other) const {
|
|
973
|
+
const vector<Flags> &this_ftab = internal->ftab;
|
|
974
|
+
vector<Flags> &other_ftab = other.internal->ftab;
|
|
975
|
+
const unsigned limit = min (max_var, other.max_var);
|
|
976
|
+
for (unsigned eidx = 1; eidx <= limit; eidx++) {
|
|
977
|
+
const int this_ilit = e2i[eidx];
|
|
978
|
+
if (!this_ilit)
|
|
979
|
+
continue;
|
|
980
|
+
const int other_ilit = other.e2i[eidx];
|
|
981
|
+
if (!other_ilit)
|
|
982
|
+
continue;
|
|
983
|
+
if (!internal->active (this_ilit))
|
|
984
|
+
continue;
|
|
985
|
+
if (!other.internal->active (other_ilit))
|
|
986
|
+
continue;
|
|
987
|
+
assert (this_ilit != INT_MIN);
|
|
988
|
+
assert (other_ilit != INT_MIN);
|
|
989
|
+
const Flags &this_flags = this_ftab[abs (this_ilit)];
|
|
990
|
+
Flags &other_flags = other_ftab[abs (other_ilit)];
|
|
991
|
+
this_flags.copy (other_flags);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/*------------------------------------------------------------------------*/
|
|
996
|
+
|
|
997
|
+
void External::export_learned_empty_clause () {
|
|
998
|
+
assert (learner);
|
|
999
|
+
if (learner->learning (0)) {
|
|
1000
|
+
LOG ("exporting learned empty clause");
|
|
1001
|
+
learner->learn (0);
|
|
1002
|
+
} else
|
|
1003
|
+
LOG ("not exporting learned empty clause");
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
void External::export_learned_unit_clause (int ilit) {
|
|
1007
|
+
assert (learner);
|
|
1008
|
+
if (learner->learning (1)) {
|
|
1009
|
+
LOG ("exporting learned unit clause");
|
|
1010
|
+
const int elit = internal->externalize (ilit);
|
|
1011
|
+
assert (elit);
|
|
1012
|
+
learner->learn (elit);
|
|
1013
|
+
learner->learn (0);
|
|
1014
|
+
} else
|
|
1015
|
+
LOG ("not exporting learned unit clause");
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
void External::export_learned_large_clause (const vector<int> &clause) {
|
|
1019
|
+
assert (learner);
|
|
1020
|
+
size_t size = clause.size ();
|
|
1021
|
+
assert (size <= (unsigned) INT_MAX);
|
|
1022
|
+
if (learner->learning ((int) size)) {
|
|
1023
|
+
LOG ("exporting learned clause of size %zu", size);
|
|
1024
|
+
for (auto ilit : clause) {
|
|
1025
|
+
const int elit = internal->externalize (ilit);
|
|
1026
|
+
assert (elit);
|
|
1027
|
+
learner->learn (elit);
|
|
1028
|
+
}
|
|
1029
|
+
learner->learn (0);
|
|
1030
|
+
} else
|
|
1031
|
+
LOG ("not exporting learned clause of size %zu", size);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
} // namespace CaDiCaL
|