GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/util/ite_utilities.cpp Lines: 458 986 46.5 %
Date: 2021-09-07 Branches: 782 3689 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
97988
inline static bool isTermITE(TNode e)
40
{
41
97988
  return (e.getKind() == kind::ITE && !e.getType().isBoolean());
42
}
43
44
156574
inline static bool triviallyContainsNoTermITEs(TNode e)
45
{
46
156574
  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
321267
struct CTIVStackElement
80
{
81
  TNode curr;
82
  unsigned pos;
83
  CTIVStackElement() : curr(), pos(0) {}
84
72587
  CTIVStackElement(TNode c) : curr(c), pos(0) {}
85
}; /* CTIVStackElement */
86
87
}  // namespace ite
88
89
9926
ITEUtilities::ITEUtilities(Env& env)
90
    : EnvObj(env),
91
9926
      d_containsVisitor(new ContainsTermITEVisitor()),
92
      d_compressor(NULL),
93
      d_simplifier(NULL),
94
19852
      d_careSimp(NULL)
95
{
96
9926
  Assert(d_containsVisitor != NULL);
97
9926
}
98
99
19846
ITEUtilities::~ITEUtilities()
100
{
101
9923
  if (d_simplifier != NULL)
102
  {
103
1
    delete d_simplifier;
104
  }
105
9923
  if (d_compressor != NULL)
106
  {
107
1
    delete d_compressor;
108
  }
109
9923
  if (d_careSimp != NULL)
110
  {
111
    delete d_careSimp;
112
  }
113
9923
}
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
35477
ContainsTermITEVisitor::ContainsTermITEVisitor() : d_cache() {}
174
35474
ContainsTermITEVisitor::~ContainsTermITEVisitor() {}
175
28327
bool ContainsTermITEVisitor::containsTermITE(TNode e)
176
{
177
  /* throughout execution skip through NOT nodes. */
178
28327
  e = (e.getKind() == kind::NOT) ? e[0] : e;
179
28327
  if (ite::triviallyContainsNoTermITEs(e))
180
  {
181
8562
    return false;
182
  }
183
184
19765
  NodeBoolMap::const_iterator end = d_cache.end();
185
19765
  NodeBoolMap::const_iterator tmp_it = d_cache.find(e);
186
19765
  if (tmp_it != end)
187
  {
188
1178
    return (*tmp_it).second;
189
  }
190
191
18587
  bool foundTermIte = false;
192
37174
  std::vector<ite::CTIVStackElement> stack;
193
18587
  stack.push_back(ite::CTIVStackElement(e));
194
416285
  while (!foundTermIte && !stack.empty())
195
  {
196
198849
    ite::CTIVStackElement& top = stack.back();
197
397698
    TNode curr = top.curr;
198
198849
    if (top.pos >= curr.getNumChildren())
199
    {
200
      // all of the children have been visited
201
      // no term ites were found
202
70602
      d_cache[curr] = false;
203
70602
      stack.pop_back();
204
    }
205
    else
206
    {
207
      // this is someone's child
208
256494
      TNode child = curr[top.pos];
209
128247
      child = (child.getKind() == kind::NOT) ? child[0] : child;
210
128247
      ++top.pos;
211
128247
      if (ite::triviallyContainsNoTermITEs(child))
212
      {
213
        // skip
214
      }
215
      else
216
      {
217
55145
        tmp_it = d_cache.find(child);
218
55145
        if (tmp_it != end)
219
        {
220
1145
          foundTermIte = (*tmp_it).second;
221
        }
222
        else
223
        {
224
54000
          stack.push_back(ite::CTIVStackElement(child));
225
54000
          foundTermIte = ite::isTermITE(child);
226
        }
227
      }
228
    }
229
  }
230
18587
  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
18587
  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
1
      d_incoming(true, true)
296
{
297
1
  Assert(d_contains != NULL);
298
299
1
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
300
1
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
301
1
}
302
303
2
ITECompressor::~ITECompressor() { reset(); }
304
305
2
void ITECompressor::reset()
306
{
307
2
  d_incoming.clear();
308
2
  d_compressed.clear();
309
2
}
310
311
void ITECompressor::garbageCollect() { reset(); }
312
313
1
ITECompressor::Statistics::Statistics()
314
    : d_compressCalls(
315
2
        smtStatisticsRegistry().registerInt("ite-simp::compressCalls")),
316
2
      d_skolemsAdded(smtStatisticsRegistry().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
1
      d_simpITECache()
657
{
658
1
  Assert(d_containsVisitor != NULL);
659
1
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
660
1
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
661
1
}
662
663
3
ITESimplifier::~ITESimplifier()
664
{
665
1
  clearSimpITECaches();
666
1
  Assert(d_constantLeaves.empty());
667
1
  Assert(d_allocatedConstantLeaves.empty());
668
2
}
669
670
156
bool ITESimplifier::leavesAreConst(TNode e)
671
{
672
156
  return leavesAreConst(e, theory::Theory::theoryOf(e));
673
}
674
675
1
void ITESimplifier::clearSimpITECaches()
676
{
677
1
  Chat() << "clear ite caches " << endl;
678
756
  for (size_t i = 0, N = d_allocatedConstantLeaves.size(); i < N; ++i)
679
  {
680
755
    NodeVec* curr = d_allocatedConstantLeaves[i];
681
755
    delete curr;
682
  }
683
1
  d_citeEqConstApplications = 0;
684
1
  d_constantLeaves.clear();
685
1
  d_allocatedConstantLeaves.clear();
686
1
  d_termITEHeight.clear();
687
1
  d_constantIteEqualsConstantCache.clear();
688
1
  d_replaceOverCache.clear();
689
1
  d_replaceOverTermIteCache.clear();
690
1
  d_simpITECache.clear();
691
1
  d_simpVars.clear();
692
1
  d_simpConstCache.clear();
693
1
  d_leavesConstCache.clear();
694
1
  d_simpContextCache.clear();
695
1
}
696
697
1
bool ITESimplifier::doneALotOfWorkHeuristic() const
698
{
699
  static const size_t SIZE_BOUND = 1000;
700
1
  Chat() << "d_citeEqConstApplications size " << d_citeEqConstApplications
701
         << endl;
702
1
  return (d_citeEqConstApplications > SIZE_BOUND);
703
}
704
705
1
ITESimplifier::Statistics::Statistics()
706
    : d_maxNonConstantsFolded(
707
2
        smtStatisticsRegistry().registerInt("ite-simp::maxNonConstantsFolded")),
708
2
      d_unexpected(smtStatisticsRegistry().registerInt("ite-simp::unexpected")),
709
      d_unsimplified(
710
2
          smtStatisticsRegistry().registerInt("ite-simp::unsimplified")),
711
      d_exactMatchFold(
712
2
          smtStatisticsRegistry().registerInt("ite-simp::exactMatchFold")),
713
      d_binaryPredFold(
714
2
          smtStatisticsRegistry().registerInt("ite-simp::binaryPredFold")),
715
1
      d_specialEqualityFolds(smtStatisticsRegistry().registerInt(
716
2
          "ite-simp::specialEqualityFolds")),
717
      d_simpITEVisits(
718
2
          smtStatisticsRegistry().registerInt("ite-simp::simpITE.visits")),
719
1
      d_inSmaller(smtStatisticsRegistry().registerHistogram<uint32_t>(
720
8
          "ite-simp::inSmaller"))
721
{
722
1
}
723
724
1253
bool ITESimplifier::isConstantIte(TNode e)
725
{
726
1253
  if (e.isConst())
727
  {
728
573
    return true;
729
  }
730
680
  else if (ite::isTermITE(e))
731
  {
732
680
    NodeVec* constants = computeConstantLeaves(e);
733
680
    return constants != NULL;
734
  }
735
  else
736
  {
737
    return false;
738
  }
739
}
740
741
43308
ITESimplifier::NodeVec* ITESimplifier::computeConstantLeaves(TNode ite)
742
{
743
43308
  Assert(ite::isTermITE(ite));
744
43308
  ConstantLeavesMap::const_iterator it = d_constantLeaves.find(ite);
745
43308
  ConstantLeavesMap::const_iterator end = d_constantLeaves.end();
746
43308
  if (it != end)
747
  {
748
42446
    return (*it).second;
749
  }
750
1724
  TNode thenB = ite[1];
751
1724
  TNode elseB = ite[2];
752
753
  // special case 2 constant children
754
862
  if (thenB.isConst() && elseB.isConst())
755
  {
756
152
    NodeVec* pair = new NodeVec(2);
757
152
    d_allocatedConstantLeaves.push_back(pair);
758
759
152
    (*pair)[0] = std::min(thenB, elseB);
760
152
    (*pair)[1] = std::max(thenB, elseB);
761
152
    d_constantLeaves[ite] = pair;
762
152
    return pair;
763
  }
764
  // At least 1 is an ITE
765
1739
  if (!(thenB.isConst() || thenB.getKind() == kind::ITE)
766
1314
      || !(elseB.isConst() || elseB.getKind() == kind::ITE))
767
  {
768
    // Cannot be a termITE tree
769
107
    d_constantLeaves[ite] = NULL;
770
107
    return NULL;
771
  }
772
773
  // At least 1 is not a constant
774
1206
  TNode definitelyITE = thenB.isConst() ? elseB : thenB;
775
1206
  TNode maybeITE = thenB.isConst() ? thenB : elseB;
776
777
603
  NodeVec* defChildren = computeConstantLeaves(definitelyITE);
778
603
  if (defChildren == NULL)
779
  {
780
    d_constantLeaves[ite] = NULL;
781
    return NULL;
782
  }
783
784
1206
  NodeVec scratch;
785
603
  NodeVec* maybeChildren = NULL;
786
603
  if (maybeITE.getKind() == kind::ITE)
787
  {
788
192
    maybeChildren = computeConstantLeaves(maybeITE);
789
  }
790
  else
791
  {
792
411
    scratch.push_back(maybeITE);
793
411
    maybeChildren = &scratch;
794
  }
795
603
  if (maybeChildren == NULL)
796
  {
797
    d_constantLeaves[ite] = NULL;
798
    return NULL;
799
  }
800
801
603
  NodeVec* both = new NodeVec(defChildren->size() + maybeChildren->size());
802
603
  d_allocatedConstantLeaves.push_back(both);
803
603
  NodeVec::iterator newEnd;
804
603
  newEnd = std::set_union(defChildren->begin(),
805
                          defChildren->end(),
806
                          maybeChildren->begin(),
807
                          maybeChildren->end(),
808
603
                          both->begin());
809
603
  both->resize(newEnd - both->begin());
810
603
  d_constantLeaves[ite] = both;
811
603
  return both;
812
}
813
814
// This is uncached! Better for protoyping or getting limited size examples
815
struct IteTreeSearchData
816
{
817
  set<Node> visited;
818
  set<Node> constants;
819
  set<Node> nonConstants;
820
  int maxConstants;
821
  int maxNonconstants;
822
  int maxDepth;
823
  bool failure;
824
  IteTreeSearchData()
825
      : maxConstants(-1), maxNonconstants(-1), maxDepth(-1), failure(false)
826
  {
827
  }
828
};
829
void iteTreeSearch(Node e, int depth, IteTreeSearchData& search)
830
{
831
  if (search.maxDepth >= 0 && depth > search.maxDepth)
832
  {
833
    search.failure = true;
834
  }
835
  if (search.failure)
836
  {
837
    return;
838
  }
839
  if (search.visited.find(e) != search.visited.end())
840
  {
841
    return;
842
  }
843
  else
844
  {
845
    search.visited.insert(e);
846
  }
847
848
  if (e.isConst())
849
  {
850
    search.constants.insert(e);
851
    if (search.maxConstants >= 0
852
        && search.constants.size() > (unsigned)search.maxConstants)
853
    {
854
      search.failure = true;
855
    }
856
  }
857
  else if (e.getKind() == kind::ITE)
858
  {
859
    iteTreeSearch(e[1], depth + 1, search);
860
    iteTreeSearch(e[2], depth + 1, search);
861
  }
862
  else
863
  {
864
    search.nonConstants.insert(e);
865
    if (search.maxNonconstants >= 0
866
        && search.nonConstants.size() > (unsigned)search.maxNonconstants)
867
    {
868
      search.failure = true;
869
    }
870
  }
871
}
872
873
Node ITESimplifier::replaceOver(Node n, Node replaceWith, Node simpVar)
874
{
875
  if (n == simpVar)
876
  {
877
    return replaceWith;
878
  }
879
  else if (n.getNumChildren() == 0)
880
  {
881
    return n;
882
  }
883
  Assert(n.getNumChildren() > 0);
884
  Assert(!n.isVar());
885
886
  pair<Node, Node> p = make_pair(n, replaceWith);
887
  if (d_replaceOverCache.find(p) != d_replaceOverCache.end())
888
  {
889
    return d_replaceOverCache[p];
890
  }
891
892
  NodeBuilder builder(n.getKind());
893
  if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
894
  {
895
    builder << n.getOperator();
896
  }
897
  unsigned i = 0;
898
  for (; i < n.getNumChildren(); ++i)
899
  {
900
    Node newChild = replaceOver(n[i], replaceWith, simpVar);
901
    builder << newChild;
902
  }
903
  // Mark the substitution and continue
904
  Node result = builder;
905
  d_replaceOverCache[p] = result;
906
  return result;
907
}
908
909
Node ITESimplifier::replaceOverTermIte(Node e, Node simpAtom, Node simpVar)
910
{
911
  if (e.getKind() == kind::ITE)
912
  {
913
    pair<Node, Node> p = make_pair(e, simpAtom);
914
    if (d_replaceOverTermIteCache.find(p) != d_replaceOverTermIteCache.end())
915
    {
916
      return d_replaceOverTermIteCache[p];
917
    }
918
    Assert(!e.getType().isBoolean());
919
    Node cnd = e[0];
920
    Node newThen = replaceOverTermIte(e[1], simpAtom, simpVar);
921
    Node newElse = replaceOverTermIte(e[2], simpAtom, simpVar);
922
    Node newIte = cnd.iteNode(newThen, newElse);
923
    d_replaceOverTermIteCache[p] = newIte;
924
    return newIte;
925
  }
926
  else
927
  {
928
    return replaceOver(simpAtom, e, simpVar);
929
  }
930
}
931
932
Node ITESimplifier::attemptLiftEquality(TNode atom)
933
{
934
  if (atom.getKind() == kind::EQUAL)
935
  {
936
    TNode left = atom[0];
937
    TNode right = atom[1];
938
    if ((left.getKind() == kind::ITE || right.getKind() == kind::ITE)
939
        && !(left.getKind() == kind::ITE && right.getKind() == kind::ITE))
940
    {
941
      // exactly 1 is an ite
942
      TNode ite = left.getKind() == kind::ITE ? left : right;
943
      TNode notIte = left.getKind() == kind::ITE ? right : left;
944
945
      if (notIte == ite[1])
946
      {
947
        ++(d_statistics.d_exactMatchFold);
948
        return ite[0].iteNode(d_true, notIte.eqNode(ite[2]));
949
      }
950
      else if (notIte == ite[2])
951
      {
952
        ++(d_statistics.d_exactMatchFold);
953
        return ite[0].iteNode(notIte.eqNode(ite[1]), d_true);
954
      }
955
      if (notIte.isConst() && (ite[1].isConst() || ite[2].isConst()))
956
      {
957
        ++(d_statistics.d_exactMatchFold);
958
        return ite[0].iteNode(notIte.eqNode(ite[1]), notIte.eqNode(ite[2]));
959
      }
960
    }
961
  }
962
963
  // try a similar more relaxed version for non-equality operators
964
  if (atom.getMetaKind() == kind::metakind::OPERATOR
965
      && atom.getNumChildren() == 2 && !atom[1].getType().isBoolean())
966
  {
967
    TNode left = atom[0];
968
    TNode right = atom[1];
969
    if ((left.getKind() == kind::ITE || right.getKind() == kind::ITE)
970
        && !(left.getKind() == kind::ITE && right.getKind() == kind::ITE))
971
    {
972
      // exactly 1 is an ite
973
      bool leftIsIte = left.getKind() == kind::ITE;
974
      Node ite = leftIsIte ? left : right;
975
      Node notIte = leftIsIte ? right : left;
976
977
      if (notIte.isConst())
978
      {
979
        IteTreeSearchData search;
980
        search.maxNonconstants = 2;
981
        iteTreeSearch(ite, 0, search);
982
        if (!search.failure)
983
        {
984
          d_statistics.d_maxNonConstantsFolded.maxAssign(
985
              search.nonConstants.size());
986
          Debug("ite::simpite") << "used " << search.nonConstants.size()
987
                                << " nonconstants" << endl;
988
          NodeManager* nm = NodeManager::currentNM();
989
          Node simpVar = getSimpVar(notIte.getType());
990
          TNode newLeft = leftIsIte ? simpVar : notIte;
991
          TNode newRight = leftIsIte ? notIte : simpVar;
992
          Node newAtom = nm->mkNode(atom.getKind(), newLeft, newRight);
993
994
          ++(d_statistics.d_binaryPredFold);
995
          return replaceOverTermIte(ite, newAtom, simpVar);
996
        }
997
      }
998
    }
999
  }
1000
1001
  // TODO "This is way too tailored. Must generalize!"
1002
  if (atom.getKind() == kind::EQUAL && atom.getNumChildren() == 2
1003
      && ite::isTermITE(atom[0]) && atom[1].getKind() == kind::MULT
1004
      && atom[1].getNumChildren() == 2 && atom[1][0].isConst()
1005
      && atom[1][0].getConst<Rational>().isNegativeOne()
1006
      && ite::isTermITE(atom[1][1])
1007
      && d_termITEHeight.termITEHeight(atom[0]) == 1
1008
      && d_termITEHeight.termITEHeight(atom[1][1]) == 1
1009
      && (atom[0][1].isConst() || atom[0][2].isConst())
1010
      && (atom[1][1][1].isConst() || atom[1][1][2].isConst()))
1011
  {
1012
    // expand all 4 cases
1013
1014
    Node negOne = atom[1][0];
1015
1016
    Node lite = atom[0];
1017
    Node lC = lite[0];
1018
    Node lT = lite[1];
1019
    Node lE = lite[2];
1020
1021
    NodeManager* nm = NodeManager::currentNM();
1022
    Node negRite = atom[1][1];
1023
    Node rC = negRite[0];
1024
    Node rT = nm->mkNode(kind::MULT, negOne, negRite[1]);
1025
    Node rE = nm->mkNode(kind::MULT, negOne, negRite[2]);
1026
1027
    // (ite lC lT lE) = (ite rC rT rE)
1028
    // (ite lc (= lT (ite rC rT rE) (= lE (ite rC rT rE))))
1029
    // (ite lc (ite rC (= lT rT) (= lT rE))
1030
    //         (ite rC (= lE rT) (= lE rE)))
1031
1032
    Node eqTT = lT.eqNode(rT);
1033
    Node eqTE = lT.eqNode(rE);
1034
    Node eqET = lE.eqNode(rT);
1035
    Node eqEE = lE.eqNode(rE);
1036
    Node thenLC = rC.iteNode(eqTT, eqTE);
1037
    Node elseLC = rC.iteNode(eqET, eqEE);
1038
    Node newIte = lC.iteNode(thenLC, elseLC);
1039
1040
    ++(d_statistics.d_specialEqualityFolds);
1041
    return newIte;
1042
  }
1043
  return Node::null();
1044
}
1045
1046
// Interesting classes of atoms:
1047
// 2. Contains constants and 1 constant term ite
1048
// 3. Contains 2 constant term ites
1049
729
Node ITESimplifier::transformAtom(TNode atom)
1050
{
1051
729
  if (!d_containsVisitor->containsTermITE(atom))
1052
  {
1053
    if (atom.getKind() == kind::EQUAL && atom[0].isConst() && atom[1].isConst())
1054
    {
1055
      // constant equality
1056
      return NodeManager::currentNM()->mkConst<bool>(atom[0] == atom[1]);
1057
    }
1058
    return Node::null();
1059
  }
1060
  else
1061
  {
1062
1458
    Node acr = attemptConstantRemoval(atom);
1063
729
    if (!acr.isNull())
1064
    {
1065
573
      return acr;
1066
    }
1067
    // Node ale = attemptLiftEquality(atom);
1068
    // if(!ale.isNull()){
1069
    //   //return ale;
1070
    // }
1071
156
    return Node::null();
1072
  }
1073
}
1074
1075
static unsigned numBranches = 0;
1076
static unsigned numFalseBranches = 0;
1077
static unsigned itesMade = 0;
1078
1079
67339
Node ITESimplifier::constantIteEqualsConstant(TNode cite, TNode constant)
1080
{
1081
  static int instance = 0;
1082
67339
  ++instance;
1083
134678
  Debug("ite::constantIteEqualsConstant")
1084
67339
      << instance << "constantIteEqualsConstant(" << cite << ", " << constant
1085
67339
      << ")" << endl;
1086
67339
  if (cite.isConst())
1087
  {
1088
45678
    Node res = (cite == constant) ? d_true : d_false;
1089
22839
    Debug("ite::constantIteEqualsConstant") << instance << "->" << res << endl;
1090
22839
    return res;
1091
  }
1092
89000
  std::pair<Node, Node> pair = make_pair(cite, constant);
1093
1094
  NodePairMap::const_iterator eq_pos =
1095
44500
      d_constantIteEqualsConstantCache.find(pair);
1096
44500
  if (eq_pos != d_constantIteEqualsConstantCache.end())
1097
  {
1098
5334
    Debug("ite::constantIteEqualsConstant")
1099
2667
        << instance << "->" << (*eq_pos).second << endl;
1100
2667
    return (*eq_pos).second;
1101
  }
1102
1103
41833
  ++d_citeEqConstApplications;
1104
1105
41833
  NodeVec* leaves = computeConstantLeaves(cite);
1106
41833
  Assert(leaves != NULL);
1107
41833
  if (std::binary_search(leaves->begin(), leaves->end(), constant))
1108
  {
1109
33383
    if (leaves->size() == 1)
1110
    {
1111
      // probably unreachable
1112
      d_constantIteEqualsConstantCache[pair] = d_true;
1113
      Debug("ite::constantIteEqualsConstant")
1114
          << instance << "->" << d_true << endl;
1115
      return d_true;
1116
    }
1117
    else
1118
    {
1119
33383
      Assert(cite.getKind() == kind::ITE);
1120
66766
      TNode cnd = cite[0];
1121
66766
      TNode tB = cite[1];
1122
66766
      TNode fB = cite[2];
1123
66766
      Node tEqs = constantIteEqualsConstant(tB, constant);
1124
66766
      Node fEqs = constantIteEqualsConstant(fB, constant);
1125
66766
      Node boolIte = cnd.iteNode(tEqs, fEqs);
1126
33383
      if (!(tEqs.isConst() || fEqs.isConst()))
1127
      {
1128
1924
        ++numBranches;
1129
      }
1130
33383
      if (!(tEqs == d_false || fEqs == d_false))
1131
      {
1132
2211
        ++numFalseBranches;
1133
      }
1134
33383
      ++itesMade;
1135
33383
      d_constantIteEqualsConstantCache[pair] = boolIte;
1136
      // Debug("ite::constantIteEqualsConstant") << instance << "->" << boolIte
1137
      // << endl;
1138
33383
      return boolIte;
1139
    }
1140
  }
1141
  else
1142
  {
1143
8450
    d_constantIteEqualsConstantCache[pair] = d_false;
1144
16900
    Debug("ite::constantIteEqualsConstant")
1145
8450
        << instance << "->" << d_false << endl;
1146
8450
    return d_false;
1147
  }
1148
}
1149
1150
573
Node ITESimplifier::intersectConstantIte(TNode lcite, TNode rcite)
1151
{
1152
  // intersect the constant ite trees lcite and rcite
1153
1154
573
  if (lcite.isConst() || rcite.isConst())
1155
  {
1156
573
    bool lIsConst = lcite.isConst();
1157
1146
    TNode constant = lIsConst ? lcite : rcite;
1158
1146
    TNode cite = lIsConst ? rcite : lcite;
1159
1160
573
    (d_statistics.d_inSmaller) << 1;
1161
573
    unsigned preItesMade = itesMade;
1162
573
    unsigned preNumBranches = numBranches;
1163
573
    unsigned preNumFalseBranches = numFalseBranches;
1164
1146
    Node bterm = constantIteEqualsConstant(cite, constant);
1165
1146
    Debug("intersectConstantIte") << (numBranches - preNumBranches) << " "
1166
1146
                                  << (numFalseBranches - preNumFalseBranches)
1167
573
                                  << " " << (itesMade - preItesMade) << endl;
1168
573
    return bterm;
1169
  }
1170
  Assert(lcite.getKind() == kind::ITE);
1171
  Assert(rcite.getKind() == kind::ITE);
1172
1173
  NodeVec* leftValues = computeConstantLeaves(lcite);
1174
  NodeVec* rightValues = computeConstantLeaves(rcite);
1175
1176
  uint32_t smaller = std::min(leftValues->size(), rightValues->size());
1177
1178
  (d_statistics.d_inSmaller) << smaller;
1179
  NodeVec intersection(smaller, Node::null());
1180
  NodeVec::iterator newEnd;
1181
  newEnd = std::set_intersection(leftValues->begin(),
1182
                                 leftValues->end(),
1183
                                 rightValues->begin(),
1184
                                 rightValues->end(),
1185
                                 intersection.begin());
1186
  intersection.resize(newEnd - intersection.begin());
1187
  if (intersection.empty())
1188
  {
1189
    return d_false;
1190
  }
1191
  else
1192
  {
1193
    NodeBuilder nb(kind::OR);
1194
    NodeVec::const_iterator it = intersection.begin(), end = intersection.end();
1195
    for (; it != end; ++it)
1196
    {
1197
      Node inBoth = *it;
1198
      Node lefteq = constantIteEqualsConstant(lcite, inBoth);
1199
      Node righteq = constantIteEqualsConstant(rcite, inBoth);
1200
      Node bothHold = lefteq.andNode(righteq);
1201
      nb << bothHold;
1202
    }
1203
    Node result = (nb.getNumChildren() > 1) ? (Node)nb : nb[0];
1204
    return result;
1205
  }
1206
}
1207
1208
Node ITESimplifier::attemptEagerRemoval(TNode atom)
1209
{
1210
  if (atom.getKind() == kind::EQUAL)
1211
  {
1212
    TNode left = atom[0];
1213
    TNode right = atom[1];
1214
    if ((left.isConst() && right.getKind() == kind::ITE && isConstantIte(right))
1215
        || (right.isConst() && left.getKind() == kind::ITE
1216
            && isConstantIte(left)))
1217
    {
1218
      TNode constant = left.isConst() ? left : right;
1219
      TNode cite = left.isConst() ? right : left;
1220
1221
      std::pair<Node, Node> pair = make_pair(cite, constant);
1222
      NodePairMap::const_iterator eq_pos =
1223
          d_constantIteEqualsConstantCache.find(pair);
1224
      if (eq_pos != d_constantIteEqualsConstantCache.end())
1225
      {
1226
        Node ret = (*eq_pos).second;
1227
        if (ret.isConst())
1228
        {
1229
          return ret;
1230
        }
1231
        else
1232
        {
1233
          return Node::null();
1234
        }
1235
      }
1236
1237
      NodeVec* leaves = computeConstantLeaves(cite);
1238
      Assert(leaves != NULL);
1239
      if (!std::binary_search(leaves->begin(), leaves->end(), constant))
1240
      {
1241
        d_constantIteEqualsConstantCache[pair] = d_false;
1242
        return d_false;
1243
      }
1244
    }
1245
  }
1246
  return Node::null();
1247
}
1248
1249
729
Node ITESimplifier::attemptConstantRemoval(TNode atom)
1250
{
1251
729
  if (atom.getKind() == kind::EQUAL)
1252
  {
1253
787
    TNode left = atom[0];
1254
787
    TNode right = atom[1];
1255
680
    if (isConstantIte(left) && isConstantIte(right))
1256
    {
1257
573
      return intersectConstantIte(left, right);
1258
    }
1259
  }
1260
156
  return Node::null();
1261
}
1262
1263
550
bool ITESimplifier::leavesAreConst(TNode e, theory::TheoryId tid)
1264
{
1265
550
  Assert((e.getKind() == kind::ITE && !e.getType().isBoolean())
1266
         || theory::Theory::theoryOf(e) != theory::THEORY_BOOL);
1267
550
  if (e.isConst())
1268
  {
1269
27
    return true;
1270
  }
1271
1272
523
  unordered_map<Node, bool>::iterator it;
1273
523
  it = d_leavesConstCache.find(e);
1274
523
  if (it != d_leavesConstCache.end())
1275
  {
1276
122
    return (*it).second;
1277
  }
1278
1279
401
  if (!containsTermITE(e) && theory::Theory::isLeafOf(e, tid))
1280
  {
1281
34
    d_leavesConstCache[e] = false;
1282
34
    return false;
1283
  }
1284
1285
367
  Assert(e.getNumChildren() > 0);
1286
367
  size_t k = 0, sz = e.getNumChildren();
1287
1288
367
  if (e.getKind() == kind::ITE)
1289
  {
1290
161
    k = 1;
1291
  }
1292
1293
421
  for (; k < sz; ++k)
1294
  {
1295
394
    if (!leavesAreConst(e[k], tid))
1296
    {
1297
367
      d_leavesConstCache[e] = false;
1298
367
      return false;
1299
    }
1300
  }
1301
  d_leavesConstCache[e] = true;
1302
  return true;
1303
}
1304
1305
Node ITESimplifier::simpConstants(TNode simpContext,
1306
                                  TNode iteNode,
1307
                                  TNode simpVar)
1308
{
1309
  NodePairMap::iterator it;
1310
  it = d_simpConstCache.find(pair<Node, Node>(simpContext, iteNode));
1311
  if (it != d_simpConstCache.end())
1312
  {
1313
    return (*it).second;
1314
  }
1315
1316
  if (iteNode.getKind() == kind::ITE)
1317
  {
1318
    NodeBuilder builder(kind::ITE);
1319
    builder << iteNode[0];
1320
    unsigned i = 1;
1321
    for (; i < iteNode.getNumChildren(); ++i)
1322
    {
1323
      Node n = simpConstants(simpContext, iteNode[i], simpVar);
1324
      if (n.isNull())
1325
      {
1326
        return n;
1327
      }
1328
      builder << n;
1329
    }
1330
    // Mark the substitution and continue
1331
    Node result = builder;
1332
    result = rewrite(result);
1333
    d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = result;
1334
    return result;
1335
  }
1336
1337
  if (!containsTermITE(iteNode))
1338
  {
1339
    Node n = rewrite(simpContext.substitute(simpVar, iteNode));
1340
    d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = n;
1341
    return n;
1342
  }
1343
1344
  Node iteNode2;
1345
  Node simpVar2;
1346
  d_simpContextCache.clear();
1347
  Node simpContext2 = createSimpContext(iteNode, iteNode2, simpVar2);
1348
  if (!simpContext2.isNull())
1349
  {
1350
    Assert(!iteNode2.isNull());
1351
    simpContext2 = simpContext.substitute(simpVar, simpContext2);
1352
    Node n = simpConstants(simpContext2, iteNode2, simpVar2);
1353
    if (n.isNull())
1354
    {
1355
      return n;
1356
    }
1357
    d_simpConstCache[pair<Node, Node>(simpContext, iteNode)] = n;
1358
    return n;
1359
  }
1360
  return Node();
1361
}
1362
1363
Node ITESimplifier::getSimpVar(TypeNode t)
1364
{
1365
  std::unordered_map<TypeNode, Node>::iterator it;
1366
  it = d_simpVars.find(t);
1367
  if (it != d_simpVars.end())
1368
  {
1369
    return (*it).second;
1370
  }
1371
  SkolemManager* sm = NodeManager::currentNM()->getSkolemManager();
1372
  Node var = sm->mkDummySkolem(
1373
      "iteSimp", t, "is a variable resulting from ITE simplification");
1374
  d_simpVars[t] = var;
1375
  return var;
1376
}
1377
1378
Node ITESimplifier::createSimpContext(TNode c, Node& iteNode, Node& simpVar)
1379
{
1380
  NodeMap::iterator it;
1381
  it = d_simpContextCache.find(c);
1382
  if (it != d_simpContextCache.end())
1383
  {
1384
    return (*it).second;
1385
  }
1386
1387
  if (!containsTermITE(c))
1388
  {
1389
    d_simpContextCache[c] = c;
1390
    return c;
1391
  }
1392
1393
  if (c.getKind() == kind::ITE && !c.getType().isBoolean())
1394
  {
1395
    // Currently only support one ite node in a simp context
1396
    // Return Null if more than one is found
1397
    if (!iteNode.isNull())
1398
    {
1399
      return Node();
1400
    }
1401
    simpVar = getSimpVar(c.getType());
1402
    if (simpVar.isNull())
1403
    {
1404
      return Node();
1405
    }
1406
    d_simpContextCache[c] = simpVar;
1407
    iteNode = c;
1408
    return simpVar;
1409
  }
1410
1411
  NodeBuilder builder(c.getKind());
1412
  if (c.getMetaKind() == kind::metakind::PARAMETERIZED)
1413
  {
1414
    builder << c.getOperator();
1415
  }
1416
  unsigned i = 0;
1417
  for (; i < c.getNumChildren(); ++i)
1418
  {
1419
    Node newChild = createSimpContext(c[i], iteNode, simpVar);
1420
    if (newChild.isNull())
1421
    {
1422
      return newChild;
1423
    }
1424
    builder << newChild;
1425
  }
1426
  // Mark the substitution and continue
1427
  Node result = builder;
1428
  d_simpContextCache[c] = result;
1429
  return result;
1430
}
1431
typedef std::unordered_set<Node> NodeSet;
1432
40741410
void countReachable_(Node x, Kind k, NodeSet& visited, uint32_t& reached)
1433
{
1434
40741410
  if (visited.find(x) != visited.end())
1435
  {
1436
37305643
    return;
1437
  }
1438
3435767
  visited.insert(x);
1439
3435767
  if (x.getKind() == k)
1440
  {
1441
1086180
    ++reached;
1442
  }
1443
44176031
  for (unsigned i = 0, N = x.getNumChildren(); i < N; ++i)
1444
  {
1445
40740264
    countReachable_(x[i], k, visited, reached);
1446
  }
1447
}
1448
1449
1146
uint32_t countReachable(TNode x, Kind k)
1450
{
1451
2292
  NodeSet visited;
1452
1146
  uint32_t reached = 0;
1453
1146
  countReachable_(x, k, visited, reached);
1454
2292
  return reached;
1455
}
1456
1457
729
Node ITESimplifier::simpITEAtom(TNode atom)
1458
{
1459
  static int CVC5_UNUSED instance = 0;
1460
729
  Debug("ite::atom") << "still simplifying " << (++instance) << endl;
1461
1458
  Node attempt = transformAtom(atom);
1462
729
  Debug("ite::atom") << "  finished " << instance << endl;
1463
729
  if (!attempt.isNull())
1464
  {
1465
1146
    Node rewritten = rewrite(attempt);
1466
1146
    Debug("ite::print-success")
1467
573
        << instance << " "
1468
1146
        << "rewriting " << countReachable(rewritten, kind::ITE) << " from "
1469
1146
        << countReachable(atom, kind::ITE) << endl
1470
573
        << "\t rewritten " << rewritten << endl
1471
573
        << "\t input " << atom << endl;
1472
573
    return rewritten;
1473
  }
1474
1475
156
  if (leavesAreConst(atom))
1476
  {
1477
    Node iteNode;
1478
    Node simpVar;
1479
    d_simpContextCache.clear();
1480
    Node simpContext = createSimpContext(atom, iteNode, simpVar);
1481
    if (!simpContext.isNull())
1482
    {
1483
      if (iteNode.isNull())
1484
      {
1485
        Assert(leavesAreConst(simpContext) && !containsTermITE(simpContext));
1486
        ++(d_statistics.d_unexpected);
1487
        Debug("ite::simpite") << instance << " "
1488
                              << "how about?" << atom << endl;
1489
        Debug("ite::simpite") << instance << " "
1490
                              << "\t" << simpContext << endl;
1491
        return rewrite(simpContext);
1492
      }
1493
      Node n = simpConstants(simpContext, iteNode, simpVar);
1494
      if (!n.isNull())
1495
      {
1496
        ++(d_statistics.d_unexpected);
1497
        Debug("ite::simpite") << instance << " "
1498
                              << "here?" << atom << endl;
1499
        Debug("ite::simpite") << instance << " "
1500
                              << "\t" << n << endl;
1501
        return n;
1502
      }
1503
    }
1504
  }
1505
156
  if (Debug.isOn("ite::simpite"))
1506
  {
1507
    if (countReachable(atom, kind::ITE) > 0)
1508
    {
1509
      Debug("ite::simpite") << instance << " "
1510
                            << "remaining " << atom << endl;
1511
    }
1512
  }
1513
156
  ++(d_statistics.d_unsimplified);
1514
156
  return atom;
1515
}
1516
1517
11456
struct preprocess_stack_element
1518
{
1519
  TNode d_node;
1520
  bool d_children_added;
1521
2454
  preprocess_stack_element(TNode node) : d_node(node), d_children_added(false)
1522
  {
1523
2454
  }
1524
}; /* struct preprocess_stack_element */
1525
1526
1
Node ITESimplifier::simpITE(TNode assertion)
1527
{
1528
  // Do a topological sort of the subexpressions and substitute them
1529
2
  vector<preprocess_stack_element> toVisit;
1530
1
  toVisit.push_back(assertion);
1531
1532
  static int call = 0;
1533
1
  ++call;
1534
1
  int iteration = 0;
1535
1536
8745
  while (!toVisit.empty())
1537
  {
1538
4372
    iteration++;
1539
    // cout << "call  " << call << " : " << iteration << endl;
1540
    // The current node we are processing
1541
4372
    preprocess_stack_element& stackHead = toVisit.back();
1542
8208
    TNode current = stackHead.d_node;
1543
1544
    // If node has no ITE's or already in the cache we're done, pop from the
1545
    // stack
1546
9269
    if (current.getNumChildren() == 0
1547
13641
        || (theory::Theory::theoryOf(current) != theory::THEORY_BOOL
1548
6014
            && !containsTermITE(current)))
1549
    {
1550
525
      d_simpITECache[current] = current;
1551
525
      ++(d_statistics.d_simpITEVisits);
1552
525
      toVisit.pop_back();
1553
525
      continue;
1554
    }
1555
1556
3847
    NodeMap::iterator find = d_simpITECache.find(current);
1557
3858
    if (find != d_simpITECache.end())
1558
    {
1559
11
      toVisit.pop_back();
1560
11
      continue;
1561
    }
1562
1563
    // Not yet substituted, so process
1564
3836
    if (stackHead.d_children_added)
1565
    {
1566
      // Children have been processed, so substitute
1567
3836
      NodeBuilder builder(current.getKind());
1568
1918
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
1569
      {
1570
        builder << current.getOperator();
1571
      }
1572
6869
      for (unsigned i = 0; i < current.getNumChildren(); ++i)
1573
      {
1574
4951
        Assert(d_simpITECache.find(current[i]) != d_simpITECache.end());
1575
9902
        Node child = current[i];
1576
9902
        Node childRes = d_simpITECache[current[i]];
1577
4951
        builder << childRes;
1578
      }
1579
      // Mark the substitution and continue
1580
3836
      Node result = builder;
1581
1582
      // If this is an atom, we process it
1583
5754
      if (theory::Theory::theoryOf(result) != theory::THEORY_BOOL
1584
5754
          && result.getType().isBoolean())
1585
      {
1586
729
        result = simpITEAtom(result);
1587
      }
1588
1589
      // if(current != result && result.isConst()){
1590
      //   static int instance = 0;
1591
      //   //cout << instance << " " << result << current << endl;
1592
      // }
1593
1594
1918
      result = rewrite(result);
1595
1918
      d_simpITECache[current] = result;
1596
1918
      ++(d_statistics.d_simpITEVisits);
1597
1918
      toVisit.pop_back();
1598
    }
1599
    else
1600
    {
1601
      // Mark that we have added the children if any
1602
1918
      if (current.getNumChildren() > 0)
1603
      {
1604
1918
        stackHead.d_children_added = true;
1605
        // We need to add the children
1606
6869
        for (TNode::iterator child_it = current.begin();
1607
6869
             child_it != current.end();
1608
             ++child_it)
1609
        {
1610
9902
          TNode childNode = *child_it;
1611
4951
          NodeMap::iterator childFind = d_simpITECache.find(childNode);
1612
4951
          if (childFind == d_simpITECache.end())
1613
          {
1614
2453
            toVisit.push_back(childNode);
1615
          }
1616
        }
1617
      }
1618
      else
1619
      {
1620
        // No children, so we're done
1621
        d_simpITECache[current] = current;
1622
        ++(d_statistics.d_simpITEVisits);
1623
        toVisit.pop_back();
1624
      }
1625
    }
1626
  }
1627
2
  return d_simpITECache[assertion];
1628
}
1629
1630
ITECareSimplifier::ITECareSimplifier() : d_careSetsOutstanding(0), d_usedSets()
1631
{
1632
  d_true = NodeManager::currentNM()->mkConst<bool>(true);
1633
  d_false = NodeManager::currentNM()->mkConst<bool>(false);
1634
}
1635
1636
ITECareSimplifier::~ITECareSimplifier()
1637
{
1638
  Assert(d_usedSets.empty());
1639
  Assert(d_careSetsOutstanding == 0);
1640
}
1641
1642
void ITECareSimplifier::clear()
1643
{
1644
  Assert(d_usedSets.empty());
1645
  Assert(d_careSetsOutstanding == 0);
1646
}
1647
1648
ITECareSimplifier::CareSetPtr ITECareSimplifier::getNewSet()
1649
{
1650
  if (d_usedSets.empty())
1651
  {
1652
    d_careSetsOutstanding++;
1653
    return ITECareSimplifier::CareSetPtr::mkNew(*this);
1654
  }
1655
  else
1656
  {
1657
    ITECareSimplifier::CareSetPtr cs =
1658
        ITECareSimplifier::CareSetPtr::recycle(d_usedSets.back());
1659
    cs.getCareSet().clear();
1660
    d_usedSets.pop_back();
1661
    return cs;
1662
  }
1663
}
1664
1665
void ITECareSimplifier::updateQueue(CareMap& queue,
1666
                                    TNode e,
1667
                                    ITECareSimplifier::CareSetPtr& careSet)
1668
{
1669
  CareMap::iterator it = queue.find(e), iend = queue.end();
1670
  if (it != iend)
1671
  {
1672
    set<Node>& cs2 = (*it).second.getCareSet();
1673
    ITECareSimplifier::CareSetPtr csNew = getNewSet();
1674
    set_intersection(careSet.getCareSet().begin(),
1675
                     careSet.getCareSet().end(),
1676
                     cs2.begin(),
1677
                     cs2.end(),
1678
                     inserter(csNew.getCareSet(), csNew.getCareSet().begin()));
1679
    (*it).second = csNew;
1680
  }
1681
  else
1682
  {
1683
    queue[e] = careSet;
1684
  }
1685
}
1686
1687
Node ITECareSimplifier::substitute(TNode e,
1688
                                   TNodeMap& substTable,
1689
                                   TNodeMap& cache)
1690
{
1691
  TNodeMap::iterator it = cache.find(e), iend = cache.end();
1692
  if (it != iend)
1693
  {
1694
    return it->second;
1695
  }
1696
1697
  // do substitution?
1698
  it = substTable.find(e);
1699
  iend = substTable.end();
1700
  if (it != iend)
1701
  {
1702
    Node result = substitute(it->second, substTable, cache);
1703
    cache[e] = result;
1704
    return result;
1705
  }
1706
1707
  size_t sz = e.getNumChildren();
1708
  if (sz == 0)
1709
  {
1710
    cache[e] = e;
1711
    return e;
1712
  }
1713
1714
  NodeBuilder builder(e.getKind());
1715
  if (e.getMetaKind() == kind::metakind::PARAMETERIZED)
1716
  {
1717
    builder << e.getOperator();
1718
  }
1719
  for (unsigned i = 0; i < e.getNumChildren(); ++i)
1720
  {
1721
    builder << substitute(e[i], substTable, cache);
1722
  }
1723
1724
  Node result = builder;
1725
  // it = substTable.find(result);
1726
  // if (it != iend) {
1727
  //   result = substitute(it->second, substTable, cache);
1728
  // }
1729
  cache[e] = result;
1730
  return result;
1731
}
1732
1733
Node ITECareSimplifier::simplifyWithCare(TNode e)
1734
{
1735
  TNodeMap substTable;
1736
1737
  /* This extra block is to trigger the destructors for cs and cs2
1738
   * before starting garbage collection.
1739
   */
1740
  {
1741
    CareMap queue;
1742
    CareMap::iterator it;
1743
    ITECareSimplifier::CareSetPtr cs = getNewSet();
1744
    ITECareSimplifier::CareSetPtr cs2;
1745
    queue[e] = cs;
1746
1747
    TNode v;
1748
    bool done;
1749
    unsigned i;
1750
1751
    while (!queue.empty())
1752
    {
1753
      it = queue.end();
1754
      --it;
1755
      v = it->first;
1756
      cs = it->second;
1757
      set<Node>& css = cs.getCareSet();
1758
      queue.erase(v);
1759
1760
      done = false;
1761
      set<Node>::iterator iCare, iCareEnd = css.end();
1762
1763
      switch (v.getKind())
1764
      {
1765
        case kind::ITE:
1766
        {
1767
          iCare = css.find(v[0]);
1768
          if (iCare != iCareEnd)
1769
          {
1770
            Assert(substTable.find(v) == substTable.end());
1771
            substTable[v] = v[1];
1772
            updateQueue(queue, v[1], cs);
1773
            done = true;
1774
            break;
1775
          }
1776
          else
1777
          {
1778
            iCare = css.find(v[0].negate());
1779
            if (iCare != iCareEnd)
1780
            {
1781
              Assert(substTable.find(v) == substTable.end());
1782
              substTable[v] = v[2];
1783
              updateQueue(queue, v[2], cs);
1784
              done = true;
1785
              break;
1786
            }
1787
          }
1788
          updateQueue(queue, v[0], cs);
1789
          cs2 = getNewSet();
1790
          cs2.getCareSet() = css;
1791
          cs2.getCareSet().insert(v[0]);
1792
          updateQueue(queue, v[1], cs2);
1793
          cs2 = getNewSet();
1794
          cs2.getCareSet() = css;
1795
          cs2.getCareSet().insert(v[0].negate());
1796
          updateQueue(queue, v[2], cs2);
1797
          done = true;
1798
          break;
1799
        }
1800
        case kind::AND:
1801
        {
1802
          for (i = 0; i < v.getNumChildren(); ++i)
1803
          {
1804
            iCare = css.find(v[i].negate());
1805
            if (iCare != iCareEnd)
1806
            {
1807
              Assert(substTable.find(v) == substTable.end());
1808
              substTable[v] = d_false;
1809
              done = true;
1810
              break;
1811
            }
1812
          }
1813
          if (done) break;
1814
1815
          Assert(v.getNumChildren() > 1);
1816
          updateQueue(queue, v[0], cs);
1817
          cs2 = getNewSet();
1818
          cs2.getCareSet() = css;
1819
          cs2.getCareSet().insert(v[0]);
1820
          for (i = 1; i < v.getNumChildren(); ++i)
1821
          {
1822
            updateQueue(queue, v[i], cs2);
1823
          }
1824
          done = true;
1825
          break;
1826
        }
1827
        case kind::OR:
1828
        {
1829
          for (i = 0; i < v.getNumChildren(); ++i)
1830
          {
1831
            iCare = css.find(v[i]);
1832
            if (iCare != iCareEnd)
1833
            {
1834
              Assert(substTable.find(v) == substTable.end());
1835
              substTable[v] = d_true;
1836
              done = true;
1837
              break;
1838
            }
1839
          }
1840
          if (done) break;
1841
1842
          Assert(v.getNumChildren() > 1);
1843
          updateQueue(queue, v[0], cs);
1844
          cs2 = getNewSet();
1845
          cs2.getCareSet() = css;
1846
          cs2.getCareSet().insert(v[0].negate());
1847
          for (i = 1; i < v.getNumChildren(); ++i)
1848
          {
1849
            updateQueue(queue, v[i], cs2);
1850
          }
1851
          done = true;
1852
          break;
1853
        }
1854
        default: break;
1855
      }
1856
1857
      if (done)
1858
      {
1859
        continue;
1860
      }
1861
1862
      for (i = 0; i < v.getNumChildren(); ++i)
1863
      {
1864
        updateQueue(queue, v[i], cs);
1865
      }
1866
    }
1867
  }
1868
  /* Perform garbage collection. */
1869
  while (!d_usedSets.empty())
1870
  {
1871
    CareSetPtrVal* used = d_usedSets.back();
1872
    d_usedSets.pop_back();
1873
    Assert(used->safeToGarbageCollect());
1874
    delete used;
1875
    Assert(d_careSetsOutstanding > 0);
1876
    d_careSetsOutstanding--;
1877
  }
1878
1879
  TNodeMap cache;
1880
  return substitute(e, substTable, cache);
1881
}
1882
1883
ITECareSimplifier::CareSetPtr ITECareSimplifier::CareSetPtr::mkNew(
1884
    ITECareSimplifier& simp)
1885
{
1886
  CareSetPtrVal* val = new CareSetPtrVal(simp);
1887
  return CareSetPtr(val);
1888
}
1889
1890
}  // namespace util
1891
}  // namespace preprocessing
1892
29502
}  // namespace cvc5