GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/ite_simp.cpp Lines: 59 120 49.2 %
Date: 2021-05-22 Branches: 67 444 15.1 %

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/smt_options.h"
21
#include "preprocessing/assertion_pipeline.h"
22
#include "preprocessing/preprocessing_pass_context.h"
23
#include "smt/smt_statistics_registry.h"
24
#include "smt_util/nary_builder.h"
25
#include "theory/arith/arith_ite_utils.h"
26
#include "theory/rewriter.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
4
Node simpITE(util::ITEUtilities* ite_utils, TNode assertion)
42
{
43
4
  if (!ite_utils->containsTermITE(assertion))
44
  {
45
2
    return assertion;
46
  }
47
  else
48
  {
49
4
    Node result = ite_utils->simpITE(assertion);
50
4
    Node res_rewritten = Rewriter::rewrite(result);
51
52
18922
    if (options::simplifyWithCareEnabled())
53
    {
54
      Chat() << "starting simplifyWithCare()" << endl;
55
      Node postSimpWithCare = ite_utils->simplifyWithCare(res_rewritten);
56
      Chat() << "ending simplifyWithCare()"
57
             << " post simplifyWithCare()" << postSimpWithCare.getId() << endl;
58
      result = Rewriter::rewrite(postSimpWithCare);
59
    }
60
    else
61
    {
62
2
      result = res_rewritten;
63
    }
64
2
    return result;
65
  }
66
}
67
68
/**
69
 * Ensures the assertions asserted after index 'before' now effectively come
70
 * before 'real_assertions_end'.
71
 */
72
2
void compressBeforeRealAssertions(AssertionPipeline* assertionsToPreprocess,
73
                                  size_t before)
74
{
75
2
  size_t cur_size = assertionsToPreprocess->size();
76
4
  if (before >= cur_size || assertionsToPreprocess->getRealAssertionsEnd() <= 0
77
4
      || assertionsToPreprocess->getRealAssertionsEnd() >= cur_size)
78
  {
79
    return;
80
  }
81
82
  // assertions
83
  // original: [0 ... assertionsToPreprocess.getRealAssertionsEnd())
84
  //  can be modified
85
  // ites skolems [assertionsToPreprocess.getRealAssertionsEnd(), before)
86
  //  cannot be moved
87
  // added [before, cur_size)
88
  //  can be modified
89
2
  Assert(0 < assertionsToPreprocess->getRealAssertionsEnd());
90
2
  Assert(assertionsToPreprocess->getRealAssertionsEnd() <= before);
91
2
  Assert(before < cur_size);
92
93
4
  std::vector<Node> intoConjunction;
94
2420
  for (size_t i = before; i < cur_size; ++i)
95
  {
96
2418
    intoConjunction.push_back((*assertionsToPreprocess)[i]);
97
  }
98
2
  assertionsToPreprocess->resize(before);
99
2
  size_t lastBeforeItes = assertionsToPreprocess->getRealAssertionsEnd() - 1;
100
2
  intoConjunction.push_back((*assertionsToPreprocess)[lastBeforeItes]);
101
4
  Node newLast = cvc5::util::NaryBuilder::mkAssoc(kind::AND, intoConjunction);
102
2
  assertionsToPreprocess->replace(lastBeforeItes, newLast);
103
2
  Assert(assertionsToPreprocess->size() == before);
104
}
105
106
}  // namespace
107
108
/* -------------------------------------------------------------------------- */
109
110
9459
ITESimp::Statistics::Statistics()
111
9459
    : d_arithSubstitutionsAdded(smtStatisticsRegistry().registerInt(
112
9459
        "preprocessing::passes::ITESimp::ArithSubstitutionsAdded"))
113
{
114
9459
}
115
116
2
bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
117
{
118
2
  bool result = true;
119
2
  bool simpDidALotOfWork = d_iteUtilities.simpIteDidALotOfWorkHeuristic();
120
2
  if (simpDidALotOfWork)
121
  {
122
7
    if (options::compressItes())
123
    {
124
2
      result = d_iteUtilities.compress(assertionsToPreprocess);
125
    }
126
127
2
    if (result)
128
    {
129
      // if false, don't bother to reclaim memory here.
130
2
      NodeManager* nm = NodeManager::currentNM();
131
4
      if (nm->poolSize() >= options::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
        Rewriter::clearCaches();
139
        nm->reclaimZombiesUntil(options::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
  TheoryEngine* theory_engine = d_preprocContext->getTheoryEngine();
148
4
  if (theory_engine->getLogicInfo().isTheoryEnabled(theory::THEORY_ARITH)
149
2
      && !options::incrementalSolving())
150
  {
151
2
    if (!simpDidALotOfWork)
152
    {
153
      util::ContainsTermITEVisitor& contains =
154
          *(d_iteUtilities.getContainsVisitor());
155
      arith::ArithIteUtils aiteu(contains,
156
                                 d_preprocContext->getUserContext(),
157
                                 theory_engine->getModel());
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 = Rewriter::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 = Rewriter::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 = Rewriter::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 = Rewriter::rewrite(more);
213
            assertionsToPreprocess->replace(i, morer);
214
          }
215
        }
216
      }
217
    }
218
  }
219
2
  return result;
220
}
221
222
/* -------------------------------------------------------------------------- */
223
224
9459
ITESimp::ITESimp(PreprocessingPassContext* preprocContext)
225
9459
    : PreprocessingPass(preprocContext, "ite-simp")
226
{
227
9459
}
228
229
2
PreprocessingPassResult ITESimp::applyInternal(
230
    AssertionPipeline* assertionsToPreprocess)
231
{
232
2
  d_preprocContext->spendResource(Resource::PreprocessStep);
233
234
2
  size_t nasserts = assertionsToPreprocess->size();
235
6
  for (size_t i = 0; i < nasserts; ++i)
236
  {
237
4
    d_preprocContext->spendResource(Resource::PreprocessStep);
238
8
    Node simp = simpITE(&d_iteUtilities, (*assertionsToPreprocess)[i]);
239
4
    assertionsToPreprocess->replace(i, simp);
240
4
    if (simp.isConst() && !simp.getConst<bool>())
241
    {
242
      return PreprocessingPassResult::CONFLICT;
243
    }
244
  }
245
2
  bool done = doneSimpITE(assertionsToPreprocess);
246
2
  if (nasserts < assertionsToPreprocess->size())
247
  {
248
2
    compressBeforeRealAssertions(assertionsToPreprocess, nasserts);
249
  }
250
2
  return done ? PreprocessingPassResult::NO_CONFLICT
251
2
              : PreprocessingPassResult::CONFLICT;
252
}
253
254
255
/* -------------------------------------------------------------------------- */
256
257
}  // namespace passes
258
}  // namespace preprocessing
259
47118
}  // namespace cvc5