GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/solver_engine_state.cpp Lines: 123 135 91.1 %
Date: 2021-11-07 Branches: 94 251 37.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Ying Sheng
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
 * Utility for maintaining the state of the SMT engine.
14
 */
15
16
#include "smt/solver_engine_state.h"
17
18
#include "base/modal_exception.h"
19
#include "options/base_options.h"
20
#include "options/main_options.h"
21
#include "options/option_exception.h"
22
#include "options/smt_options.h"
23
#include "smt/env.h"
24
#include "smt/solver_engine.h"
25
26
namespace cvc5 {
27
namespace smt {
28
29
18633
SolverEngineState::SolverEngineState(Env& env, SolverEngine& slv)
30
    : EnvObj(env),
31
      d_slv(slv),
32
      d_pendingPops(0),
33
      d_fullyInited(false),
34
      d_queryMade(false),
35
      d_needPostsolve(false),
36
      d_status(),
37
      d_expectedStatus(),
38
18633
      d_smtMode(SmtMode::START)
39
{
40
18633
}
41
42
3827
void SolverEngineState::notifyExpectedStatus(const std::string& status)
43
{
44
3827
  Assert(status == "sat" || status == "unsat" || status == "unknown")
45
      << "SolverEngineState::notifyExpectedStatus: unexpected status string "
46
      << status;
47
3827
  d_expectedStatus = Result(status, options().driver.filename);
48
3827
}
49
50
67
void SolverEngineState::notifyResetAssertions()
51
{
52
67
  doPendingPops();
53
99
  while (!d_userLevels.empty())
54
  {
55
16
    userPop();
56
  }
57
  // Remember the global push/pop around everything when beyond Start mode
58
  // (see solver execution modes in the SMT-LIB standard)
59
67
  Assert(d_userLevels.size() == 0 && userContext()->getLevel() == 1);
60
67
  popto(0);
61
67
}
62
63
20579
void SolverEngineState::notifyCheckSat(bool hasAssumptions)
64
{
65
  // process the pending pops
66
20579
  doPendingPops();
67
20579
  if (d_queryMade && !options().base.incrementalSolving)
68
  {
69
    throw ModalException(
70
        "Cannot make multiple queries unless "
71
        "incremental solving is enabled "
72
        "(try --incremental)");
73
  }
74
75
  // Note that a query has been made and we are in assert mode
76
20579
  d_queryMade = true;
77
20579
  d_smtMode = SmtMode::ASSERT;
78
79
  // push if there are assumptions
80
20579
  if (hasAssumptions)
81
  {
82
2574
    internalPush();
83
  }
84
20579
}
85
86
20537
void SolverEngineState::notifyCheckSatResult(bool hasAssumptions, Result r)
87
{
88
20537
  d_needPostsolve = true;
89
90
  // Pop the context
91
20537
  if (hasAssumptions)
92
  {
93
2554
    internalPop();
94
  }
95
96
  // Remember the status
97
20537
  d_status = r;
98
  // Check against expected status
99
44837
  if (!d_expectedStatus.isUnknown() && !d_status.isUnknown()
100
24297
      && d_status != d_expectedStatus)
101
  {
102
    CVC5_FATAL() << "Expected result " << d_expectedStatus << " but got "
103
                 << d_status;
104
  }
105
  // clear expected status
106
20537
  d_expectedStatus = Result();
107
  // Update the SMT mode
108
20537
  switch (d_status.asSatisfiabilityResult().isSat())
109
  {
110
10849
    case Result::UNSAT: d_smtMode = SmtMode::UNSAT; break;
111
9532
    case Result::SAT: d_smtMode = SmtMode::SAT; break;
112
156
    default: d_smtMode = SmtMode::SAT_UNKNOWN;
113
  }
114
20537
}
115
116
38
void SolverEngineState::notifyGetAbduct(bool success)
117
{
118
38
  if (success)
119
  {
120
    // successfully generated an abduct, update to abduct state
121
34
    d_smtMode = SmtMode::ABDUCT;
122
  }
123
  else
124
  {
125
    // failed, we revert to the assert state
126
4
    d_smtMode = SmtMode::ASSERT;
127
  }
128
38
}
129
130
10
void SolverEngineState::notifyGetInterpol(bool success)
131
{
132
10
  if (success)
133
  {
134
    // successfully generated an interpolant, update to interpol state
135
10
    d_smtMode = SmtMode::INTERPOL;
136
  }
137
  else
138
  {
139
    // failed, we revert to the assert state
140
    d_smtMode = SmtMode::ASSERT;
141
  }
142
10
}
143
144
15340
void SolverEngineState::setup()
145
{
146
  // push a context
147
15340
  push();
148
15340
}
149
150
15273
void SolverEngineState::finishInit()
151
{
152
  // set the flag to remember that we are fully initialized
153
15273
  d_fullyInited = true;
154
15273
}
155
156
15884
void SolverEngineState::shutdown()
157
{
158
15884
  doPendingPops();
159
160
16964
  while (options().base.incrementalSolving && userContext()->getLevel() > 1)
161
  {
162
540
    internalPop(true);
163
  }
164
15884
}
165
166
15884
void SolverEngineState::cleanup()
167
{
168
  // pop to level zero
169
15884
  popto(0);
170
15884
}
171
172
4112
void SolverEngineState::userPush()
173
{
174
4112
  if (!options().base.incrementalSolving)
175
  {
176
    throw ModalException(
177
        "Cannot push when not solving incrementally (use --incremental)");
178
  }
179
  // The problem isn't really "extended" yet, but this disallows
180
  // get-model after a push, simplifying our lives somewhat and
181
  // staying symmetric with pop.
182
4112
  d_smtMode = SmtMode::ASSERT;
183
184
4112
  d_userLevels.push_back(userContext()->getLevel());
185
4112
  internalPush();
186
8224
  Trace("userpushpop") << "SolverEngineState: pushed to level "
187
4112
                       << userContext()->getLevel() << std::endl;
188
4112
}
189
190
3574
void SolverEngineState::userPop()
191
{
192
3574
  if (!options().base.incrementalSolving)
193
  {
194
    throw ModalException(
195
        "Cannot pop when not solving incrementally (use --incremental)");
196
  }
197
3574
  if (d_userLevels.size() == 0)
198
  {
199
    throw ModalException("Cannot pop beyond the first user frame");
200
  }
201
  // The problem isn't really "extended" yet, but this disallows
202
  // get-model after a pop, simplifying our lives somewhat.  It might
203
  // not be strictly necessary to do so, since the pops occur lazily,
204
  // but also it would be weird to have a legally-executed (get-model)
205
  // that only returns a subset of the assignment (because the rest
206
  // is no longer in scope!).
207
3574
  d_smtMode = SmtMode::ASSERT;
208
209
3574
  AlwaysAssert(userContext()->getLevel() > 0);
210
3574
  AlwaysAssert(d_userLevels.back() < userContext()->getLevel());
211
10722
  while (d_userLevels.back() < userContext()->getLevel())
212
  {
213
3574
    internalPop(true);
214
  }
215
3574
  d_userLevels.pop_back();
216
3574
}
217
15340
void SolverEngineState::push()
218
{
219
15340
  userContext()->push();
220
15340
  context()->push();
221
15340
}
222
223
void SolverEngineState::pop()
224
{
225
  userContext()->pop();
226
  context()->pop();
227
}
228
229
15951
void SolverEngineState::popto(int toLevel)
230
{
231
15951
  context()->popto(toLevel);
232
15951
  userContext()->popto(toLevel);
233
15951
}
234
235
11
Result SolverEngineState::getStatus() const { return d_status; }
236
237
313979
bool SolverEngineState::isFullyInited() const { return d_fullyInited; }
238
29698
bool SolverEngineState::isFullyReady() const
239
{
240
29698
  return d_fullyInited && d_pendingPops == 0;
241
}
242
11200
bool SolverEngineState::isQueryMade() const { return d_queryMade; }
243
2886
size_t SolverEngineState::getNumUserLevels() const
244
{
245
2886
  return d_userLevels.size();
246
}
247
248
16896
SmtMode SolverEngineState::getMode() const { return d_smtMode; }
249
250
6686
void SolverEngineState::internalPush()
251
{
252
6686
  Assert(d_fullyInited);
253
6686
  Trace("smt") << "SolverEngineState::internalPush()" << std::endl;
254
6686
  doPendingPops();
255
6686
  if (options().base.incrementalSolving)
256
  {
257
    // notifies the SolverEngine to process the assertions immediately
258
4937
    d_slv.notifyPushPre();
259
4937
    userContext()->push();
260
    // the context push is done inside of the SAT solver
261
4937
    d_slv.notifyPushPost();
262
  }
263
6686
}
264
265
6668
void SolverEngineState::internalPop(bool immediate)
266
{
267
6668
  Assert(d_fullyInited);
268
6668
  Trace("smt") << "SolverEngineState::internalPop()" << std::endl;
269
6668
  if (options().base.incrementalSolving)
270
  {
271
4937
    ++d_pendingPops;
272
  }
273
6668
  if (immediate)
274
  {
275
4114
    doPendingPops();
276
  }
277
6668
}
278
279
156588
void SolverEngineState::doPendingPops()
280
{
281
156588
  Trace("smt") << "SolverEngineState::doPendingPops()" << std::endl;
282
156588
  Assert(d_pendingPops == 0 || options().base.incrementalSolving);
283
  // check to see if a postsolve() is pending
284
156588
  if (d_needPostsolve)
285
  {
286
20537
    d_slv.notifyPostSolvePre();
287
  }
288
166462
  while (d_pendingPops > 0)
289
  {
290
    // the context pop is done inside of the SAT solver
291
4937
    d_slv.notifyPopPre();
292
    // pop the context
293
4937
    userContext()->pop();
294
4937
    --d_pendingPops;
295
    // no need for pop post (for now)
296
  }
297
156588
  if (d_needPostsolve)
298
  {
299
20537
    d_slv.notifyPostSolvePost();
300
20537
    d_needPostsolve = false;
301
  }
302
156588
}
303
304
}  // namespace smt
305
31137
}  // namespace cvc5