GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_solver.cpp Lines: 91 102 89.2 %
Date: 2021-08-14 Branches: 143 290 49.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Aina Niemetz, Morgan Deters
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
 * The solver for SMT queries in an SmtEngine.
14
 */
15
16
#include "smt/smt_solver.h"
17
18
#include "options/smt_options.h"
19
#include "prop/prop_engine.h"
20
#include "smt/assertions.h"
21
#include "smt/env.h"
22
#include "smt/preprocessor.h"
23
#include "smt/smt_engine.h"
24
#include "smt/smt_engine_state.h"
25
#include "smt/smt_engine_stats.h"
26
#include "theory/logic_info.h"
27
#include "theory/theory_engine.h"
28
#include "theory/theory_traits.h"
29
30
using namespace std;
31
32
namespace cvc5 {
33
namespace smt {
34
35
10497
SmtSolver::SmtSolver(Env& env,
36
                     SmtEngineState& state,
37
                     Preprocessor& pp,
38
10497
                     SmtEngineStatistics& stats)
39
    : d_env(env),
40
      d_state(state),
41
      d_pp(pp),
42
      d_stats(stats),
43
      d_pnm(nullptr),
44
      d_theoryEngine(nullptr),
45
10497
      d_propEngine(nullptr)
46
{
47
10497
}
48
49
10497
SmtSolver::~SmtSolver() {}
50
51
9853
void SmtSolver::finishInit(const LogicInfo& logicInfo)
52
{
53
  // We have mutual dependency here, so we add the prop engine to the theory
54
  // engine later (it is non-essential there)
55
19706
  d_theoryEngine.reset(new TheoryEngine(
56
      d_env,
57
      // Other than whether d_pm is set, theory engine proofs are conditioned on
58
      // the relationshup between proofs and unsat cores: the unsat cores are in
59
      // FULL_PROOF mode, no proofs are generated on theory engine.
60
9853
      (options::unsatCores()
61
3773
       && options::unsatCoresMode() != options::UnsatCoresMode::FULL_PROOF)
62
17178
          ? nullptr
63
9853
          : d_pnm));
64
65
  // Add the theories
66
137942
  for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST;
67
       ++id)
68
  {
69
128089
    theory::TheoryConstructor::addTheory(d_theoryEngine.get(), id);
70
  }
71
  // Add the proof checkers for each theory
72
9853
  if (d_pnm)
73
  {
74
3768
    d_theoryEngine->initializeProofChecker(d_pnm->getChecker());
75
  }
76
9853
  Trace("smt-debug") << "Making prop engine..." << std::endl;
77
  /* force destruction of referenced PropEngine to enforce that statistics
78
   * are unregistered by the obsolete PropEngine object before registered
79
   * again by the new PropEngine object */
80
9853
  d_propEngine.reset(nullptr);
81
9853
  d_propEngine.reset(new prop::PropEngine(d_theoryEngine.get(), d_env, d_pnm));
82
83
9853
  Trace("smt-debug") << "Setting up theory engine..." << std::endl;
84
9853
  d_theoryEngine->setPropEngine(getPropEngine());
85
9853
  Trace("smt-debug") << "Finishing init for theory engine..." << std::endl;
86
9853
  d_theoryEngine->finishInit();
87
9853
  d_propEngine->finishInit();
88
9853
}
89
90
67
void SmtSolver::resetAssertions()
91
{
92
  /* Create new PropEngine.
93
   * First force destruction of referenced PropEngine to enforce that
94
   * statistics are unregistered by the obsolete PropEngine object before
95
   * registered again by the new PropEngine object */
96
67
  d_propEngine.reset(nullptr);
97
67
  d_propEngine.reset(new prop::PropEngine(d_theoryEngine.get(), d_env, d_pnm));
98
67
  d_theoryEngine->setPropEngine(getPropEngine());
99
  // Notice that we do not reset TheoryEngine, nor does it require calling
100
  // finishInit again. In particular, TheoryEngine::finishInit does not
101
  // depend on knowing the associated PropEngine.
102
67
  d_propEngine->finishInit();
103
67
}
104
105
void SmtSolver::interrupt()
106
{
107
  if (d_propEngine != nullptr)
108
  {
109
    d_propEngine->interrupt();
110
  }
111
  if (d_theoryEngine != nullptr)
112
  {
113
    d_theoryEngine->interrupt();
114
  }
115
}
116
117
10497
void SmtSolver::shutdown()
118
{
119
10497
  if (d_propEngine != nullptr)
120
  {
121
9853
    d_propEngine->shutdown();
122
  }
123
10497
  if (d_theoryEngine != nullptr)
124
  {
125
9853
    d_theoryEngine->shutdown();
126
  }
127
10497
}
128
129
15218
Result SmtSolver::checkSatisfiability(Assertions& as,
130
                                      const std::vector<Node>& assumptions,
131
                                      bool isEntailmentCheck)
132
{
133
  // update the state to indicate we are about to run a check-sat
134
15218
  bool hasAssumptions = !assumptions.empty();
135
15218
  d_state.notifyCheckSat(hasAssumptions);
136
137
  // then, initialize the assertions
138
15218
  as.initializeCheckSat(assumptions, isEntailmentCheck);
139
140
  // make the check, where notice smt engine should be fully inited by now
141
142
15218
  Trace("smt") << "SmtSolver::check()" << endl;
143
144
15218
  const std::string& filename = d_state.getFilename();
145
15218
  ResourceManager* rm = d_env.getResourceManager();
146
15218
  if (rm->out())
147
  {
148
    Result::UnknownExplanation why =
149
        rm->outOfResources() ? Result::RESOURCEOUT : Result::TIMEOUT;
150
    return Result(Result::ENTAILMENT_UNKNOWN, why, filename);
151
  }
152
15218
  rm->beginCall();
153
154
  // Make sure the prop layer has all of the assertions
155
15218
  Trace("smt") << "SmtSolver::check(): processing assertions" << endl;
156
15218
  processAssertions(as);
157
15204
  Trace("smt") << "SmtSolver::check(): done processing assertions" << endl;
158
159
30408
  TimerStat::CodeTimer solveTimer(d_stats.d_solveTime);
160
161
15204
  Chat() << "solving..." << endl;
162
15204
  Trace("smt") << "SmtSolver::check(): running check" << endl;
163
30392
  Result result = d_propEngine->checkSat();
164
165
15188
  rm->endCall();
166
30376
  Trace("limit") << "SmtSolver::check(): cumulative millis "
167
30376
                 << rm->getTimeUsage() << ", resources "
168
15188
                 << rm->getResourceUsage() << endl;
169
170
45551
  if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
171
30403
      && result.asSatisfiabilityResult().isSat() == Result::UNSAT)
172
  {
173
6
    result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
174
  }
175
  // flipped if we did a global negation
176
15188
  if (as.isGlobalNegated())
177
  {
178
6
    Trace("smt") << "SmtSolver::process global negate " << result << std::endl;
179
6
    if (result.asSatisfiabilityResult().isSat() == Result::UNSAT)
180
    {
181
4
      result = Result(Result::SAT);
182
    }
183
2
    else if (result.asSatisfiabilityResult().isSat() == Result::SAT)
184
    {
185
      // Only can answer unsat if the theory is satisfaction complete. This
186
      // includes linear arithmetic and bitvectors, which are the primary
187
      // targets for the global negate option. Other logics are possible here
188
      // but not considered.
189
4
      LogicInfo logic = d_env.getLogicInfo();
190
2
      if ((logic.isPure(theory::THEORY_ARITH) && logic.isLinear()) ||
191
          logic.isPure(theory::THEORY_BV))
192
      {
193
2
        result = Result(Result::UNSAT);
194
      }
195
      else
196
      {
197
        result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
198
      }
199
    }
200
6
    Trace("smt") << "SmtSolver::global negate returned " << result << std::endl;
201
  }
202
203
  // set the filename on the result
204
30376
  Result r = Result(result, filename);
205
206
  // notify our state of the check-sat result
207
15188
  d_state.notifyCheckSatResult(hasAssumptions, r);
208
209
15188
  return r;
210
}
211
212
24191
void SmtSolver::processAssertions(Assertions& as)
213
{
214
37941
  TimerStat::CodeTimer paTimer(d_stats.d_processAssertionsTime);
215
24191
  d_env.getResourceManager()->spendResource(Resource::PreprocessStep);
216
24191
  Assert(d_state.isFullyReady());
217
218
24191
  preprocessing::AssertionPipeline& ap = as.getAssertionPipeline();
219
220
24191
  if (ap.size() == 0)
221
  {
222
    // nothing to do
223
10441
    return;
224
  }
225
226
  // process the assertions with the preprocessor
227
13750
  d_pp.process(as);
228
229
  // end: INVARIANT to maintain: no reordering of assertions or
230
  // introducing new ones
231
232
  // Push the formula to SAT
233
  {
234
13740
    Chat() << "converting to CNF..." << endl;
235
13740
    const std::vector<Node>& assertions = ap.ref();
236
    // It is important to distinguish the input assertions from the skolem
237
    // definitions, as the decision justification heuristic treates the latter
238
    // specially.
239
13740
    preprocessing::IteSkolemMap& ism = ap.getIteSkolemMap();
240
13740
    d_propEngine->assertInputFormulas(assertions, ism);
241
  }
242
243
  // clear the current assertions
244
13736
  as.clearCurrent();
245
}
246
247
3768
void SmtSolver::setProofNodeManager(ProofNodeManager* pnm) { d_pnm = pnm; }
248
249
358718
TheoryEngine* SmtSolver::getTheoryEngine() { return d_theoryEngine.get(); }
250
251
66120
prop::PropEngine* SmtSolver::getPropEngine() { return d_propEngine.get(); }
252
253
374
theory::QuantifiersEngine* SmtSolver::getQuantifiersEngine()
254
{
255
374
  Assert(d_theoryEngine != nullptr);
256
374
  return d_theoryEngine->getQuantifiersEngine();
257
}
258
259
Preprocessor* SmtSolver::getPreprocessor() { return &d_pp; }
260
261
}  // namespace smt
262
29340
}  // namespace cvc5