GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/unconstrained_simplifier.cpp Lines: 336 403 83.4 %
Date: 2021-05-22 Branches: 724 1719 42.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Clark Barrett, Andres Noetzli, Andrew Reynolds
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 based on unconstrained variables.
14
 *
15
 * This module implements a preprocessing phase which replaces certain
16
 * "unconstrained" expressions by variables.  Based on Roberto
17
 * Bruttomesso's PhD thesis.
18
 */
19
20
#include "preprocessing/passes/unconstrained_simplifier.h"
21
22
#include "expr/dtype.h"
23
#include "expr/skolem_manager.h"
24
#include "preprocessing/assertion_pipeline.h"
25
#include "preprocessing/preprocessing_pass_context.h"
26
#include "smt/logic_exception.h"
27
#include "smt/smt_statistics_registry.h"
28
#include "theory/logic_info.h"
29
#include "theory/rewriter.h"
30
31
namespace cvc5 {
32
namespace preprocessing {
33
namespace passes {
34
35
using namespace std;
36
using namespace cvc5::theory;
37
38
9459
UnconstrainedSimplifier::UnconstrainedSimplifier(
39
9459
    PreprocessingPassContext* preprocContext)
40
    : PreprocessingPass(preprocContext, "unconstrained-simplifier"),
41
9459
      d_numUnconstrainedElim(smtStatisticsRegistry().registerInt(
42
18918
          "preprocessor::number of unconstrained elims")),
43
9459
      d_context(preprocContext->getDecisionContext()),
44
37836
      d_substitutions(preprocContext->getDecisionContext())
45
{
46
9459
}
47
48
448793
struct unc_preprocess_stack_element
49
{
50
  TNode node;
51
  TNode parent;
52
1242
  unc_preprocess_stack_element(TNode n) : node(n) {}
53
129245
  unc_preprocess_stack_element(TNode n, TNode p) : node(n), parent(p) {}
54
}; /* struct unc_preprocess_stack_element */
55
56
1242
void UnconstrainedSimplifier::visitAll(TNode assertion)
57
{
58
  // Do a topological sort of the subexpressions and substitute them
59
2484
  vector<unc_preprocess_stack_element> toVisit;
60
1242
  toVisit.push_back(assertion);
61
62
262216
  while (!toVisit.empty())
63
  {
64
    // The current node we are processing
65
172461
    TNode current = toVisit.back().node;
66
172461
    TNode parent = toVisit.back().parent;
67
130487
    toVisit.pop_back();
68
69
130487
    TNodeCountMap::iterator find = d_visited.find(current);
70
130487
    if (find != d_visited.end())
71
    {
72
88513
      if (find->second == 1)
73
      {
74
11613
        d_visitedOnce.erase(current);
75
11613
        if (current.isVar())
76
        {
77
3170
          d_unconstrained.erase(current);
78
        }
79
        else
80
        {
81
          // Also erase the children from the visited-once set when we visit a
82
          // node a second time, otherwise variables in this node are not
83
          // erased from the set of unconstrained variables.
84
20223
          for (TNode childNode : current)
85
          {
86
11780
            toVisit.push_back(unc_preprocess_stack_element(childNode, current));
87
          }
88
        }
89
      }
90
88513
      ++find->second;
91
88513
      continue;
92
    }
93
94
41974
    d_visited[current] = 1;
95
41974
    d_visitedOnce[current] = parent;
96
97
41974
    if (current.getNumChildren() == 0)
98
    {
99
14962
      if (current.getKind() == kind::VARIABLE
100
7481
          || current.getKind() == kind::SKOLEM)
101
      {
102
4386
        d_unconstrained.insert(current);
103
      }
104
    }
105
34493
    else if (current.isClosure())
106
    {
107
      // Throw an exception. This should never happen in practice unless the
108
      // user specifically enabled unconstrained simplification in an illegal
109
      // logic.
110
      throw LogicException(
111
          "Cannot use unconstrained simplification in this logic, due to "
112
          "(possibly internally introduced) quantified formula.");
113
    }
114
    else
115
    {
116
151958
      for (TNode childNode : current)
117
      {
118
117465
        toVisit.push_back(unc_preprocess_stack_element(childNode, current));
119
      }
120
    }
121
  }
122
1242
}
123
124
265
Node UnconstrainedSimplifier::newUnconstrainedVar(TypeNode t, TNode var)
125
{
126
265
  SkolemManager* sm = NodeManager::currentNM()->getSkolemManager();
127
  Node n = sm->mkDummySkolem(
128
      "unconstrained",
129
      t,
130
      "a new var introduced because of unconstrained variable "
131
265
          + var.toString());
132
265
  return n;
133
}
134
135
167
void UnconstrainedSimplifier::processUnconstrained()
136
{
137
167
  NodeManager* nm = NodeManager::currentNM();
138
139
334
  vector<TNode> workList(d_unconstrained.begin(), d_unconstrained.end());
140
334
  Node currentSub;
141
334
  TNode parent;
142
  bool swap;
143
  bool isSigned;
144
  bool strict;
145
334
  vector<TNode> delayQueueLeft;
146
334
  vector<Node> delayQueueRight;
147
148
334
  TNode current = workList.back();
149
167
  workList.pop_back();
150
  for (;;)
151
  {
152
1661
    Assert(d_visitedOnce.find(current) != d_visitedOnce.end());
153
1661
    parent = d_visitedOnce[current];
154
1661
    if (!parent.isNull())
155
    {
156
1587
      swap = isSigned = strict = false;
157
1587
      bool checkParent = false;
158
1587
      switch (parent.getKind())
159
      {
160
        // If-then-else operator - any two unconstrained children makes the
161
        // parent unconstrained
162
159
        case kind::ITE:
163
        {
164
159
          Assert(parent[0] == current || parent[1] == current
165
                 || parent[2] == current);
166
          bool uCond =
167
477
              parent[0] == current
168
477
              || d_unconstrained.find(parent[0]) != d_unconstrained.end();
169
          bool uThen =
170
477
              parent[1] == current
171
477
              || d_unconstrained.find(parent[1]) != d_unconstrained.end();
172
          bool uElse =
173
477
              parent[2] == current
174
477
              || d_unconstrained.find(parent[2]) != d_unconstrained.end();
175
159
          if ((uCond && uThen) || (uCond && uElse) || (uThen && uElse))
176
          {
177
249
            if (d_unconstrained.find(parent) == d_unconstrained.end()
178
166
                && !d_substitutions.hasSubstitution(parent))
179
            {
180
57
              ++d_numUnconstrainedElim;
181
57
              if (uThen)
182
              {
183
40
                if (parent[1] != current)
184
                {
185
30
                  if (parent[1].isVar())
186
                  {
187
30
                    currentSub = parent[1];
188
                  }
189
                  else
190
                  {
191
                    Assert(d_substitutions.hasSubstitution(parent[1]));
192
                    currentSub = d_substitutions.apply(parent[1]);
193
                  }
194
                }
195
10
                else if (currentSub.isNull())
196
                {
197
8
                  currentSub = current;
198
                }
199
              }
200
17
              else if (parent[2] != current)
201
              {
202
9
                if (parent[2].isVar())
203
                {
204
9
                  currentSub = parent[2];
205
                }
206
                else
207
                {
208
                  Assert(d_substitutions.hasSubstitution(parent[2]));
209
                  currentSub = d_substitutions.apply(parent[2]);
210
                }
211
              }
212
8
              else if (currentSub.isNull())
213
              {
214
8
                currentSub = current;
215
              }
216
57
              current = parent;
217
            }
218
            else
219
            {
220
26
              currentSub = Node();
221
            }
222
          }
223
76
          else if (uCond)
224
          {
225
50
            Cardinality card = parent.getType().getCardinality();
226
75
            if (card.isFinite() && !card.isLargeFinite()
227
66
                && card.getFiniteCardinality() == 2)
228
            {
229
              // Special case: condition is unconstrained, then and else are
230
              // different, and total cardinality of the type is 2, then the
231
              // result is unconstrained
232
8
              Node test = Rewriter::rewrite(parent[1].eqNode(parent[2]));
233
4
              if (test == nm->mkConst<bool>(false))
234
              {
235
4
                ++d_numUnconstrainedElim;
236
4
                if (currentSub.isNull())
237
                {
238
                  currentSub = current;
239
                }
240
4
                currentSub = newUnconstrainedVar(parent.getType(), currentSub);
241
4
                current = parent;
242
              }
243
            }
244
          }
245
159
          break;
246
        }
247
248
        // Comparisons that return a different type - assuming domains are
249
        // larger than 1, any unconstrained child makes parent unconstrained as
250
        // well
251
110
        case kind::EQUAL:
252
110
          if (parent[0].getType() != parent[1].getType())
253
          {
254
2
            TNode other = (parent[0] == current) ? parent[1] : parent[0];
255
2
            if (current.getType().isSubtypeOf(other.getType()))
256
            {
257
2
              break;
258
            }
259
          }
260
108
          if (parent[0].getType().getCardinality().isOne())
261
          {
262
            break;
263
          }
264
108
          if (parent[0].getType().isDatatype())
265
          {
266
            TypeNode tn = parent[0].getType();
267
            const DType& dt = tn.getDType();
268
            if (dt.isRecursiveSingleton(tn))
269
            {
270
              // domain size may be 1
271
              break;
272
            }
273
          }
274
108
          if (parent[0].getType().isBoolean())
275
          {
276
2
            checkParent = true;
277
2
            break;
278
          }
279
          CVC5_FALLTHROUGH;
280
        case kind::BITVECTOR_COMP:
281
        case kind::LT:
282
        case kind::LEQ:
283
        case kind::GT:
284
        case kind::GEQ:
285
        {
286
236
          if (d_unconstrained.find(parent) == d_unconstrained.end()
287
236
              && !d_substitutions.hasSubstitution(parent))
288
          {
289
118
            ++d_numUnconstrainedElim;
290
118
            Assert(parent[0] != parent[1]
291
                   && (parent[0] == current || parent[1] == current));
292
118
            if (currentSub.isNull())
293
            {
294
27
              currentSub = current;
295
            }
296
118
            currentSub = newUnconstrainedVar(parent.getType(), currentSub);
297
118
            current = parent;
298
          }
299
          else
300
          {
301
            currentSub = Node();
302
          }
303
118
          break;
304
        }
305
306
        // Unary operators that propagate unconstrainedness
307
86
        case kind::NOT:
308
        case kind::BITVECTOR_NOT:
309
        case kind::BITVECTOR_NEG:
310
        case kind::UMINUS:
311
86
          ++d_numUnconstrainedElim;
312
86
          Assert(parent[0] == current);
313
86
          if (currentSub.isNull())
314
          {
315
4
            currentSub = current;
316
          }
317
86
          current = parent;
318
86
          break;
319
320
        // Unary operators that propagate unconstrainedness and return a
321
        // different type
322
7
        case kind::BITVECTOR_EXTRACT:
323
7
          ++d_numUnconstrainedElim;
324
7
          Assert(parent[0] == current);
325
7
          if (currentSub.isNull())
326
          {
327
5
            currentSub = current;
328
          }
329
7
          currentSub = newUnconstrainedVar(parent.getType(), currentSub);
330
7
          current = parent;
331
7
          break;
332
333
        // Operators returning same type requiring all children to be
334
        // unconstrained
335
66
        case kind::AND:
336
        case kind::OR:
337
        case kind::IMPLIES:
338
        case kind::BITVECTOR_AND:
339
        case kind::BITVECTOR_OR:
340
        case kind::BITVECTOR_NAND:
341
        case kind::BITVECTOR_NOR:
342
        {
343
66
          bool allUnconstrained = true;
344
162
          for (TNode child : parent)
345
          {
346
124
            if (d_unconstrained.find(child) == d_unconstrained.end())
347
            {
348
28
              allUnconstrained = false;
349
28
              break;
350
            }
351
          }
352
66
          if (allUnconstrained)
353
          {
354
38
            checkParent = true;
355
          }
356
        }
357
66
        break;
358
359
        // Require all children to be unconstrained and different
360
54
        case kind::BITVECTOR_SHL:
361
        case kind::BITVECTOR_LSHR:
362
        case kind::BITVECTOR_ASHR:
363
        case kind::BITVECTOR_UDIV:
364
        case kind::BITVECTOR_UREM:
365
        case kind::BITVECTOR_SDIV:
366
        case kind::BITVECTOR_SREM:
367
        case kind::BITVECTOR_SMOD:
368
        {
369
54
          bool allUnconstrained = true;
370
54
          bool allDifferent = true;
371
138
          for (TNode::iterator child_it = parent.begin();
372
138
               child_it != parent.end();
373
               ++child_it)
374
          {
375
96
            if (d_unconstrained.find(*child_it) == d_unconstrained.end())
376
            {
377
12
              allUnconstrained = false;
378
12
              break;
379
            }
380
126
            for (TNode::iterator child_it2 = child_it + 1;
381
126
                 child_it2 != parent.end();
382
                 ++child_it2)
383
            {
384
42
              if (*child_it == *child_it2)
385
              {
386
                allDifferent = false;
387
                break;
388
              }
389
            }
390
          }
391
54
          if (allUnconstrained && allDifferent)
392
          {
393
42
            checkParent = true;
394
          }
395
54
          break;
396
        }
397
398
        // Requires all children to be unconstrained and different, and returns
399
        // a different type
400
22
        case kind::BITVECTOR_CONCAT:
401
        {
402
22
          bool allUnconstrained = true;
403
22
          bool allDifferent = true;
404
35
          for (TNode::iterator child_it = parent.begin();
405
35
               child_it != parent.end();
406
               ++child_it)
407
          {
408
33
            if (d_unconstrained.find(*child_it) == d_unconstrained.end())
409
            {
410
20
              allUnconstrained = false;
411
20
              break;
412
            }
413
24
            for (TNode::iterator child_it2 = child_it + 1;
414
24
                 child_it2 != parent.end();
415
                 ++child_it2)
416
            {
417
11
              if (*child_it == *child_it2)
418
              {
419
                allDifferent = false;
420
                break;
421
              }
422
            }
423
          }
424
22
          if (allUnconstrained && allDifferent)
425
          {
426
4
            if (d_unconstrained.find(parent) == d_unconstrained.end()
427
4
                && !d_substitutions.hasSubstitution(parent))
428
            {
429
2
              ++d_numUnconstrainedElim;
430
2
              if (currentSub.isNull())
431
              {
432
                currentSub = current;
433
              }
434
2
              currentSub = newUnconstrainedVar(parent.getType(), currentSub);
435
2
              current = parent;
436
            }
437
            else
438
            {
439
              currentSub = Node();
440
            }
441
          }
442
        }
443
22
        break;
444
445
        // N-ary operators returning same type requiring at least one child to
446
        // be unconstrained
447
4
        case kind::PLUS:
448
        case kind::MINUS:
449
4
          if (current.getType().isInteger() && !parent.getType().isInteger())
450
          {
451
            break;
452
          }
453
          CVC5_FALLTHROUGH;
454
        case kind::XOR:
455
        case kind::BITVECTOR_XOR:
456
        case kind::BITVECTOR_XNOR:
457
        case kind::BITVECTOR_ADD:
458
14
        case kind::BITVECTOR_SUB: checkParent = true; break;
459
460
        // Multiplication/division: must be non-integer and other operand must
461
        // be non-zero
462
8
        case kind::MULT:
463
        case kind::DIVISION:
464
        {
465
8
          Assert(parent.getNumChildren() == 2);
466
16
          TNode other;
467
8
          if (parent[0] == current)
468
          {
469
            other = parent[1];
470
          }
471
          else
472
          {
473
8
            Assert(parent[1] == current);
474
8
            other = parent[0];
475
          }
476
8
          if (d_unconstrained.find(other) != d_unconstrained.end())
477
          {
478
            if (d_unconstrained.find(parent) == d_unconstrained.end()
479
                && !d_substitutions.hasSubstitution(parent))
480
            {
481
              if (current.getType().isInteger() && other.getType().isInteger())
482
              {
483
                Assert(parent.getKind() == kind::DIVISION
484
                       || parent.getType().isInteger());
485
                if (parent.getKind() == kind::DIVISION)
486
                {
487
                  break;
488
                }
489
              }
490
              ++d_numUnconstrainedElim;
491
              if (currentSub.isNull())
492
              {
493
                currentSub = current;
494
              }
495
              current = parent;
496
            }
497
            else
498
            {
499
              currentSub = Node();
500
            }
501
          }
502
          else
503
          {
504
            // if only the denominator of a division is unconstrained, can't
505
            // set it to 0 so the result is not unconstrained
506
8
            if (parent.getKind() == kind::DIVISION && current == parent[1])
507
            {
508
              break;
509
            }
510
            // if we are an integer, the only way we are unconstrained is if
511
            // we are a MULT by -1
512
8
            if (current.getType().isInteger())
513
            {
514
              // div/mult by 1 should have been simplified
515
4
              Assert(other != nm->mkConst<Rational>(1));
516
              // div by -1 should have been simplified
517
4
              if (other != nm->mkConst<Rational>(-1))
518
              {
519
2
                break;
520
              }
521
              else
522
              {
523
2
                Assert(parent.getKind() == kind::MULT);
524
2
                Assert(parent.getType().isInteger());
525
              }
526
            }
527
            else
528
            {
529
              // TODO(#2377): could build ITE here
530
8
              Node test = other.eqNode(nm->mkConst<Rational>(0));
531
4
              if (Rewriter::rewrite(test) != nm->mkConst<bool>(false))
532
              {
533
                break;
534
              }
535
            }
536
6
            ++d_numUnconstrainedElim;
537
6
            if (currentSub.isNull())
538
            {
539
6
              currentSub = current;
540
            }
541
6
            current = parent;
542
          }
543
6
          break;
544
        }
545
546
        // Bitvector MULT - current must only appear once in the children:
547
        // all other children must be unconstrained or odd
548
870
        case kind::BITVECTOR_MULT:
549
        {
550
870
          bool found = false;
551
870
          bool done = false;
552
553
876
          for (TNode child : parent)
554
          {
555
2286
            if (child == current)
556
            {
557
708
              if (found)
558
              {
559
                done = true;
560
                break;
561
              }
562
708
              found = true;
563
708
              continue;
564
            }
565
870
            else if (d_unconstrained.find(child) == d_unconstrained.end())
566
            {
567
              Node extractOp =
568
868
                  nm->mkConst<BitVectorExtract>(BitVectorExtract(0, 0));
569
868
              vector<Node> children;
570
866
              children.push_back(child);
571
868
              Node test = nm->mkNode(extractOp, children);
572
868
              BitVector one(1, unsigned(1));
573
866
              test = test.eqNode(nm->mkConst<BitVector>(one));
574
866
              if (Rewriter::rewrite(test) != nm->mkConst<bool>(true))
575
              {
576
864
                done = true;
577
864
                break;
578
              }
579
            }
580
          }
581
870
          if (done)
582
          {
583
864
            break;
584
          }
585
6
          checkParent = true;
586
6
          break;
587
        }
588
589
        // Uninterpreted function - if domain is infinite, no quantifiers are
590
        // used, and any child is unconstrained, result is unconstrained
591
62
        case kind::APPLY_UF:
592
124
          if (d_preprocContext->getLogicInfo().isQuantified()
593
124
              || !current.getType().getCardinality().isInfinite())
594
          {
595
            break;
596
          }
597
124
          if (d_unconstrained.find(parent) == d_unconstrained.end()
598
124
              && !d_substitutions.hasSubstitution(parent))
599
          {
600
62
            ++d_numUnconstrainedElim;
601
62
            if (currentSub.isNull())
602
            {
603
              currentSub = current;
604
            }
605
            // always introduce a new variable; it is unsound to try to reuse
606
            // currentSub as the variable, see issue #4469.
607
62
            currentSub = newUnconstrainedVar(parent.getType(), currentSub);
608
62
            current = parent;
609
          }
610
          else
611
          {
612
            currentSub = Node();
613
          }
614
62
          break;
615
616
        // Array select - if array is unconstrained, so is result
617
24
        case kind::SELECT:
618
24
          if (parent[0] == current)
619
          {
620
20
            ++d_numUnconstrainedElim;
621
20
            Assert(current.getType().isArray());
622
20
            if (currentSub.isNull())
623
            {
624
20
              currentSub = current;
625
            }
626
60
            currentSub = newUnconstrainedVar(
627
40
                current.getType().getArrayConstituentType(), currentSub);
628
20
            current = parent;
629
          }
630
24
          break;
631
632
        // Array store - if both store and value are unconstrained, so is
633
        // resulting store
634
12
        case kind::STORE:
635
36
          if (((parent[0] == current
636
24
                && d_unconstrained.find(parent[2]) != d_unconstrained.end())
637
60
               || (parent[2] == current
638
12
                   && d_unconstrained.find(parent[0])
639
12
                          != d_unconstrained.end())))
640
          {
641
            if (d_unconstrained.find(parent) == d_unconstrained.end()
642
                && !d_substitutions.hasSubstitution(parent))
643
            {
644
              ++d_numUnconstrainedElim;
645
              if (parent[0] != current)
646
              {
647
                if (parent[0].isVar())
648
                {
649
                  currentSub = parent[0];
650
                }
651
                else
652
                {
653
                  Assert(d_substitutions.hasSubstitution(parent[0]));
654
                  currentSub = d_substitutions.apply(parent[0]);
655
                }
656
              }
657
              else if (currentSub.isNull())
658
              {
659
                currentSub = current;
660
              }
661
              current = parent;
662
            }
663
            else
664
            {
665
              currentSub = Node();
666
            }
667
          }
668
12
          break;
669
670
        // Bit-vector comparisons: replace with new Boolean variable, but have
671
        // to also conjoin with a side condition as there is always one case
672
        // when the comparison is forced to be false
673
60
        case kind::BITVECTOR_ULT:
674
        case kind::BITVECTOR_UGE:
675
        case kind::BITVECTOR_UGT:
676
        case kind::BITVECTOR_ULE:
677
        case kind::BITVECTOR_SLT:
678
        case kind::BITVECTOR_SGE:
679
        case kind::BITVECTOR_SGT:
680
        case kind::BITVECTOR_SLE:
681
        {
682
          // Tuples over (signed, swap, strict).
683
60
          switch (parent.getKind())
684
          {
685
            case kind::BITVECTOR_UGE: break;
686
30
            case kind::BITVECTOR_ULT: strict = true; break;
687
            case kind::BITVECTOR_ULE: swap = true; break;
688
            case kind::BITVECTOR_UGT:
689
              swap = true;
690
              strict = true;
691
              break;
692
            case kind::BITVECTOR_SGE: isSigned = true; break;
693
30
            case kind::BITVECTOR_SLT:
694
30
              isSigned = true;
695
30
              strict = true;
696
30
              break;
697
            case kind::BITVECTOR_SLE:
698
              isSigned = true;
699
              swap = true;
700
              break;
701
            case kind::BITVECTOR_SGT:
702
              isSigned = true;
703
              swap = true;
704
              strict = true;
705
              break;
706
            default: Unreachable();
707
          }
708
120
          TNode other;
709
60
          bool left = false;
710
60
          if (parent[0] == current)
711
          {
712
29
            other = parent[1];
713
29
            left = true;
714
          }
715
          else
716
          {
717
31
            Assert(parent[1] == current);
718
31
            other = parent[0];
719
          }
720
60
          if (d_unconstrained.find(other) != d_unconstrained.end())
721
          {
722
34
            if (d_unconstrained.find(parent) == d_unconstrained.end()
723
34
                && !d_substitutions.hasSubstitution(parent))
724
            {
725
9
              ++d_numUnconstrainedElim;
726
9
              if (currentSub.isNull())
727
              {
728
8
                currentSub = current;
729
              }
730
9
              currentSub = newUnconstrainedVar(parent.getType(), currentSub);
731
9
              current = parent;
732
            }
733
            else
734
            {
735
8
              currentSub = Node();
736
            }
737
          }
738
          else
739
          {
740
43
            unsigned size = current.getType().getBitVectorSize();
741
            BitVector bv =
742
64
                isSigned ? BitVector(size, Integer(1).multiplyByPow2(size - 1))
743
103
                         : BitVector(size, unsigned(0));
744
43
            if (swap == left)
745
            {
746
23
              bv = ~bv;
747
            }
748
43
            if (currentSub.isNull())
749
            {
750
35
              currentSub = current;
751
            }
752
43
            currentSub = newUnconstrainedVar(parent.getType(), currentSub);
753
43
            current = parent;
754
            Node test =
755
82
                Rewriter::rewrite(other.eqNode(nm->mkConst<BitVector>(bv)));
756
43
            if (test == nm->mkConst<bool>(false))
757
            {
758
4
              break;
759
            }
760
39
            currentSub = strict ? currentSub.andNode(test.notNode())
761
                                : currentSub.orNode(test);
762
            // Delay adding this substitution - see comment at end of function
763
39
            delayQueueLeft.push_back(current);
764
39
            delayQueueRight.push_back(currentSub);
765
39
            currentSub = Node();
766
39
            parent = TNode();
767
          }
768
56
          break;
769
        }
770
771
        // Do nothing
772
21
        case kind::BITVECTOR_SIGN_EXTEND:
773
        case kind::BITVECTOR_ZERO_EXTEND:
774
        case kind::BITVECTOR_REPEAT:
775
        case kind::BITVECTOR_ROTATE_LEFT:
776
        case kind::BITVECTOR_ROTATE_RIGHT:
777
778
21
        default: break;
779
      }
780
1587
      if (checkParent)
781
      {
782
        // run for various cases from above
783
204
        if (d_unconstrained.find(parent) == d_unconstrained.end()
784
204
            && !d_substitutions.hasSubstitution(parent))
785
        {
786
70
          ++d_numUnconstrainedElim;
787
70
          if (currentSub.isNull())
788
          {
789
30
            currentSub = current;
790
          }
791
70
          current = parent;
792
        }
793
        else
794
        {
795
32
          currentSub = Node();
796
        }
797
      }
798
2032
      if (current == parent && d_visited[parent] == 1)
799
      {
800
445
        d_unconstrained.insert(parent);
801
445
        continue;
802
      }
803
    }
804
1216
    if (!currentSub.isNull())
805
    {
806
224
      Trace("unc-simp")
807
112
          << "UnconstrainedSimplifier::processUnconstrained: introduce "
808
112
          << currentSub << " for " << current << ", parent " << parent
809
112
          << std::endl;
810
112
      Assert(currentSub.isVar());
811
112
      d_substitutions.addSubstitution(current, currentSub, false);
812
    }
813
1216
    if (workList.empty())
814
    {
815
167
      break;
816
    }
817
1049
    current = workList.back();
818
1049
    currentSub = Node();
819
1049
    workList.pop_back();
820
1494
  }
821
334
  TNode left;
822
334
  Node right;
823
  // All substitutions except those arising from bitvector comparisons are
824
  // substitutions t -> x where x is a variable.  This allows us to build the
825
  // substitution very quickly (never invalidating the substitution cache).
826
  // Bitvector comparisons are more complicated and may require
827
  // back-substitution and cache-invalidation.  So we do these last.
828
245
  while (!delayQueueLeft.empty())
829
  {
830
39
    left = delayQueueLeft.back();
831
39
    if (!d_substitutions.hasSubstitution(left))
832
    {
833
38
      right = d_substitutions.apply(delayQueueRight.back());
834
38
      d_substitutions.addSubstitution(delayQueueLeft.back(), right);
835
    }
836
39
    delayQueueLeft.pop_back();
837
39
    delayQueueRight.pop_back();
838
  }
839
167
}
840
841
515
PreprocessingPassResult UnconstrainedSimplifier::applyInternal(
842
    AssertionPipeline* assertionsToPreprocess)
843
{
844
515
  d_preprocContext->spendResource(Resource::PreprocessStep);
845
846
515
  const std::vector<Node>& assertions = assertionsToPreprocess->ref();
847
848
515
  d_context->push();
849
850
1757
  for (const Node& assertion : assertions)
851
  {
852
1242
    visitAll(assertion);
853
  }
854
855
515
  if (!d_unconstrained.empty())
856
  {
857
167
    processUnconstrained();
858
    //    d_substitutions.print(CVC5Message.getStream());
859
575
    for (size_t i = 0, asize = assertions.size(); i < asize; ++i)
860
    {
861
816
      Node a = assertions[i];
862
816
      Node as = Rewriter::rewrite(d_substitutions.apply(a));
863
      // replace the assertion
864
408
      assertionsToPreprocess->replace(i, as);
865
    }
866
  }
867
868
  // to clear substitutions map
869
515
  d_context->pop();
870
871
515
  d_visited.clear();
872
515
  d_visitedOnce.clear();
873
515
  d_unconstrained.clear();
874
875
515
  return PreprocessingPassResult::NO_CONFLICT;
876
}
877
878
879
}  // namespace passes
880
}  // namespace preprocessing
881
28191
}  // namespace cvc5