GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine_state.cpp Lines: 124 137 90.5 %
Date: 2021-09-15 Branches: 93 251 37.1 %

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/smt_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/smt_engine.h"
25
26
namespace cvc5 {
27
namespace smt {
28
29
13209
SmtEngineState::SmtEngineState(Env& env, SmtEngine& smt)
30
    : d_smt(smt),
31
      d_env(env),
32
      d_pendingPops(0),
33
      d_fullyInited(false),
34
      d_queryMade(false),
35
      d_needPostsolve(false),
36
      d_status(),
37
      d_expectedStatus(),
38
13209
      d_smtMode(SmtMode::START)
39
{
40
13209
}
41
42
3694
void SmtEngineState::notifyExpectedStatus(const std::string& status)
43
{
44
3694
  Assert(status == "sat" || status == "unsat" || status == "unknown")
45
      << "SmtEngineState::notifyExpectedStatus: unexpected status string "
46
      << status;
47
3694
  d_expectedStatus = Result(status, d_env.getOptions().driver.filename);
48
3694
}
49
50
67
void SmtEngineState::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 && getUserContext()->getLevel() == 1);
60
67
  popto(0);
61
67
}
62
63
15278
void SmtEngineState::notifyCheckSat(bool hasAssumptions)
64
{
65
  // process the pending pops
66
15278
  doPendingPops();
67
15278
  if (d_queryMade && !options::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
15278
  d_queryMade = true;
77
15278
  d_smtMode = SmtMode::ASSERT;
78
79
  // push if there are assumptions
80
15278
  if (hasAssumptions)
81
  {
82
2457
    internalPush();
83
  }
84
15278
}
85
86
15248
void SmtEngineState::notifyCheckSatResult(bool hasAssumptions, Result r)
87
{
88
15248
  d_needPostsolve = true;
89
90
  // Pop the context
91
15248
  if (hasAssumptions)
92
  {
93
2443
    internalPop();
94
  }
95
96
  // Remember the status
97
15248
  d_status = r;
98
  // Check against expected status
99
34126
  if (!d_expectedStatus.isUnknown() && !d_status.isUnknown()
100
18875
      && d_status != d_expectedStatus)
101
  {
102
    CVC5_FATAL() << "Expected result " << d_expectedStatus << " but got "
103
                 << d_status;
104
  }
105
  // clear expected status
106
15248
  d_expectedStatus = Result();
107
  // Update the SMT mode
108
15248
  switch (d_status.asSatisfiabilityResult().isSat())
109
  {
110
7751
    case Result::UNSAT: d_smtMode = SmtMode::UNSAT; break;
111
7378
    case Result::SAT: d_smtMode = SmtMode::SAT; break;
112
119
    default: d_smtMode = SmtMode::SAT_UNKNOWN;
113
  }
114
15248
}
115
116
14
void SmtEngineState::notifyGetAbduct(bool success)
117
{
118
14
  if (success)
119
  {
120
    // successfully generated an abduct, update to abduct state
121
14
    d_smtMode = SmtMode::ABDUCT;
122
  }
123
  else
124
  {
125
    // failed, we revert to the assert state
126
    d_smtMode = SmtMode::ASSERT;
127
  }
128
14
}
129
130
10
void SmtEngineState::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
10009
void SmtEngineState::setup()
145
{
146
  // push a context
147
10009
  push();
148
10009
}
149
150
9942
void SmtEngineState::finishInit()
151
{
152
  // set the flag to remember that we are fully initialized
153
9942
  d_fullyInited = true;
154
9942
}
155
156
10562
void SmtEngineState::shutdown()
157
{
158
10562
  doPendingPops();
159
160
11608
  while (options::incrementalSolving() && getUserContext()->getLevel() > 1)
161
  {
162
523
    internalPop(true);
163
  }
164
10562
}
165
166
10562
void SmtEngineState::cleanup()
167
{
168
  // pop to level zero
169
10562
  popto(0);
170
10562
}
171
172
4036
void SmtEngineState::userPush()
173
{
174
4036
  if (!options::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
4036
  d_smtMode = SmtMode::ASSERT;
183
184
4036
  d_userLevels.push_back(getUserContext()->getLevel());
185
4036
  internalPush();
186
8072
  Trace("userpushpop") << "SmtEngineState: pushed to level "
187
4036
                       << getUserContext()->getLevel() << std::endl;
188
4036
}
189
190
3513
void SmtEngineState::userPop()
191
{
192
3513
  if (!options::incrementalSolving())
193
  {
194
    throw ModalException(
195
        "Cannot pop when not solving incrementally (use --incremental)");
196
  }
197
3513
  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
3513
  d_smtMode = SmtMode::ASSERT;
208
209
3513
  AlwaysAssert(getUserContext()->getLevel() > 0);
210
3513
  AlwaysAssert(d_userLevels.back() < getUserContext()->getLevel());
211
10539
  while (d_userLevels.back() < getUserContext()->getLevel())
212
  {
213
3513
    internalPop(true);
214
  }
215
3513
  d_userLevels.pop_back();
216
3513
}
217
20638
context::Context* SmtEngineState::getContext() { return d_env.getContext(); }
218
55910
context::UserContext* SmtEngineState::getUserContext()
219
{
220
55910
  return d_env.getUserContext();
221
}
222
10009
void SmtEngineState::push()
223
{
224
10009
  getUserContext()->push();
225
10009
  getContext()->push();
226
10009
}
227
228
void SmtEngineState::pop()
229
{
230
  getUserContext()->pop();
231
  getContext()->pop();
232
}
233
234
10629
void SmtEngineState::popto(int toLevel)
235
{
236
10629
  getContext()->popto(toLevel);
237
10629
  getUserContext()->popto(toLevel);
238
10629
}
239
240
11
Result SmtEngineState::getStatus() const { return d_status; }
241
242
269592
bool SmtEngineState::isFullyInited() const { return d_fullyInited; }
243
24251
bool SmtEngineState::isFullyReady() const
244
{
245
24251
  return d_fullyInited && d_pendingPops == 0;
246
}
247
11005
bool SmtEngineState::isQueryMade() const { return d_queryMade; }
248
2825
size_t SmtEngineState::getNumUserLevels() const { return d_userLevels.size(); }
249
250
6544
SmtMode SmtEngineState::getMode() const { return d_smtMode; }
251
252
6493
void SmtEngineState::internalPush()
253
{
254
6493
  Assert(d_fullyInited);
255
6493
  Trace("smt") << "SmtEngineState::internalPush()" << std::endl;
256
6493
  doPendingPops();
257
6493
  if (options::incrementalSolving())
258
  {
259
    // notifies the SmtEngine to process the assertions immediately
260
4869
    d_smt.notifyPushPre();
261
4869
    getUserContext()->push();
262
    // the context push is done inside of the SAT solver
263
4869
    d_smt.notifyPushPost();
264
  }
265
6493
}
266
267
6479
void SmtEngineState::internalPop(bool immediate)
268
{
269
6479
  Assert(d_fullyInited);
270
6479
  Trace("smt") << "SmtEngineState::internalPop()" << std::endl;
271
6479
  if (options::incrementalSolving())
272
  {
273
4869
    ++d_pendingPops;
274
  }
275
6479
  if (immediate)
276
  {
277
4036
    doPendingPops();
278
  }
279
6479
}
280
281
132596
void SmtEngineState::doPendingPops()
282
{
283
132596
  Trace("smt") << "SmtEngineState::doPendingPops()" << std::endl;
284
132596
  Assert(d_pendingPops == 0 || options::incrementalSolving());
285
  // check to see if a postsolve() is pending
286
132596
  if (d_needPostsolve)
287
  {
288
15248
    d_smt.notifyPostSolvePre();
289
  }
290
142334
  while (d_pendingPops > 0)
291
  {
292
    // the context pop is done inside of the SAT solver
293
4869
    d_smt.notifyPopPre();
294
    // pop the context
295
4869
    getUserContext()->pop();
296
4869
    --d_pendingPops;
297
    // no need for pop post (for now)
298
  }
299
132596
  if (d_needPostsolve)
300
  {
301
15248
    d_smt.notifyPostSolvePost();
302
15248
    d_needPostsolve = false;
303
  }
304
132596
}
305
306
}  // namespace smt
307
29577
}  // namespace cvc5