GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine_state.cpp Lines: 126 141 89.4 %
Date: 2021-05-22 Branches: 92 253 36.4 %

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