1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Liana Hadarean, Mathias Preiner, 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 |
|
* Bitblaster for the eager bv solver. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/bv/bitblast/eager_bitblaster.h" |
17 |
|
|
18 |
|
#include "cvc5_private.h" |
19 |
|
#include "options/bv_options.h" |
20 |
|
#include "options/smt_options.h" |
21 |
|
#include "prop/cnf_stream.h" |
22 |
|
#include "prop/sat_solver_factory.h" |
23 |
|
#include "smt/smt_engine.h" |
24 |
|
#include "smt/smt_statistics_registry.h" |
25 |
|
#include "theory/bv/bv_solver_lazy.h" |
26 |
|
#include "theory/bv/theory_bv.h" |
27 |
|
#include "theory/theory_model.h" |
28 |
|
|
29 |
|
namespace cvc5 { |
30 |
|
namespace theory { |
31 |
|
namespace bv { |
32 |
|
|
33 |
21 |
EagerBitblaster::EagerBitblaster(BVSolverLazy* theory_bv, context::Context* c) |
34 |
|
: TBitblaster<Node>(), |
35 |
|
d_context(c), |
36 |
|
d_satSolver(), |
37 |
21 |
d_bitblastingRegistrar(new BitblastingRegistrar(this)), |
38 |
|
d_bv(theory_bv), |
39 |
|
d_bbAtoms(), |
40 |
|
d_variables(), |
41 |
42 |
d_notify() |
42 |
|
{ |
43 |
21 |
prop::SatSolver *solver = nullptr; |
44 |
56 |
switch (options::bvSatSolver()) |
45 |
|
{ |
46 |
15 |
case options::SatSolverMode::MINISAT: |
47 |
|
{ |
48 |
|
prop::BVSatSolverInterface* minisat = |
49 |
30 |
prop::SatSolverFactory::createMinisat( |
50 |
|
d_nullContext.get(), |
51 |
|
smtStatisticsRegistry(), |
52 |
15 |
"theory::bv::EagerBitblaster::"); |
53 |
15 |
d_notify.reset(new MinisatEmptyNotify()); |
54 |
15 |
minisat->setNotify(d_notify.get()); |
55 |
15 |
solver = minisat; |
56 |
15 |
break; |
57 |
|
} |
58 |
3 |
case options::SatSolverMode::CADICAL: |
59 |
3 |
solver = prop::SatSolverFactory::createCadical( |
60 |
|
smtStatisticsRegistry(), "theory::bv::EagerBitblaster::"); |
61 |
3 |
break; |
62 |
3 |
case options::SatSolverMode::CRYPTOMINISAT: |
63 |
3 |
solver = prop::SatSolverFactory::createCryptoMinisat( |
64 |
|
smtStatisticsRegistry(), "theory::bv::EagerBitblaster::"); |
65 |
3 |
break; |
66 |
|
case options::SatSolverMode::KISSAT: |
67 |
|
solver = prop::SatSolverFactory::createKissat( |
68 |
|
smtStatisticsRegistry(), "theory::bv::EagerBitblaster::"); |
69 |
|
break; |
70 |
|
default: Unreachable() << "Unknown SAT solver type"; |
71 |
|
} |
72 |
21 |
d_satSolver.reset(solver); |
73 |
21 |
ResourceManager* rm = smt::currentResourceManager(); |
74 |
63 |
d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(), |
75 |
21 |
d_bitblastingRegistrar.get(), |
76 |
21 |
d_nullContext.get(), |
77 |
|
nullptr, |
78 |
|
rm, |
79 |
|
prop::FormulaLitPolicy::INTERNAL, |
80 |
21 |
"EagerBitblaster")); |
81 |
21 |
} |
82 |
|
|
83 |
42 |
EagerBitblaster::~EagerBitblaster() {} |
84 |
|
|
85 |
532 |
void EagerBitblaster::bbFormula(TNode node) |
86 |
|
{ |
87 |
|
/* For incremental eager solving we assume formulas at context levels > 1. */ |
88 |
532 |
if (options::incrementalSolving() && d_context->getLevel() > 1) |
89 |
|
{ |
90 |
24 |
d_cnfStream->ensureLiteral(node); |
91 |
|
} |
92 |
|
else |
93 |
|
{ |
94 |
508 |
d_cnfStream->convertAndAssert(node, false, false); |
95 |
|
} |
96 |
532 |
} |
97 |
|
|
98 |
|
/** |
99 |
|
* Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver |
100 |
|
* NOTE: duplicate clauses are not detected because of marker literal |
101 |
|
* @param node the atom to be bitblasted |
102 |
|
* |
103 |
|
*/ |
104 |
2569 |
void EagerBitblaster::bbAtom(TNode node) |
105 |
|
{ |
106 |
2569 |
node = node.getKind() == kind::NOT ? node[0] : node; |
107 |
5138 |
if (node.getKind() == kind::BITVECTOR_BITOF |
108 |
5138 |
|| node.getKind() == kind::CONST_BOOLEAN || hasBBAtom(node)) |
109 |
|
{ |
110 |
1906 |
return; |
111 |
|
} |
112 |
|
|
113 |
663 |
Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n"; |
114 |
|
|
115 |
|
// the bitblasted definition of the atom |
116 |
1326 |
Node normalized = Rewriter::rewrite(node); |
117 |
|
Node atom_bb = |
118 |
663 |
normalized.getKind() != kind::CONST_BOOLEAN |
119 |
663 |
? d_atomBBStrategies[normalized.getKind()](normalized, this) |
120 |
1989 |
: normalized; |
121 |
|
|
122 |
663 |
atom_bb = Rewriter::rewrite(atom_bb); |
123 |
|
|
124 |
|
// asserting that the atom is true iff the definition holds |
125 |
|
Node atom_definition = |
126 |
1326 |
NodeManager::currentNM()->mkNode(kind::EQUAL, node, atom_bb); |
127 |
|
|
128 |
663 |
AlwaysAssert(options::bitblastMode() == options::BitblastMode::EAGER); |
129 |
663 |
storeBBAtom(node, atom_bb); |
130 |
663 |
d_cnfStream->convertAndAssert(atom_definition, false, false); |
131 |
|
} |
132 |
|
|
133 |
663 |
void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) { |
134 |
663 |
d_bbAtoms.insert(atom); |
135 |
663 |
} |
136 |
|
|
137 |
669 |
void EagerBitblaster::storeBBTerm(TNode node, const Bits& bits) { |
138 |
669 |
d_termCache.insert(std::make_pair(node, bits)); |
139 |
669 |
} |
140 |
|
|
141 |
663 |
bool EagerBitblaster::hasBBAtom(TNode atom) const { |
142 |
663 |
return d_bbAtoms.find(atom) != d_bbAtoms.end(); |
143 |
|
} |
144 |
|
|
145 |
1989 |
void EagerBitblaster::bbTerm(TNode node, Bits& bits) { |
146 |
1989 |
Assert(node.getType().isBitVector()); |
147 |
|
|
148 |
1989 |
if (hasBBTerm(node)) { |
149 |
1320 |
getBBTerm(node, bits); |
150 |
1320 |
return; |
151 |
|
} |
152 |
|
|
153 |
669 |
d_bv->spendResource(Resource::BitblastStep); |
154 |
669 |
Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n"; |
155 |
|
|
156 |
669 |
d_termBBStrategies[node.getKind()](node, bits, this); |
157 |
|
|
158 |
669 |
Assert(bits.size() == utils::getSize(node)); |
159 |
|
|
160 |
669 |
storeBBTerm(node, bits); |
161 |
|
} |
162 |
|
|
163 |
271 |
void EagerBitblaster::makeVariable(TNode var, Bits& bits) { |
164 |
271 |
Assert(bits.size() == 0); |
165 |
2183 |
for (unsigned i = 0; i < utils::getSize(var); ++i) { |
166 |
1912 |
bits.push_back(utils::mkBitOf(var, i)); |
167 |
|
} |
168 |
271 |
d_variables.insert(var); |
169 |
271 |
} |
170 |
|
|
171 |
|
Node EagerBitblaster::getBBAtom(TNode node) const { return node; } |
172 |
|
|
173 |
|
/** |
174 |
|
* Calls the solve method for the Sat Solver. |
175 |
|
* |
176 |
|
* @return true for sat, and false for unsat |
177 |
|
*/ |
178 |
|
|
179 |
13 |
bool EagerBitblaster::solve() { |
180 |
13 |
if (Trace.isOn("bitvector")) { |
181 |
|
Trace("bitvector") << "EagerBitblaster::solve(). \n"; |
182 |
|
} |
183 |
13 |
Debug("bitvector") << "EagerBitblaster::solve(). \n"; |
184 |
|
// TODO: clear some memory |
185 |
|
// if (something) { |
186 |
|
// NodeManager* nm= NodeManager::currentNM(); |
187 |
|
// Rewriter::garbageCollect(); |
188 |
|
// nm->reclaimZombiesUntil(options::zombieHuntThreshold()); |
189 |
|
// } |
190 |
13 |
return prop::SAT_VALUE_TRUE == d_satSolver->solve(); |
191 |
|
} |
192 |
|
|
193 |
24 |
bool EagerBitblaster::solve(const std::vector<Node>& assumptions) |
194 |
|
{ |
195 |
48 |
std::vector<prop::SatLiteral> assumpts; |
196 |
42 |
for (const Node& assumption : assumptions) |
197 |
|
{ |
198 |
18 |
Assert(d_cnfStream->hasLiteral(assumption)); |
199 |
18 |
assumpts.push_back(d_cnfStream->getLiteral(assumption)); |
200 |
|
} |
201 |
48 |
return prop::SAT_VALUE_TRUE == d_satSolver->solve(assumpts); |
202 |
|
} |
203 |
|
|
204 |
|
/** |
205 |
|
* Returns the value a is currently assigned to in the SAT solver |
206 |
|
* or null if the value is completely unassigned. |
207 |
|
* |
208 |
|
* @param a |
209 |
|
* @param fullModel whether to create a "full model," i.e., add |
210 |
|
* constants to equivalence classes that don't already have them |
211 |
|
* |
212 |
|
* @return |
213 |
|
*/ |
214 |
21 |
Node EagerBitblaster::getModelFromSatSolver(TNode a, bool fullModel) { |
215 |
21 |
if (!hasBBTerm(a)) { |
216 |
|
return fullModel ? utils::mkConst(utils::getSize(a), 0u) : Node(); |
217 |
|
} |
218 |
|
|
219 |
42 |
Bits bits; |
220 |
21 |
getBBTerm(a, bits); |
221 |
42 |
Integer value(0); |
222 |
357 |
for (int i = bits.size() - 1; i >= 0; --i) { |
223 |
|
prop::SatValue bit_value; |
224 |
336 |
if (d_cnfStream->hasLiteral(bits[i])) { |
225 |
336 |
prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]); |
226 |
336 |
bit_value = d_satSolver->value(bit); |
227 |
336 |
Assert(bit_value != prop::SAT_VALUE_UNKNOWN); |
228 |
|
} else { |
229 |
|
if (!fullModel) return Node(); |
230 |
|
// unconstrained bits default to false |
231 |
|
bit_value = prop::SAT_VALUE_FALSE; |
232 |
|
} |
233 |
|
Integer bit_int = |
234 |
672 |
bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0); |
235 |
336 |
value = value * 2 + bit_int; |
236 |
|
} |
237 |
21 |
return utils::mkConst(bits.size(), value); |
238 |
|
} |
239 |
|
|
240 |
9 |
bool EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel) |
241 |
|
{ |
242 |
9 |
NodeManager* nm = NodeManager::currentNM(); |
243 |
|
|
244 |
|
// Collect the values for the bit-vector variables |
245 |
9 |
TNodeSet::iterator it = d_variables.begin(); |
246 |
51 |
for (; it != d_variables.end(); ++it) { |
247 |
42 |
TNode var = *it; |
248 |
63 |
if (d_bv->isLeaf(var) || isSharedTerm(var) || |
249 |
21 |
(var.isVar() && var.getType().isBoolean())) { |
250 |
|
// only shared terms could not have been bit-blasted |
251 |
21 |
Assert(hasBBTerm(var) || isSharedTerm(var)); |
252 |
|
|
253 |
42 |
Node const_value = getModelFromSatSolver(var, true); |
254 |
|
|
255 |
21 |
if (const_value != Node()) { |
256 |
42 |
Debug("bitvector-model") |
257 |
21 |
<< "EagerBitblaster::collectModelInfo (assert (= " << var << " " |
258 |
21 |
<< const_value << "))\n"; |
259 |
21 |
if (!m->assertEquality(var, const_value, true)) |
260 |
|
{ |
261 |
|
return false; |
262 |
|
} |
263 |
|
} |
264 |
|
} |
265 |
|
} |
266 |
|
|
267 |
|
// Collect the values for the Boolean variables |
268 |
18 |
std::vector<TNode> vars; |
269 |
9 |
d_cnfStream->getBooleanVariables(vars); |
270 |
15 |
for (TNode var : vars) |
271 |
|
{ |
272 |
6 |
Assert(d_cnfStream->hasLiteral(var)); |
273 |
6 |
prop::SatLiteral bit = d_cnfStream->getLiteral(var); |
274 |
6 |
prop::SatValue value = d_satSolver->value(bit); |
275 |
6 |
Assert(value != prop::SAT_VALUE_UNKNOWN); |
276 |
12 |
if (!m->assertEquality( |
277 |
12 |
var, nm->mkConst(value == prop::SAT_VALUE_TRUE), true)) |
278 |
|
{ |
279 |
|
return false; |
280 |
|
} |
281 |
|
} |
282 |
9 |
return true; |
283 |
|
} |
284 |
|
|
285 |
|
bool EagerBitblaster::isSharedTerm(TNode node) { |
286 |
|
return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end(); |
287 |
|
} |
288 |
|
|
289 |
|
|
290 |
|
} // namespace bv |
291 |
|
} // namespace theory |
292 |
27770 |
} // namespace cvc5 |