GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/util/ite_utilities.cpp Lines: 456 984 46.3 %
Date: 2021-09-29 Branches: 784 3693 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/theory.h"
30
#include "util/rational.h"
31
32
using namespace std;
33
namespace cvc5 {
34
namespace preprocessing {
35
namespace util {
36
37
namespace ite {
38
39
86799
inline static bool isTermITE(TNode e)
40
{
41
86799
  return (e.getKind() == kind::ITE && !e.getType().isBoolean());
42
}
43
44
127319
inline static bool triviallyContainsNoTermITEs(TNode e)
45
{
46
127319
  return e.isConst() || e.isVar();
47
}
48
49
5258
static bool isTheoryAtom(TNode a)
50
{
51
  using namespace kind;
52
5258
  switch (a.getKind())
53
  {
54
109
    case EQUAL:
55
109
    case DISTINCT: return !(a[0].getType().isBoolean());
56
57
    /* from uf */
58
    case APPLY_UF: return a.getType().isBoolean();
59
44
    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
44
    case BITVECTOR_SGE: return true;
75
5105
    default: return false;
76
  }
77
}
78
79
255494
struct CTIVStackElement
80
{
81
  TNode curr;
82
  unsigned pos;
83
  CTIVStackElement() : curr(), pos(0) {}
84
57818
  CTIVStackElement(TNode c) : curr(c), pos(0) {}
85
}; /* CTIVStackElement */
86
87
}  // namespace ite
88
89
6271
ITEUtilities::ITEUtilities(Env& env)
90
    : EnvObj(env),
91
6271
      d_containsVisitor(new ContainsTermITEVisitor()),
92
      d_compressor(NULL),
93
      d_simplifier(NULL),
94
12542
      d_careSimp(NULL)
95
{
96
6271
  Assert(d_containsVisitor != NULL);
97
6271
}
98
99
12536
ITEUtilities::~ITEUtilities()
100
{
101
6268
  if (d_simplifier != NULL)
102
  {
103
1
    delete d_simplifier;
104
  }
105
6268
  if (d_compressor != NULL)
106
  {
107
1
    delete d_compressor;
108
  }
109
6268
  if (d_careSimp != NULL)
110
  {
111
    delete d_careSimp;
112
  }
113
6268
}
114
115
1
Node ITEUtilities::simpITE(TNode assertion)
116
{
117
1
  if (d_simplifier == NULL)
118
  {
119
1
    d_simplifier = new ITESimplifier(d_env, d_containsVisitor.get());
120
  }
121
1
  return d_simplifier->simpITE(assertion);
122
}
123
124
1
bool ITEUtilities::simpIteDidALotOfWorkHeuristic() const
125
{
126
1
  if (d_simplifier == NULL)
127
  {
128
    return false;
129
  }
130
  else
131
  {
132
1
    return d_simplifier->doneALotOfWorkHeuristic();
133
  }
134
}
135
136
/* returns false if an assertion is discovered to be equal to false. */
137
1
bool ITEUtilities::compress(AssertionPipeline* assertionsToPreprocess)
138
{
139
1
  if (d_compressor == NULL)
140
  {
141
1
    d_compressor = new ITECompressor(d_env, d_containsVisitor.get());
142
  }
143
1
  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
26434
ContainsTermITEVisitor::ContainsTermITEVisitor() : d_cache() {}
174
26431
ContainsTermITEVisitor::~ContainsTermITEVisitor() {}
175
22939
bool ContainsTermITEVisitor::containsTermITE(TNode e)
176
{
177
  /* throughout execution skip through NOT nodes. */
178
22939
  e = (e.getKind() == kind::NOT) ? e[0] : e;
179
22939
  if (ite::triviallyContainsNoTermITEs(e))
180
  {
181
6754
    return false;
182
  }
183
184
16185
  NodeBoolMap::const_iterator end = d_cache.end();
185
16185
  NodeBoolMap::const_iterator tmp_it = d_cache.find(e);
186
16185
  if (tmp_it != end)
187
  {
188
1178
    return (*tmp_it).second;
189
  }
190
191
15007
  bool foundTermIte = false;
192
30014
  std::vector<ite::CTIVStackElement> stack;
193
15007
  stack.push_back(ite::CTIVStackElement(e));
194
335433
  while (!foundTermIte && !stack.empty())
195
  {
196
160213
    ite::CTIVStackElement& top = stack.back();
197
320426
    TNode curr = top.curr;
198
160213
    if (top.pos >= curr.getNumChildren())
199
    {
200
      // all of the children have been visited
201
      // no term ites were found
202
55833
      d_cache[curr] = false;
203
55833
      stack.pop_back();
204
    }
205
    else
206
    {
207
      // this is someone's child
208
208760
      TNode child = curr[top.pos];
209
104380
      child = (child.getKind() == kind::NOT) ? child[0] : child;
210
104380
      ++top.pos;
211
104380
      if (ite::triviallyContainsNoTermITEs(child))
212
      {
213
        // skip
214
      }
215
      else
216
      {
217
43956
        tmp_it = d_cache.find(child);
218
43956
        if (tmp_it != end)
219
        {
220
1145
          foundTermIte = (*tmp_it).second;
221
        }
222
        else
223
        {
224
42811
          stack.push_back(ite::CTIVStackElement(child));
225
42811
          foundTermIte = ite::isTermITE(child);
226
        }
227
      }
228
    }
229
  }
230
15007
  if (foundTermIte)
231
  {
232
5497
    while (!stack.empty())
233
    {
234
3970
      TNode curr = stack.back().curr;
235
1985
      stack.pop_back();
236
1985
      d_cache[curr] = true;
237
    }
238
  }
239
15007
  return foundTermIte;
240
}
241
void ContainsTermITEVisitor::garbageCollect() { d_cache.clear(); }
242
243
/** IncomingArcCounter. */
244
1
IncomingArcCounter::IncomingArcCounter(bool skipVars, bool skipConstants)
245
1
    : d_reachCount(), d_skipVariables(skipVars), d_skipConstants(skipConstants)
246
{
247
1
}
248
1
IncomingArcCounter::~IncomingArcCounter() {}
249
250
1
void IncomingArcCounter::computeReachability(
251
    const std::vector<Node>& assertions)
252
{
253
2
  std::vector<TNode> tovisit(assertions.begin(), assertions.end());
254
255
229045
  while (!tovisit.empty())
256
  {
257
228530
    TNode back = tovisit.back();
258
114522
    tovisit.pop_back();
259
260
114522
    bool skip = false;
261
114522
    switch (back.getMetaKind())
262
    {
263
304
      case kind::metakind::CONSTANT: skip = d_skipConstants; break;
264
210
      case kind::metakind::VARIABLE: skip = d_skipVariables; break;
265
114008
      default: break;
266
    }
267
268
114522
    if (skip)
269
    {
270
514
      continue;
271
    }
272
114008
    if (d_reachCount.find(back) != d_reachCount.end())
273
    {
274
106422
      d_reachCount[back] = 1 + d_reachCount[back];
275
    }
276
    else
277
    {
278
7586
      d_reachCount[back] = 1;
279
122106
      for (TNode::iterator cit = back.begin(), end = back.end(); cit != end;
280
           ++cit)
281
      {
282
114520
        tovisit.push_back(*cit);
283
      }
284
    }
285
  }
286
1
}
287
288
2
void IncomingArcCounter::clear() { d_reachCount.clear(); }
289
290
/** ITECompressor. */
291
1
ITECompressor::ITECompressor(Env& env, ContainsTermITEVisitor* contains)
292
    : EnvObj(env),
293
      d_contains(contains),
294
      d_assertions(NULL),
295
      d_incoming(true, true),
296
1
      d_statistics(env.getStatisticsRegistry())
297
{
298
1
  Assert(d_contains != NULL);
299
300
1
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
301
1
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
302
1
}
303
304
2
ITECompressor::~ITECompressor() { reset(); }
305
306
2
void ITECompressor::reset()
307
{
308
2
  d_incoming.clear();
309
2
  d_compressed.clear();
310
2
}
311
312
void ITECompressor::garbageCollect() { reset(); }
313
314
1
ITECompressor::Statistics::Statistics(StatisticsRegistry& reg)
315
2
    : d_compressCalls(reg.registerInt("ite-simp::compressCalls")),
316
2
      d_skolemsAdded(reg.registerInt("ite-simp::skolems"))
317
{
318
1
}
319
320
1720
Node ITECompressor::push_back_boolean(Node original, Node compressed)
321
{
322
3440
  Node rewritten = rewrite(compressed);
323
  // There is a bug if the rewritter takes a pure boolean expression
324
  // and changes its theory
325
1720
  if (rewritten.isConst())
326
  {
327
    d_compressed[compressed] = rewritten;
328
    d_compressed[original] = rewritten;
329
    d_compressed[rewritten] = rewritten;
330
    return rewritten;
331
  }
332
1720
  else if (d_compressed.find(rewritten) != d_compressed.end())
333
  {
334
    Node res = d_compressed[rewritten];
335
    d_compressed[original] = res;
336
    d_compressed[compressed] = res;
337
    return res;
338
  }
339
3440
  else if (rewritten.isVar()
340
3440
           || (rewritten.getKind() == kind::NOT && rewritten[0].isVar()))
341
  {
342
511
    d_compressed[original] = rewritten;
343
511
    d_compressed[compressed] = rewritten;
344
511
    d_compressed[rewritten] = rewritten;
345
511
    return rewritten;
346
  }
347
  else
348
  {
349
1209
    NodeManager* nm = NodeManager::currentNM();
350
1209
    SkolemManager* sm = nm->getSkolemManager();
351
2418
    Node skolem = sm->mkDummySkolem("compress", nm->booleanType());
352
1209
    d_compressed[rewritten] = skolem;
353
1209
    d_compressed[original] = skolem;
354
1209
    d_compressed[compressed] = skolem;
355
356
2418
    Node iff = skolem.eqNode(rewritten);
357
1209
    d_assertions->push_back(iff);
358
1209
    ++(d_statistics.d_skolemsAdded);
359
1209
    return skolem;
360
  }
361
}
362
363
7109
bool ITECompressor::multipleParents(TNode c)
364
{
365
7109
  return d_incoming.lookupIncoming(c) >= 2;
366
}
367
368
1920
Node ITECompressor::compressBooleanITEs(Node toCompress)
369
{
370
1920
  Assert(toCompress.getKind() == kind::ITE);
371
1920
  Assert(toCompress.getType().isBoolean());
372
373
1920
  if (!(toCompress[1] == d_false || toCompress[2] == d_false))
374
  {
375
3840
    Node cmpCnd = compressBoolean(toCompress[0]);
376
1920
    if (cmpCnd.isConst())
377
    {
378
      Node branch = (cmpCnd == d_true) ? toCompress[1] : toCompress[2];
379
      Node res = compressBoolean(branch);
380
      d_compressed[toCompress] = res;
381
      return res;
382
    }
383
    else
384
    {
385
3840
      Node cmpThen = compressBoolean(toCompress[1]);
386
3840
      Node cmpElse = compressBoolean(toCompress[2]);
387
3840
      Node newIte = cmpCnd.iteNode(cmpThen, cmpElse);
388
1920
      if (multipleParents(toCompress))
389
      {
390
534
        return push_back_boolean(toCompress, newIte);
391
      }
392
      else
393
      {
394
1386
        return newIte;
395
      }
396
    }
397
  }
398
399
  NodeBuilder nb(kind::AND);
400
  Node curr = toCompress;
401
  while (curr.getKind() == kind::ITE
402
         && (curr[1] == d_false || curr[2] == d_false)
403
         && (!multipleParents(curr) || curr == toCompress))
404
  {
405
    bool negateCnd = (curr[1] == d_false);
406
    Node compressCnd = compressBoolean(curr[0]);
407
    if (compressCnd.isConst())
408
    {
409
      if (compressCnd.getConst<bool>() == negateCnd)
410
      {
411
        return push_back_boolean(toCompress, d_false);
412
      }
413
      else
414
      {
415
        // equivalent to true don't push back
416
      }
417
    }
418
    else
419
    {
420
      Node pb = negateCnd ? compressCnd.notNode() : compressCnd;
421
      nb << pb;
422
    }
423
    curr = negateCnd ? curr[2] : curr[1];
424
  }
425
  Assert(toCompress != curr);
426
427
  nb << compressBoolean(curr);
428
  Node res = nb.getNumChildren() == 1 ? nb[0] : (Node)nb;
429
  return push_back_boolean(toCompress, res);
430
}
431
432
1122
Node ITECompressor::compressTerm(Node toCompress)
433
{
434
1122
  if (toCompress.isConst() || toCompress.isVar())
435
  {
436
513
    return toCompress;
437
  }
438
439
609
  if (d_compressed.find(toCompress) != d_compressed.end())
440
  {
441
201
    return d_compressed[toCompress];
442
  }
443
408
  if (toCompress.getKind() == kind::ITE)
444
  {
445
648
    Node cmpCnd = compressBoolean(toCompress[0]);
446
324
    if (cmpCnd.isConst())
447
    {
448
      Node branch = (cmpCnd == d_true) ? toCompress[1] : toCompress[2];
449
      Node res = compressTerm(branch);
450
      d_compressed[toCompress] = res;
451
      return res;
452
    }
453
    else
454
    {
455
648
      Node cmpThen = compressTerm(toCompress[1]);
456
648
      Node cmpElse = compressTerm(toCompress[2]);
457
648
      Node newIte = cmpCnd.iteNode(cmpThen, cmpElse);
458
324
      d_compressed[toCompress] = newIte;
459
324
      return newIte;
460
    }
461
  }
462
463
168
  NodeBuilder nb(toCompress.getKind());
464
465
84
  if (toCompress.getMetaKind() == kind::metakind::PARAMETERIZED)
466
  {
467
    nb << (toCompress.getOperator());
468
  }
469
252
  for (Node::iterator it = toCompress.begin(), end = toCompress.end();
470
252
       it != end;
471
       ++it)
472
  {
473
168
    nb << compressTerm(*it);
474
  }
475
168
  Node compressed = (Node)nb;
476
84
  if (multipleParents(toCompress))
477
  {
478
13
    d_compressed[toCompress] = compressed;
479
  }
480
84
  return compressed;
481
}
482
483
113400
Node ITECompressor::compressBoolean(Node toCompress)
484
{
485
  static int instance = 0;
486
113400
  ++instance;
487
113400
  if (toCompress.isConst() || toCompress.isVar())
488
  {
489
1
    return toCompress;
490
  }
491
113399
  if (d_compressed.find(toCompress) != d_compressed.end())
492
  {
493
106221
    return d_compressed[toCompress];
494
  }
495
7178
  else if (toCompress.getKind() == kind::ITE)
496
  {
497
1920
    return compressBooleanITEs(toCompress);
498
  }
499
  else
500
  {
501
5258
    bool ta = ite::isTheoryAtom(toCompress);
502
10516
    NodeBuilder nb(toCompress.getKind());
503
5258
    if (toCompress.getMetaKind() == kind::metakind::PARAMETERIZED)
504
    {
505
      nb << (toCompress.getOperator());
506
    }
507
112878
    for (Node::iterator it = toCompress.begin(), end = toCompress.end();
508
112878
         it != end;
509
         ++it)
510
    {
511
215240
      Node pb = (ta) ? compressTerm(*it) : compressBoolean(*it);
512
107620
      nb << pb;
513
    }
514
10516
    Node compressed = nb;
515
5258
    if (ta || multipleParents(toCompress))
516
    {
517
1186
      return push_back_boolean(toCompress, compressed);
518
    }
519
    else
520
    {
521
4072
      return compressed;
522
    }
523
  }
524
}
525
526
1
bool ITECompressor::compress(AssertionPipeline* assertionsToPreprocess)
527
{
528
1
  reset();
529
530
1
  d_assertions = assertionsToPreprocess;
531
1
  d_incoming.computeReachability(assertionsToPreprocess->ref());
532
533
1
  ++(d_statistics.d_compressCalls);
534
1
  Chat() << "Computed reachability" << endl;
535
536
1
  bool nofalses = true;
537
1
  const std::vector<Node>& assertions = assertionsToPreprocess->ref();
538
1
  size_t original_size = assertions.size();
539
1
  Chat() << "compressing " << original_size << endl;
540
3
  for (size_t i = 0; i < original_size && nofalses; ++i)
541
  {
542
4
    Node assertion = assertions[i];
543
4
    Node compressed = compressBoolean(assertion);
544
4
    Node rewritten = rewrite(compressed);
545
    // replace
546
2
    assertionsToPreprocess->replace(i, rewritten);
547
2
    Assert(!d_contains->containsTermITE(rewritten));
548
549
2
    nofalses = (rewritten != d_false);
550
  }
551
552
1
  d_assertions = NULL;
553
554
1
  return nofalses;
555
}
556
557
1
TermITEHeightCounter::TermITEHeightCounter() : d_termITEHeight() {}
558
559
1
TermITEHeightCounter::~TermITEHeightCounter() {}
560
561
1
void TermITEHeightCounter::clear() { d_termITEHeight.clear(); }
562
563
size_t TermITEHeightCounter::cache_size() const
564
{
565
  return d_termITEHeight.size();
566
}
567
568
namespace ite {
569
struct TITEHStackElement
570
{
571
  TNode curr;
572
  unsigned pos;
573
  uint32_t maxChildHeight;
574
  TITEHStackElement() : curr(), pos(0), maxChildHeight(0) {}
575
  TITEHStackElement(TNode c) : curr(c), pos(0), maxChildHeight(0) {}
576
};
577
} /* namespace ite */
578
579
uint32_t TermITEHeightCounter::termITEHeight(TNode e)
580
{
581
  if (ite::triviallyContainsNoTermITEs(e))
582
  {
583
    return 0;
584
  }
585
586
  NodeCountMap::const_iterator end = d_termITEHeight.end();
587
  NodeCountMap::const_iterator tmp_it = d_termITEHeight.find(e);
588
  if (tmp_it != end)
589
  {
590
    return (*tmp_it).second;
591
  }
592
593
  uint32_t returnValue = 0;
594
  // This is initially 0 as the very first call this is included in the max,
595
  // but this has no effect.
596
  std::vector<ite::TITEHStackElement> stack;
597
  stack.push_back(ite::TITEHStackElement(e));
598
  while (!stack.empty())
599
  {
600
    ite::TITEHStackElement& top = stack.back();
601
    top.maxChildHeight = std::max(top.maxChildHeight, returnValue);
602
    TNode curr = top.curr;
603
    if (top.pos >= curr.getNumChildren())
604
    {
605
      // done with the current node
606
      returnValue = top.maxChildHeight + (ite::isTermITE(curr) ? 1 : 0);
607
      d_termITEHeight[curr] = returnValue;
608
      stack.pop_back();
609
      continue;
610
    }
611
    else
612
    {
613
      if (top.pos == 0 && curr.getKind() == kind::ITE)
614
      {
615
        ++top.pos;
616
        returnValue = 0;
617
        continue;
618
      }
619
      // this is someone's child
620
      TNode child = curr[top.pos];
621
      ++top.pos;
622
      if (ite::triviallyContainsNoTermITEs(child))
623
      {
624
        returnValue = 0;
625
      }
626
      else
627
      {
628
        tmp_it = d_termITEHeight.find(child);
629
        if (tmp_it != end)
630
        {
631
          returnValue = (*tmp_it).second;
632
        }
633
        else
634
        {
635
          stack.push_back(ite::TITEHStackElement(child));
636
        }
637
      }
638
    }
639
  }
640
  return returnValue;
641
}
642
643
1
ITESimplifier::ITESimplifier(Env& env, ContainsTermITEVisitor* contains)
644
    : EnvObj(env),
645
      d_containsVisitor(contains),
646
      d_termITEHeight(),
647
      d_constantLeaves(),
648
      d_allocatedConstantLeaves(),
649
      d_citeEqConstApplications(0),
650
      d_constantIteEqualsConstantCache(),
651
      d_replaceOverCache(),
652
      d_replaceOverTermIteCache(),
653
      d_leavesConstCache(),
654
      d_simpConstCache(),
655
      d_simpContextCache(),
656
      d_simpITECache(),
657
1
      d_statistics(env.getStatisticsRegistry())
658
{
659
1
  Assert(d_containsVisitor != NULL);
660
1
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
661
1
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
662
1
}
663
664
3
ITESimplifier::~ITESimplifier()
665
{
666
1
  clearSimpITECaches();
667
1
  Assert(d_constantLeaves.empty());
668
1
  Assert(d_allocatedConstantLeaves.empty());
669
2
}
670
671
156
bool ITESimplifier::leavesAreConst(TNode e)
672
{
673
156
  return leavesAreConst(e, theory::Theory::theoryOf(e));
674
}
675
676
1
void ITESimplifier::clearSimpITECaches()
677
{
678
1
  Chat() << "clear ite caches " << endl;
679
756
  for (size_t i = 0, N = d_allocatedConstantLeaves.size(); i < N; ++i)
680
  {
681
755
    NodeVec* curr = d_allocatedConstantLeaves[i];
682
755
    delete curr;
683
  }
684
1
  d_citeEqConstApplications = 0;
685
1
  d_constantLeaves.clear();
686
1
  d_allocatedConstantLeaves.clear();
687
1
  d_termITEHeight.clear();
688
1
  d_constantIteEqualsConstantCache.clear();
689
1
  d_replaceOverCache.clear();
690
1
  d_replaceOverTermIteCache.clear();
691
1
  d_simpITECache.clear();
692
1
  d_simpVars.clear();
693
1
  d_simpConstCache.clear();
694
1
  d_leavesConstCache.clear();
695
1
  d_simpContextCache.clear();
696
1
}
697
698
1
bool ITESimplifier::doneALotOfWorkHeuristic() const
699
{
700
  static const size_t SIZE_BOUND = 1000;
701
1
  Chat() << "d_citeEqConstApplications size " << d_citeEqConstApplications
702
         << endl;
703
1
  return (d_citeEqConstApplications > SIZE_BOUND);
704
}
705
706
1
ITESimplifier::Statistics::Statistics(StatisticsRegistry& reg)
707
    : d_maxNonConstantsFolded(
708
2
        reg.registerInt("ite-simp::maxNonConstantsFolded")),
709
2
      d_unexpected(reg.registerInt("ite-simp::unexpected")),
710
2
      d_unsimplified(reg.registerInt("ite-simp::unsimplified")),
711
2
      d_exactMatchFold(reg.registerInt("ite-simp::exactMatchFold")),
712
2
      d_binaryPredFold(reg.registerInt("ite-simp::binaryPredFold")),
713
2
      d_specialEqualityFolds(reg.registerInt("ite-simp::specialEqualityFolds")),
714
2
      d_simpITEVisits(reg.registerInt("ite-simp::simpITE.visits")),
715
8
      d_inSmaller(reg.registerHistogram<uint32_t>("ite-simp::inSmaller"))
716
{
717
1
}
718
719
1253
bool ITESimplifier::isConstantIte(TNode e)
720
{
721
1253
  if (e.isConst())
722
  {
723
573
    return true;
724
  }
725
680
  else if (ite::isTermITE(e))
726
  {
727
680
    NodeVec* constants = computeConstantLeaves(e);
728
680
    return constants != NULL;
729
  }
730
  else
731
  {
732
    return false;
733
  }
734
}
735
736
43308
ITESimplifier::NodeVec* ITESimplifier::computeConstantLeaves(TNode ite)
737
{
738
43308
  Assert(ite::isTermITE(ite));
739
43308
  ConstantLeavesMap::const_iterator it = d_constantLeaves.find(ite);
740
43308
  ConstantLeavesMap::const_iterator end = d_constantLeaves.end();
741
43308
  if (it != end)
742
  {
743
42446
    return (*it).second;
744
  }
745
1724
  TNode thenB = ite[1];
746
1724
  TNode elseB = ite[2];
747
748
  // special case 2 constant children
749
862
  if (thenB.isConst() && elseB.isConst())
750
  {
751
152
    NodeVec* pair = new NodeVec(2);
752
152
    d_allocatedConstantLeaves.push_back(pair);
753
754
152
    (*pair)[0] = std::min(thenB, elseB);
755
152
    (*pair)[1] = std::max(thenB, elseB);
756
152
    d_constantLeaves[ite] = pair;
757
152
    return pair;
758
  }
759
  // At least 1 is an ITE
760
1739
  if (!(thenB.isConst() || thenB.getKind() == kind::ITE)
761
1314
      || !(elseB.isConst() || elseB.getKind() == kind::ITE))
762
  {
763
    // Cannot be a termITE tree
764
107
    d_constantLeaves[ite] = NULL;
765
107
    return NULL;
766
  }
767
768
  // At least 1 is not a constant
769
1206
  TNode definitelyITE = thenB.isConst() ? elseB : thenB;
770
1206
  TNode maybeITE = thenB.isConst() ? thenB : elseB;
771
772
603
  NodeVec* defChildren = computeConstantLeaves(definitelyITE);
773
603
  if (defChildren == NULL)
774
  {
775
    d_constantLeaves[ite] = NULL;
776
    return NULL;
777
  }
778
779
1206
  NodeVec scratch;
780
603
  NodeVec* maybeChildren = NULL;
781
603
  if (maybeITE.getKind() == kind::ITE)
782
  {
783
192
    maybeChildren = computeConstantLeaves(maybeITE);
784
  }
785
  else
786
  {
787
411
    scratch.push_back(maybeITE);
788
411
    maybeChildren = &scratch;
789
  }
790
603
  if (maybeChildren == NULL)
791
  {
792
    d_constantLeaves[ite] = NULL;
793
    return NULL;
794
  }
795
796
603
  NodeVec* both = new NodeVec(defChildren->size() + maybeChildren->size());
797
603
  d_allocatedConstantLeaves.push_back(both);
798
603
  NodeVec::iterator newEnd;
799
603
  newEnd = std::set_union(defChildren->begin(),
800
                          defChildren->end(),
801
                          maybeChildren->begin(),
802
                          maybeChildren->end(),
803
603
                          both->begin());
804
603
  both->resize(newEnd - both->begin());
805
603
  d_constantLeaves[ite] = both;
806
603
  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
729
Node ITESimplifier::transformAtom(TNode atom)
1045
{
1046
729
  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
1458
    Node acr = attemptConstantRemoval(atom);
1058
729
    if (!acr.isNull())
1059
    {
1060
573
      return acr;
1061
    }
1062
    // Node ale = attemptLiftEquality(atom);
1063
    // if(!ale.isNull()){
1064
    //   //return ale;
1065
    // }
1066
156
    return Node::null();
1067
  }
1068
}
1069
1070
static unsigned numBranches = 0;
1071
static unsigned numFalseBranches = 0;
1072
static unsigned itesMade = 0;
1073
1074
67339
Node ITESimplifier::constantIteEqualsConstant(TNode cite, TNode constant)
1075
{
1076
  static int instance = 0;
1077
67339
  ++instance;
1078
134678
  Debug("ite::constantIteEqualsConstant")
1079
67339
      << instance << "constantIteEqualsConstant(" << cite << ", " << constant
1080
67339
      << ")" << endl;
1081
67339
  if (cite.isConst())
1082
  {
1083
45678
    Node res = (cite == constant) ? d_true : d_false;
1084
22839
    Debug("ite::constantIteEqualsConstant") << instance << "->" << res << endl;
1085
22839
    return res;
1086
  }
1087
89000
  std::pair<Node, Node> pair = make_pair(cite, constant);
1088
1089
  NodePairMap::const_iterator eq_pos =
1090
44500
      d_constantIteEqualsConstantCache.find(pair);
1091
44500
  if (eq_pos != d_constantIteEqualsConstantCache.end())
1092
  {
1093
5334
    Debug("ite::constantIteEqualsConstant")
1094
2667
        << instance << "->" << (*eq_pos).second << endl;
1095
2667
    return (*eq_pos).second;
1096
  }
1097
1098
41833
  ++d_citeEqConstApplications;
1099
1100
41833
  NodeVec* leaves = computeConstantLeaves(cite);
1101
41833
  Assert(leaves != NULL);
1102
41833
  if (std::binary_search(leaves->begin(), leaves->end(), constant))
1103
  {
1104
33383
    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
33383
      Assert(cite.getKind() == kind::ITE);
1115
66766
      TNode cnd = cite[0];
1116
66766
      TNode tB = cite[1];
1117
66766
      TNode fB = cite[2];
1118
66766
      Node tEqs = constantIteEqualsConstant(tB, constant);
1119
66766
      Node fEqs = constantIteEqualsConstant(fB, constant);
1120
66766
      Node boolIte = cnd.iteNode(tEqs, fEqs);
1121
33383
      if (!(tEqs.isConst() || fEqs.isConst()))
1122
      {
1123
1924
        ++numBranches;
1124
      }
1125
33383
      if (!(tEqs == d_false || fEqs == d_false))
1126
      {
1127
2211
        ++numFalseBranches;
1128
      }
1129
33383
      ++itesMade;
1130
33383
      d_constantIteEqualsConstantCache[pair] = boolIte;
1131
      // Debug("ite::constantIteEqualsConstant") << instance << "->" << boolIte
1132
      // << endl;
1133
33383
      return boolIte;
1134
    }
1135
  }
1136
  else
1137
  {
1138
8450
    d_constantIteEqualsConstantCache[pair] = d_false;
1139
16900
    Debug("ite::constantIteEqualsConstant")
1140
8450
        << instance << "->" << d_false << endl;
1141
8450
    return d_false;
1142
  }
1143
}
1144
1145
573
Node ITESimplifier::intersectConstantIte(TNode lcite, TNode rcite)
1146
{
1147
  // intersect the constant ite trees lcite and rcite
1148
1149
573
  if (lcite.isConst() || rcite.isConst())
1150
  {
1151
573
    bool lIsConst = lcite.isConst();
1152
1146
    TNode constant = lIsConst ? lcite : rcite;
1153
1146
    TNode cite = lIsConst ? rcite : lcite;
1154
1155
573
    (d_statistics.d_inSmaller) << 1;
1156
573
    unsigned preItesMade = itesMade;
1157
573
    unsigned preNumBranches = numBranches;
1158
573
    unsigned preNumFalseBranches = numFalseBranches;
1159
1146
    Node bterm = constantIteEqualsConstant(cite, constant);
1160
1146
    Debug("intersectConstantIte") << (numBranches - preNumBranches) << " "
1161
1146
                                  << (numFalseBranches - preNumFalseBranches)
1162
573
                                  << " " << (itesMade - preItesMade) << endl;
1163
573
    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
729
Node ITESimplifier::attemptConstantRemoval(TNode atom)
1245
{
1246
729
  if (atom.getKind() == kind::EQUAL)
1247
  {
1248
787
    TNode left = atom[0];
1249
787
    TNode right = atom[1];
1250
680
    if (isConstantIte(left) && isConstantIte(right))
1251
    {
1252
573
      return intersectConstantIte(left, right);
1253
    }
1254
  }
1255
156
  return Node::null();
1256
}
1257
1258
550
bool ITESimplifier::leavesAreConst(TNode e, theory::TheoryId tid)
1259
{
1260
550
  Assert((e.getKind() == kind::ITE && !e.getType().isBoolean())
1261
         || theory::Theory::theoryOf(e) != theory::THEORY_BOOL);
1262
550
  if (e.isConst())
1263
  {
1264
27
    return true;
1265
  }
1266
1267
523
  unordered_map<Node, bool>::iterator it;
1268
523
  it = d_leavesConstCache.find(e);
1269
523
  if (it != d_leavesConstCache.end())
1270
  {
1271
122
    return (*it).second;
1272
  }
1273
1274
401
  if (!containsTermITE(e) && theory::Theory::isLeafOf(e, tid))
1275
  {
1276
34
    d_leavesConstCache[e] = false;
1277
34
    return false;
1278
  }
1279
1280
367
  Assert(e.getNumChildren() > 0);
1281
367
  size_t k = 0, sz = e.getNumChildren();
1282
1283
367
  if (e.getKind() == kind::ITE)
1284
  {
1285
161
    k = 1;
1286
  }
1287
1288
421
  for (; k < sz; ++k)
1289
  {
1290
394
    if (!leavesAreConst(e[k], tid))
1291
    {
1292
367
      d_leavesConstCache[e] = false;
1293
367
      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 = rewrite(result);
1328
    d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = result;
1329
    return result;
1330
  }
1331
1332
  if (!containsTermITE(iteNode))
1333
  {
1334
    Node n = rewrite(simpContext.substitute(simpVar, iteNode));
1335
    d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = n;
1336
    return n;
1337
  }
1338
1339
  Node iteNode2;
1340
  Node simpVar2;
1341
  d_simpContextCache.clear();
1342
  Node simpContext2 = createSimpContext(iteNode, iteNode2, simpVar2);
1343
  if (!simpContext2.isNull())
1344
  {
1345
    Assert(!iteNode2.isNull());
1346
    simpContext2 = simpContext.substitute(simpVar, simpContext2);
1347
    Node n = simpConstants(simpContext2, iteNode2, simpVar2);
1348
    if (n.isNull())
1349
    {
1350
      return n;
1351
    }
1352
    d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = n;
1353
    return n;
1354
  }
1355
  return Node();
1356
}
1357
1358
Node ITESimplifier::getSimpVar(TypeNode t)
1359
{
1360
  std::unordered_map<TypeNode, Node>::iterator it;
1361
  it = d_simpVars.find(t);
1362
  if (it != d_simpVars.end())
1363
  {
1364
    return (*it).second;
1365
  }
1366
  SkolemManager* sm = NodeManager::currentNM()->getSkolemManager();
1367
  Node var = sm->mkDummySkolem(
1368
      "iteSimp", t, "is a variable resulting from ITE simplification");
1369
  d_simpVars[t] = var;
1370
  return var;
1371
}
1372
1373
Node ITESimplifier::createSimpContext(TNode c, Node& iteNode, Node& simpVar)
1374
{
1375
  NodeMap::iterator it;
1376
  it = d_simpContextCache.find(c);
1377
  if (it != d_simpContextCache.end())
1378
  {
1379
    return (*it).second;
1380
  }
1381
1382
  if (!containsTermITE(c))
1383
  {
1384
    d_simpContextCache[c] = c;
1385
    return c;
1386
  }
1387
1388
  if (c.getKind() == kind::ITE && !c.getType().isBoolean())
1389
  {
1390
    // Currently only support one ite node in a simp context
1391
    // Return Null if more than one is found
1392
    if (!iteNode.isNull())
1393
    {
1394
      return Node();
1395
    }
1396
    simpVar = getSimpVar(c.getType());
1397
    if (simpVar.isNull())
1398
    {
1399
      return Node();
1400
    }
1401
    d_simpContextCache[c] = simpVar;
1402
    iteNode = c;
1403
    return simpVar;
1404
  }
1405
1406
  NodeBuilder builder(c.getKind());
1407
  if (c.getMetaKind() == kind::metakind::PARAMETERIZED)
1408
  {
1409
    builder << c.getOperator();
1410
  }
1411
  unsigned i = 0;
1412
  for (; i < c.getNumChildren(); ++i)
1413
  {
1414
    Node newChild = createSimpContext(c[i], iteNode, simpVar);
1415
    if (newChild.isNull())
1416
    {
1417
      return newChild;
1418
    }
1419
    builder << newChild;
1420
  }
1421
  // Mark the substitution and continue
1422
  Node result = builder;
1423
  d_simpContextCache[c] = result;
1424
  return result;
1425
}
1426
typedef std::unordered_set<Node> NodeSet;
1427
40741410
void countReachable_(Node x, Kind k, NodeSet& visited, uint32_t& reached)
1428
{
1429
40741410
  if (visited.find(x) != visited.end())
1430
  {
1431
37305643
    return;
1432
  }
1433
3435767
  visited.insert(x);
1434
3435767
  if (x.getKind() == k)
1435
  {
1436
1086180
    ++reached;
1437
  }
1438
44176031
  for (unsigned i = 0, N = x.getNumChildren(); i < N; ++i)
1439
  {
1440
40740264
    countReachable_(x[i], k, visited, reached);
1441
  }
1442
}
1443
1444
1146
uint32_t countReachable(TNode x, Kind k)
1445
{
1446
2292
  NodeSet visited;
1447
1146
  uint32_t reached = 0;
1448
1146
  countReachable_(x, k, visited, reached);
1449
2292
  return reached;
1450
}
1451
1452
729
Node ITESimplifier::simpITEAtom(TNode atom)
1453
{
1454
  CVC5_UNUSED static int instance = 0;
1455
729
  Debug("ite::atom") << "still simplifying " << (++instance) << endl;
1456
1458
  Node attempt = transformAtom(atom);
1457
729
  Debug("ite::atom") << "  finished " << instance << endl;
1458
729
  if (!attempt.isNull())
1459
  {
1460
1146
    Node rewritten = rewrite(attempt);
1461
1146
    Debug("ite::print-success")
1462
573
        << instance << " "
1463
1146
        << "rewriting " << countReachable(rewritten, kind::ITE) << " from "
1464
1146
        << countReachable(atom, kind::ITE) << endl
1465
573
        << "\t rewritten " << rewritten << endl
1466
573
        << "\t input " << atom << endl;
1467
573
    return rewritten;
1468
  }
1469
1470
156
  if (leavesAreConst(atom))
1471
  {
1472
    Node iteNode;
1473
    Node simpVar;
1474
    d_simpContextCache.clear();
1475
    Node simpContext = createSimpContext(atom, iteNode, simpVar);
1476
    if (!simpContext.isNull())
1477
    {
1478
      if (iteNode.isNull())
1479
      {
1480
        Assert(leavesAreConst(simpContext) && !containsTermITE(simpContext));
1481
        ++(d_statistics.d_unexpected);
1482
        Debug("ite::simpite") << instance << " "
1483
                              << "how about?" << atom << endl;
1484
        Debug("ite::simpite") << instance << " "
1485
                              << "\t" << simpContext << endl;
1486
        return rewrite(simpContext);
1487
      }
1488
      Node n = simpConstants(simpContext, iteNode, simpVar);
1489
      if (!n.isNull())
1490
      {
1491
        ++(d_statistics.d_unexpected);
1492
        Debug("ite::simpite") << instance << " "
1493
                              << "here?" << atom << endl;
1494
        Debug("ite::simpite") << instance << " "
1495
                              << "\t" << n << endl;
1496
        return n;
1497
      }
1498
    }
1499
  }
1500
156
  if (Debug.isOn("ite::simpite"))
1501
  {
1502
    if (countReachable(atom, kind::ITE) > 0)
1503
    {
1504
      Debug("ite::simpite") << instance << " "
1505
                            << "remaining " << atom << endl;
1506
    }
1507
  }
1508
156
  ++(d_statistics.d_unsimplified);
1509
156
  return atom;
1510
}
1511
1512
11456
struct preprocess_stack_element
1513
{
1514
  TNode d_node;
1515
  bool d_children_added;
1516
2454
  preprocess_stack_element(TNode node) : d_node(node), d_children_added(false)
1517
  {
1518
2454
  }
1519
}; /* struct preprocess_stack_element */
1520
1521
1
Node ITESimplifier::simpITE(TNode assertion)
1522
{
1523
  // Do a topological sort of the subexpressions and substitute them
1524
2
  vector<preprocess_stack_element> toVisit;
1525
1
  toVisit.push_back(assertion);
1526
1527
  static int call = 0;
1528
1
  ++call;
1529
1
  int iteration = 0;
1530
1531
8745
  while (!toVisit.empty())
1532
  {
1533
4372
    iteration++;
1534
    // cout << "call  " << call << " : " << iteration << endl;
1535
    // The current node we are processing
1536
4372
    preprocess_stack_element& stackHead = toVisit.back();
1537
8208
    TNode current = stackHead.d_node;
1538
1539
    // If node has no ITE's or already in the cache we're done, pop from the
1540
    // stack
1541
9269
    if (current.getNumChildren() == 0
1542
13641
        || (theory::Theory::theoryOf(current) != theory::THEORY_BOOL
1543
6014
            && !containsTermITE(current)))
1544
    {
1545
525
      d_simpITECache[current] = current;
1546
525
      ++(d_statistics.d_simpITEVisits);
1547
525
      toVisit.pop_back();
1548
525
      continue;
1549
    }
1550
1551
3847
    NodeMap::iterator find = d_simpITECache.find(current);
1552
3858
    if (find != d_simpITECache.end())
1553
    {
1554
11
      toVisit.pop_back();
1555
11
      continue;
1556
    }
1557
1558
    // Not yet substituted, so process
1559
3836
    if (stackHead.d_children_added)
1560
    {
1561
      // Children have been processed, so substitute
1562
3836
      NodeBuilder builder(current.getKind());
1563
1918
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
1564
      {
1565
        builder << current.getOperator();
1566
      }
1567
6869
      for (unsigned i = 0; i < current.getNumChildren(); ++i)
1568
      {
1569
4951
        Assert(d_simpITECache.find(current[i]) != d_simpITECache.end());
1570
9902
        Node child = current[i];
1571
9902
        Node childRes = d_simpITECache[current[i]];
1572
4951
        builder << childRes;
1573
      }
1574
      // Mark the substitution and continue
1575
3836
      Node result = builder;
1576
1577
      // If this is an atom, we process it
1578
5754
      if (theory::Theory::theoryOf(result) != theory::THEORY_BOOL
1579
5754
          && result.getType().isBoolean())
1580
      {
1581
729
        result = simpITEAtom(result);
1582
      }
1583
1584
      // if(current != result && result.isConst()){
1585
      //   static int instance = 0;
1586
      //   //cout << instance << " " << result << current << endl;
1587
      // }
1588
1589
1918
      result = rewrite(result);
1590
1918
      d_simpITECache[current] = result;
1591
1918
      ++(d_statistics.d_simpITEVisits);
1592
1918
      toVisit.pop_back();
1593
    }
1594
    else
1595
    {
1596
      // Mark that we have added the children if any
1597
1918
      if (current.getNumChildren() > 0)
1598
      {
1599
1918
        stackHead.d_children_added = true;
1600
        // We need to add the children
1601
6869
        for (TNode::iterator child_it = current.begin();
1602
6869
             child_it != current.end();
1603
             ++child_it)
1604
        {
1605
9902
          TNode childNode = *child_it;
1606
4951
          NodeMap::iterator childFind = d_simpITECache.find(childNode);
1607
4951
          if (childFind == d_simpITECache.end())
1608
          {
1609
2453
            toVisit.push_back(childNode);
1610
          }
1611
        }
1612
      }
1613
      else
1614
      {
1615
        // No children, so we're done
1616
        d_simpITECache[current] = current;
1617
        ++(d_statistics.d_simpITEVisits);
1618
        toVisit.pop_back();
1619
      }
1620
    }
1621
  }
1622
2
  return d_simpITECache[assertion];
1623
}
1624
1625
ITECareSimplifier::ITECareSimplifier() : d_careSetsOutstanding(0), d_usedSets()
1626
{
1627
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
1628
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
1629
}
1630
1631
ITECareSimplifier::~ITECareSimplifier()
1632
{
1633
  Assert(d_usedSets.empty());
1634
  Assert(d_careSetsOutstanding == 0);
1635
}
1636
1637
void ITECareSimplifier::clear()
1638
{
1639
  Assert(d_usedSets.empty());
1640
  Assert(d_careSetsOutstanding == 0);
1641
}
1642
1643
ITECareSimplifier::CareSetPtr ITECareSimplifier::getNewSet()
1644
{
1645
  if (d_usedSets.empty())
1646
  {
1647
    d_careSetsOutstanding++;
1648
    return ITECareSimplifier::CareSetPtr::mkNew(*this);
1649
  }
1650
  else
1651
  {
1652
    ITECareSimplifier::CareSetPtr cs =
1653
        ITECareSimplifier::CareSetPtr::recycle(d_usedSets.back());
1654
    cs.getCareSet().clear();
1655
    d_usedSets.pop_back();
1656
    return cs;
1657
  }
1658
}
1659
1660
void ITECareSimplifier::updateQueue(CareMap& queue,
1661
                                    TNode e,
1662
                                    ITECareSimplifier::CareSetPtr& careSet)
1663
{
1664
  CareMap::iterator it = queue.find(e), iend = queue.end();
1665
  if (it != iend)
1666
  {
1667
    set<Node>& cs2 = (*it).second.getCareSet();
1668
    ITECareSimplifier::CareSetPtr csNew = getNewSet();
1669
    set_intersection(careSet.getCareSet().begin(),
1670
                     careSet.getCareSet().end(),
1671
                     cs2.begin(),
1672
                     cs2.end(),
1673
                     inserter(csNew.getCareSet(), csNew.getCareSet().begin()));
1674
    (*it).second = csNew;
1675
  }
1676
  else
1677
  {
1678
    queue[e] = careSet;
1679
  }
1680
}
1681
1682
Node ITECareSimplifier::substitute(TNode e,
1683
                                   TNodeMap& substTable,
1684
                                   TNodeMap& cache)
1685
{
1686
  TNodeMap::iterator it = cache.find(e), iend = cache.end();
1687
  if (it != iend)
1688
  {
1689
    return it->second;
1690
  }
1691
1692
  // do substitution?
1693
  it = substTable.find(e);
1694
  iend = substTable.end();
1695
  if (it != iend)
1696
  {
1697
    Node result = substitute(it->second, substTable, cache);
1698
    cache[e] = result;
1699
    return result;
1700
  }
1701
1702
  size_t sz = e.getNumChildren();
1703
  if (sz == 0)
1704
  {
1705
    cache[e] = e;
1706
    return e;
1707
  }
1708
1709
  NodeBuilder builder(e.getKind());
1710
  if (e.getMetaKind() == kind::metakind::PARAMETERIZED)
1711
  {
1712
    builder << e.getOperator();
1713
  }
1714
  for (unsigned i = 0; i < e.getNumChildren(); ++i)
1715
  {
1716
    builder << substitute(e[i], substTable, cache);
1717
  }
1718
1719
  Node result = builder;
1720
  // it = substTable.find(result);
1721
  // if (it != iend) {
1722
  //   result = substitute(it->second, substTable, cache);
1723
  // }
1724
  cache[e] = result;
1725
  return result;
1726
}
1727
1728
Node ITECareSimplifier::simplifyWithCare(TNode e)
1729
{
1730
  TNodeMap substTable;
1731
1732
  /* This extra block is to trigger the destructors for cs and cs2
1733
   * before starting garbage collection.
1734
   */
1735
  {
1736
    CareMap queue;
1737
    CareMap::iterator it;
1738
    ITECareSimplifier::CareSetPtr cs = getNewSet();
1739
    ITECareSimplifier::CareSetPtr cs2;
1740
    queue[e] = cs;
1741
1742
    TNode v;
1743
    bool done;
1744
    unsigned i;
1745
1746
    while (!queue.empty())
1747
    {
1748
      it = queue.end();
1749
      --it;
1750
      v = it->first;
1751
      cs = it->second;
1752
      set<Node>& css = cs.getCareSet();
1753
      queue.erase(v);
1754
1755
      done = false;
1756
      set<Node>::iterator iCare, iCareEnd = css.end();
1757
1758
      switch (v.getKind())
1759
      {
1760
        case kind::ITE:
1761
        {
1762
          iCare = css.find(v[0]);
1763
          if (iCare != iCareEnd)
1764
          {
1765
            Assert(substTable.find(v) == substTable.end());
1766
            substTable[v] = v[1];
1767
            updateQueue(queue, v[1], cs);
1768
            done = true;
1769
            break;
1770
          }
1771
          else
1772
          {
1773
            iCare = css.find(v[0].negate());
1774
            if (iCare != iCareEnd)
1775
            {
1776
              Assert(substTable.find(v) == substTable.end());
1777
              substTable[v] = v[2];
1778
              updateQueue(queue, v[2], cs);
1779
              done = true;
1780
              break;
1781
            }
1782
          }
1783
          updateQueue(queue, v[0], cs);
1784
          cs2 = getNewSet();
1785
          cs2.getCareSet() = css;
1786
          cs2.getCareSet().insert(v[0]);
1787
          updateQueue(queue, v[1], cs2);
1788
          cs2 = getNewSet();
1789
          cs2.getCareSet() = css;
1790
          cs2.getCareSet().insert(v[0].negate());
1791
          updateQueue(queue, v[2], cs2);
1792
          done = true;
1793
          break;
1794
        }
1795
        case kind::AND:
1796
        {
1797
          for (i = 0; i < v.getNumChildren(); ++i)
1798
          {
1799
            iCare = css.find(v[i].negate());
1800
            if (iCare != iCareEnd)
1801
            {
1802
              Assert(substTable.find(v) == substTable.end());
1803
              substTable[v] = d_false;
1804
              done = true;
1805
              break;
1806
            }
1807
          }
1808
          if (done) break;
1809
1810
          Assert(v.getNumChildren() > 1);
1811
          updateQueue(queue, v[0], cs);
1812
          cs2 = getNewSet();
1813
          cs2.getCareSet() = css;
1814
          cs2.getCareSet().insert(v[0]);
1815
          for (i = 1; i < v.getNumChildren(); ++i)
1816
          {
1817
            updateQueue(queue, v[i], cs2);
1818
          }
1819
          done = true;
1820
          break;
1821
        }
1822
        case kind::OR:
1823
        {
1824
          for (i = 0; i < v.getNumChildren(); ++i)
1825
          {
1826
            iCare = css.find(v[i]);
1827
            if (iCare != iCareEnd)
1828
            {
1829
              Assert(substTable.find(v) == substTable.end());
1830
              substTable[v] = d_true;
1831
              done = true;
1832
              break;
1833
            }
1834
          }
1835
          if (done) break;
1836
1837
          Assert(v.getNumChildren() > 1);
1838
          updateQueue(queue, v[0], cs);
1839
          cs2 = getNewSet();
1840
          cs2.getCareSet() = css;
1841
          cs2.getCareSet().insert(v[0].negate());
1842
          for (i = 1; i < v.getNumChildren(); ++i)
1843
          {
1844
            updateQueue(queue, v[i], cs2);
1845
          }
1846
          done = true;
1847
          break;
1848
        }
1849
        default: break;
1850
      }
1851
1852
      if (done)
1853
      {
1854
        continue;
1855
      }
1856
1857
      for (i = 0; i < v.getNumChildren(); ++i)
1858
      {
1859
        updateQueue(queue, v[i], cs);
1860
      }
1861
    }
1862
  }
1863
  /* Perform garbage collection. */
1864
  while (!d_usedSets.empty())
1865
  {
1866
    CareSetPtrVal* used = d_usedSets.back();
1867
    d_usedSets.pop_back();
1868
    Assert(used->safeToGarbageCollect());
1869
    delete used;
1870
    Assert(d_careSetsOutstanding > 0);
1871
    d_careSetsOutstanding--;
1872
  }
1873
1874
  TNodeMap cache;
1875
  return substitute(e, substTable, cache);
1876
}
1877
1878
ITECareSimplifier::CareSetPtr ITECareSimplifier::CareSetPtr::mkNew(
1879
    ITECareSimplifier& simp)
1880
{
1881
  CareSetPtrVal* val = new CareSetPtrVal(simp);
1882
  return CareSetPtr(val);
1883
}
1884
1885
}  // namespace util
1886
}  // namespace preprocessing
1887
22746
}  // namespace cvc5