GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine_state.cpp Lines: 126 141 89.4 %
Date: 2021-08-06 Branches: 92 251 36.7 %

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