1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Mathias Preiner, Gereon Kremer, Andres Noetzli |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Bit-blasting solver that supports multiple SAT backends. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/bv/bv_solver_bitblast.h" |
17 |
|
|
18 |
|
#include "options/bv_options.h" |
19 |
|
#include "prop/sat_solver_factory.h" |
20 |
|
#include "smt/smt_statistics_registry.h" |
21 |
|
#include "theory/bv/theory_bv.h" |
22 |
|
#include "theory/bv/theory_bv_utils.h" |
23 |
|
#include "theory/theory_model.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
namespace theory { |
27 |
|
namespace bv { |
28 |
|
|
29 |
|
/** |
30 |
|
* Notifies the BV solver when assertions were reset. |
31 |
|
* |
32 |
|
* This class is notified after every user-context pop and maintains a flag |
33 |
|
* that indicates whether assertions have been reset. If the user-context level |
34 |
|
* reaches level 0 it means that the assertions were reset. |
35 |
|
*/ |
36 |
14568 |
class NotifyResetAssertions : public context::ContextNotifyObj |
37 |
|
{ |
38 |
|
public: |
39 |
7289 |
NotifyResetAssertions(context::Context* c) |
40 |
7289 |
: context::ContextNotifyObj(c, false), |
41 |
|
d_context(c), |
42 |
7289 |
d_doneResetAssertions(false) |
43 |
|
{ |
44 |
7289 |
} |
45 |
|
|
46 |
6 |
bool doneResetAssertions() { return d_doneResetAssertions; } |
47 |
|
|
48 |
2 |
void reset() { d_doneResetAssertions = false; } |
49 |
|
|
50 |
|
protected: |
51 |
10511 |
void contextNotifyPop() override |
52 |
|
{ |
53 |
|
// If the user-context level reaches 0 it means that reset-assertions was |
54 |
|
// called. |
55 |
10511 |
if (d_context->getLevel() == 0) |
56 |
|
{ |
57 |
7329 |
d_doneResetAssertions = true; |
58 |
|
} |
59 |
10511 |
} |
60 |
|
|
61 |
|
private: |
62 |
|
/** The user-context. */ |
63 |
|
context::Context* d_context; |
64 |
|
|
65 |
|
/** Flag to notify whether reset assertions was called. */ |
66 |
|
bool d_doneResetAssertions; |
67 |
|
}; |
68 |
|
|
69 |
|
/** |
70 |
|
* Bit-blasting registrar. |
71 |
|
* |
72 |
|
* The CnfStream calls preRegister() if it encounters a theory atom. |
73 |
|
* This registrar bit-blasts given atom and remembers which bit-vector atoms |
74 |
|
* were bit-blasted. |
75 |
|
* |
76 |
|
* This registrar is needed when --bitblast=eager is enabled. |
77 |
|
*/ |
78 |
14568 |
class BBRegistrar : public prop::Registrar |
79 |
|
{ |
80 |
|
public: |
81 |
7289 |
BBRegistrar(NodeBitblaster* bb) : d_bitblaster(bb) {} |
82 |
|
|
83 |
153686 |
void preRegister(Node n) override |
84 |
|
{ |
85 |
153686 |
if (d_registeredAtoms.find(n) != d_registeredAtoms.end()) |
86 |
|
{ |
87 |
|
return; |
88 |
|
} |
89 |
|
/* We are only interested in bit-vector atoms. */ |
90 |
307540 |
if ((n.getKind() == kind::EQUAL && n[0].getType().isBitVector()) |
91 |
153518 |
|| n.getKind() == kind::BITVECTOR_ULT |
92 |
153479 |
|| n.getKind() == kind::BITVECTOR_ULE |
93 |
153479 |
|| n.getKind() == kind::BITVECTOR_SLT |
94 |
460851 |
|| n.getKind() == kind::BITVECTOR_SLE) |
95 |
|
{ |
96 |
207 |
d_registeredAtoms.insert(n); |
97 |
207 |
d_bitblaster->bbAtom(n); |
98 |
|
} |
99 |
|
} |
100 |
|
|
101 |
96 |
std::unordered_set<TNode>& getRegisteredAtoms() { return d_registeredAtoms; } |
102 |
|
|
103 |
|
private: |
104 |
|
/** The bitblaster used. */ |
105 |
|
NodeBitblaster* d_bitblaster; |
106 |
|
|
107 |
|
/** Stores bit-vector atoms encounterd on preRegister(). */ |
108 |
|
std::unordered_set<TNode> d_registeredAtoms; |
109 |
|
}; |
110 |
|
|
111 |
7289 |
BVSolverBitblast::BVSolverBitblast(Env& env, |
112 |
|
TheoryState* s, |
113 |
|
TheoryInferenceManager& inferMgr, |
114 |
7289 |
ProofNodeManager* pnm) |
115 |
|
: BVSolver(env, *s, inferMgr), |
116 |
7289 |
d_bitblaster(new NodeBitblaster(env, s)), |
117 |
7289 |
d_bbRegistrar(new BBRegistrar(d_bitblaster.get())), |
118 |
7289 |
d_nullContext(new context::Context()), |
119 |
|
d_bbFacts(context()), |
120 |
|
d_bbInputFacts(context()), |
121 |
|
d_assumptions(context()), |
122 |
|
d_assertions(context()), |
123 |
12 |
d_epg(pnm ? new EagerProofGenerator(pnm, userContext(), "") |
124 |
|
: nullptr), |
125 |
|
d_factLiteralCache(context()), |
126 |
|
d_literalFactCache(context()), |
127 |
7289 |
d_propagate(options().bv.bitvectorPropagate), |
128 |
36457 |
d_resetNotify(new NotifyResetAssertions(userContext())) |
129 |
|
{ |
130 |
7289 |
if (pnm != nullptr) |
131 |
|
{ |
132 |
6 |
d_bvProofChecker.registerTo(pnm->getChecker()); |
133 |
|
} |
134 |
|
|
135 |
7289 |
initSatSolver(); |
136 |
7289 |
} |
137 |
|
|
138 |
780972 |
void BVSolverBitblast::postCheck(Theory::Effort level) |
139 |
|
{ |
140 |
780972 |
if (level != Theory::Effort::EFFORT_FULL) |
141 |
|
{ |
142 |
|
/* Do bit-level propagation only if the SAT solver supports it. */ |
143 |
744699 |
if (!d_propagate || !d_satSolver->setPropagateOnly()) |
144 |
|
{ |
145 |
744699 |
return; |
146 |
|
} |
147 |
|
} |
148 |
|
|
149 |
|
// If we permanently added assertions to the SAT solver and the assertions |
150 |
|
// were reset, we have to reset the SAT solver and the CNF stream. |
151 |
36273 |
if (options().bv.bvAssertInput && d_resetNotify->doneResetAssertions()) |
152 |
|
{ |
153 |
2 |
d_satSolver.reset(nullptr); |
154 |
2 |
d_cnfStream.reset(nullptr); |
155 |
2 |
initSatSolver(); |
156 |
2 |
d_resetNotify->reset(); |
157 |
|
} |
158 |
|
|
159 |
36273 |
NodeManager* nm = NodeManager::currentNM(); |
160 |
|
|
161 |
|
/* Process input assertions bit-blast queue. */ |
162 |
36289 |
while (!d_bbInputFacts.empty()) |
163 |
|
{ |
164 |
16 |
Node fact = d_bbInputFacts.front(); |
165 |
8 |
d_bbInputFacts.pop(); |
166 |
|
/* Bit-blast fact and cache literal. */ |
167 |
8 |
if (d_factLiteralCache.find(fact) == d_factLiteralCache.end()) |
168 |
|
{ |
169 |
8 |
if (fact.getKind() == kind::BITVECTOR_EAGER_ATOM) |
170 |
|
{ |
171 |
|
handleEagerAtom(fact, true); |
172 |
|
} |
173 |
|
else |
174 |
|
{ |
175 |
8 |
d_bitblaster->bbAtom(fact); |
176 |
16 |
Node bb_fact = d_bitblaster->getStoredBBAtom(fact); |
177 |
8 |
d_cnfStream->convertAndAssert(bb_fact, false, false); |
178 |
|
} |
179 |
|
} |
180 |
8 |
d_assertions.push_back(fact); |
181 |
|
} |
182 |
|
|
183 |
|
/* Process bit-blast queue and store SAT literals. */ |
184 |
5389299 |
while (!d_bbFacts.empty()) |
185 |
|
{ |
186 |
5353026 |
Node fact = d_bbFacts.front(); |
187 |
2676513 |
d_bbFacts.pop(); |
188 |
|
/* Bit-blast fact and cache literal. */ |
189 |
2676513 |
if (d_factLiteralCache.find(fact) == d_factLiteralCache.end()) |
190 |
|
{ |
191 |
2676513 |
prop::SatLiteral lit; |
192 |
2676513 |
if (fact.getKind() == kind::BITVECTOR_EAGER_ATOM) |
193 |
|
{ |
194 |
96 |
handleEagerAtom(fact, false); |
195 |
96 |
lit = d_cnfStream->getLiteral(fact[0]); |
196 |
|
} |
197 |
|
else |
198 |
|
{ |
199 |
2676417 |
d_bitblaster->bbAtom(fact); |
200 |
5352834 |
Node bb_fact = d_bitblaster->getStoredBBAtom(fact); |
201 |
2676417 |
d_cnfStream->ensureLiteral(bb_fact); |
202 |
2676417 |
lit = d_cnfStream->getLiteral(bb_fact); |
203 |
|
} |
204 |
2676513 |
d_factLiteralCache[fact] = lit; |
205 |
2676513 |
d_literalFactCache[lit] = fact; |
206 |
|
} |
207 |
2676513 |
d_assumptions.push_back(d_factLiteralCache[fact]); |
208 |
|
} |
209 |
|
|
210 |
|
std::vector<prop::SatLiteral> assumptions(d_assumptions.begin(), |
211 |
72546 |
d_assumptions.end()); |
212 |
36273 |
prop::SatValue val = d_satSolver->solve(assumptions); |
213 |
|
|
214 |
36273 |
if (val == prop::SatValue::SAT_VALUE_FALSE) |
215 |
|
{ |
216 |
29944 |
std::vector<prop::SatLiteral> unsat_assumptions; |
217 |
14972 |
d_satSolver->getUnsatAssumptions(unsat_assumptions); |
218 |
|
|
219 |
29944 |
Node conflict; |
220 |
|
// Unsat assumptions produce conflict. |
221 |
14972 |
if (unsat_assumptions.size() > 0) |
222 |
|
{ |
223 |
29944 |
std::vector<Node> conf; |
224 |
127296 |
for (const prop::SatLiteral& lit : unsat_assumptions) |
225 |
|
{ |
226 |
112324 |
conf.push_back(d_literalFactCache[lit]); |
227 |
224648 |
Debug("bv-bitblast") |
228 |
112324 |
<< "unsat assumption (" << lit << "): " << conf.back() << std::endl; |
229 |
|
} |
230 |
14972 |
conflict = nm->mkAnd(conf); |
231 |
|
} |
232 |
|
else // Input assertions produce conflict. |
233 |
|
{ |
234 |
|
std::vector<Node> assertions(d_assertions.begin(), d_assertions.end()); |
235 |
|
conflict = nm->mkAnd(assertions); |
236 |
|
} |
237 |
14972 |
d_im.conflict(conflict, InferenceId::BV_BITBLAST_CONFLICT); |
238 |
|
} |
239 |
|
} |
240 |
|
|
241 |
1302326 |
bool BVSolverBitblast::preNotifyFact( |
242 |
|
TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal) |
243 |
|
{ |
244 |
1302326 |
Valuation& val = d_state.getValuation(); |
245 |
|
|
246 |
|
/** |
247 |
|
* Check whether `fact` is an input assertion on user-level 0. |
248 |
|
* |
249 |
|
* If this is the case we can assert `fact` to the SAT solver instead of |
250 |
|
* using assumptions. |
251 |
|
*/ |
252 |
2604660 |
if (options().bv.bvAssertInput && val.isSatLiteral(fact) |
253 |
2604660 |
&& val.getDecisionLevel(fact) == 0 && val.getIntroLevel(fact) == 0) |
254 |
|
{ |
255 |
8 |
Assert(!val.isDecision(fact)); |
256 |
8 |
d_bbInputFacts.push_back(fact); |
257 |
|
} |
258 |
|
else |
259 |
|
{ |
260 |
1302318 |
d_bbFacts.push_back(fact); |
261 |
|
} |
262 |
|
|
263 |
1302326 |
return false; // Return false to enable equality engine reasoning in Theory. |
264 |
|
} |
265 |
|
|
266 |
4806 |
TrustNode BVSolverBitblast::explain(TNode n) |
267 |
|
{ |
268 |
4806 |
Debug("bv-bitblast") << "explain called on " << n << std::endl; |
269 |
4806 |
return d_im.explainLit(n); |
270 |
|
} |
271 |
|
|
272 |
7318 |
void BVSolverBitblast::computeRelevantTerms(std::set<Node>& termSet) |
273 |
|
{ |
274 |
|
/* BITVECTOR_EAGER_ATOM wraps input assertions that may also contain |
275 |
|
* equalities. As a result, these equalities are not handled by the equality |
276 |
|
* engine and terms below these equalities do not appear in `termSet`. |
277 |
|
* We need to make sure that we compute model values for all relevant terms |
278 |
|
* in BitblastMode::EAGER and therefore add all variables from the |
279 |
|
* bit-blaster to `termSet`. |
280 |
|
*/ |
281 |
7318 |
if (options().bv.bitblastMode == options::BitblastMode::EAGER) |
282 |
|
{ |
283 |
10 |
d_bitblaster->computeRelevantTerms(termSet); |
284 |
|
} |
285 |
7318 |
} |
286 |
|
|
287 |
7318 |
bool BVSolverBitblast::collectModelValues(TheoryModel* m, |
288 |
|
const std::set<Node>& termSet) |
289 |
|
{ |
290 |
262811 |
for (const auto& term : termSet) |
291 |
|
{ |
292 |
255493 |
if (!d_bitblaster->isVariable(term)) |
293 |
|
{ |
294 |
216705 |
continue; |
295 |
|
} |
296 |
|
|
297 |
77576 |
Node value = getValue(term, true); |
298 |
38788 |
Assert(value.isConst()); |
299 |
38788 |
if (!m->assertEquality(term, value, true)) |
300 |
|
{ |
301 |
|
return false; |
302 |
|
} |
303 |
|
} |
304 |
|
|
305 |
|
// In eager bitblast mode we also have to collect the model values for |
306 |
|
// Boolean variables in the CNF stream. |
307 |
7318 |
if (options().bv.bitblastMode == options::BitblastMode::EAGER) |
308 |
|
{ |
309 |
10 |
NodeManager* nm = NodeManager::currentNM(); |
310 |
20 |
std::vector<TNode> vars; |
311 |
10 |
d_cnfStream->getBooleanVariables(vars); |
312 |
12 |
for (TNode var : vars) |
313 |
|
{ |
314 |
2 |
Assert(d_cnfStream->hasLiteral(var)); |
315 |
2 |
prop::SatLiteral bit = d_cnfStream->getLiteral(var); |
316 |
2 |
prop::SatValue value = d_satSolver->value(bit); |
317 |
2 |
Assert(value != prop::SAT_VALUE_UNKNOWN); |
318 |
4 |
if (!m->assertEquality( |
319 |
4 |
var, nm->mkConst(value == prop::SAT_VALUE_TRUE), true)) |
320 |
|
{ |
321 |
|
return false; |
322 |
|
} |
323 |
|
} |
324 |
|
} |
325 |
|
|
326 |
7318 |
return true; |
327 |
|
} |
328 |
|
|
329 |
7291 |
void BVSolverBitblast::initSatSolver() |
330 |
|
{ |
331 |
7291 |
switch (options().bv.bvSatSolver) |
332 |
|
{ |
333 |
4 |
case options::SatSolverMode::CRYPTOMINISAT: |
334 |
4 |
d_satSolver.reset(prop::SatSolverFactory::createCryptoMinisat( |
335 |
|
smtStatisticsRegistry(), "theory::bv::BVSolverBitblast::")); |
336 |
4 |
break; |
337 |
7287 |
default: |
338 |
7287 |
d_satSolver.reset(prop::SatSolverFactory::createCadical( |
339 |
|
smtStatisticsRegistry(), "theory::bv::BVSolverBitblast::")); |
340 |
|
} |
341 |
21873 |
d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(), |
342 |
7291 |
d_bbRegistrar.get(), |
343 |
7291 |
d_nullContext.get(), |
344 |
|
nullptr, |
345 |
7291 |
d_env.getResourceManager(), |
346 |
|
prop::FormulaLitPolicy::INTERNAL, |
347 |
7291 |
"theory::bv::BVSolverBitblast")); |
348 |
7291 |
} |
349 |
|
|
350 |
39904 |
Node BVSolverBitblast::getValue(TNode node, bool initialize) |
351 |
|
{ |
352 |
39904 |
if (node.isConst()) |
353 |
|
{ |
354 |
|
return node; |
355 |
|
} |
356 |
|
|
357 |
39904 |
if (!d_bitblaster->hasBBTerm(node)) |
358 |
|
{ |
359 |
654 |
return initialize ? utils::mkConst(utils::getSize(node), 0u) : Node(); |
360 |
|
} |
361 |
|
|
362 |
78500 |
std::vector<Node> bits; |
363 |
39250 |
d_bitblaster->getBBTerm(node, bits); |
364 |
78500 |
Integer value(0), one(1), zero(0), bit; |
365 |
962851 |
for (size_t i = 0, size = bits.size(), j = size - 1; i < size; ++i, --j) |
366 |
|
{ |
367 |
923691 |
if (d_cnfStream->hasLiteral(bits[j])) |
368 |
|
{ |
369 |
916787 |
prop::SatLiteral lit = d_cnfStream->getLiteral(bits[j]); |
370 |
916787 |
prop::SatValue val = d_satSolver->modelValue(lit); |
371 |
916787 |
bit = val == prop::SatValue::SAT_VALUE_TRUE ? one : zero; |
372 |
|
} |
373 |
|
else |
374 |
|
{ |
375 |
6904 |
if (!initialize) return Node(); |
376 |
6814 |
bit = zero; |
377 |
|
} |
378 |
923601 |
value = value * 2 + bit; |
379 |
|
} |
380 |
39160 |
return utils::mkConst(bits.size(), value); |
381 |
|
} |
382 |
|
|
383 |
96 |
void BVSolverBitblast::handleEagerAtom(TNode fact, bool assertFact) |
384 |
|
{ |
385 |
96 |
Assert(fact.getKind() == kind::BITVECTOR_EAGER_ATOM); |
386 |
|
|
387 |
96 |
if (assertFact) |
388 |
|
{ |
389 |
|
d_cnfStream->convertAndAssert(fact[0], false, false); |
390 |
|
} |
391 |
|
else |
392 |
|
{ |
393 |
96 |
d_cnfStream->ensureLiteral(fact[0]); |
394 |
|
} |
395 |
|
|
396 |
|
/* convertAndAssert() does not make the connection between the bit-vector |
397 |
|
* atom and it's bit-blasted form (it only calls preRegister() from the |
398 |
|
* registrar). Thus, we add the equalities now. */ |
399 |
96 |
auto& registeredAtoms = d_bbRegistrar->getRegisteredAtoms(); |
400 |
303 |
for (auto atom : registeredAtoms) |
401 |
|
{ |
402 |
414 |
Node bb_atom = d_bitblaster->getStoredBBAtom(atom); |
403 |
207 |
d_cnfStream->convertAndAssert(atom.eqNode(bb_atom), false, false); |
404 |
|
} |
405 |
|
// Clear cache since we only need to do this once per bit-blasted atom. |
406 |
96 |
registeredAtoms.clear(); |
407 |
96 |
} |
408 |
|
|
409 |
|
} // namespace bv |
410 |
|
} // namespace theory |
411 |
31125 |
} // namespace cvc5 |