GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/ite_simp.cpp Lines: 57 118 48.3 %
Date: 2021-09-16 Branches: 64 434 14.7 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Aina Niemetz, Tim King, 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
 * ITE simplification preprocessing pass.
14
 */
15
16
#include "preprocessing/passes/ite_simp.h"
17
18
#include <vector>
19
20
#include "options/base_options.h"
21
#include "options/smt_options.h"
22
#include "preprocessing/assertion_pipeline.h"
23
#include "preprocessing/preprocessing_pass_context.h"
24
#include "smt/smt_statistics_registry.h"
25
#include "smt_util/nary_builder.h"
26
#include "theory/arith/arith_ite_utils.h"
27
#include "theory/theory_engine.h"
28
29
using namespace std;
30
using namespace cvc5;
31
using namespace cvc5::theory;
32
33
namespace cvc5 {
34
namespace preprocessing {
35
namespace passes {
36
37
/* -------------------------------------------------------------------------- */
38
39
namespace {
40
41
/**
42
 * Ensures the assertions asserted after index 'before' now effectively come
43
 * before 'real_assertions_end'.
44
 */
45
1
void compressBeforeRealAssertions(AssertionPipeline* assertionsToPreprocess,
46
                                  size_t before)
47
{
48
1
  size_t cur_size = assertionsToPreprocess->size();
49
2
  if (before >= cur_size || assertionsToPreprocess->getRealAssertionsEnd() <= 0
50
2
      || assertionsToPreprocess->getRealAssertionsEnd() >= cur_size)
51
  {
52
    return;
53
  }
54
55
  // assertions
56
  // original: [0 ... assertionsToPreprocess.getRealAssertionsEnd())
57
  //  can be modified
58
  // ites skolems [assertionsToPreprocess.getRealAssertionsEnd(), before)
59
  //  cannot be moved
60
  // added [before, cur_size)
61
  //  can be modified
62
1
  Assert(0 < assertionsToPreprocess->getRealAssertionsEnd());
63
1
  Assert(assertionsToPreprocess->getRealAssertionsEnd() <= before);
64
1
  Assert(before < cur_size);
65
66
2
  std::vector<Node> intoConjunction;
67
1210
  for (size_t i = before; i < cur_size; ++i)
68
  {
69
1209
    intoConjunction.push_back((*assertionsToPreprocess)[i]);
70
  }
71
1
  assertionsToPreprocess->resize(before);
72
1
  size_t lastBeforeItes = assertionsToPreprocess->getRealAssertionsEnd() - 1;
73
1
  intoConjunction.push_back((*assertionsToPreprocess)[lastBeforeItes]);
74
2
  Node newLast = cvc5::util::NaryBuilder::mkAssoc(kind::AND, intoConjunction);
75
1
  assertionsToPreprocess->replace(lastBeforeItes, newLast);
76
1
  Assert(assertionsToPreprocess->size() == before);
77
}
78
79
}  // namespace
80
81
/* -------------------------------------------------------------------------- */
82
83
9942
ITESimp::Statistics::Statistics(StatisticsRegistry& reg)
84
    : d_arithSubstitutionsAdded(reg.registerInt(
85
9942
        "preprocessing::passes::ITESimp::ArithSubstitutionsAdded"))
86
{
87
9942
}
88
89
2
Node ITESimp::simpITE(util::ITEUtilities* ite_utils, TNode assertion)
90
{
91
2
  if (!ite_utils->containsTermITE(assertion))
92
  {
93
1
    return assertion;
94
  }
95
  else
96
  {
97
2
    Node result = ite_utils->simpITE(assertion);
98
2
    Node res_rewritten = rewrite(result);
99
100
1
    if (options().smt.simplifyWithCareEnabled)
101
    {
102
      Chat() << "starting simplifyWithCare()" << endl;
103
      Node postSimpWithCare = ite_utils->simplifyWithCare(res_rewritten);
104
      Chat() << "ending simplifyWithCare()"
105
             << " post simplifyWithCare()" << postSimpWithCare.getId() << endl;
106
      result = rewrite(postSimpWithCare);
107
    }
108
    else
109
    {
110
1
      result = res_rewritten;
111
    }
112
1
    return result;
113
  }
114
}
115
116
1
bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
117
{
118
1
  bool result = true;
119
1
  bool simpDidALotOfWork = d_iteUtilities.simpIteDidALotOfWorkHeuristic();
120
1
  if (simpDidALotOfWork)
121
  {
122
1
    if (options().smt.compressItes)
123
    {
124
1
      result = d_iteUtilities.compress(assertionsToPreprocess);
125
    }
126
127
1
    if (result)
128
    {
129
      // if false, don't bother to reclaim memory here.
130
1
      NodeManager* nm = NodeManager::currentNM();
131
1
      if (nm->poolSize() >= options().smt.zombieHuntThreshold)
132
      {
133
        Chat() << "..ite simplifier did quite a bit of work.. "
134
               << nm->poolSize() << endl;
135
        Chat() << "....node manager contains " << nm->poolSize()
136
               << " nodes before cleanup" << endl;
137
        d_iteUtilities.clear();
138
        d_env.getRewriter()->clearCaches();
139
        nm->reclaimZombiesUntil(options().smt.zombieHuntThreshold);
140
        Chat() << "....node manager contains " << nm->poolSize()
141
               << " nodes after cleanup" << endl;
142
      }
143
    }
144
  }
145
146
  // Do theory specific preprocessing passes
147
2
  if (logicInfo().isTheoryEnabled(theory::THEORY_ARITH)
148
1
      && !options().base.incrementalSolving)
149
  {
150
1
    if (!simpDidALotOfWork)
151
    {
152
      util::ContainsTermITEVisitor& contains =
153
          *(d_iteUtilities.getContainsVisitor());
154
      arith::ArithIteUtils aiteu(
155
          contains,
156
          userContext(),
157
          d_preprocContext->getTopLevelSubstitutions().get());
158
      bool anyItes = false;
159
      for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
160
      {
161
        Node curr = (*assertionsToPreprocess)[i];
162
        if (contains.containsTermITE(curr))
163
        {
164
          anyItes = true;
165
          Node res = aiteu.reduceVariablesInItes(curr);
166
          Debug("arith::ite::red") << "@ " << i << " ... " << curr << endl
167
                                   << "   ->" << res << endl;
168
          if (curr != res)
169
          {
170
            Node more = aiteu.reduceConstantIteByGCD(res);
171
            Debug("arith::ite::red") << "  gcd->" << more << endl;
172
            Node morer = rewrite(more);
173
            assertionsToPreprocess->replace(i, morer);
174
          }
175
        }
176
      }
177
      if (!anyItes)
178
      {
179
        unsigned prevSubCount = aiteu.getSubCount();
180
        aiteu.learnSubstitutions(assertionsToPreprocess->ref());
181
        if (prevSubCount < aiteu.getSubCount())
182
        {
183
          d_statistics.d_arithSubstitutionsAdded +=
184
              aiteu.getSubCount() - prevSubCount;
185
          bool anySuccess = false;
186
          for (size_t i = 0, N = assertionsToPreprocess->size(); i < N; ++i)
187
          {
188
            Node curr = (*assertionsToPreprocess)[i];
189
            Node next = rewrite(aiteu.applySubstitutions(curr));
190
            Node res = aiteu.reduceVariablesInItes(next);
191
            Debug("arith::ite::red") << "@ " << i << " ... " << next << endl
192
                                     << "   ->" << res << endl;
193
            Node more = aiteu.reduceConstantIteByGCD(res);
194
            Debug("arith::ite::red") << "  gcd->" << more << endl;
195
            if (more != next)
196
            {
197
              anySuccess = true;
198
              break;
199
            }
200
          }
201
          for (size_t i = 0, N = assertionsToPreprocess->size();
202
               anySuccess && i < N;
203
               ++i)
204
          {
205
            Node curr = (*assertionsToPreprocess)[i];
206
            Node next = rewrite(aiteu.applySubstitutions(curr));
207
            Node res = aiteu.reduceVariablesInItes(next);
208
            Debug("arith::ite::red") << "@ " << i << " ... " << next << endl
209
                                     << "   ->" << res << endl;
210
            Node more = aiteu.reduceConstantIteByGCD(res);
211
            Debug("arith::ite::red") << "  gcd->" << more << endl;
212
            Node morer = rewrite(more);
213
            assertionsToPreprocess->replace(i, morer);
214
          }
215
        }
216
      }
217
    }
218
  }
219
1
  return result;
220
}
221
222
/* -------------------------------------------------------------------------- */
223
224
9942
ITESimp::ITESimp(PreprocessingPassContext* preprocContext)
225
    : PreprocessingPass(preprocContext, "ite-simp"),
226
      d_iteUtilities(d_env),
227
9942
      d_statistics(statisticsRegistry())
228
{
229
9942
}
230
231
1
PreprocessingPassResult ITESimp::applyInternal(
232
    AssertionPipeline* assertionsToPreprocess)
233
{
234
1
  d_preprocContext->spendResource(Resource::PreprocessStep);
235
236
1
  size_t nasserts = assertionsToPreprocess->size();
237
3
  for (size_t i = 0; i < nasserts; ++i)
238
  {
239
2
    d_preprocContext->spendResource(Resource::PreprocessStep);
240
4
    Node simp = simpITE(&d_iteUtilities, (*assertionsToPreprocess)[i]);
241
2
    assertionsToPreprocess->replace(i, simp);
242
2
    if (simp.isConst() && !simp.getConst<bool>())
243
    {
244
      return PreprocessingPassResult::CONFLICT;
245
    }
246
  }
247
1
  bool done = doneSimpITE(assertionsToPreprocess);
248
1
  if (nasserts < assertionsToPreprocess->size())
249
  {
250
1
    compressBeforeRealAssertions(assertionsToPreprocess, nasserts);
251
  }
252
1
  return done ? PreprocessingPassResult::NO_CONFLICT
253
1
              : PreprocessingPassResult::CONFLICT;
254
}
255
256
257
/* -------------------------------------------------------------------------- */
258
259
}  // namespace passes
260
}  // namespace preprocessing
261
29577
}  // namespace cvc5