GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_solver.cpp Lines: 87 98 88.8 %
Date: 2021-08-17 Branches: 139 286 48.6 %

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
10494
SmtSolver::SmtSolver(Env& env,
36
                     SmtEngineState& state,
37
                     Preprocessor& pp,
38
10494
                     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
10494
      d_propEngine(nullptr)
46
{
47
10494
}
48
49
10494
SmtSolver::~SmtSolver() {}
50
51
9850
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
9850
  d_theoryEngine.reset(new TheoryEngine(d_env));
56
57
  // Add the theories
58
137900
  for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST;
59
       ++id)
60
  {
61
128050
    theory::TheoryConstructor::addTheory(d_theoryEngine.get(), id);
62
  }
63
  // Add the proof checkers for each theory
64
9850
  if (d_pnm)
65
  {
66
3766
    d_theoryEngine->initializeProofChecker(d_pnm->getChecker());
67
  }
68
9850
  Trace("smt-debug") << "Making prop engine..." << std::endl;
69
  /* force destruction of referenced PropEngine to enforce that statistics
70
   * are unregistered by the obsolete PropEngine object before registered
71
   * again by the new PropEngine object */
72
9850
  d_propEngine.reset(nullptr);
73
9850
  d_propEngine.reset(new prop::PropEngine(d_theoryEngine.get(), d_env, d_pnm));
74
75
9850
  Trace("smt-debug") << "Setting up theory engine..." << std::endl;
76
9850
  d_theoryEngine->setPropEngine(getPropEngine());
77
9850
  Trace("smt-debug") << "Finishing init for theory engine..." << std::endl;
78
9850
  d_theoryEngine->finishInit();
79
9850
  d_propEngine->finishInit();
80
9850
}
81
82
67
void SmtSolver::resetAssertions()
83
{
84
  /* Create new PropEngine.
85
   * First force destruction of referenced PropEngine to enforce that
86
   * statistics are unregistered by the obsolete PropEngine object before
87
   * registered again by the new PropEngine object */
88
67
  d_propEngine.reset(nullptr);
89
67
  d_propEngine.reset(new prop::PropEngine(d_theoryEngine.get(), d_env, d_pnm));
90
67
  d_theoryEngine->setPropEngine(getPropEngine());
91
  // Notice that we do not reset TheoryEngine, nor does it require calling
92
  // finishInit again. In particular, TheoryEngine::finishInit does not
93
  // depend on knowing the associated PropEngine.
94
67
  d_propEngine->finishInit();
95
67
}
96
97
void SmtSolver::interrupt()
98
{
99
  if (d_propEngine != nullptr)
100
  {
101
    d_propEngine->interrupt();
102
  }
103
  if (d_theoryEngine != nullptr)
104
  {
105
    d_theoryEngine->interrupt();
106
  }
107
}
108
109
10494
void SmtSolver::shutdown()
110
{
111
10494
  if (d_propEngine != nullptr)
112
  {
113
9850
    d_propEngine->shutdown();
114
  }
115
10494
  if (d_theoryEngine != nullptr)
116
  {
117
9850
    d_theoryEngine->shutdown();
118
  }
119
10494
}
120
121
15215
Result SmtSolver::checkSatisfiability(Assertions& as,
122
                                      const std::vector<Node>& assumptions,
123
                                      bool isEntailmentCheck)
124
{
125
  // update the state to indicate we are about to run a check-sat
126
15215
  bool hasAssumptions = !assumptions.empty();
127
15215
  d_state.notifyCheckSat(hasAssumptions);
128
129
  // then, initialize the assertions
130
15215
  as.initializeCheckSat(assumptions, isEntailmentCheck);
131
132
  // make the check, where notice smt engine should be fully inited by now
133
134
15215
  Trace("smt") << "SmtSolver::check()" << endl;
135
136
15215
  const std::string& filename = d_state.getFilename();
137
15215
  ResourceManager* rm = d_env.getResourceManager();
138
15215
  if (rm->out())
139
  {
140
    Result::UnknownExplanation why =
141
        rm->outOfResources() ? Result::RESOURCEOUT : Result::TIMEOUT;
142
    return Result(Result::ENTAILMENT_UNKNOWN, why, filename);
143
  }
144
15215
  rm->beginCall();
145
146
  // Make sure the prop layer has all of the assertions
147
15215
  Trace("smt") << "SmtSolver::check(): processing assertions" << endl;
148
15215
  processAssertions(as);
149
15201
  Trace("smt") << "SmtSolver::check(): done processing assertions" << endl;
150
151
30402
  TimerStat::CodeTimer solveTimer(d_stats.d_solveTime);
152
153
15201
  Chat() << "solving..." << endl;
154
15201
  Trace("smt") << "SmtSolver::check(): running check" << endl;
155
30386
  Result result = d_propEngine->checkSat();
156
157
15185
  rm->endCall();
158
30370
  Trace("limit") << "SmtSolver::check(): cumulative millis "
159
30370
                 << rm->getTimeUsage() << ", resources "
160
15185
                 << rm->getResourceUsage() << endl;
161
162
45542
  if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
163
30397
      && result.asSatisfiabilityResult().isSat() == Result::UNSAT)
164
  {
165
6
    result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
166
  }
167
  // flipped if we did a global negation
168
15185
  if (as.isGlobalNegated())
169
  {
170
6
    Trace("smt") << "SmtSolver::process global negate " << result << std::endl;
171
6
    if (result.asSatisfiabilityResult().isSat() == Result::UNSAT)
172
    {
173
4
      result = Result(Result::SAT);
174
    }
175
2
    else if (result.asSatisfiabilityResult().isSat() == Result::SAT)
176
    {
177
      // Only can answer unsat if the theory is satisfaction complete. This
178
      // includes linear arithmetic and bitvectors, which are the primary
179
      // targets for the global negate option. Other logics are possible here
180
      // but not considered.
181
4
      LogicInfo logic = d_env.getLogicInfo();
182
2
      if ((logic.isPure(theory::THEORY_ARITH) && logic.isLinear()) ||
183
          logic.isPure(theory::THEORY_BV))
184
      {
185
2
        result = Result(Result::UNSAT);
186
      }
187
      else
188
      {
189
        result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
190
      }
191
    }
192
6
    Trace("smt") << "SmtSolver::global negate returned " << result << std::endl;
193
  }
194
195
  // set the filename on the result
196
30370
  Result r = Result(result, filename);
197
198
  // notify our state of the check-sat result
199
15185
  d_state.notifyCheckSatResult(hasAssumptions, r);
200
201
15185
  return r;
202
}
203
204
24188
void SmtSolver::processAssertions(Assertions& as)
205
{
206
37935
  TimerStat::CodeTimer paTimer(d_stats.d_processAssertionsTime);
207
24188
  d_env.getResourceManager()->spendResource(Resource::PreprocessStep);
208
24188
  Assert(d_state.isFullyReady());
209
210
24188
  preprocessing::AssertionPipeline& ap = as.getAssertionPipeline();
211
212
24188
  if (ap.size() == 0)
213
  {
214
    // nothing to do
215
10441
    return;
216
  }
217
218
  // process the assertions with the preprocessor
219
13747
  d_pp.process(as);
220
221
  // end: INVARIANT to maintain: no reordering of assertions or
222
  // introducing new ones
223
224
  // Push the formula to SAT
225
  {
226
13737
    Chat() << "converting to CNF..." << endl;
227
13737
    const std::vector<Node>& assertions = ap.ref();
228
    // It is important to distinguish the input assertions from the skolem
229
    // definitions, as the decision justification heuristic treates the latter
230
    // specially.
231
13737
    preprocessing::IteSkolemMap& ism = ap.getIteSkolemMap();
232
13737
    d_propEngine->assertInputFormulas(assertions, ism);
233
  }
234
235
  // clear the current assertions
236
13733
  as.clearCurrent();
237
}
238
239
3766
void SmtSolver::setProofNodeManager(ProofNodeManager* pnm) { d_pnm = pnm; }
240
241
358732
TheoryEngine* SmtSolver::getTheoryEngine() { return d_theoryEngine.get(); }
242
243
66107
prop::PropEngine* SmtSolver::getPropEngine() { return d_propEngine.get(); }
244
245
374
theory::QuantifiersEngine* SmtSolver::getQuantifiersEngine()
246
{
247
374
  Assert(d_theoryEngine != nullptr);
248
374
  return d_theoryEngine->getQuantifiersEngine();
249
}
250
251
Preprocessor* SmtSolver::getPreprocessor() { return &d_pp; }
252
253
}  // namespace smt
254
29337
}  // namespace cvc5