GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/util/ite_utilities.cpp Lines: 458 986 46.5 %
Date: 2021-08-20 Branches: 779 3683 21.2 %

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