1 /********************* */
2 /*! \file bool_to_bv.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Makai Mann, Yoni Zohar, Clark Barrett
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
11 **
12 ** \brief The BoolToBV preprocessing pass
13 **
14 **/
15
16 #include "preprocessing/passes/bool_to_bv.h"
17
18 #include <string>
19
20 #include "base/map_util.h"
21 #include "expr/node.h"
22 #include "options/bv_options.h"
23 #include "smt/smt_statistics_registry.h"
24 #include "theory/rewriter.h"
25 #include "theory/theory.h"
26
27 namespace CVC4 {
28 namespace preprocessing {
29 namespace passes {
30 using namespace CVC4::theory;
31
BoolToBV(PreprocessingPassContext * preprocContext)32 BoolToBV::BoolToBV(PreprocessingPassContext* preprocContext)
33 : PreprocessingPass(preprocContext, "bool-to-bv"), d_statistics(){};
34
applyInternal(AssertionPipeline * assertionsToPreprocess)35 PreprocessingPassResult BoolToBV::applyInternal(
36 AssertionPipeline* assertionsToPreprocess)
37 {
38 NodeManager::currentResourceManager()->spendResource(
39 options::preprocessStep());
40
41 unsigned size = assertionsToPreprocess->size();
42 for (unsigned i = 0; i < size; ++i)
43 {
44 assertionsToPreprocess->replace(
45 i, Rewriter::rewrite(lowerAssertion((*assertionsToPreprocess)[i])));
46 }
47
48 return PreprocessingPassResult::NO_CONFLICT;
49 }
50
fromCache(TNode n) const51 Node BoolToBV::fromCache(TNode n) const
52 {
53 if (d_lowerCache.find(n) != d_lowerCache.end())
54 {
55 return d_lowerCache.find(n)->second;
56 }
57 return n;
58 }
59
needToRebuild(TNode n) const60 bool BoolToBV::needToRebuild(TNode n) const
61 {
62 // check if any children were rebuilt
63 for (const Node& nn : n)
64 {
65 if (ContainsKey(d_lowerCache, nn))
66 {
67 return true;
68 }
69 }
70 return false;
71 }
72
lowerAssertion(const TNode & a)73 Node BoolToBV::lowerAssertion(const TNode& a)
74 {
75 bool optionITE = options::boolToBitvector() == BOOL_TO_BV_ITE;
76 NodeManager* nm = NodeManager::currentNM();
77 std::vector<TNode> visit;
78 visit.push_back(a);
79 std::unordered_set<TNode, TNodeHashFunction> visited;
80 // for ite mode, keeps track of whether you're in an ite condition
81 // for all mode, unused
82 std::unordered_set<TNode, TNodeHashFunction> ite_cond;
83
84 while (!visit.empty())
85 {
86 TNode n = visit.back();
87 visit.pop_back();
88
89 int numChildren = n.getNumChildren();
90 Kind k = n.getKind();
91 Debug("bool-to-bv") << "BoolToBV::lowerAssertion Post-traversal with " << n
92 << " and visited = " << ContainsKey(visited, n)
93 << std::endl;
94
95 // Mark as visited
96 /* Optimization: if it's a leaf, don't need to wait to do the work */
97 if (!ContainsKey(visited, n) && (numChildren > 0))
98 {
99 visited.insert(n);
100 visit.push_back(n);
101
102 // insert children in reverse order so that they're processed in order
103 // important for rewriting which sorts by node id
104 for (int i = numChildren - 1; i >= 0; --i)
105 {
106 visit.push_back(n[i]);
107 }
108
109 if (optionITE)
110 {
111 // check for ite-conditions
112 if (k == kind::ITE)
113 {
114 ite_cond.insert(n[0]);
115 }
116 else if (ContainsKey(ite_cond, n))
117 {
118 // being part of an ite condition is inherited from the parent
119 ite_cond.insert(n.begin(), n.end());
120 }
121 }
122 }
123 /* Optimization for ite mode */
124 else if (optionITE && !ContainsKey(ite_cond, n) && !needToRebuild(n))
125 {
126 Debug("bool-to-bv")
127 << "BoolToBV::lowerAssertion Skipping because don't need to rebuild: "
128 << n << std::endl;
129 // in ite mode, if you've already visited the node but it's not
130 // in an ite condition and doesn't need to be rebuilt, then
131 // don't need to do anything
132 continue;
133 }
134 else
135 {
136 lowerNode(n);
137 }
138 }
139
140 if (fromCache(a).getType().isBitVector())
141 {
142 return nm->mkNode(kind::EQUAL, fromCache(a), bv::utils::mkOne(1));
143 }
144 else
145 {
146 Assert(a == fromCache(a));
147 return a;
148 }
149 }
150
lowerNode(const TNode & n)151 void BoolToBV::lowerNode(const TNode& n)
152 {
153 NodeManager* nm = NodeManager::currentNM();
154 Kind k = n.getKind();
155
156 bool all_bv = true;
157 // check if it was able to convert all children to bitvectors
158 for (const Node& nn : n)
159 {
160 all_bv = all_bv && fromCache(nn).getType().isBitVector();
161 if (!all_bv)
162 {
163 break;
164 }
165 }
166
167 if (!all_bv || (n.getNumChildren() == 0))
168 {
169 if ((options::boolToBitvector() == BOOL_TO_BV_ALL)
170 && n.getType().isBoolean())
171 {
172 if (k == kind::CONST_BOOLEAN)
173 {
174 d_lowerCache[n] = (n == bv::utils::mkTrue()) ? bv::utils::mkOne(1)
175 : bv::utils::mkZero(1);
176 }
177 else
178 {
179 d_lowerCache[n] =
180 nm->mkNode(kind::ITE, n, bv::utils::mkOne(1), bv::utils::mkZero(1));
181 }
182
183 Debug("bool-to-bv") << "BoolToBV::lowerNode " << n << " =>\n"
184 << fromCache(n) << std::endl;
185 ++(d_statistics.d_numTermsForcedLowered);
186 return;
187 }
188 else
189 {
190 // invariant
191 // either one of the children is not a bit-vector or bool
192 // i.e. something that can't be 'forced' to a bitvector
193 // or it's in 'ite' mode which will give up on bools that
194 // can't be converted easily
195
196 Debug("bool-to-bv") << "BoolToBV::lowerNode skipping: " << n << std::endl;
197 return;
198 }
199 }
200
201 Kind new_kind = k;
202 switch (k)
203 {
204 case kind::EQUAL: new_kind = kind::BITVECTOR_COMP; break;
205 case kind::AND: new_kind = kind::BITVECTOR_AND; break;
206 case kind::OR: new_kind = kind::BITVECTOR_OR; break;
207 case kind::NOT: new_kind = kind::BITVECTOR_NOT; break;
208 case kind::XOR: new_kind = kind::BITVECTOR_XOR; break;
209 case kind::IMPLIES: new_kind = kind::BITVECTOR_OR; break;
210 case kind::ITE: new_kind = kind::BITVECTOR_ITE; break;
211 case kind::BITVECTOR_ULT: new_kind = kind::BITVECTOR_ULTBV; break;
212 case kind::BITVECTOR_SLT: new_kind = kind::BITVECTOR_SLTBV; break;
213 case kind::BITVECTOR_ULE:
214 case kind::BITVECTOR_UGT:
215 case kind::BITVECTOR_UGE:
216 case kind::BITVECTOR_SLE:
217 case kind::BITVECTOR_SGT:
218 case kind::BITVECTOR_SGE:
219 // Should have been removed by rewriting.
220 Unreachable();
221 default: break;
222 }
223
224 NodeBuilder<> builder(new_kind);
225 if ((options::boolToBitvector() == BOOL_TO_BV_ALL) && (new_kind != k))
226 {
227 ++(d_statistics.d_numTermsLowered);
228 }
229
230 if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
231 {
232 builder << n.getOperator();
233 }
234
235 // special case IMPLIES because needs to be rewritten
236 if (k == kind::IMPLIES)
237 {
238 builder << nm->mkNode(kind::BITVECTOR_NOT, fromCache(n[0]));
239 builder << fromCache(n[1]);
240 }
241 else
242 {
243 for (const Node& nn : n)
244 {
245 builder << fromCache(nn);
246 }
247 }
248
249 Debug("bool-to-bv") << "BoolToBV::lowerNode " << n << " =>\n"
250 << builder << std::endl;
251
252 d_lowerCache[n] = builder.constructNode();
253 }
254
Statistics()255 BoolToBV::Statistics::Statistics()
256 : d_numIteToBvite("preprocessing::passes::BoolToBV::NumIteToBvite", 0),
257 d_numTermsLowered("preprocessing::passes:BoolToBV::NumTermsLowered", 0),
258 d_numTermsForcedLowered(
259 "preprocessing::passes::BoolToBV::NumTermsForcedLowered", 0)
260 {
261 smtStatisticsRegistry()->registerStat(&d_numIteToBvite);
262 if (options::boolToBitvector() == BOOL_TO_BV_ALL)
263 {
264 // these statistics wouldn't be correct in the ITE mode,
265 // because it might discard rebuilt nodes if it fails to
266 // convert a bool to width-one bit-vector (never forces)
267 smtStatisticsRegistry()->registerStat(&d_numTermsLowered);
268 smtStatisticsRegistry()->registerStat(&d_numTermsForcedLowered);
269 }
270 }
271
~Statistics()272 BoolToBV::Statistics::~Statistics()
273 {
274 smtStatisticsRegistry()->unregisterStat(&d_numIteToBvite);
275 if (options::boolToBitvector() == BOOL_TO_BV_ALL)
276 {
277 smtStatisticsRegistry()->unregisterStat(&d_numTermsLowered);
278 smtStatisticsRegistry()->unregisterStat(&d_numTermsForcedLowered);
279 }
280 }
281
282
283 } // namespace passes
284 } // namespace preprocessing
285 } // namespace CVC4
286