GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/unconstrained_simplifier.cpp Lines: 336 403 83.4 %
Date: 2021-08-17 Branches: 724 1717 42.2 %

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