GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/process_assertions.cpp Lines: 171 184 92.9 %
Date: 2021-05-22 Branches: 378 766 49.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Aina Niemetz
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
 * Implementation of module for processing assertions for an SMT engine.
14
 */
15
16
#include "smt/process_assertions.h"
17
18
#include <utility>
19
20
#include "expr/node_manager_attributes.h"
21
#include "options/arith_options.h"
22
#include "options/base_options.h"
23
#include "options/bv_options.h"
24
#include "options/quantifiers_options.h"
25
#include "options/sep_options.h"
26
#include "options/smt_options.h"
27
#include "options/strings_options.h"
28
#include "options/uf_options.h"
29
#include "preprocessing/assertion_pipeline.h"
30
#include "preprocessing/preprocessing_pass.h"
31
#include "preprocessing/preprocessing_pass_registry.h"
32
#include "printer/printer.h"
33
#include "smt/assertions.h"
34
#include "smt/dump.h"
35
#include "smt/expand_definitions.h"
36
#include "smt/smt_engine.h"
37
#include "smt/smt_engine_stats.h"
38
#include "theory/logic_info.h"
39
#include "theory/theory_engine.h"
40
41
using namespace std;
42
using namespace cvc5::preprocessing;
43
using namespace cvc5::theory;
44
using namespace cvc5::kind;
45
46
namespace cvc5 {
47
namespace smt {
48
49
/** Useful for counting the number of recursive calls. */
50
class ScopeCounter
51
{
52
 public:
53
13371
  ScopeCounter(unsigned& d) : d_depth(d) { ++d_depth; }
54
13371
  ~ScopeCounter() { --d_depth; }
55
56
 private:
57
  unsigned& d_depth;
58
};
59
60
10092
ProcessAssertions::ProcessAssertions(SmtEngine& smt,
61
                                     ResourceManager& rm,
62
10092
                                     SmtEngineStatistics& stats)
63
    : d_smt(smt),
64
      d_resourceManager(rm),
65
      d_smtStats(stats),
66
10092
      d_preprocessingPassContext(nullptr)
67
{
68
10092
  d_true = NodeManager::currentNM()->mkConst(true);
69
10092
}
70
71
10092
ProcessAssertions::~ProcessAssertions()
72
{
73
10092
}
74
75
9459
void ProcessAssertions::finishInit(PreprocessingPassContext* pc)
76
{
77
9459
  Assert(d_preprocessingPassContext == nullptr);
78
9459
  d_preprocessingPassContext = pc;
79
80
9459
  PreprocessingPassRegistry& ppReg = PreprocessingPassRegistry::getInstance();
81
  // TODO: this will likely change when we add support for actually assembling
82
  // preprocessing pipelines. For now, we just create an instance of each
83
  // available preprocessing pass.
84
18918
  std::vector<std::string> passNames = ppReg.getAvailablePasses();
85
321606
  for (const std::string& passName : passNames)
86
  {
87
312147
    d_passes[passName].reset(
88
        ppReg.createPass(d_preprocessingPassContext, passName));
89
  }
90
9459
}
91
92
10092
void ProcessAssertions::cleanup() { d_passes.clear(); }
93
94
13126
void ProcessAssertions::spendResource(Resource r)
95
{
96
13126
  d_resourceManager.spendResource(r);
97
13126
}
98
99
12883
bool ProcessAssertions::apply(Assertions& as)
100
{
101
12883
  AssertionPipeline& assertions = as.getAssertionPipeline();
102
12883
  Assert(d_preprocessingPassContext != nullptr);
103
  // Dump the assertions
104
12883
  dumpAssertions("pre-everything", assertions);
105
106
12883
  Trace("smt-proc") << "ProcessAssertions::processAssertions() begin" << endl;
107
12883
  Trace("smt") << "ProcessAssertions::processAssertions()" << endl;
108
109
12883
  Debug("smt") << "#Assertions : " << assertions.size() << endl;
110
12883
  Debug("smt") << "#Assumptions: " << assertions.getNumAssumptions() << endl;
111
112
12883
  if (assertions.size() == 0)
113
  {
114
    // nothing to do
115
    return true;
116
  }
117
118
25766
  if (options::bvGaussElim())
119
  {
120
    d_passes["bv-gauss"]->apply(&assertions);
121
  }
122
123
  // Add dummy assertion in last position - to be used as a
124
  // placeholder for any new assertions to get added
125
12883
  assertions.push_back(d_true);
126
  // any assertions added beyond realAssertionsEnd must NOT affect the
127
  // equisatisfiability
128
12883
  assertions.updateRealAssertionsEnd();
129
130
  // Assertions are NOT guaranteed to be rewritten by this point
131
132
25766
  Trace("smt-proc")
133
12883
      << "ProcessAssertions::processAssertions() : pre-definition-expansion"
134
12883
      << endl;
135
12883
  dumpAssertions("pre-definition-expansion", assertions);
136
  // Apply substitutions first. If we are non-incremental, this has only the
137
  // effect of replacing defined functions with their definitions.
138
  // We do not call theory-specific expand definitions here, since we want
139
  // to give the opportunity to rewrite/preprocess terms before expansion.
140
12885
  d_passes["apply-substs"]->apply(&assertions);
141
25762
  Trace("smt-proc")
142
12881
      << "ProcessAssertions::processAssertions() : post-definition-expansion"
143
12881
      << endl;
144
12881
  dumpAssertions("post-definition-expansion", assertions);
145
146
12881
  Debug("smt") << " assertions     : " << assertions.size() << endl;
147
148
53402
  if (options::globalNegate())
149
  {
150
    // global negation of the formula
151
6
    d_passes["global-negate"]->apply(&assertions);
152
6
    as.flipGlobalNegated();
153
  }
154
155
25766
  if (options::nlExtPurify())
156
  {
157
6
    d_passes["nl-ext-purify"]->apply(&assertions);
158
  }
159
160
40065
  if (options::solveRealAsInt())
161
  {
162
13
    d_passes["real-to-int"]->apply(&assertions);
163
  }
164
165
12881
  if (options::solveIntAsBV() > 0)
166
  {
167
8
    d_passes["int-to-bv"]->apply(&assertions);
168
  }
169
170
44749
  if (options::ackermann())
171
  {
172
64
    d_passes["ackermann"]->apply(&assertions);
173
  }
174
175
2003626
  if (options::bvAbstraction())
176
  {
177
4
    d_passes["bv-abstraction"]->apply(&assertions);
178
  }
179
180
12881
  Debug("smt") << " assertions     : " << assertions.size() << endl;
181
182
12881
  bool noConflict = true;
183
184
25781
  if (options::extRewPrep())
185
  {
186
24
    d_passes["ext-rew-pre"]->apply(&assertions);
187
  }
188
189
  // Unconstrained simplification
190
62397
  if (options::unconstrainedSimp())
191
  {
192
182
    d_passes["rewrite"]->apply(&assertions);
193
182
    d_passes["unconstrained-simplifier"]->apply(&assertions);
194
  }
195
196
28178
  if (options::bvIntroducePow2())
197
  {
198
2
    d_passes["bv-intro-pow2"]->apply(&assertions);
199
  }
200
201
  // Lift bit-vectors of size 1 to bool
202
28483
  if (options::bitvectorToBool())
203
  {
204
155
    d_passes["bv-to-bool"]->apply(&assertions);
205
  }
206
12881
  if (options::solveBVAsInt() != options::SolveBVAsIntMode::OFF)
207
  {
208
187
    d_passes["bv-to-int"]->apply(&assertions);
209
  }
210
25764
  if (options::foreignTheoryRewrite())
211
  {
212
2
    d_passes["foreign-theory-rewrite"]->apply(&assertions);
213
  }
214
215
  // Since this pass is not robust for the information tracking necessary for
216
  // unsat cores, it's only applied if we are not doing unsat core computation
217
12881
  d_passes["apply-substs"]->apply(&assertions);
218
219
  // Assertions MUST BE guaranteed to be rewritten by this point
220
12881
  d_passes["rewrite"]->apply(&assertions);
221
222
  // Convert non-top-level Booleans to bit-vectors of size 1
223
12881
  if (options::boolToBitvector() != options::BoolToBVMode::OFF)
224
  {
225
12
    d_passes["bool-to-bv"]->apply(&assertions);
226
  }
227
25763
  if (options::sepPreSkolemEmp())
228
  {
229
1
    d_passes["sep-skolem-emp"]->apply(&assertions);
230
  }
231
232
12881
  if (d_smt.getLogicInfo().isQuantified())
233
  {
234
    // remove rewrite rules, apply pre-skolemization to existential quantifiers
235
7321
    d_passes["quantifiers-preprocess"]->apply(&assertions);
236
237
    // fmf-fun : assume admissible functions, applying preprocessing reduction
238
    // to FMF
239
24172
    if (options::fmfFunWellDefined())
240
    {
241
117
      d_passes["fun-def-fmf"]->apply(&assertions);
242
    }
243
  }
244
34225
  if (!options::stringLazyPreproc())
245
  {
246
36
    d_passes["strings-eager-pp"]->apply(&assertions);
247
  }
248
12881
  if (options::sortInference() || options::ufssFairnessMonotone())
249
  {
250
24
    d_passes["sort-inference"]->apply(&assertions);
251
  }
252
253
28178
  if (options::pbRewrites())
254
  {
255
2
    d_passes["pseudo-boolean-processor"]->apply(&assertions);
256
  }
257
258
  // rephrasing normal inputs as sygus problems
259
12881
  if (!d_smt.isInternalSubsolver())
260
  {
261
29551
    if (options::sygusInference())
262
    {
263
58
      d_passes["sygus-infer"]->apply(&assertions);
264
    }
265
27516
    else if (options::sygusRewSynthInput())
266
    {
267
      // do candidate rewrite rule synthesis
268
      d_passes["synth-rr"]->apply(&assertions);
269
    }
270
  }
271
272
25762
  Trace("smt-proc") << "ProcessAssertions::processAssertions() : pre-simplify"
273
12881
                    << endl;
274
12881
  dumpAssertions("pre-simplify", assertions);
275
12881
  Chat() << "simplifying assertions..." << endl;
276
12881
  noConflict = simplifyAssertions(assertions);
277
12881
  if (!noConflict)
278
  {
279
1045
    ++(d_smtStats.d_simplifiedToFalse);
280
  }
281
25762
  Trace("smt-proc") << "ProcessAssertions::processAssertions() : post-simplify"
282
12881
                    << endl;
283
12881
  dumpAssertions("post-simplify", assertions);
284
285
25762
  if (options::doStaticLearning())
286
  {
287
12881
    d_passes["static-learning"]->apply(&assertions);
288
  }
289
12881
  Debug("smt") << " assertions     : " << assertions.size() << endl;
290
291
25768
  if (options::earlyIteRemoval())
292
  {
293
2
    d_smtStats.d_numAssertionsPre += assertions.size();
294
2
    d_passes["ite-removal"]->apply(&assertions);
295
    // This is needed because when solving incrementally, removeITEs may
296
    // introduce skolems that were solved for earlier and thus appear in the
297
    // substitution map.
298
2
    d_passes["apply-substs"]->apply(&assertions);
299
2
    d_smtStats.d_numAssertionsPost += assertions.size();
300
  }
301
302
12881
  dumpAssertions("pre-repeat-simplify", assertions);
303
59170
  if (options::repeatSimp())
304
  {
305
490
    Trace("smt-proc")
306
245
        << "ProcessAssertions::processAssertions() : pre-repeat-simplify"
307
245
        << endl;
308
245
    Chat() << "re-simplifying assertions..." << endl;
309
490
    ScopeCounter depth(d_simplifyAssertionsDepth);
310
245
    noConflict &= simplifyAssertions(assertions);
311
490
    Trace("smt-proc")
312
245
        << "ProcessAssertions::processAssertions() : post-repeat-simplify"
313
245
        << endl;
314
  }
315
12881
  dumpAssertions("post-repeat-simplify", assertions);
316
317
12881
  if (options::ufHo())
318
  {
319
198
    d_passes["ho-elim"]->apply(&assertions);
320
  }
321
322
  // begin: INVARIANT to maintain: no reordering of assertions or
323
  // introducing new ones
324
325
12881
  Debug("smt") << " assertions     : " << assertions.size() << endl;
326
327
25762
  Debug("smt") << "ProcessAssertions::processAssertions() POST SIMPLIFICATION"
328
12881
               << endl;
329
12881
  Debug("smt") << " assertions     : " << assertions.size() << endl;
330
331
  // ensure rewritten
332
12881
  d_passes["rewrite"]->apply(&assertions);
333
  // rewrite equalities based on theory-specific rewriting
334
12881
  d_passes["theory-rewrite-eq"]->apply(&assertions);
335
  // apply theory preprocess, which includes ITE removal
336
12888
  d_passes["theory-preprocess"]->apply(&assertions);
337
  // notice that we do not apply substitutions as a last step here, since
338
  // the range of substitutions is not theory-preprocessed.
339
340
12874
  if (options::bitblastMode() == options::BitblastMode::EAGER)
341
  {
342
56
    d_passes["bv-eager-atoms"]->apply(&assertions);
343
  }
344
345
12874
  Trace("smt-proc") << "SmtEnginePrivate::processAssertions() end" << endl;
346
12874
  dumpAssertions("post-everything", assertions);
347
348
12874
  return noConflict;
349
}
350
351
// returns false if simplification led to "false"
352
13126
bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions)
353
{
354
13126
  spendResource(Resource::PreprocessStep);
355
  try
356
  {
357
25198
    ScopeCounter depth(d_simplifyAssertionsDepth);
358
359
13126
    Trace("simplify") << "SmtEnginePrivate::simplify()" << endl;
360
361
45445
    if (options::simplificationMode() != options::SimplificationMode::NONE)
362
    {
363
      // Perform non-clausal simplification
364
      PreprocessingPassResult res =
365
9815
          d_passes["non-clausal-simp"]->apply(&assertions);
366
9815
      if (res == PreprocessingPassResult::CONFLICT)
367
      {
368
1050
        return false;
369
      }
370
371
      // We piggy-back off of the BackEdgesMap in the CircuitPropagator to
372
      // do the miplib trick.
373
8765
      if (  // check that option is on
374
29053
          options::arithMLTrick() &&
375
          // only useful in arith
376
8773
          d_smt.getLogicInfo().isTheoryEnabled(THEORY_ARITH) &&
377
          // we add new assertions and need this (in practice, this
378
          // restriction only disables miplib processing during
379
          // re-simplification, which we don't expect to be useful anyway)
380
8
          assertions.getRealAssertionsEnd() == assertions.size())
381
      {
382
8
        d_passes["miplib-trick"]->apply(&assertions);
383
      }
384
      else
385
      {
386
17514
        Trace("simplify") << "SmtEnginePrivate::simplify(): "
387
8757
                          << "skipping miplib pseudobooleans pass..." << endl;
388
      }
389
    }
390
391
12076
    Debug("smt") << " assertions     : " << assertions.size() << endl;
392
393
    // ITE simplification
394
48105
    if (options::doITESimp()
395
12076
        && (d_simplifyAssertionsDepth <= 1 || options::doITESimpOnRepeat()))
396
    {
397
2
      PreprocessingPassResult res = d_passes["ite-simp"]->apply(&assertions);
398
2
      if (res == PreprocessingPassResult::CONFLICT)
399
      {
400
        Chat() << "...ITE simplification found unsat..." << endl;
401
        return false;
402
      }
403
    }
404
405
12076
    Debug("smt") << " assertions     : " << assertions.size() << endl;
406
407
    // Unconstrained simplification
408
12076
    if (options::unconstrainedSimp())
409
    {
410
333
      d_passes["unconstrained-simplifier"]->apply(&assertions);
411
    }
412
413
24152
    if (options::repeatSimp()
414
12076
        && options::simplificationMode() != options::SimplificationMode::NONE)
415
    {
416
      PreprocessingPassResult res =
417
462
          d_passes["non-clausal-simp"]->apply(&assertions);
418
462
      if (res == PreprocessingPassResult::CONFLICT)
419
      {
420
4
        return false;
421
      }
422
    }
423
424
12072
    dumpAssertions("post-repeatsimp", assertions);
425
12072
    Trace("smt") << "POST repeatSimp" << endl;
426
12072
    Debug("smt") << " assertions     : " << assertions.size() << endl;
427
  }
428
  catch (TypeCheckingExceptionPrivate& tcep)
429
  {
430
    // Calls to this function should have already weeded out any
431
    // typechecking exceptions via (e.g.) ensureBoolean().  But a
432
    // theory could still create a new expression that isn't
433
    // well-typed, and we don't want the C++ runtime to abort our
434
    // process without any error notice.
435
    InternalError()
436
        << "A bad expression was produced.  Original exception follows:\n"
437
        << tcep;
438
  }
439
12072
  return true;
440
}
441
442
115117
void ProcessAssertions::dumpAssertions(const char* key,
443
                                       const AssertionPipeline& assertionList)
444
{
445
115117
  if (Dump.isOn("assertions") && Dump.isOn(string("assertions:") + key))
446
  {
447
    // Push the simplified assertions to the dump output stream
448
    for (unsigned i = 0; i < assertionList.size(); ++i)
449
    {
450
      TNode n = assertionList[i];
451
      d_smt.getOutputManager().getPrinter().toStreamCmdAssert(
452
          d_smt.getOutputManager().getDumpOut(), n);
453
    }
454
  }
455
115117
}
456
457
}  // namespace smt
458
2502813
}  // namespace cvc5