1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Tim King, Aina Niemetz, Clark Barrett |
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 |
|
* Simplifications for ITE expressions. |
14 |
|
* |
15 |
|
* This module implements preprocessing phases designed to simplify ITE |
16 |
|
* expressions. Based on: |
17 |
|
* Kim, Somenzi, Jin. Efficient Term-ITE Conversion for SMT. FMCAD 2009. |
18 |
|
* Burch, Jerry. Techniques for Verifying Superscalar Microprocessors. DAC |
19 |
|
*'96 |
20 |
|
*/ |
21 |
|
#include "preprocessing/util/ite_utilities.h" |
22 |
|
|
23 |
|
#include <utility> |
24 |
|
|
25 |
|
#include "expr/skolem_manager.h" |
26 |
|
#include "preprocessing/assertion_pipeline.h" |
27 |
|
#include "preprocessing/passes/rewrite.h" |
28 |
|
#include "smt/smt_statistics_registry.h" |
29 |
|
#include "theory/rewriter.h" |
30 |
|
#include "theory/theory.h" |
31 |
|
|
32 |
|
using namespace std; |
33 |
|
namespace cvc5 { |
34 |
|
namespace preprocessing { |
35 |
|
namespace util { |
36 |
|
|
37 |
|
namespace ite { |
38 |
|
|
39 |
120184 |
inline static bool isTermITE(TNode e) |
40 |
|
{ |
41 |
120184 |
return (e.getKind() == kind::ITE && !e.getType().isBoolean()); |
42 |
|
} |
43 |
|
|
44 |
116531 |
inline static bool triviallyContainsNoTermITEs(TNode e) |
45 |
|
{ |
46 |
116531 |
return e.isConst() || e.isVar(); |
47 |
|
} |
48 |
|
|
49 |
10516 |
static bool isTheoryAtom(TNode a) |
50 |
|
{ |
51 |
|
using namespace kind; |
52 |
10516 |
switch (a.getKind()) |
53 |
|
{ |
54 |
218 |
case EQUAL: |
55 |
218 |
case DISTINCT: return !(a[0].getType().isBoolean()); |
56 |
|
|
57 |
|
/* from uf */ |
58 |
|
case APPLY_UF: return a.getType().isBoolean(); |
59 |
88 |
case CARDINALITY_CONSTRAINT: |
60 |
|
case DIVISIBLE: |
61 |
|
case LT: |
62 |
|
case LEQ: |
63 |
|
case GT: |
64 |
|
case GEQ: |
65 |
|
case IS_INTEGER: |
66 |
|
case BITVECTOR_COMP: |
67 |
|
case BITVECTOR_ULT: |
68 |
|
case BITVECTOR_ULE: |
69 |
|
case BITVECTOR_UGT: |
70 |
|
case BITVECTOR_UGE: |
71 |
|
case BITVECTOR_SLT: |
72 |
|
case BITVECTOR_SLE: |
73 |
|
case BITVECTOR_SGT: |
74 |
88 |
case BITVECTOR_SGE: return true; |
75 |
10210 |
default: return false; |
76 |
|
} |
77 |
|
} |
78 |
|
|
79 |
194850 |
struct CTIVStackElement |
80 |
|
{ |
81 |
|
TNode curr; |
82 |
|
unsigned pos; |
83 |
|
CTIVStackElement() : curr(), pos(0) {} |
84 |
44990 |
CTIVStackElement(TNode c) : curr(c), pos(0) {} |
85 |
|
}; /* CTIVStackElement */ |
86 |
|
|
87 |
|
} // namespace ite |
88 |
|
|
89 |
9459 |
ITEUtilities::ITEUtilities() |
90 |
9459 |
: d_containsVisitor(new ContainsTermITEVisitor()), |
91 |
|
d_compressor(NULL), |
92 |
|
d_simplifier(NULL), |
93 |
18918 |
d_careSimp(NULL) |
94 |
|
{ |
95 |
9459 |
Assert(d_containsVisitor != NULL); |
96 |
9459 |
} |
97 |
|
|
98 |
18918 |
ITEUtilities::~ITEUtilities() |
99 |
|
{ |
100 |
9459 |
if (d_simplifier != NULL) |
101 |
|
{ |
102 |
2 |
delete d_simplifier; |
103 |
|
} |
104 |
9459 |
if (d_compressor != NULL) |
105 |
|
{ |
106 |
2 |
delete d_compressor; |
107 |
|
} |
108 |
9459 |
if (d_careSimp != NULL) |
109 |
|
{ |
110 |
|
delete d_careSimp; |
111 |
|
} |
112 |
9459 |
} |
113 |
|
|
114 |
2 |
Node ITEUtilities::simpITE(TNode assertion) |
115 |
|
{ |
116 |
2 |
if (d_simplifier == NULL) |
117 |
|
{ |
118 |
2 |
d_simplifier = new ITESimplifier(d_containsVisitor.get()); |
119 |
|
} |
120 |
2 |
return d_simplifier->simpITE(assertion); |
121 |
|
} |
122 |
|
|
123 |
2 |
bool ITEUtilities::simpIteDidALotOfWorkHeuristic() const |
124 |
|
{ |
125 |
2 |
if (d_simplifier == NULL) |
126 |
|
{ |
127 |
|
return false; |
128 |
|
} |
129 |
|
else |
130 |
|
{ |
131 |
2 |
return d_simplifier->doneALotOfWorkHeuristic(); |
132 |
|
} |
133 |
|
} |
134 |
|
|
135 |
|
/* returns false if an assertion is discovered to be equal to false. */ |
136 |
2 |
bool ITEUtilities::compress(AssertionPipeline* assertionsToPreprocess) |
137 |
|
{ |
138 |
2 |
if (d_compressor == NULL) |
139 |
|
{ |
140 |
2 |
d_compressor = new ITECompressor(d_containsVisitor.get()); |
141 |
|
} |
142 |
2 |
return d_compressor->compress(assertionsToPreprocess); |
143 |
|
} |
144 |
|
|
145 |
|
Node ITEUtilities::simplifyWithCare(TNode e) |
146 |
|
{ |
147 |
|
if (d_careSimp == NULL) |
148 |
|
{ |
149 |
|
d_careSimp = new ITECareSimplifier(); |
150 |
|
} |
151 |
|
return d_careSimp->simplifyWithCare(e); |
152 |
|
} |
153 |
|
|
154 |
|
void ITEUtilities::clear() |
155 |
|
{ |
156 |
|
if (d_simplifier != NULL) |
157 |
|
{ |
158 |
|
d_simplifier->clearSimpITECaches(); |
159 |
|
} |
160 |
|
if (d_compressor != NULL) |
161 |
|
{ |
162 |
|
d_compressor->garbageCollect(); |
163 |
|
} |
164 |
|
if (d_careSimp != NULL) |
165 |
|
{ |
166 |
|
d_careSimp->clear(); |
167 |
|
} |
168 |
|
d_containsVisitor->garbageCollect(); |
169 |
|
} |
170 |
|
|
171 |
|
/** ContainsTermITEVisitor. */ |
172 |
23949 |
ContainsTermITEVisitor::ContainsTermITEVisitor() : d_cache() {} |
173 |
23949 |
ContainsTermITEVisitor::~ContainsTermITEVisitor() {} |
174 |
20042 |
bool ContainsTermITEVisitor::containsTermITE(TNode e) |
175 |
|
{ |
176 |
|
/* throughout execution skip through NOT nodes. */ |
177 |
20042 |
e = (e.getKind() == kind::NOT) ? e[0] : e; |
178 |
20042 |
if (ite::triviallyContainsNoTermITEs(e)) |
179 |
|
{ |
180 |
4904 |
return false; |
181 |
|
} |
182 |
|
|
183 |
15138 |
NodeBoolMap::const_iterator end = d_cache.end(); |
184 |
15138 |
NodeBoolMap::const_iterator tmp_it = d_cache.find(e); |
185 |
15138 |
if (tmp_it != end) |
186 |
|
{ |
187 |
2356 |
return (*tmp_it).second; |
188 |
|
} |
189 |
|
|
190 |
12782 |
bool foundTermIte = false; |
191 |
25564 |
std::vector<ite::CTIVStackElement> stack; |
192 |
12782 |
stack.push_back(ite::CTIVStackElement(e)); |
193 |
287800 |
while (!foundTermIte && !stack.empty()) |
194 |
|
{ |
195 |
137509 |
ite::CTIVStackElement& top = stack.back(); |
196 |
275018 |
TNode curr = top.curr; |
197 |
137509 |
if (top.pos >= curr.getNumChildren()) |
198 |
|
{ |
199 |
|
// all of the children have been visited |
200 |
|
// no term ites were found |
201 |
41020 |
d_cache[curr] = false; |
202 |
41020 |
stack.pop_back(); |
203 |
|
} |
204 |
|
else |
205 |
|
{ |
206 |
|
// this is someone's child |
207 |
192978 |
TNode child = curr[top.pos]; |
208 |
96489 |
child = (child.getKind() == kind::NOT) ? child[0] : child; |
209 |
96489 |
++top.pos; |
210 |
96489 |
if (ite::triviallyContainsNoTermITEs(child)) |
211 |
|
{ |
212 |
|
// skip |
213 |
|
} |
214 |
|
else |
215 |
|
{ |
216 |
34498 |
tmp_it = d_cache.find(child); |
217 |
34498 |
if (tmp_it != end) |
218 |
|
{ |
219 |
2290 |
foundTermIte = (*tmp_it).second; |
220 |
|
} |
221 |
|
else |
222 |
|
{ |
223 |
32208 |
stack.push_back(ite::CTIVStackElement(child)); |
224 |
32208 |
foundTermIte = ite::isTermITE(child); |
225 |
|
} |
226 |
|
} |
227 |
|
} |
228 |
|
} |
229 |
12782 |
if (foundTermIte) |
230 |
|
{ |
231 |
10994 |
while (!stack.empty()) |
232 |
|
{ |
233 |
7940 |
TNode curr = stack.back().curr; |
234 |
3970 |
stack.pop_back(); |
235 |
3970 |
d_cache[curr] = true; |
236 |
|
} |
237 |
|
} |
238 |
12782 |
return foundTermIte; |
239 |
|
} |
240 |
|
void ContainsTermITEVisitor::garbageCollect() { d_cache.clear(); } |
241 |
|
|
242 |
|
/** IncomingArcCounter. */ |
243 |
2 |
IncomingArcCounter::IncomingArcCounter(bool skipVars, bool skipConstants) |
244 |
2 |
: d_reachCount(), d_skipVariables(skipVars), d_skipConstants(skipConstants) |
245 |
|
{ |
246 |
2 |
} |
247 |
2 |
IncomingArcCounter::~IncomingArcCounter() {} |
248 |
|
|
249 |
2 |
void IncomingArcCounter::computeReachability( |
250 |
|
const std::vector<Node>& assertions) |
251 |
|
{ |
252 |
4 |
std::vector<TNode> tovisit(assertions.begin(), assertions.end()); |
253 |
|
|
254 |
458090 |
while (!tovisit.empty()) |
255 |
|
{ |
256 |
457060 |
TNode back = tovisit.back(); |
257 |
229044 |
tovisit.pop_back(); |
258 |
|
|
259 |
229044 |
bool skip = false; |
260 |
229044 |
switch (back.getMetaKind()) |
261 |
|
{ |
262 |
608 |
case kind::metakind::CONSTANT: skip = d_skipConstants; break; |
263 |
420 |
case kind::metakind::VARIABLE: skip = d_skipVariables; break; |
264 |
228016 |
default: break; |
265 |
|
} |
266 |
|
|
267 |
229044 |
if (skip) |
268 |
|
{ |
269 |
1028 |
continue; |
270 |
|
} |
271 |
228016 |
if (d_reachCount.find(back) != d_reachCount.end()) |
272 |
|
{ |
273 |
212844 |
d_reachCount[back] = 1 + d_reachCount[back]; |
274 |
|
} |
275 |
|
else |
276 |
|
{ |
277 |
15172 |
d_reachCount[back] = 1; |
278 |
244212 |
for (TNode::iterator cit = back.begin(), end = back.end(); cit != end; |
279 |
|
++cit) |
280 |
|
{ |
281 |
229040 |
tovisit.push_back(*cit); |
282 |
|
} |
283 |
|
} |
284 |
|
} |
285 |
2 |
} |
286 |
|
|
287 |
4 |
void IncomingArcCounter::clear() { d_reachCount.clear(); } |
288 |
|
|
289 |
|
/** ITECompressor. */ |
290 |
2 |
ITECompressor::ITECompressor(ContainsTermITEVisitor* contains) |
291 |
2 |
: d_contains(contains), d_assertions(NULL), d_incoming(true, true) |
292 |
|
{ |
293 |
2 |
Assert(d_contains != NULL); |
294 |
|
|
295 |
2 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
296 |
2 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
297 |
2 |
} |
298 |
|
|
299 |
2 |
ITECompressor::~ITECompressor() { reset(); } |
300 |
|
|
301 |
4 |
void ITECompressor::reset() |
302 |
|
{ |
303 |
4 |
d_incoming.clear(); |
304 |
4 |
d_compressed.clear(); |
305 |
4 |
} |
306 |
|
|
307 |
|
void ITECompressor::garbageCollect() { reset(); } |
308 |
|
|
309 |
2 |
ITECompressor::Statistics::Statistics() |
310 |
|
: d_compressCalls( |
311 |
4 |
smtStatisticsRegistry().registerInt("ite-simp::compressCalls")), |
312 |
4 |
d_skolemsAdded(smtStatisticsRegistry().registerInt("ite-simp::skolems")) |
313 |
|
{ |
314 |
2 |
} |
315 |
|
|
316 |
3440 |
Node ITECompressor::push_back_boolean(Node original, Node compressed) |
317 |
|
{ |
318 |
6880 |
Node rewritten = theory::Rewriter::rewrite(compressed); |
319 |
|
// There is a bug if the rewritter takes a pure boolean expression |
320 |
|
// and changes its theory |
321 |
3440 |
if (rewritten.isConst()) |
322 |
|
{ |
323 |
|
d_compressed[compressed] = rewritten; |
324 |
|
d_compressed[original] = rewritten; |
325 |
|
d_compressed[rewritten] = rewritten; |
326 |
|
return rewritten; |
327 |
|
} |
328 |
3440 |
else if (d_compressed.find(rewritten) != d_compressed.end()) |
329 |
|
{ |
330 |
|
Node res = d_compressed[rewritten]; |
331 |
|
d_compressed[original] = res; |
332 |
|
d_compressed[compressed] = res; |
333 |
|
return res; |
334 |
|
} |
335 |
6880 |
else if (rewritten.isVar() |
336 |
6880 |
|| (rewritten.getKind() == kind::NOT && rewritten[0].isVar())) |
337 |
|
{ |
338 |
1022 |
d_compressed[original] = rewritten; |
339 |
1022 |
d_compressed[compressed] = rewritten; |
340 |
1022 |
d_compressed[rewritten] = rewritten; |
341 |
1022 |
return rewritten; |
342 |
|
} |
343 |
|
else |
344 |
|
{ |
345 |
2418 |
NodeManager* nm = NodeManager::currentNM(); |
346 |
2418 |
SkolemManager* sm = nm->getSkolemManager(); |
347 |
4836 |
Node skolem = sm->mkDummySkolem("compress", nm->booleanType()); |
348 |
2418 |
d_compressed[rewritten] = skolem; |
349 |
2418 |
d_compressed[original] = skolem; |
350 |
2418 |
d_compressed[compressed] = skolem; |
351 |
|
|
352 |
4836 |
Node iff = skolem.eqNode(rewritten); |
353 |
2418 |
d_assertions->push_back(iff); |
354 |
2418 |
++(d_statistics.d_skolemsAdded); |
355 |
2418 |
return skolem; |
356 |
|
} |
357 |
|
} |
358 |
|
|
359 |
14218 |
bool ITECompressor::multipleParents(TNode c) |
360 |
|
{ |
361 |
14218 |
return d_incoming.lookupIncoming(c) >= 2; |
362 |
|
} |
363 |
|
|
364 |
3840 |
Node ITECompressor::compressBooleanITEs(Node toCompress) |
365 |
|
{ |
366 |
3840 |
Assert(toCompress.getKind() == kind::ITE); |
367 |
3840 |
Assert(toCompress.getType().isBoolean()); |
368 |
|
|
369 |
3840 |
if (!(toCompress[1] == d_false || toCompress[2] == d_false)) |
370 |
|
{ |
371 |
7680 |
Node cmpCnd = compressBoolean(toCompress[0]); |
372 |
3840 |
if (cmpCnd.isConst()) |
373 |
|
{ |
374 |
|
Node branch = (cmpCnd == d_true) ? toCompress[1] : toCompress[2]; |
375 |
|
Node res = compressBoolean(branch); |
376 |
|
d_compressed[toCompress] = res; |
377 |
|
return res; |
378 |
|
} |
379 |
|
else |
380 |
|
{ |
381 |
7680 |
Node cmpThen = compressBoolean(toCompress[1]); |
382 |
7680 |
Node cmpElse = compressBoolean(toCompress[2]); |
383 |
7680 |
Node newIte = cmpCnd.iteNode(cmpThen, cmpElse); |
384 |
3840 |
if (multipleParents(toCompress)) |
385 |
|
{ |
386 |
1068 |
return push_back_boolean(toCompress, newIte); |
387 |
|
} |
388 |
|
else |
389 |
|
{ |
390 |
2772 |
return newIte; |
391 |
|
} |
392 |
|
} |
393 |
|
} |
394 |
|
|
395 |
|
NodeBuilder nb(kind::AND); |
396 |
|
Node curr = toCompress; |
397 |
|
while (curr.getKind() == kind::ITE |
398 |
|
&& (curr[1] == d_false || curr[2] == d_false) |
399 |
|
&& (!multipleParents(curr) || curr == toCompress)) |
400 |
|
{ |
401 |
|
bool negateCnd = (curr[1] == d_false); |
402 |
|
Node compressCnd = compressBoolean(curr[0]); |
403 |
|
if (compressCnd.isConst()) |
404 |
|
{ |
405 |
|
if (compressCnd.getConst<bool>() == negateCnd) |
406 |
|
{ |
407 |
|
return push_back_boolean(toCompress, d_false); |
408 |
|
} |
409 |
|
else |
410 |
|
{ |
411 |
|
// equivalent to true don't push back |
412 |
|
} |
413 |
|
} |
414 |
|
else |
415 |
|
{ |
416 |
|
Node pb = negateCnd ? compressCnd.notNode() : compressCnd; |
417 |
|
nb << pb; |
418 |
|
} |
419 |
|
curr = negateCnd ? curr[2] : curr[1]; |
420 |
|
} |
421 |
|
Assert(toCompress != curr); |
422 |
|
|
423 |
|
nb << compressBoolean(curr); |
424 |
|
Node res = nb.getNumChildren() == 1 ? nb[0] : (Node)nb; |
425 |
|
return push_back_boolean(toCompress, res); |
426 |
|
} |
427 |
|
|
428 |
2244 |
Node ITECompressor::compressTerm(Node toCompress) |
429 |
|
{ |
430 |
2244 |
if (toCompress.isConst() || toCompress.isVar()) |
431 |
|
{ |
432 |
1026 |
return toCompress; |
433 |
|
} |
434 |
|
|
435 |
1218 |
if (d_compressed.find(toCompress) != d_compressed.end()) |
436 |
|
{ |
437 |
402 |
return d_compressed[toCompress]; |
438 |
|
} |
439 |
816 |
if (toCompress.getKind() == kind::ITE) |
440 |
|
{ |
441 |
1296 |
Node cmpCnd = compressBoolean(toCompress[0]); |
442 |
648 |
if (cmpCnd.isConst()) |
443 |
|
{ |
444 |
|
Node branch = (cmpCnd == d_true) ? toCompress[1] : toCompress[2]; |
445 |
|
Node res = compressTerm(branch); |
446 |
|
d_compressed[toCompress] = res; |
447 |
|
return res; |
448 |
|
} |
449 |
|
else |
450 |
|
{ |
451 |
1296 |
Node cmpThen = compressTerm(toCompress[1]); |
452 |
1296 |
Node cmpElse = compressTerm(toCompress[2]); |
453 |
1296 |
Node newIte = cmpCnd.iteNode(cmpThen, cmpElse); |
454 |
648 |
d_compressed[toCompress] = newIte; |
455 |
648 |
return newIte; |
456 |
|
} |
457 |
|
} |
458 |
|
|
459 |
336 |
NodeBuilder nb(toCompress.getKind()); |
460 |
|
|
461 |
168 |
if (toCompress.getMetaKind() == kind::metakind::PARAMETERIZED) |
462 |
|
{ |
463 |
|
nb << (toCompress.getOperator()); |
464 |
|
} |
465 |
504 |
for (Node::iterator it = toCompress.begin(), end = toCompress.end(); |
466 |
504 |
it != end; |
467 |
|
++it) |
468 |
|
{ |
469 |
336 |
nb << compressTerm(*it); |
470 |
|
} |
471 |
336 |
Node compressed = (Node)nb; |
472 |
168 |
if (multipleParents(toCompress)) |
473 |
|
{ |
474 |
26 |
d_compressed[toCompress] = compressed; |
475 |
|
} |
476 |
168 |
return compressed; |
477 |
|
} |
478 |
|
|
479 |
226800 |
Node ITECompressor::compressBoolean(Node toCompress) |
480 |
|
{ |
481 |
|
static int instance = 0; |
482 |
226800 |
++instance; |
483 |
226800 |
if (toCompress.isConst() || toCompress.isVar()) |
484 |
|
{ |
485 |
2 |
return toCompress; |
486 |
|
} |
487 |
226798 |
if (d_compressed.find(toCompress) != d_compressed.end()) |
488 |
|
{ |
489 |
212442 |
return d_compressed[toCompress]; |
490 |
|
} |
491 |
14356 |
else if (toCompress.getKind() == kind::ITE) |
492 |
|
{ |
493 |
3840 |
return compressBooleanITEs(toCompress); |
494 |
|
} |
495 |
|
else |
496 |
|
{ |
497 |
10516 |
bool ta = ite::isTheoryAtom(toCompress); |
498 |
21032 |
NodeBuilder nb(toCompress.getKind()); |
499 |
10516 |
if (toCompress.getMetaKind() == kind::metakind::PARAMETERIZED) |
500 |
|
{ |
501 |
|
nb << (toCompress.getOperator()); |
502 |
|
} |
503 |
225756 |
for (Node::iterator it = toCompress.begin(), end = toCompress.end(); |
504 |
225756 |
it != end; |
505 |
|
++it) |
506 |
|
{ |
507 |
430480 |
Node pb = (ta) ? compressTerm(*it) : compressBoolean(*it); |
508 |
215240 |
nb << pb; |
509 |
|
} |
510 |
21032 |
Node compressed = nb; |
511 |
10516 |
if (ta || multipleParents(toCompress)) |
512 |
|
{ |
513 |
2372 |
return push_back_boolean(toCompress, compressed); |
514 |
|
} |
515 |
|
else |
516 |
|
{ |
517 |
8144 |
return compressed; |
518 |
|
} |
519 |
|
} |
520 |
|
} |
521 |
|
|
522 |
2 |
bool ITECompressor::compress(AssertionPipeline* assertionsToPreprocess) |
523 |
|
{ |
524 |
2 |
reset(); |
525 |
|
|
526 |
2 |
d_assertions = assertionsToPreprocess; |
527 |
2 |
d_incoming.computeReachability(assertionsToPreprocess->ref()); |
528 |
|
|
529 |
2 |
++(d_statistics.d_compressCalls); |
530 |
2 |
Chat() << "Computed reachability" << endl; |
531 |
|
|
532 |
2 |
bool nofalses = true; |
533 |
2 |
const std::vector<Node>& assertions = assertionsToPreprocess->ref(); |
534 |
2 |
size_t original_size = assertions.size(); |
535 |
2 |
Chat() << "compressing " << original_size << endl; |
536 |
6 |
for (size_t i = 0; i < original_size && nofalses; ++i) |
537 |
|
{ |
538 |
8 |
Node assertion = assertions[i]; |
539 |
8 |
Node compressed = compressBoolean(assertion); |
540 |
8 |
Node rewritten = theory::Rewriter::rewrite(compressed); |
541 |
|
// replace |
542 |
4 |
assertionsToPreprocess->replace(i, rewritten); |
543 |
4 |
Assert(!d_contains->containsTermITE(rewritten)); |
544 |
|
|
545 |
4 |
nofalses = (rewritten != d_false); |
546 |
|
} |
547 |
|
|
548 |
2 |
d_assertions = NULL; |
549 |
|
|
550 |
2 |
return nofalses; |
551 |
|
} |
552 |
|
|
553 |
2 |
TermITEHeightCounter::TermITEHeightCounter() : d_termITEHeight() {} |
554 |
|
|
555 |
2 |
TermITEHeightCounter::~TermITEHeightCounter() {} |
556 |
|
|
557 |
2 |
void TermITEHeightCounter::clear() { d_termITEHeight.clear(); } |
558 |
|
|
559 |
|
size_t TermITEHeightCounter::cache_size() const |
560 |
|
{ |
561 |
|
return d_termITEHeight.size(); |
562 |
|
} |
563 |
|
|
564 |
|
namespace ite { |
565 |
|
struct TITEHStackElement |
566 |
|
{ |
567 |
|
TNode curr; |
568 |
|
unsigned pos; |
569 |
|
uint32_t maxChildHeight; |
570 |
|
TITEHStackElement() : curr(), pos(0), maxChildHeight(0) {} |
571 |
|
TITEHStackElement(TNode c) : curr(c), pos(0), maxChildHeight(0) {} |
572 |
|
}; |
573 |
|
} /* namespace ite */ |
574 |
|
|
575 |
|
uint32_t TermITEHeightCounter::termITEHeight(TNode e) |
576 |
|
{ |
577 |
|
if (ite::triviallyContainsNoTermITEs(e)) |
578 |
|
{ |
579 |
|
return 0; |
580 |
|
} |
581 |
|
|
582 |
|
NodeCountMap::const_iterator end = d_termITEHeight.end(); |
583 |
|
NodeCountMap::const_iterator tmp_it = d_termITEHeight.find(e); |
584 |
|
if (tmp_it != end) |
585 |
|
{ |
586 |
|
return (*tmp_it).second; |
587 |
|
} |
588 |
|
|
589 |
|
uint32_t returnValue = 0; |
590 |
|
// This is initially 0 as the very first call this is included in the max, |
591 |
|
// but this has no effect. |
592 |
|
std::vector<ite::TITEHStackElement> stack; |
593 |
|
stack.push_back(ite::TITEHStackElement(e)); |
594 |
|
while (!stack.empty()) |
595 |
|
{ |
596 |
|
ite::TITEHStackElement& top = stack.back(); |
597 |
|
top.maxChildHeight = std::max(top.maxChildHeight, returnValue); |
598 |
|
TNode curr = top.curr; |
599 |
|
if (top.pos >= curr.getNumChildren()) |
600 |
|
{ |
601 |
|
// done with the current node |
602 |
|
returnValue = top.maxChildHeight + (ite::isTermITE(curr) ? 1 : 0); |
603 |
|
d_termITEHeight[curr] = returnValue; |
604 |
|
stack.pop_back(); |
605 |
|
continue; |
606 |
|
} |
607 |
|
else |
608 |
|
{ |
609 |
|
if (top.pos == 0 && curr.getKind() == kind::ITE) |
610 |
|
{ |
611 |
|
++top.pos; |
612 |
|
returnValue = 0; |
613 |
|
continue; |
614 |
|
} |
615 |
|
// this is someone's child |
616 |
|
TNode child = curr[top.pos]; |
617 |
|
++top.pos; |
618 |
|
if (ite::triviallyContainsNoTermITEs(child)) |
619 |
|
{ |
620 |
|
returnValue = 0; |
621 |
|
} |
622 |
|
else |
623 |
|
{ |
624 |
|
tmp_it = d_termITEHeight.find(child); |
625 |
|
if (tmp_it != end) |
626 |
|
{ |
627 |
|
returnValue = (*tmp_it).second; |
628 |
|
} |
629 |
|
else |
630 |
|
{ |
631 |
|
stack.push_back(ite::TITEHStackElement(child)); |
632 |
|
} |
633 |
|
} |
634 |
|
} |
635 |
|
} |
636 |
|
return returnValue; |
637 |
|
} |
638 |
|
|
639 |
2 |
ITESimplifier::ITESimplifier(ContainsTermITEVisitor* contains) |
640 |
|
: d_containsVisitor(contains), |
641 |
|
d_termITEHeight(), |
642 |
|
d_constantLeaves(), |
643 |
|
d_allocatedConstantLeaves(), |
644 |
|
d_citeEqConstApplications(0), |
645 |
|
d_constantIteEqualsConstantCache(), |
646 |
|
d_replaceOverCache(), |
647 |
|
d_replaceOverTermIteCache(), |
648 |
|
d_leavesConstCache(), |
649 |
|
d_simpConstCache(), |
650 |
|
d_simpContextCache(), |
651 |
2 |
d_simpITECache() |
652 |
|
{ |
653 |
2 |
Assert(d_containsVisitor != NULL); |
654 |
2 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
655 |
2 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
656 |
2 |
} |
657 |
|
|
658 |
4 |
ITESimplifier::~ITESimplifier() |
659 |
|
{ |
660 |
2 |
clearSimpITECaches(); |
661 |
2 |
Assert(d_constantLeaves.empty()); |
662 |
2 |
Assert(d_allocatedConstantLeaves.empty()); |
663 |
2 |
} |
664 |
|
|
665 |
312 |
bool ITESimplifier::leavesAreConst(TNode e) |
666 |
|
{ |
667 |
312 |
return leavesAreConst(e, theory::Theory::theoryOf(e)); |
668 |
|
} |
669 |
|
|
670 |
2 |
void ITESimplifier::clearSimpITECaches() |
671 |
|
{ |
672 |
2 |
Chat() << "clear ite caches " << endl; |
673 |
1512 |
for (size_t i = 0, N = d_allocatedConstantLeaves.size(); i < N; ++i) |
674 |
|
{ |
675 |
1510 |
NodeVec* curr = d_allocatedConstantLeaves[i]; |
676 |
1510 |
delete curr; |
677 |
|
} |
678 |
2 |
d_citeEqConstApplications = 0; |
679 |
2 |
d_constantLeaves.clear(); |
680 |
2 |
d_allocatedConstantLeaves.clear(); |
681 |
2 |
d_termITEHeight.clear(); |
682 |
2 |
d_constantIteEqualsConstantCache.clear(); |
683 |
2 |
d_replaceOverCache.clear(); |
684 |
2 |
d_replaceOverTermIteCache.clear(); |
685 |
2 |
d_simpITECache.clear(); |
686 |
2 |
d_simpVars.clear(); |
687 |
2 |
d_simpConstCache.clear(); |
688 |
2 |
d_leavesConstCache.clear(); |
689 |
2 |
d_simpContextCache.clear(); |
690 |
2 |
} |
691 |
|
|
692 |
2 |
bool ITESimplifier::doneALotOfWorkHeuristic() const |
693 |
|
{ |
694 |
|
static const size_t SIZE_BOUND = 1000; |
695 |
2 |
Chat() << "d_citeEqConstApplications size " << d_citeEqConstApplications |
696 |
|
<< endl; |
697 |
2 |
return (d_citeEqConstApplications > SIZE_BOUND); |
698 |
|
} |
699 |
|
|
700 |
2 |
ITESimplifier::Statistics::Statistics() |
701 |
|
: d_maxNonConstantsFolded( |
702 |
4 |
smtStatisticsRegistry().registerInt("ite-simp::maxNonConstantsFolded")), |
703 |
4 |
d_unexpected(smtStatisticsRegistry().registerInt("ite-simp::unexpected")), |
704 |
|
d_unsimplified( |
705 |
4 |
smtStatisticsRegistry().registerInt("ite-simp::unsimplified")), |
706 |
|
d_exactMatchFold( |
707 |
4 |
smtStatisticsRegistry().registerInt("ite-simp::exactMatchFold")), |
708 |
|
d_binaryPredFold( |
709 |
4 |
smtStatisticsRegistry().registerInt("ite-simp::binaryPredFold")), |
710 |
2 |
d_specialEqualityFolds(smtStatisticsRegistry().registerInt( |
711 |
4 |
"ite-simp::specialEqualityFolds")), |
712 |
|
d_simpITEVisits( |
713 |
4 |
smtStatisticsRegistry().registerInt("ite-simp::simpITE.visits")), |
714 |
2 |
d_inSmaller(smtStatisticsRegistry().registerHistogram<uint32_t>( |
715 |
16 |
"ite-simp::inSmaller")) |
716 |
|
{ |
717 |
2 |
} |
718 |
|
|
719 |
2506 |
bool ITESimplifier::isConstantIte(TNode e) |
720 |
|
{ |
721 |
2506 |
if (e.isConst()) |
722 |
|
{ |
723 |
1146 |
return true; |
724 |
|
} |
725 |
1360 |
else if (ite::isTermITE(e)) |
726 |
|
{ |
727 |
1360 |
NodeVec* constants = computeConstantLeaves(e); |
728 |
1360 |
return constants != NULL; |
729 |
|
} |
730 |
|
else |
731 |
|
{ |
732 |
|
return false; |
733 |
|
} |
734 |
|
} |
735 |
|
|
736 |
86616 |
ITESimplifier::NodeVec* ITESimplifier::computeConstantLeaves(TNode ite) |
737 |
|
{ |
738 |
86616 |
Assert(ite::isTermITE(ite)); |
739 |
86616 |
ConstantLeavesMap::const_iterator it = d_constantLeaves.find(ite); |
740 |
86616 |
ConstantLeavesMap::const_iterator end = d_constantLeaves.end(); |
741 |
86616 |
if (it != end) |
742 |
|
{ |
743 |
84892 |
return (*it).second; |
744 |
|
} |
745 |
3448 |
TNode thenB = ite[1]; |
746 |
3448 |
TNode elseB = ite[2]; |
747 |
|
|
748 |
|
// special case 2 constant children |
749 |
1724 |
if (thenB.isConst() && elseB.isConst()) |
750 |
|
{ |
751 |
304 |
NodeVec* pair = new NodeVec(2); |
752 |
304 |
d_allocatedConstantLeaves.push_back(pair); |
753 |
|
|
754 |
304 |
(*pair)[0] = std::min(thenB, elseB); |
755 |
304 |
(*pair)[1] = std::max(thenB, elseB); |
756 |
304 |
d_constantLeaves[ite] = pair; |
757 |
304 |
return pair; |
758 |
|
} |
759 |
|
// At least 1 is an ITE |
760 |
3478 |
if (!(thenB.isConst() || thenB.getKind() == kind::ITE) |
761 |
2628 |
|| !(elseB.isConst() || elseB.getKind() == kind::ITE)) |
762 |
|
{ |
763 |
|
// Cannot be a termITE tree |
764 |
214 |
d_constantLeaves[ite] = NULL; |
765 |
214 |
return NULL; |
766 |
|
} |
767 |
|
|
768 |
|
// At least 1 is not a constant |
769 |
2412 |
TNode definitelyITE = thenB.isConst() ? elseB : thenB; |
770 |
2412 |
TNode maybeITE = thenB.isConst() ? thenB : elseB; |
771 |
|
|
772 |
1206 |
NodeVec* defChildren = computeConstantLeaves(definitelyITE); |
773 |
1206 |
if (defChildren == NULL) |
774 |
|
{ |
775 |
|
d_constantLeaves[ite] = NULL; |
776 |
|
return NULL; |
777 |
|
} |
778 |
|
|
779 |
2412 |
NodeVec scratch; |
780 |
1206 |
NodeVec* maybeChildren = NULL; |
781 |
1206 |
if (maybeITE.getKind() == kind::ITE) |
782 |
|
{ |
783 |
384 |
maybeChildren = computeConstantLeaves(maybeITE); |
784 |
|
} |
785 |
|
else |
786 |
|
{ |
787 |
822 |
scratch.push_back(maybeITE); |
788 |
822 |
maybeChildren = &scratch; |
789 |
|
} |
790 |
1206 |
if (maybeChildren == NULL) |
791 |
|
{ |
792 |
|
d_constantLeaves[ite] = NULL; |
793 |
|
return NULL; |
794 |
|
} |
795 |
|
|
796 |
1206 |
NodeVec* both = new NodeVec(defChildren->size() + maybeChildren->size()); |
797 |
1206 |
d_allocatedConstantLeaves.push_back(both); |
798 |
1206 |
NodeVec::iterator newEnd; |
799 |
1206 |
newEnd = std::set_union(defChildren->begin(), |
800 |
|
defChildren->end(), |
801 |
|
maybeChildren->begin(), |
802 |
|
maybeChildren->end(), |
803 |
1206 |
both->begin()); |
804 |
1206 |
both->resize(newEnd - both->begin()); |
805 |
1206 |
d_constantLeaves[ite] = both; |
806 |
1206 |
return both; |
807 |
|
} |
808 |
|
|
809 |
|
// This is uncached! Better for protoyping or getting limited size examples |
810 |
|
struct IteTreeSearchData |
811 |
|
{ |
812 |
|
set<Node> visited; |
813 |
|
set<Node> constants; |
814 |
|
set<Node> nonConstants; |
815 |
|
int maxConstants; |
816 |
|
int maxNonconstants; |
817 |
|
int maxDepth; |
818 |
|
bool failure; |
819 |
|
IteTreeSearchData() |
820 |
|
: maxConstants(-1), maxNonconstants(-1), maxDepth(-1), failure(false) |
821 |
|
{ |
822 |
|
} |
823 |
|
}; |
824 |
|
void iteTreeSearch(Node e, int depth, IteTreeSearchData& search) |
825 |
|
{ |
826 |
|
if (search.maxDepth >= 0 && depth > search.maxDepth) |
827 |
|
{ |
828 |
|
search.failure = true; |
829 |
|
} |
830 |
|
if (search.failure) |
831 |
|
{ |
832 |
|
return; |
833 |
|
} |
834 |
|
if (search.visited.find(e) != search.visited.end()) |
835 |
|
{ |
836 |
|
return; |
837 |
|
} |
838 |
|
else |
839 |
|
{ |
840 |
|
search.visited.insert(e); |
841 |
|
} |
842 |
|
|
843 |
|
if (e.isConst()) |
844 |
|
{ |
845 |
|
search.constants.insert(e); |
846 |
|
if (search.maxConstants >= 0 |
847 |
|
&& search.constants.size() > (unsigned)search.maxConstants) |
848 |
|
{ |
849 |
|
search.failure = true; |
850 |
|
} |
851 |
|
} |
852 |
|
else if (e.getKind() == kind::ITE) |
853 |
|
{ |
854 |
|
iteTreeSearch(e[1], depth + 1, search); |
855 |
|
iteTreeSearch(e[2], depth + 1, search); |
856 |
|
} |
857 |
|
else |
858 |
|
{ |
859 |
|
search.nonConstants.insert(e); |
860 |
|
if (search.maxNonconstants >= 0 |
861 |
|
&& search.nonConstants.size() > (unsigned)search.maxNonconstants) |
862 |
|
{ |
863 |
|
search.failure = true; |
864 |
|
} |
865 |
|
} |
866 |
|
} |
867 |
|
|
868 |
|
Node ITESimplifier::replaceOver(Node n, Node replaceWith, Node simpVar) |
869 |
|
{ |
870 |
|
if (n == simpVar) |
871 |
|
{ |
872 |
|
return replaceWith; |
873 |
|
} |
874 |
|
else if (n.getNumChildren() == 0) |
875 |
|
{ |
876 |
|
return n; |
877 |
|
} |
878 |
|
Assert(n.getNumChildren() > 0); |
879 |
|
Assert(!n.isVar()); |
880 |
|
|
881 |
|
pair<Node, Node> p = make_pair(n, replaceWith); |
882 |
|
if (d_replaceOverCache.find(p) != d_replaceOverCache.end()) |
883 |
|
{ |
884 |
|
return d_replaceOverCache[p]; |
885 |
|
} |
886 |
|
|
887 |
|
NodeBuilder builder(n.getKind()); |
888 |
|
if (n.getMetaKind() == kind::metakind::PARAMETERIZED) |
889 |
|
{ |
890 |
|
builder << n.getOperator(); |
891 |
|
} |
892 |
|
unsigned i = 0; |
893 |
|
for (; i < n.getNumChildren(); ++i) |
894 |
|
{ |
895 |
|
Node newChild = replaceOver(n[i], replaceWith, simpVar); |
896 |
|
builder << newChild; |
897 |
|
} |
898 |
|
// Mark the substitution and continue |
899 |
|
Node result = builder; |
900 |
|
d_replaceOverCache[p] = result; |
901 |
|
return result; |
902 |
|
} |
903 |
|
|
904 |
|
Node ITESimplifier::replaceOverTermIte(Node e, Node simpAtom, Node simpVar) |
905 |
|
{ |
906 |
|
if (e.getKind() == kind::ITE) |
907 |
|
{ |
908 |
|
pair<Node, Node> p = make_pair(e, simpAtom); |
909 |
|
if (d_replaceOverTermIteCache.find(p) != d_replaceOverTermIteCache.end()) |
910 |
|
{ |
911 |
|
return d_replaceOverTermIteCache[p]; |
912 |
|
} |
913 |
|
Assert(!e.getType().isBoolean()); |
914 |
|
Node cnd = e[0]; |
915 |
|
Node newThen = replaceOverTermIte(e[1], simpAtom, simpVar); |
916 |
|
Node newElse = replaceOverTermIte(e[2], simpAtom, simpVar); |
917 |
|
Node newIte = cnd.iteNode(newThen, newElse); |
918 |
|
d_replaceOverTermIteCache[p] = newIte; |
919 |
|
return newIte; |
920 |
|
} |
921 |
|
else |
922 |
|
{ |
923 |
|
return replaceOver(simpAtom, e, simpVar); |
924 |
|
} |
925 |
|
} |
926 |
|
|
927 |
|
Node ITESimplifier::attemptLiftEquality(TNode atom) |
928 |
|
{ |
929 |
|
if (atom.getKind() == kind::EQUAL) |
930 |
|
{ |
931 |
|
TNode left = atom[0]; |
932 |
|
TNode right = atom[1]; |
933 |
|
if ((left.getKind() == kind::ITE || right.getKind() == kind::ITE) |
934 |
|
&& !(left.getKind() == kind::ITE && right.getKind() == kind::ITE)) |
935 |
|
{ |
936 |
|
// exactly 1 is an ite |
937 |
|
TNode ite = left.getKind() == kind::ITE ? left : right; |
938 |
|
TNode notIte = left.getKind() == kind::ITE ? right : left; |
939 |
|
|
940 |
|
if (notIte == ite[1]) |
941 |
|
{ |
942 |
|
++(d_statistics.d_exactMatchFold); |
943 |
|
return ite[0].iteNode(d_true, notIte.eqNode(ite[2])); |
944 |
|
} |
945 |
|
else if (notIte == ite[2]) |
946 |
|
{ |
947 |
|
++(d_statistics.d_exactMatchFold); |
948 |
|
return ite[0].iteNode(notIte.eqNode(ite[1]), d_true); |
949 |
|
} |
950 |
|
if (notIte.isConst() && (ite[1].isConst() || ite[2].isConst())) |
951 |
|
{ |
952 |
|
++(d_statistics.d_exactMatchFold); |
953 |
|
return ite[0].iteNode(notIte.eqNode(ite[1]), notIte.eqNode(ite[2])); |
954 |
|
} |
955 |
|
} |
956 |
|
} |
957 |
|
|
958 |
|
// try a similar more relaxed version for non-equality operators |
959 |
|
if (atom.getMetaKind() == kind::metakind::OPERATOR |
960 |
|
&& atom.getNumChildren() == 2 && !atom[1].getType().isBoolean()) |
961 |
|
{ |
962 |
|
TNode left = atom[0]; |
963 |
|
TNode right = atom[1]; |
964 |
|
if ((left.getKind() == kind::ITE || right.getKind() == kind::ITE) |
965 |
|
&& !(left.getKind() == kind::ITE && right.getKind() == kind::ITE)) |
966 |
|
{ |
967 |
|
// exactly 1 is an ite |
968 |
|
bool leftIsIte = left.getKind() == kind::ITE; |
969 |
|
Node ite = leftIsIte ? left : right; |
970 |
|
Node notIte = leftIsIte ? right : left; |
971 |
|
|
972 |
|
if (notIte.isConst()) |
973 |
|
{ |
974 |
|
IteTreeSearchData search; |
975 |
|
search.maxNonconstants = 2; |
976 |
|
iteTreeSearch(ite, 0, search); |
977 |
|
if (!search.failure) |
978 |
|
{ |
979 |
|
d_statistics.d_maxNonConstantsFolded.maxAssign( |
980 |
|
search.nonConstants.size()); |
981 |
|
Debug("ite::simpite") << "used " << search.nonConstants.size() |
982 |
|
<< " nonconstants" << endl; |
983 |
|
NodeManager* nm = NodeManager::currentNM(); |
984 |
|
Node simpVar = getSimpVar(notIte.getType()); |
985 |
|
TNode newLeft = leftIsIte ? simpVar : notIte; |
986 |
|
TNode newRight = leftIsIte ? notIte : simpVar; |
987 |
|
Node newAtom = nm->mkNode(atom.getKind(), newLeft, newRight); |
988 |
|
|
989 |
|
++(d_statistics.d_binaryPredFold); |
990 |
|
return replaceOverTermIte(ite, newAtom, simpVar); |
991 |
|
} |
992 |
|
} |
993 |
|
} |
994 |
|
} |
995 |
|
|
996 |
|
// TODO "This is way too tailored. Must generalize!" |
997 |
|
if (atom.getKind() == kind::EQUAL && atom.getNumChildren() == 2 |
998 |
|
&& ite::isTermITE(atom[0]) && atom[1].getKind() == kind::MULT |
999 |
|
&& atom[1].getNumChildren() == 2 && atom[1][0].isConst() |
1000 |
|
&& atom[1][0].getConst<Rational>().isNegativeOne() |
1001 |
|
&& ite::isTermITE(atom[1][1]) |
1002 |
|
&& d_termITEHeight.termITEHeight(atom[0]) == 1 |
1003 |
|
&& d_termITEHeight.termITEHeight(atom[1][1]) == 1 |
1004 |
|
&& (atom[0][1].isConst() || atom[0][2].isConst()) |
1005 |
|
&& (atom[1][1][1].isConst() || atom[1][1][2].isConst())) |
1006 |
|
{ |
1007 |
|
// expand all 4 cases |
1008 |
|
|
1009 |
|
Node negOne = atom[1][0]; |
1010 |
|
|
1011 |
|
Node lite = atom[0]; |
1012 |
|
Node lC = lite[0]; |
1013 |
|
Node lT = lite[1]; |
1014 |
|
Node lE = lite[2]; |
1015 |
|
|
1016 |
|
NodeManager* nm = NodeManager::currentNM(); |
1017 |
|
Node negRite = atom[1][1]; |
1018 |
|
Node rC = negRite[0]; |
1019 |
|
Node rT = nm->mkNode(kind::MULT, negOne, negRite[1]); |
1020 |
|
Node rE = nm->mkNode(kind::MULT, negOne, negRite[2]); |
1021 |
|
|
1022 |
|
// (ite lC lT lE) = (ite rC rT rE) |
1023 |
|
// (ite lc (= lT (ite rC rT rE) (= lE (ite rC rT rE)))) |
1024 |
|
// (ite lc (ite rC (= lT rT) (= lT rE)) |
1025 |
|
// (ite rC (= lE rT) (= lE rE))) |
1026 |
|
|
1027 |
|
Node eqTT = lT.eqNode(rT); |
1028 |
|
Node eqTE = lT.eqNode(rE); |
1029 |
|
Node eqET = lE.eqNode(rT); |
1030 |
|
Node eqEE = lE.eqNode(rE); |
1031 |
|
Node thenLC = rC.iteNode(eqTT, eqTE); |
1032 |
|
Node elseLC = rC.iteNode(eqET, eqEE); |
1033 |
|
Node newIte = lC.iteNode(thenLC, elseLC); |
1034 |
|
|
1035 |
|
++(d_statistics.d_specialEqualityFolds); |
1036 |
|
return newIte; |
1037 |
|
} |
1038 |
|
return Node::null(); |
1039 |
|
} |
1040 |
|
|
1041 |
|
// Interesting classes of atoms: |
1042 |
|
// 2. Contains constants and 1 constant term ite |
1043 |
|
// 3. Contains 2 constant term ites |
1044 |
1458 |
Node ITESimplifier::transformAtom(TNode atom) |
1045 |
|
{ |
1046 |
1458 |
if (!d_containsVisitor->containsTermITE(atom)) |
1047 |
|
{ |
1048 |
|
if (atom.getKind() == kind::EQUAL && atom[0].isConst() && atom[1].isConst()) |
1049 |
|
{ |
1050 |
|
// constant equality |
1051 |
|
return NodeManager::currentNM()->mkConst<bool>(atom[0] == atom[1]); |
1052 |
|
} |
1053 |
|
return Node::null(); |
1054 |
|
} |
1055 |
|
else |
1056 |
|
{ |
1057 |
2916 |
Node acr = attemptConstantRemoval(atom); |
1058 |
1458 |
if (!acr.isNull()) |
1059 |
|
{ |
1060 |
1146 |
return acr; |
1061 |
|
} |
1062 |
|
// Node ale = attemptLiftEquality(atom); |
1063 |
|
// if(!ale.isNull()){ |
1064 |
|
// //return ale; |
1065 |
|
// } |
1066 |
312 |
return Node::null(); |
1067 |
|
} |
1068 |
|
} |
1069 |
|
|
1070 |
|
static unsigned numBranches = 0; |
1071 |
|
static unsigned numFalseBranches = 0; |
1072 |
|
static unsigned itesMade = 0; |
1073 |
|
|
1074 |
134678 |
Node ITESimplifier::constantIteEqualsConstant(TNode cite, TNode constant) |
1075 |
|
{ |
1076 |
|
static int instance = 0; |
1077 |
134678 |
++instance; |
1078 |
269356 |
Debug("ite::constantIteEqualsConstant") |
1079 |
134678 |
<< instance << "constantIteEqualsConstant(" << cite << ", " << constant |
1080 |
134678 |
<< ")" << endl; |
1081 |
134678 |
if (cite.isConst()) |
1082 |
|
{ |
1083 |
91356 |
Node res = (cite == constant) ? d_true : d_false; |
1084 |
45678 |
Debug("ite::constantIteEqualsConstant") << instance << "->" << res << endl; |
1085 |
45678 |
return res; |
1086 |
|
} |
1087 |
178000 |
std::pair<Node, Node> pair = make_pair(cite, constant); |
1088 |
|
|
1089 |
|
NodePairMap::const_iterator eq_pos = |
1090 |
89000 |
d_constantIteEqualsConstantCache.find(pair); |
1091 |
89000 |
if (eq_pos != d_constantIteEqualsConstantCache.end()) |
1092 |
|
{ |
1093 |
10668 |
Debug("ite::constantIteEqualsConstant") |
1094 |
5334 |
<< instance << "->" << (*eq_pos).second << endl; |
1095 |
5334 |
return (*eq_pos).second; |
1096 |
|
} |
1097 |
|
|
1098 |
83666 |
++d_citeEqConstApplications; |
1099 |
|
|
1100 |
83666 |
NodeVec* leaves = computeConstantLeaves(cite); |
1101 |
83666 |
Assert(leaves != NULL); |
1102 |
83666 |
if (std::binary_search(leaves->begin(), leaves->end(), constant)) |
1103 |
|
{ |
1104 |
66766 |
if (leaves->size() == 1) |
1105 |
|
{ |
1106 |
|
// probably unreachable |
1107 |
|
d_constantIteEqualsConstantCache[pair] = d_true; |
1108 |
|
Debug("ite::constantIteEqualsConstant") |
1109 |
|
<< instance << "->" << d_true << endl; |
1110 |
|
return d_true; |
1111 |
|
} |
1112 |
|
else |
1113 |
|
{ |
1114 |
66766 |
Assert(cite.getKind() == kind::ITE); |
1115 |
133532 |
TNode cnd = cite[0]; |
1116 |
133532 |
TNode tB = cite[1]; |
1117 |
133532 |
TNode fB = cite[2]; |
1118 |
133532 |
Node tEqs = constantIteEqualsConstant(tB, constant); |
1119 |
133532 |
Node fEqs = constantIteEqualsConstant(fB, constant); |
1120 |
133532 |
Node boolIte = cnd.iteNode(tEqs, fEqs); |
1121 |
66766 |
if (!(tEqs.isConst() || fEqs.isConst())) |
1122 |
|
{ |
1123 |
3848 |
++numBranches; |
1124 |
|
} |
1125 |
66766 |
if (!(tEqs == d_false || fEqs == d_false)) |
1126 |
|
{ |
1127 |
4422 |
++numFalseBranches; |
1128 |
|
} |
1129 |
66766 |
++itesMade; |
1130 |
66766 |
d_constantIteEqualsConstantCache[pair] = boolIte; |
1131 |
|
// Debug("ite::constantIteEqualsConstant") << instance << "->" << boolIte |
1132 |
|
// << endl; |
1133 |
66766 |
return boolIte; |
1134 |
|
} |
1135 |
|
} |
1136 |
|
else |
1137 |
|
{ |
1138 |
16900 |
d_constantIteEqualsConstantCache[pair] = d_false; |
1139 |
33800 |
Debug("ite::constantIteEqualsConstant") |
1140 |
16900 |
<< instance << "->" << d_false << endl; |
1141 |
16900 |
return d_false; |
1142 |
|
} |
1143 |
|
} |
1144 |
|
|
1145 |
1146 |
Node ITESimplifier::intersectConstantIte(TNode lcite, TNode rcite) |
1146 |
|
{ |
1147 |
|
// intersect the constant ite trees lcite and rcite |
1148 |
|
|
1149 |
1146 |
if (lcite.isConst() || rcite.isConst()) |
1150 |
|
{ |
1151 |
1146 |
bool lIsConst = lcite.isConst(); |
1152 |
2292 |
TNode constant = lIsConst ? lcite : rcite; |
1153 |
2292 |
TNode cite = lIsConst ? rcite : lcite; |
1154 |
|
|
1155 |
1146 |
(d_statistics.d_inSmaller) << 1; |
1156 |
1146 |
unsigned preItesMade = itesMade; |
1157 |
1146 |
unsigned preNumBranches = numBranches; |
1158 |
1146 |
unsigned preNumFalseBranches = numFalseBranches; |
1159 |
2292 |
Node bterm = constantIteEqualsConstant(cite, constant); |
1160 |
2292 |
Debug("intersectConstantIte") << (numBranches - preNumBranches) << " " |
1161 |
2292 |
<< (numFalseBranches - preNumFalseBranches) |
1162 |
1146 |
<< " " << (itesMade - preItesMade) << endl; |
1163 |
1146 |
return bterm; |
1164 |
|
} |
1165 |
|
Assert(lcite.getKind() == kind::ITE); |
1166 |
|
Assert(rcite.getKind() == kind::ITE); |
1167 |
|
|
1168 |
|
NodeVec* leftValues = computeConstantLeaves(lcite); |
1169 |
|
NodeVec* rightValues = computeConstantLeaves(rcite); |
1170 |
|
|
1171 |
|
uint32_t smaller = std::min(leftValues->size(), rightValues->size()); |
1172 |
|
|
1173 |
|
(d_statistics.d_inSmaller) << smaller; |
1174 |
|
NodeVec intersection(smaller, Node::null()); |
1175 |
|
NodeVec::iterator newEnd; |
1176 |
|
newEnd = std::set_intersection(leftValues->begin(), |
1177 |
|
leftValues->end(), |
1178 |
|
rightValues->begin(), |
1179 |
|
rightValues->end(), |
1180 |
|
intersection.begin()); |
1181 |
|
intersection.resize(newEnd - intersection.begin()); |
1182 |
|
if (intersection.empty()) |
1183 |
|
{ |
1184 |
|
return d_false; |
1185 |
|
} |
1186 |
|
else |
1187 |
|
{ |
1188 |
|
NodeBuilder nb(kind::OR); |
1189 |
|
NodeVec::const_iterator it = intersection.begin(), end = intersection.end(); |
1190 |
|
for (; it != end; ++it) |
1191 |
|
{ |
1192 |
|
Node inBoth = *it; |
1193 |
|
Node lefteq = constantIteEqualsConstant(lcite, inBoth); |
1194 |
|
Node righteq = constantIteEqualsConstant(rcite, inBoth); |
1195 |
|
Node bothHold = lefteq.andNode(righteq); |
1196 |
|
nb << bothHold; |
1197 |
|
} |
1198 |
|
Node result = (nb.getNumChildren() > 1) ? (Node)nb : nb[0]; |
1199 |
|
return result; |
1200 |
|
} |
1201 |
|
} |
1202 |
|
|
1203 |
|
Node ITESimplifier::attemptEagerRemoval(TNode atom) |
1204 |
|
{ |
1205 |
|
if (atom.getKind() == kind::EQUAL) |
1206 |
|
{ |
1207 |
|
TNode left = atom[0]; |
1208 |
|
TNode right = atom[1]; |
1209 |
|
if ((left.isConst() && right.getKind() == kind::ITE && isConstantIte(right)) |
1210 |
|
|| (right.isConst() && left.getKind() == kind::ITE |
1211 |
|
&& isConstantIte(left))) |
1212 |
|
{ |
1213 |
|
TNode constant = left.isConst() ? left : right; |
1214 |
|
TNode cite = left.isConst() ? right : left; |
1215 |
|
|
1216 |
|
std::pair<Node, Node> pair = make_pair(cite, constant); |
1217 |
|
NodePairMap::const_iterator eq_pos = |
1218 |
|
d_constantIteEqualsConstantCache.find(pair); |
1219 |
|
if (eq_pos != d_constantIteEqualsConstantCache.end()) |
1220 |
|
{ |
1221 |
|
Node ret = (*eq_pos).second; |
1222 |
|
if (ret.isConst()) |
1223 |
|
{ |
1224 |
|
return ret; |
1225 |
|
} |
1226 |
|
else |
1227 |
|
{ |
1228 |
|
return Node::null(); |
1229 |
|
} |
1230 |
|
} |
1231 |
|
|
1232 |
|
NodeVec* leaves = computeConstantLeaves(cite); |
1233 |
|
Assert(leaves != NULL); |
1234 |
|
if (!std::binary_search(leaves->begin(), leaves->end(), constant)) |
1235 |
|
{ |
1236 |
|
d_constantIteEqualsConstantCache[pair] = d_false; |
1237 |
|
return d_false; |
1238 |
|
} |
1239 |
|
} |
1240 |
|
} |
1241 |
|
return Node::null(); |
1242 |
|
} |
1243 |
|
|
1244 |
1458 |
Node ITESimplifier::attemptConstantRemoval(TNode atom) |
1245 |
|
{ |
1246 |
1458 |
if (atom.getKind() == kind::EQUAL) |
1247 |
|
{ |
1248 |
1574 |
TNode left = atom[0]; |
1249 |
1574 |
TNode right = atom[1]; |
1250 |
1360 |
if (isConstantIte(left) && isConstantIte(right)) |
1251 |
|
{ |
1252 |
1146 |
return intersectConstantIte(left, right); |
1253 |
|
} |
1254 |
|
} |
1255 |
312 |
return Node::null(); |
1256 |
|
} |
1257 |
|
|
1258 |
1100 |
bool ITESimplifier::leavesAreConst(TNode e, theory::TheoryId tid) |
1259 |
|
{ |
1260 |
1100 |
Assert((e.getKind() == kind::ITE && !e.getType().isBoolean()) |
1261 |
|
|| theory::Theory::theoryOf(e) != theory::THEORY_BOOL); |
1262 |
1100 |
if (e.isConst()) |
1263 |
|
{ |
1264 |
54 |
return true; |
1265 |
|
} |
1266 |
|
|
1267 |
1046 |
unordered_map<Node, bool>::iterator it; |
1268 |
1046 |
it = d_leavesConstCache.find(e); |
1269 |
1046 |
if (it != d_leavesConstCache.end()) |
1270 |
|
{ |
1271 |
244 |
return (*it).second; |
1272 |
|
} |
1273 |
|
|
1274 |
802 |
if (!containsTermITE(e) && theory::Theory::isLeafOf(e, tid)) |
1275 |
|
{ |
1276 |
68 |
d_leavesConstCache[e] = false; |
1277 |
68 |
return false; |
1278 |
|
} |
1279 |
|
|
1280 |
734 |
Assert(e.getNumChildren() > 0); |
1281 |
734 |
size_t k = 0, sz = e.getNumChildren(); |
1282 |
|
|
1283 |
734 |
if (e.getKind() == kind::ITE) |
1284 |
|
{ |
1285 |
322 |
k = 1; |
1286 |
|
} |
1287 |
|
|
1288 |
842 |
for (; k < sz; ++k) |
1289 |
|
{ |
1290 |
788 |
if (!leavesAreConst(e[k], tid)) |
1291 |
|
{ |
1292 |
734 |
d_leavesConstCache[e] = false; |
1293 |
734 |
return false; |
1294 |
|
} |
1295 |
|
} |
1296 |
|
d_leavesConstCache[e] = true; |
1297 |
|
return true; |
1298 |
|
} |
1299 |
|
|
1300 |
|
Node ITESimplifier::simpConstants(TNode simpContext, |
1301 |
|
TNode iteNode, |
1302 |
|
TNode simpVar) |
1303 |
|
{ |
1304 |
|
NodePairMap::iterator it; |
1305 |
|
it = d_simpConstCache.find(pair<Node, Node>(simpContext, iteNode)); |
1306 |
|
if (it != d_simpConstCache.end()) |
1307 |
|
{ |
1308 |
|
return (*it).second; |
1309 |
|
} |
1310 |
|
|
1311 |
|
if (iteNode.getKind() == kind::ITE) |
1312 |
|
{ |
1313 |
|
NodeBuilder builder(kind::ITE); |
1314 |
|
builder << iteNode[0]; |
1315 |
|
unsigned i = 1; |
1316 |
|
for (; i < iteNode.getNumChildren(); ++i) |
1317 |
|
{ |
1318 |
|
Node n = simpConstants(simpContext, iteNode[i], simpVar); |
1319 |
|
if (n.isNull()) |
1320 |
|
{ |
1321 |
|
return n; |
1322 |
|
} |
1323 |
|
builder << n; |
1324 |
|
} |
1325 |
|
// Mark the substitution and continue |
1326 |
|
Node result = builder; |
1327 |
|
result = theory::Rewriter::rewrite(result); |
1328 |
|
d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = result; |
1329 |
|
return result; |
1330 |
|
} |
1331 |
|
|
1332 |
|
if (!containsTermITE(iteNode)) |
1333 |
|
{ |
1334 |
|
Node n = |
1335 |
|
theory::Rewriter::rewrite(simpContext.substitute(simpVar, iteNode)); |
1336 |
|
d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = n; |
1337 |
|
return n; |
1338 |
|
} |
1339 |
|
|
1340 |
|
Node iteNode2; |
1341 |
|
Node simpVar2; |
1342 |
|
d_simpContextCache.clear(); |
1343 |
|
Node simpContext2 = createSimpContext(iteNode, iteNode2, simpVar2); |
1344 |
|
if (!simpContext2.isNull()) |
1345 |
|
{ |
1346 |
|
Assert(!iteNode2.isNull()); |
1347 |
|
simpContext2 = simpContext.substitute(simpVar, simpContext2); |
1348 |
|
Node n = simpConstants(simpContext2, iteNode2, simpVar2); |
1349 |
|
if (n.isNull()) |
1350 |
|
{ |
1351 |
|
return n; |
1352 |
|
} |
1353 |
|
d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = n; |
1354 |
|
return n; |
1355 |
|
} |
1356 |
|
return Node(); |
1357 |
|
} |
1358 |
|
|
1359 |
|
Node ITESimplifier::getSimpVar(TypeNode t) |
1360 |
|
{ |
1361 |
|
std::unordered_map<TypeNode, Node>::iterator it; |
1362 |
|
it = d_simpVars.find(t); |
1363 |
|
if (it != d_simpVars.end()) |
1364 |
|
{ |
1365 |
|
return (*it).second; |
1366 |
|
} |
1367 |
|
SkolemManager* sm = NodeManager::currentNM()->getSkolemManager(); |
1368 |
|
Node var = sm->mkDummySkolem( |
1369 |
|
"iteSimp", t, "is a variable resulting from ITE simplification"); |
1370 |
|
d_simpVars[t] = var; |
1371 |
|
return var; |
1372 |
|
} |
1373 |
|
|
1374 |
|
Node ITESimplifier::createSimpContext(TNode c, Node& iteNode, Node& simpVar) |
1375 |
|
{ |
1376 |
|
NodeMap::iterator it; |
1377 |
|
it = d_simpContextCache.find(c); |
1378 |
|
if (it != d_simpContextCache.end()) |
1379 |
|
{ |
1380 |
|
return (*it).second; |
1381 |
|
} |
1382 |
|
|
1383 |
|
if (!containsTermITE(c)) |
1384 |
|
{ |
1385 |
|
d_simpContextCache[c] = c; |
1386 |
|
return c; |
1387 |
|
} |
1388 |
|
|
1389 |
|
if (c.getKind() == kind::ITE && !c.getType().isBoolean()) |
1390 |
|
{ |
1391 |
|
// Currently only support one ite node in a simp context |
1392 |
|
// Return Null if more than one is found |
1393 |
|
if (!iteNode.isNull()) |
1394 |
|
{ |
1395 |
|
return Node(); |
1396 |
|
} |
1397 |
|
simpVar = getSimpVar(c.getType()); |
1398 |
|
if (simpVar.isNull()) |
1399 |
|
{ |
1400 |
|
return Node(); |
1401 |
|
} |
1402 |
|
d_simpContextCache[c] = simpVar; |
1403 |
|
iteNode = c; |
1404 |
|
return simpVar; |
1405 |
|
} |
1406 |
|
|
1407 |
|
NodeBuilder builder(c.getKind()); |
1408 |
|
if (c.getMetaKind() == kind::metakind::PARAMETERIZED) |
1409 |
|
{ |
1410 |
|
builder << c.getOperator(); |
1411 |
|
} |
1412 |
|
unsigned i = 0; |
1413 |
|
for (; i < c.getNumChildren(); ++i) |
1414 |
|
{ |
1415 |
|
Node newChild = createSimpContext(c[i], iteNode, simpVar); |
1416 |
|
if (newChild.isNull()) |
1417 |
|
{ |
1418 |
|
return newChild; |
1419 |
|
} |
1420 |
|
builder << newChild; |
1421 |
|
} |
1422 |
|
// Mark the substitution and continue |
1423 |
|
Node result = builder; |
1424 |
|
d_simpContextCache[c] = result; |
1425 |
|
return result; |
1426 |
|
} |
1427 |
|
typedef std::unordered_set<Node> NodeSet; |
1428 |
81482820 |
void countReachable_(Node x, Kind k, NodeSet& visited, uint32_t& reached) |
1429 |
|
{ |
1430 |
81482820 |
if (visited.find(x) != visited.end()) |
1431 |
|
{ |
1432 |
74611286 |
return; |
1433 |
|
} |
1434 |
6871534 |
visited.insert(x); |
1435 |
6871534 |
if (x.getKind() == k) |
1436 |
|
{ |
1437 |
2172360 |
++reached; |
1438 |
|
} |
1439 |
88352062 |
for (unsigned i = 0, N = x.getNumChildren(); i < N; ++i) |
1440 |
|
{ |
1441 |
81480528 |
countReachable_(x[i], k, visited, reached); |
1442 |
|
} |
1443 |
|
} |
1444 |
|
|
1445 |
2292 |
uint32_t countReachable(TNode x, Kind k) |
1446 |
|
{ |
1447 |
4584 |
NodeSet visited; |
1448 |
2292 |
uint32_t reached = 0; |
1449 |
2292 |
countReachable_(x, k, visited, reached); |
1450 |
4584 |
return reached; |
1451 |
|
} |
1452 |
|
|
1453 |
1458 |
Node ITESimplifier::simpITEAtom(TNode atom) |
1454 |
|
{ |
1455 |
|
static int CVC5_UNUSED instance = 0; |
1456 |
1458 |
Debug("ite::atom") << "still simplifying " << (++instance) << endl; |
1457 |
2916 |
Node attempt = transformAtom(atom); |
1458 |
1458 |
Debug("ite::atom") << " finished " << instance << endl; |
1459 |
1458 |
if (!attempt.isNull()) |
1460 |
|
{ |
1461 |
2292 |
Node rewritten = theory::Rewriter::rewrite(attempt); |
1462 |
2292 |
Debug("ite::print-success") |
1463 |
1146 |
<< instance << " " |
1464 |
2292 |
<< "rewriting " << countReachable(rewritten, kind::ITE) << " from " |
1465 |
2292 |
<< countReachable(atom, kind::ITE) << endl |
1466 |
1146 |
<< "\t rewritten " << rewritten << endl |
1467 |
1146 |
<< "\t input " << atom << endl; |
1468 |
1146 |
return rewritten; |
1469 |
|
} |
1470 |
|
|
1471 |
312 |
if (leavesAreConst(atom)) |
1472 |
|
{ |
1473 |
|
Node iteNode; |
1474 |
|
Node simpVar; |
1475 |
|
d_simpContextCache.clear(); |
1476 |
|
Node simpContext = createSimpContext(atom, iteNode, simpVar); |
1477 |
|
if (!simpContext.isNull()) |
1478 |
|
{ |
1479 |
|
if (iteNode.isNull()) |
1480 |
|
{ |
1481 |
|
Assert(leavesAreConst(simpContext) && !containsTermITE(simpContext)); |
1482 |
|
++(d_statistics.d_unexpected); |
1483 |
|
Debug("ite::simpite") << instance << " " |
1484 |
|
<< "how about?" << atom << endl; |
1485 |
|
Debug("ite::simpite") << instance << " " |
1486 |
|
<< "\t" << simpContext << endl; |
1487 |
|
return theory::Rewriter::rewrite(simpContext); |
1488 |
|
} |
1489 |
|
Node n = simpConstants(simpContext, iteNode, simpVar); |
1490 |
|
if (!n.isNull()) |
1491 |
|
{ |
1492 |
|
++(d_statistics.d_unexpected); |
1493 |
|
Debug("ite::simpite") << instance << " " |
1494 |
|
<< "here?" << atom << endl; |
1495 |
|
Debug("ite::simpite") << instance << " " |
1496 |
|
<< "\t" << n << endl; |
1497 |
|
return n; |
1498 |
|
} |
1499 |
|
} |
1500 |
|
} |
1501 |
312 |
if (Debug.isOn("ite::simpite")) |
1502 |
|
{ |
1503 |
|
if (countReachable(atom, kind::ITE) > 0) |
1504 |
|
{ |
1505 |
|
Debug("ite::simpite") << instance << " " |
1506 |
|
<< "remaining " << atom << endl; |
1507 |
|
} |
1508 |
|
} |
1509 |
312 |
++(d_statistics.d_unsimplified); |
1510 |
312 |
return atom; |
1511 |
|
} |
1512 |
|
|
1513 |
22912 |
struct preprocess_stack_element |
1514 |
|
{ |
1515 |
|
TNode d_node; |
1516 |
|
bool d_children_added; |
1517 |
4908 |
preprocess_stack_element(TNode node) : d_node(node), d_children_added(false) |
1518 |
|
{ |
1519 |
4908 |
} |
1520 |
|
}; /* struct preprocess_stack_element */ |
1521 |
|
|
1522 |
2 |
Node ITESimplifier::simpITE(TNode assertion) |
1523 |
|
{ |
1524 |
|
// Do a topological sort of the subexpressions and substitute them |
1525 |
4 |
vector<preprocess_stack_element> toVisit; |
1526 |
2 |
toVisit.push_back(assertion); |
1527 |
|
|
1528 |
|
static int call = 0; |
1529 |
2 |
++call; |
1530 |
2 |
int iteration = 0; |
1531 |
|
|
1532 |
17490 |
while (!toVisit.empty()) |
1533 |
|
{ |
1534 |
8744 |
iteration++; |
1535 |
|
// cout << "call " << call << " : " << iteration << endl; |
1536 |
|
// The current node we are processing |
1537 |
8744 |
preprocess_stack_element& stackHead = toVisit.back(); |
1538 |
16416 |
TNode current = stackHead.d_node; |
1539 |
|
|
1540 |
|
// If node has no ITE's or already in the cache we're done, pop from the |
1541 |
|
// stack |
1542 |
18538 |
if (current.getNumChildren() == 0 |
1543 |
27282 |
|| (theory::Theory::theoryOf(current) != theory::THEORY_BOOL |
1544 |
12028 |
&& !containsTermITE(current))) |
1545 |
|
{ |
1546 |
1050 |
d_simpITECache[current] = current; |
1547 |
1050 |
++(d_statistics.d_simpITEVisits); |
1548 |
1050 |
toVisit.pop_back(); |
1549 |
1050 |
continue; |
1550 |
|
} |
1551 |
|
|
1552 |
7694 |
NodeMap::iterator find = d_simpITECache.find(current); |
1553 |
7716 |
if (find != d_simpITECache.end()) |
1554 |
|
{ |
1555 |
22 |
toVisit.pop_back(); |
1556 |
22 |
continue; |
1557 |
|
} |
1558 |
|
|
1559 |
|
// Not yet substituted, so process |
1560 |
7672 |
if (stackHead.d_children_added) |
1561 |
|
{ |
1562 |
|
// Children have been processed, so substitute |
1563 |
7672 |
NodeBuilder builder(current.getKind()); |
1564 |
3836 |
if (current.getMetaKind() == kind::metakind::PARAMETERIZED) |
1565 |
|
{ |
1566 |
|
builder << current.getOperator(); |
1567 |
|
} |
1568 |
13738 |
for (unsigned i = 0; i < current.getNumChildren(); ++i) |
1569 |
|
{ |
1570 |
9902 |
Assert(d_simpITECache.find(current[i]) != d_simpITECache.end()); |
1571 |
19804 |
Node child = current[i]; |
1572 |
19804 |
Node childRes = d_simpITECache[current[i]]; |
1573 |
9902 |
builder << childRes; |
1574 |
|
} |
1575 |
|
// Mark the substitution and continue |
1576 |
7672 |
Node result = builder; |
1577 |
|
|
1578 |
|
// If this is an atom, we process it |
1579 |
11508 |
if (theory::Theory::theoryOf(result) != theory::THEORY_BOOL |
1580 |
11508 |
&& result.getType().isBoolean()) |
1581 |
|
{ |
1582 |
1458 |
result = simpITEAtom(result); |
1583 |
|
} |
1584 |
|
|
1585 |
|
// if(current != result && result.isConst()){ |
1586 |
|
// static int instance = 0; |
1587 |
|
// //cout << instance << " " << result << current << endl; |
1588 |
|
// } |
1589 |
|
|
1590 |
3836 |
result = theory::Rewriter::rewrite(result); |
1591 |
3836 |
d_simpITECache[current] = result; |
1592 |
3836 |
++(d_statistics.d_simpITEVisits); |
1593 |
3836 |
toVisit.pop_back(); |
1594 |
|
} |
1595 |
|
else |
1596 |
|
{ |
1597 |
|
// Mark that we have added the children if any |
1598 |
3836 |
if (current.getNumChildren() > 0) |
1599 |
|
{ |
1600 |
3836 |
stackHead.d_children_added = true; |
1601 |
|
// We need to add the children |
1602 |
13738 |
for (TNode::iterator child_it = current.begin(); |
1603 |
13738 |
child_it != current.end(); |
1604 |
|
++child_it) |
1605 |
|
{ |
1606 |
19804 |
TNode childNode = *child_it; |
1607 |
9902 |
NodeMap::iterator childFind = d_simpITECache.find(childNode); |
1608 |
9902 |
if (childFind == d_simpITECache.end()) |
1609 |
|
{ |
1610 |
4906 |
toVisit.push_back(childNode); |
1611 |
|
} |
1612 |
|
} |
1613 |
|
} |
1614 |
|
else |
1615 |
|
{ |
1616 |
|
// No children, so we're done |
1617 |
|
d_simpITECache[current] = current; |
1618 |
|
++(d_statistics.d_simpITEVisits); |
1619 |
|
toVisit.pop_back(); |
1620 |
|
} |
1621 |
|
} |
1622 |
|
} |
1623 |
4 |
return d_simpITECache[assertion]; |
1624 |
|
} |
1625 |
|
|
1626 |
|
ITECareSimplifier::ITECareSimplifier() : d_careSetsOutstanding(0), d_usedSets() |
1627 |
|
{ |
1628 |
|
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
1629 |
|
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
1630 |
|
} |
1631 |
|
|
1632 |
|
ITECareSimplifier::~ITECareSimplifier() |
1633 |
|
{ |
1634 |
|
Assert(d_usedSets.empty()); |
1635 |
|
Assert(d_careSetsOutstanding == 0); |
1636 |
|
} |
1637 |
|
|
1638 |
|
void ITECareSimplifier::clear() |
1639 |
|
{ |
1640 |
|
Assert(d_usedSets.empty()); |
1641 |
|
Assert(d_careSetsOutstanding == 0); |
1642 |
|
} |
1643 |
|
|
1644 |
|
ITECareSimplifier::CareSetPtr ITECareSimplifier::getNewSet() |
1645 |
|
{ |
1646 |
|
if (d_usedSets.empty()) |
1647 |
|
{ |
1648 |
|
d_careSetsOutstanding++; |
1649 |
|
return ITECareSimplifier::CareSetPtr::mkNew(*this); |
1650 |
|
} |
1651 |
|
else |
1652 |
|
{ |
1653 |
|
ITECareSimplifier::CareSetPtr cs = |
1654 |
|
ITECareSimplifier::CareSetPtr::recycle(d_usedSets.back()); |
1655 |
|
cs.getCareSet().clear(); |
1656 |
|
d_usedSets.pop_back(); |
1657 |
|
return cs; |
1658 |
|
} |
1659 |
|
} |
1660 |
|
|
1661 |
|
void ITECareSimplifier::updateQueue(CareMap& queue, |
1662 |
|
TNode e, |
1663 |
|
ITECareSimplifier::CareSetPtr& careSet) |
1664 |
|
{ |
1665 |
|
CareMap::iterator it = queue.find(e), iend = queue.end(); |
1666 |
|
if (it != iend) |
1667 |
|
{ |
1668 |
|
set<Node>& cs2 = (*it).second.getCareSet(); |
1669 |
|
ITECareSimplifier::CareSetPtr csNew = getNewSet(); |
1670 |
|
set_intersection(careSet.getCareSet().begin(), |
1671 |
|
careSet.getCareSet().end(), |
1672 |
|
cs2.begin(), |
1673 |
|
cs2.end(), |
1674 |
|
inserter(csNew.getCareSet(), csNew.getCareSet().begin())); |
1675 |
|
(*it).second = csNew; |
1676 |
|
} |
1677 |
|
else |
1678 |
|
{ |
1679 |
|
queue[e] = careSet; |
1680 |
|
} |
1681 |
|
} |
1682 |
|
|
1683 |
|
Node ITECareSimplifier::substitute(TNode e, |
1684 |
|
TNodeMap& substTable, |
1685 |
|
TNodeMap& cache) |
1686 |
|
{ |
1687 |
|
TNodeMap::iterator it = cache.find(e), iend = cache.end(); |
1688 |
|
if (it != iend) |
1689 |
|
{ |
1690 |
|
return it->second; |
1691 |
|
} |
1692 |
|
|
1693 |
|
// do substitution? |
1694 |
|
it = substTable.find(e); |
1695 |
|
iend = substTable.end(); |
1696 |
|
if (it != iend) |
1697 |
|
{ |
1698 |
|
Node result = substitute(it->second, substTable, cache); |
1699 |
|
cache[e] = result; |
1700 |
|
return result; |
1701 |
|
} |
1702 |
|
|
1703 |
|
size_t sz = e.getNumChildren(); |
1704 |
|
if (sz == 0) |
1705 |
|
{ |
1706 |
|
cache[e] = e; |
1707 |
|
return e; |
1708 |
|
} |
1709 |
|
|
1710 |
|
NodeBuilder builder(e.getKind()); |
1711 |
|
if (e.getMetaKind() == kind::metakind::PARAMETERIZED) |
1712 |
|
{ |
1713 |
|
builder << e.getOperator(); |
1714 |
|
} |
1715 |
|
for (unsigned i = 0; i < e.getNumChildren(); ++i) |
1716 |
|
{ |
1717 |
|
builder << substitute(e[i], substTable, cache); |
1718 |
|
} |
1719 |
|
|
1720 |
|
Node result = builder; |
1721 |
|
// it = substTable.find(result); |
1722 |
|
// if (it != iend) { |
1723 |
|
// result = substitute(it->second, substTable, cache); |
1724 |
|
// } |
1725 |
|
cache[e] = result; |
1726 |
|
return result; |
1727 |
|
} |
1728 |
|
|
1729 |
|
Node ITECareSimplifier::simplifyWithCare(TNode e) |
1730 |
|
{ |
1731 |
|
TNodeMap substTable; |
1732 |
|
|
1733 |
|
/* This extra block is to trigger the destructors for cs and cs2 |
1734 |
|
* before starting garbage collection. |
1735 |
|
*/ |
1736 |
|
{ |
1737 |
|
CareMap queue; |
1738 |
|
CareMap::iterator it; |
1739 |
|
ITECareSimplifier::CareSetPtr cs = getNewSet(); |
1740 |
|
ITECareSimplifier::CareSetPtr cs2; |
1741 |
|
queue[e] = cs; |
1742 |
|
|
1743 |
|
TNode v; |
1744 |
|
bool done; |
1745 |
|
unsigned i; |
1746 |
|
|
1747 |
|
while (!queue.empty()) |
1748 |
|
{ |
1749 |
|
it = queue.end(); |
1750 |
|
--it; |
1751 |
|
v = it->first; |
1752 |
|
cs = it->second; |
1753 |
|
set<Node>& css = cs.getCareSet(); |
1754 |
|
queue.erase(v); |
1755 |
|
|
1756 |
|
done = false; |
1757 |
|
set<Node>::iterator iCare, iCareEnd = css.end(); |
1758 |
|
|
1759 |
|
switch (v.getKind()) |
1760 |
|
{ |
1761 |
|
case kind::ITE: |
1762 |
|
{ |
1763 |
|
iCare = css.find(v[0]); |
1764 |
|
if (iCare != iCareEnd) |
1765 |
|
{ |
1766 |
|
Assert(substTable.find(v) == substTable.end()); |
1767 |
|
substTable[v] = v[1]; |
1768 |
|
updateQueue(queue, v[1], cs); |
1769 |
|
done = true; |
1770 |
|
break; |
1771 |
|
} |
1772 |
|
else |
1773 |
|
{ |
1774 |
|
iCare = css.find(v[0].negate()); |
1775 |
|
if (iCare != iCareEnd) |
1776 |
|
{ |
1777 |
|
Assert(substTable.find(v) == substTable.end()); |
1778 |
|
substTable[v] = v[2]; |
1779 |
|
updateQueue(queue, v[2], cs); |
1780 |
|
done = true; |
1781 |
|
break; |
1782 |
|
} |
1783 |
|
} |
1784 |
|
updateQueue(queue, v[0], cs); |
1785 |
|
cs2 = getNewSet(); |
1786 |
|
cs2.getCareSet() = css; |
1787 |
|
cs2.getCareSet().insert(v[0]); |
1788 |
|
updateQueue(queue, v[1], cs2); |
1789 |
|
cs2 = getNewSet(); |
1790 |
|
cs2.getCareSet() = css; |
1791 |
|
cs2.getCareSet().insert(v[0].negate()); |
1792 |
|
updateQueue(queue, v[2], cs2); |
1793 |
|
done = true; |
1794 |
|
break; |
1795 |
|
} |
1796 |
|
case kind::AND: |
1797 |
|
{ |
1798 |
|
for (i = 0; i < v.getNumChildren(); ++i) |
1799 |
|
{ |
1800 |
|
iCare = css.find(v[i].negate()); |
1801 |
|
if (iCare != iCareEnd) |
1802 |
|
{ |
1803 |
|
Assert(substTable.find(v) == substTable.end()); |
1804 |
|
substTable[v] = d_false; |
1805 |
|
done = true; |
1806 |
|
break; |
1807 |
|
} |
1808 |
|
} |
1809 |
|
if (done) break; |
1810 |
|
|
1811 |
|
Assert(v.getNumChildren() > 1); |
1812 |
|
updateQueue(queue, v[0], cs); |
1813 |
|
cs2 = getNewSet(); |
1814 |
|
cs2.getCareSet() = css; |
1815 |
|
cs2.getCareSet().insert(v[0]); |
1816 |
|
for (i = 1; i < v.getNumChildren(); ++i) |
1817 |
|
{ |
1818 |
|
updateQueue(queue, v[i], cs2); |
1819 |
|
} |
1820 |
|
done = true; |
1821 |
|
break; |
1822 |
|
} |
1823 |
|
case kind::OR: |
1824 |
|
{ |
1825 |
|
for (i = 0; i < v.getNumChildren(); ++i) |
1826 |
|
{ |
1827 |
|
iCare = css.find(v[i]); |
1828 |
|
if (iCare != iCareEnd) |
1829 |
|
{ |
1830 |
|
Assert(substTable.find(v) == substTable.end()); |
1831 |
|
substTable[v] = d_true; |
1832 |
|
done = true; |
1833 |
|
break; |
1834 |
|
} |
1835 |
|
} |
1836 |
|
if (done) break; |
1837 |
|
|
1838 |
|
Assert(v.getNumChildren() > 1); |
1839 |
|
updateQueue(queue, v[0], cs); |
1840 |
|
cs2 = getNewSet(); |
1841 |
|
cs2.getCareSet() = css; |
1842 |
|
cs2.getCareSet().insert(v[0].negate()); |
1843 |
|
for (i = 1; i < v.getNumChildren(); ++i) |
1844 |
|
{ |
1845 |
|
updateQueue(queue, v[i], cs2); |
1846 |
|
} |
1847 |
|
done = true; |
1848 |
|
break; |
1849 |
|
} |
1850 |
|
default: break; |
1851 |
|
} |
1852 |
|
|
1853 |
|
if (done) |
1854 |
|
{ |
1855 |
|
continue; |
1856 |
|
} |
1857 |
|
|
1858 |
|
for (i = 0; i < v.getNumChildren(); ++i) |
1859 |
|
{ |
1860 |
|
updateQueue(queue, v[i], cs); |
1861 |
|
} |
1862 |
|
} |
1863 |
|
} |
1864 |
|
/* Perform garbage collection. */ |
1865 |
|
while (!d_usedSets.empty()) |
1866 |
|
{ |
1867 |
|
CareSetPtrVal* used = d_usedSets.back(); |
1868 |
|
d_usedSets.pop_back(); |
1869 |
|
Assert(used->safeToGarbageCollect()); |
1870 |
|
delete used; |
1871 |
|
Assert(d_careSetsOutstanding > 0); |
1872 |
|
d_careSetsOutstanding--; |
1873 |
|
} |
1874 |
|
|
1875 |
|
TNodeMap cache; |
1876 |
|
return substitute(e, substTable, cache); |
1877 |
|
} |
1878 |
|
|
1879 |
|
ITECareSimplifier::CareSetPtr ITECareSimplifier::CareSetPtr::mkNew( |
1880 |
|
ITECareSimplifier& simp) |
1881 |
|
{ |
1882 |
|
CareSetPtrVal* val = new CareSetPtrVal(simp); |
1883 |
|
return CareSetPtr(val); |
1884 |
|
} |
1885 |
|
|
1886 |
|
} // namespace util |
1887 |
|
} // namespace preprocessing |
1888 |
158394768 |
} // namespace cvc5 |