GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/ite_simp.cpp Lines: 59 120 49.2 %
Date: 2021-08-16 Branches: 63 432 14.6 %

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