GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/util/ite_utilities.cpp Lines: 458 986 46.5 %
Date: 2021-05-22 Branches: 780 3689 21.1 %

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