5b70fb3a26fabf4b554bde27c9b661194505d51e
1 /******************************************************************************
2 * Top contributors (to current version):
3 * Mathias Preiner, Gereon Kremer, Andres Noetzli
5 * This file is part of the cvc5 project.
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 * ****************************************************************************
13 * Bit-blasting solver that supports multiple SAT backends.
16 #include "theory/bv/bv_solver_bitblast.h"
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"
30 * Notifies the BV solver when assertions were reset.
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.
36 class NotifyResetAssertions
: public context::ContextNotifyObj
39 NotifyResetAssertions(context::Context
* c
)
40 : context::ContextNotifyObj(c
, false),
42 d_doneResetAssertions(false)
46 bool doneResetAssertions() { return d_doneResetAssertions
; }
48 void reset() { d_doneResetAssertions
= false; }
51 void contextNotifyPop() override
53 // If the user-context level reaches 0 it means that reset-assertions was
55 if (d_context
->getLevel() == 0)
57 d_doneResetAssertions
= true;
62 /** The user-context. */
63 context::Context
* d_context
;
65 /** Flag to notify whether reset assertions was called. */
66 bool d_doneResetAssertions
;
70 * Bit-blasting registrar.
72 * The CnfStream calls preRegister() if it encounters a theory atom.
73 * This registrar bit-blasts given atom and remembers which bit-vector atoms
76 * This registrar is needed when --bitblast=eager is enabled.
78 class BBRegistrar
: public prop::Registrar
81 BBRegistrar(NodeBitblaster
* bb
) : d_bitblaster(bb
) {}
83 void preRegister(Node n
) override
85 if (d_registeredAtoms
.find(n
) != d_registeredAtoms
.end())
89 /* We are only interested in bit-vector atoms. */
90 if ((n
.getKind() == kind::EQUAL
&& n
[0].getType().isBitVector())
91 || n
.getKind() == kind::BITVECTOR_ULT
92 || n
.getKind() == kind::BITVECTOR_ULE
93 || n
.getKind() == kind::BITVECTOR_SLT
94 || n
.getKind() == kind::BITVECTOR_SLE
)
96 d_registeredAtoms
.insert(n
);
97 d_bitblaster
->bbAtom(n
);
101 std::unordered_set
<TNode
>& getRegisteredAtoms() { return d_registeredAtoms
; }
104 /** The bitblaster used. */
105 NodeBitblaster
* d_bitblaster
;
107 /** Stores bit-vector atoms encounterd on preRegister(). */
108 std::unordered_set
<TNode
> d_registeredAtoms
;
111 BVSolverBitblast::BVSolverBitblast(TheoryState
* s
,
112 TheoryInferenceManager
& inferMgr
,
113 ProofNodeManager
* pnm
)
114 : BVSolver(*s
, inferMgr
),
115 d_bitblaster(new NodeBitblaster(s
)),
116 d_bbRegistrar(new BBRegistrar(d_bitblaster
.get())),
117 d_nullContext(new context::Context()),
118 d_bbFacts(s
->getSatContext()),
119 d_bbInputFacts(s
->getSatContext()),
120 d_assumptions(s
->getSatContext()),
121 d_assertions(s
->getSatContext()),
122 d_invalidateModelCache(s
->getSatContext(), true),
123 d_inSatMode(s
->getSatContext(), false),
124 d_epg(pnm
? new EagerProofGenerator(pnm
, s
->getUserContext(), "")
126 d_factLiteralCache(s
->getSatContext()),
127 d_literalFactCache(s
->getSatContext()),
128 d_propagate(options::bitvectorPropagate()),
129 d_resetNotify(new NotifyResetAssertions(s
->getUserContext()))
133 d_bvProofChecker
.registerTo(pnm
->getChecker());
139 void BVSolverBitblast::postCheck(Theory::Effort level
)
141 if (level
!= Theory::Effort::EFFORT_FULL
)
143 /* Do bit-level propagation only if the SAT solver supports it. */
144 if (!d_propagate
|| !d_satSolver
->setPropagateOnly())
150 // If we permanently added assertions to the SAT solver and the assertions
151 // were reset, we have to reset the SAT solver and the CNF stream.
152 if (options::bvAssertInput() && d_resetNotify
->doneResetAssertions())
154 d_satSolver
.reset(nullptr);
155 d_cnfStream
.reset(nullptr);
157 d_resetNotify
->reset();
160 NodeManager
* nm
= NodeManager::currentNM();
162 /* Process input assertions bit-blast queue. */
163 while (!d_bbInputFacts
.empty())
165 Node fact
= d_bbInputFacts
.front();
166 d_bbInputFacts
.pop();
167 /* Bit-blast fact and cache literal. */
168 if (d_factLiteralCache
.find(fact
) == d_factLiteralCache
.end())
170 if (fact
.getKind() == kind::BITVECTOR_EAGER_ATOM
)
172 handleEagerAtom(fact
, true);
176 d_bitblaster
->bbAtom(fact
);
177 Node bb_fact
= d_bitblaster
->getStoredBBAtom(fact
);
178 d_cnfStream
->convertAndAssert(bb_fact
, false, false);
181 d_assertions
.push_back(fact
);
184 /* Process bit-blast queue and store SAT literals. */
185 while (!d_bbFacts
.empty())
187 Node fact
= d_bbFacts
.front();
189 /* Bit-blast fact and cache literal. */
190 if (d_factLiteralCache
.find(fact
) == d_factLiteralCache
.end())
192 prop::SatLiteral lit
;
193 if (fact
.getKind() == kind::BITVECTOR_EAGER_ATOM
)
195 handleEagerAtom(fact
, false);
196 lit
= d_cnfStream
->getLiteral(fact
[0]);
200 d_bitblaster
->bbAtom(fact
);
201 Node bb_fact
= d_bitblaster
->getStoredBBAtom(fact
);
202 d_cnfStream
->ensureLiteral(bb_fact
);
203 lit
= d_cnfStream
->getLiteral(bb_fact
);
205 d_factLiteralCache
[fact
] = lit
;
206 d_literalFactCache
[lit
] = fact
;
208 d_assumptions
.push_back(d_factLiteralCache
[fact
]);
211 d_invalidateModelCache
.set(true);
212 std::vector
<prop::SatLiteral
> assumptions(d_assumptions
.begin(),
213 d_assumptions
.end());
214 prop::SatValue val
= d_satSolver
->solve(assumptions
);
215 d_inSatMode
= val
== prop::SatValue::SAT_VALUE_TRUE
;
216 Debug("bv-bitblast") << "d_inSatMode: " << d_inSatMode
<< std::endl
;
218 if (val
== prop::SatValue::SAT_VALUE_FALSE
)
220 std::vector
<prop::SatLiteral
> unsat_assumptions
;
221 d_satSolver
->getUnsatAssumptions(unsat_assumptions
);
224 // Unsat assumptions produce conflict.
225 if (unsat_assumptions
.size() > 0)
227 std::vector
<Node
> conf
;
228 for (const prop::SatLiteral
& lit
: unsat_assumptions
)
230 conf
.push_back(d_literalFactCache
[lit
]);
232 << "unsat assumption (" << lit
<< "): " << conf
.back() << std::endl
;
234 conflict
= nm
->mkAnd(conf
);
236 else // Input assertions produce conflict.
238 std::vector
<Node
> assertions(d_assertions
.begin(), d_assertions
.end());
239 conflict
= nm
->mkAnd(assertions
);
241 d_im
.conflict(conflict
, InferenceId::BV_BITBLAST_CONFLICT
);
245 bool BVSolverBitblast::preNotifyFact(
246 TNode atom
, bool pol
, TNode fact
, bool isPrereg
, bool isInternal
)
248 Valuation
& val
= d_state
.getValuation();
251 * Check whether `fact` is an input assertion on user-level 0.
253 * If this is the case we can assert `fact` to the SAT solver instead of
256 if (options::bvAssertInput() && val
.isSatLiteral(fact
)
257 && val
.getDecisionLevel(fact
) == 0 && val
.getIntroLevel(fact
) == 0)
259 Assert(!val
.isDecision(fact
));
260 d_bbInputFacts
.push_back(fact
);
264 d_bbFacts
.push_back(fact
);
267 return false; // Return false to enable equality engine reasoning in Theory.
270 TrustNode
BVSolverBitblast::explain(TNode n
)
272 Debug("bv-bitblast") << "explain called on " << n
<< std::endl
;
273 return d_im
.explainLit(n
);
276 void BVSolverBitblast::computeRelevantTerms(std::set
<Node
>& termSet
)
278 /* BITVECTOR_EAGER_ATOM wraps input assertions that may also contain
279 * equalities. As a result, these equalities are not handled by the equality
280 * engine and terms below these equalities do not appear in `termSet`.
281 * We need to make sure that we compute model values for all relevant terms
282 * in BitblastMode::EAGER and therefore add all variables from the
283 * bit-blaster to `termSet`.
285 if (options::bitblastMode() == options::BitblastMode::EAGER
)
287 d_bitblaster
->computeRelevantTerms(termSet
);
291 bool BVSolverBitblast::collectModelValues(TheoryModel
* m
,
292 const std::set
<Node
>& termSet
)
294 for (const auto& term
: termSet
)
296 if (!d_bitblaster
->isVariable(term
))
301 Node value
= getValueFromSatSolver(term
, true);
302 Assert(value
.isConst());
303 if (!m
->assertEquality(term
, value
, true))
309 // In eager bitblast mode we also have to collect the model values for
310 // Boolean variables in the CNF stream.
311 if (options::bitblastMode() == options::BitblastMode::EAGER
)
313 NodeManager
* nm
= NodeManager::currentNM();
314 std::vector
<TNode
> vars
;
315 d_cnfStream
->getBooleanVariables(vars
);
316 for (TNode var
: vars
)
318 Assert(d_cnfStream
->hasLiteral(var
));
319 prop::SatLiteral bit
= d_cnfStream
->getLiteral(var
);
320 prop::SatValue value
= d_satSolver
->value(bit
);
321 Assert(value
!= prop::SAT_VALUE_UNKNOWN
);
322 if (!m
->assertEquality(
323 var
, nm
->mkConst(value
== prop::SAT_VALUE_TRUE
), true))
333 EqualityStatus
BVSolverBitblast::getEqualityStatus(TNode a
, TNode b
)
335 Debug("bv-bitblast") << "getEqualityStatus on " << a
<< " and " << b
339 Debug("bv-bitblast") << EQUALITY_UNKNOWN
<< std::endl
;
340 return EQUALITY_UNKNOWN
;
342 Node value_a
= getValue(a
);
343 Node value_b
= getValue(b
);
345 if (value_a
== value_b
)
347 Debug("bv-bitblast") << EQUALITY_TRUE_IN_MODEL
<< std::endl
;
348 return EQUALITY_TRUE_IN_MODEL
;
350 Debug("bv-bitblast") << EQUALITY_FALSE_IN_MODEL
<< std::endl
;
351 return EQUALITY_FALSE_IN_MODEL
;
354 void BVSolverBitblast::initSatSolver()
356 switch (options::bvSatSolver())
358 case options::SatSolverMode::CRYPTOMINISAT
:
359 d_satSolver
.reset(prop::SatSolverFactory::createCryptoMinisat(
360 smtStatisticsRegistry(), "theory::bv::BVSolverBitblast::"));
363 d_satSolver
.reset(prop::SatSolverFactory::createCadical(
364 smtStatisticsRegistry(), "theory::bv::BVSolverBitblast::"));
366 d_cnfStream
.reset(new prop::CnfStream(d_satSolver
.get(),
370 smt::currentResourceManager(),
371 prop::FormulaLitPolicy::INTERNAL
,
372 "theory::bv::BVSolverBitblast"));
375 Node
BVSolverBitblast::getValueFromSatSolver(TNode node
, bool initialize
)
382 if (!d_bitblaster
->hasBBTerm(node
))
384 return initialize
? utils::mkConst(utils::getSize(node
), 0u) : Node();
387 std::vector
<Node
> bits
;
388 d_bitblaster
->getBBTerm(node
, bits
);
389 Integer
value(0), one(1), zero(0), bit
;
390 for (size_t i
= 0, size
= bits
.size(), j
= size
- 1; i
< size
; ++i
, --j
)
392 if (d_cnfStream
->hasLiteral(bits
[j
]))
394 prop::SatLiteral lit
= d_cnfStream
->getLiteral(bits
[j
]);
395 prop::SatValue val
= d_satSolver
->modelValue(lit
);
396 bit
= val
== prop::SatValue::SAT_VALUE_TRUE
? one
: zero
;
400 if (!initialize
) return Node();
403 value
= value
* 2 + bit
;
405 return utils::mkConst(bits
.size(), value
);
408 Node
BVSolverBitblast::getValue(TNode node
)
410 if (d_invalidateModelCache
.get())
412 d_modelCache
.clear();
414 d_invalidateModelCache
.set(false);
416 std::vector
<TNode
> visit
;
419 visit
.push_back(node
);
425 auto it
= d_modelCache
.find(cur
);
426 if (it
!= d_modelCache
.end() && !it
->second
.isNull())
431 if (d_bitblaster
->hasBBTerm(cur
))
433 Node value
= getValueFromSatSolver(cur
, false);
436 d_modelCache
[cur
] = value
;
440 if (Theory::isLeafOf(cur
, theory::THEORY_BV
))
442 Node value
= getValueFromSatSolver(cur
, true);
443 d_modelCache
[cur
] = value
;
447 if (it
== d_modelCache
.end())
449 visit
.push_back(cur
);
450 d_modelCache
.emplace(cur
, Node());
451 visit
.insert(visit
.end(), cur
.begin(), cur
.end());
453 else if (it
->second
.isNull())
455 NodeBuilder
nb(cur
.getKind());
456 if (cur
.getMetaKind() == kind::metakind::PARAMETERIZED
)
458 nb
<< cur
.getOperator();
461 std::unordered_map
<Node
, Node
>::iterator iit
;
462 for (const TNode
& child
: cur
)
464 iit
= d_modelCache
.find(child
);
465 Assert(iit
!= d_modelCache
.end());
466 Assert(iit
->second
.isConst());
469 it
->second
= Rewriter::rewrite(nb
.constructNode());
471 } while (!visit
.empty());
473 auto it
= d_modelCache
.find(node
);
474 Assert(it
!= d_modelCache
.end());
478 void BVSolverBitblast::handleEagerAtom(TNode fact
, bool assertFact
)
480 Assert(fact
.getKind() == kind::BITVECTOR_EAGER_ATOM
);
484 d_cnfStream
->convertAndAssert(fact
[0], false, false);
488 d_cnfStream
->ensureLiteral(fact
[0]);
491 /* convertAndAssert() does not make the connection between the bit-vector
492 * atom and it's bit-blasted form (it only calls preRegister() from the
493 * registrar). Thus, we add the equalities now. */
494 auto& registeredAtoms
= d_bbRegistrar
->getRegisteredAtoms();
495 for (auto atom
: registeredAtoms
)
497 Node bb_atom
= d_bitblaster
->getStoredBBAtom(atom
);
498 d_cnfStream
->convertAndAssert(atom
.eqNode(bb_atom
), false, false);
500 // Clear cache since we only need to do this once per bit-blasted atom.
501 registeredAtoms
.clear();
505 } // namespace theory