GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 850 1026 82.8 %
Date: 2021-08-04 Branches: 1233 3251 37.9 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Abdalrhman Mohamed
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 main entry point into the cvc5 library's SMT interface.
14
 */
15
16
#include "smt/smt_engine.h"
17
18
#include "base/check.h"
19
#include "base/exception.h"
20
#include "base/modal_exception.h"
21
#include "base/output.h"
22
#include "decision/decision_engine.h"
23
#include "expr/bound_var_manager.h"
24
#include "expr/node.h"
25
#include "options/base_options.h"
26
#include "options/expr_options.h"
27
#include "options/language.h"
28
#include "options/main_options.h"
29
#include "options/option_exception.h"
30
#include "options/options_public.h"
31
#include "options/parser_options.h"
32
#include "options/printer_options.h"
33
#include "options/proof_options.h"
34
#include "options/smt_options.h"
35
#include "options/theory_options.h"
36
#include "printer/printer.h"
37
#include "proof/unsat_core.h"
38
#include "prop/prop_engine.h"
39
#include "smt/abduction_solver.h"
40
#include "smt/abstract_values.h"
41
#include "smt/assertions.h"
42
#include "smt/check_models.h"
43
#include "smt/dump.h"
44
#include "smt/dump_manager.h"
45
#include "smt/env.h"
46
#include "smt/interpolation_solver.h"
47
#include "smt/listeners.h"
48
#include "smt/logic_exception.h"
49
#include "smt/model_blocker.h"
50
#include "smt/model_core_builder.h"
51
#include "smt/node_command.h"
52
#include "smt/options_manager.h"
53
#include "smt/preprocessor.h"
54
#include "smt/proof_manager.h"
55
#include "smt/quant_elim_solver.h"
56
#include "smt/smt_engine_scope.h"
57
#include "smt/smt_engine_state.h"
58
#include "smt/smt_engine_stats.h"
59
#include "smt/smt_solver.h"
60
#include "smt/sygus_solver.h"
61
#include "smt/unsat_core_manager.h"
62
#include "theory/quantifiers/instantiation_list.h"
63
#include "theory/quantifiers/quantifiers_attributes.h"
64
#include "theory/quantifiers_engine.h"
65
#include "theory/rewriter.h"
66
#include "theory/smt_engine_subsolver.h"
67
#include "theory/theory_engine.h"
68
#include "util/random.h"
69
#include "util/rational.h"
70
#include "util/resource_manager.h"
71
#include "util/sexpr.h"
72
#include "util/statistics_registry.h"
73
74
// required for hacks related to old proofs for unsat cores
75
#include "base/configuration.h"
76
#include "base/configuration_private.h"
77
78
using namespace std;
79
using namespace cvc5::smt;
80
using namespace cvc5::preprocessing;
81
using namespace cvc5::prop;
82
using namespace cvc5::context;
83
using namespace cvc5::theory;
84
85
namespace cvc5 {
86
87
10484
SmtEngine::SmtEngine(NodeManager* nm, Options* optr)
88
10484
    : d_env(new Env(nm, optr)),
89
10484
      d_state(new SmtEngineState(getContext(), getUserContext(), *this)),
90
10484
      d_absValues(new AbstractValues(getNodeManager())),
91
10484
      d_asserts(new Assertions(*d_env.get(), *d_absValues.get())),
92
10484
      d_routListener(new ResourceOutListener(*this)),
93
10484
      d_snmListener(new SmtNodeManagerListener(*getDumpManager(), d_outMgr)),
94
      d_smtSolver(nullptr),
95
      d_model(nullptr),
96
      d_checkModels(nullptr),
97
      d_pfManager(nullptr),
98
      d_ucManager(nullptr),
99
      d_sygusSolver(nullptr),
100
      d_abductSolver(nullptr),
101
      d_interpolSolver(nullptr),
102
      d_quantElimSolver(nullptr),
103
      d_isInternalSubsolver(false),
104
      d_stats(nullptr),
105
      d_outMgr(this),
106
      d_optm(nullptr),
107
      d_pp(nullptr),
108
73389
      d_scope(nullptr)
109
{
110
  // !!!!!!!!!!!!!!!!!!!!!! temporary hack: this makes the current SmtEngine
111
  // we are constructing the current SmtEngine in scope for the lifetime of
112
  // this SmtEngine, or until another SmtEngine is constructed (that SmtEngine
113
  // is then in scope during its lifetime). This is mostly to ensure that
114
  // options are always in scope, for e.g. printing expressions, which rely
115
  // on knowing the output language.
116
  // Notice that the SmtEngine may spawn new SmtEngine "subsolvers" internally.
117
  // These are created, used, and deleted in a modular fashion while not
118
  // interleaving calls to the master SmtEngine. Thus the hack here does not
119
  // break this use case.
120
  // On the other hand, this hack breaks use cases where multiple SmtEngine
121
  // objects are created by the user.
122
10484
  d_scope.reset(new SmtScope(this));
123
  // set the options manager
124
10485
  d_optm.reset(new smt::OptionsManager(&getOptions()));
125
  // listen to node manager events
126
10483
  getNodeManager()->subscribeEvents(d_snmListener.get());
127
  // listen to resource out
128
10483
  getResourceManager()->registerListener(d_routListener.get());
129
  // make statistics
130
10483
  d_stats.reset(new SmtEngineStatistics());
131
  // reset the preprocessor
132
31449
  d_pp.reset(
133
20966
      new smt::Preprocessor(*this, *d_env.get(), *d_absValues.get(), *d_stats));
134
  // make the SMT solver
135
10483
  d_smtSolver.reset(new SmtSolver(*d_env.get(), *d_state, *d_pp, *d_stats));
136
  // make the SyGuS solver
137
41932
  d_sygusSolver.reset(
138
31449
      new SygusSolver(*d_smtSolver, *d_pp, getUserContext(), d_outMgr));
139
  // make the quantifier elimination solver
140
10483
  d_quantElimSolver.reset(new QuantElimSolver(*d_smtSolver));
141
142
10483
}
143
144
13174
bool SmtEngine::isFullyInited() const { return d_state->isFullyInited(); }
145
10943
bool SmtEngine::isQueryMade() const { return d_state->isQueryMade(); }
146
2825
size_t SmtEngine::getNumUserLevels() const
147
{
148
2825
  return d_state->getNumUserLevels();
149
}
150
166
SmtMode SmtEngine::getSmtMode() const { return d_state->getMode(); }
151
128
bool SmtEngine::isSmtModeSat() const
152
{
153
128
  SmtMode mode = getSmtMode();
154
128
  return mode == SmtMode::SAT || mode == SmtMode::SAT_UNKNOWN;
155
}
156
Result SmtEngine::getStatusOfLastCommand() const
157
{
158
  return d_state->getStatus();
159
}
160
28265
context::UserContext* SmtEngine::getUserContext()
161
{
162
28265
  return d_env->getUserContext();
163
}
164
10502
context::Context* SmtEngine::getContext() { return d_env->getContext(); }
165
166
344683
TheoryEngine* SmtEngine::getTheoryEngine()
167
{
168
344683
  return d_smtSolver->getTheoryEngine();
169
}
170
171
56155
prop::PropEngine* SmtEngine::getPropEngine()
172
{
173
56155
  return d_smtSolver->getPropEngine();
174
}
175
176
121624
void SmtEngine::finishInit()
177
{
178
121624
  if (d_state->isFullyInited())
179
  {
180
    // already initialized, return
181
111782
    return;
182
  }
183
184
  // Notice that finishInitInternal is called when options are finalized. If we
185
  // are parsing smt2, this occurs at the moment we enter "Assert mode", page 52
186
  // of SMT-LIB 2.6 standard.
187
188
  // set the logic
189
9842
  const LogicInfo& logic = getLogicInfo();
190
9842
  if (!logic.isLocked())
191
  {
192
1570
    setLogicInternal();
193
  }
194
195
  // set the random seed
196
9842
  Random::getRandom().setSeed(d_env->getOptions().driver.seed);
197
198
  // Call finish init on the options manager. This inializes the resource
199
  // manager based on the options, and sets up the best default options
200
  // based on our heuristics.
201
9842
  d_optm->finishInit(d_env->d_logic, d_isInternalSubsolver);
202
203
9841
  ProofNodeManager* pnm = nullptr;
204
9841
  if (d_env->getOptions().smt.produceProofs)
205
  {
206
    // ensure bound variable uses canonical bound variables
207
3759
    getNodeManager()->getBoundVarManager()->enableKeepCacheValues();
208
    // make the proof manager
209
3759
    d_pfManager.reset(new PfManager(getUserContext(), this));
210
3759
    PreprocessProofGenerator* pppg = d_pfManager->getPreprocessProofGenerator();
211
    // start the unsat core manager
212
3759
    d_ucManager.reset(new UnsatCoreManager());
213
    // use this proof node manager
214
3759
    pnm = d_pfManager->getProofNodeManager();
215
    // enable proof support in the environment/rewriter
216
3759
    d_env->setProofNodeManager(pnm);
217
    // enable it in the assertions pipeline
218
3759
    d_asserts->setProofGenerator(pppg);
219
    // enable it in the SmtSolver
220
3759
    d_smtSolver->setProofNodeManager(pnm);
221
    // enabled proofs in the preprocessor
222
3759
    d_pp->setProofGenerator(pppg);
223
  }
224
225
9841
  Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
226
9841
  d_smtSolver->finishInit(logic);
227
228
  // now can construct the SMT-level model object
229
9841
  TheoryEngine* te = d_smtSolver->getTheoryEngine();
230
9841
  Assert(te != nullptr);
231
9841
  TheoryModel* tm = te->getModel();
232
9841
  if (tm != nullptr)
233
  {
234
9841
    d_model.reset(new Model(tm));
235
    // make the check models utility
236
9841
    d_checkModels.reset(new CheckModels(*d_env.get()));
237
  }
238
239
  // global push/pop around everything, to ensure proper destruction
240
  // of context-dependent data structures
241
9841
  d_state->setup();
242
243
9841
  Trace("smt-debug") << "Set up assertions..." << std::endl;
244
9841
  d_asserts->finishInit();
245
246
  // dump out a set-logic command only when raw-benchmark is disabled to avoid
247
  // dumping the command twice.
248
9841
  if (Dump.isOn("benchmark") && !Dump.isOn("raw-benchmark"))
249
  {
250
2
      LogicInfo everything;
251
1
      everything.lock();
252
2
      getPrinter().toStreamCmdComment(
253
          d_env->getDumpOut(),
254
          "cvc5 always dumps the most general, all-supported logic (below), as "
255
          "some internals might require the use of a logic more general than "
256
1
          "the input.");
257
2
      getPrinter().toStreamCmdSetBenchmarkLogic(d_env->getDumpOut(),
258
2
                                                everything.getLogicString());
259
  }
260
261
  // initialize the dump manager
262
9841
  getDumpManager()->finishInit();
263
264
  // subsolvers
265
9841
  if (d_env->getOptions().smt.produceAbducts)
266
  {
267
326
    d_abductSolver.reset(new AbductionSolver(this));
268
  }
269
19682
  if (d_env->getOptions().smt.produceInterpols
270
9841
      != options::ProduceInterpols::NONE)
271
  {
272
114
    d_interpolSolver.reset(new InterpolationSolver(this));
273
  }
274
275
9841
  d_pp->finishInit();
276
277
9841
  AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
278
      << "The PropEngine has pushed but the SmtEngine "
279
         "hasn't finished initializing!";
280
281
9841
  Assert(getLogicInfo().isLocked());
282
283
  // store that we are finished initializing
284
9841
  d_state->finishInit();
285
9841
  Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
286
}
287
288
10483
void SmtEngine::shutdown() {
289
10483
  d_state->shutdown();
290
291
10483
  d_smtSolver->shutdown();
292
293
10483
  d_env->shutdown();
294
10483
}
295
296
20966
SmtEngine::~SmtEngine()
297
{
298
20966
  SmtScope smts(this);
299
300
  try {
301
10483
    shutdown();
302
303
    // global push/pop around everything, to ensure proper destruction
304
    // of context-dependent data structures
305
10483
    d_state->cleanup();
306
307
    //destroy all passes before destroying things that they refer to
308
10483
    d_pp->cleanup();
309
310
10483
    d_pfManager.reset(nullptr);
311
10483
    d_ucManager.reset(nullptr);
312
313
10483
    d_absValues.reset(nullptr);
314
10483
    d_asserts.reset(nullptr);
315
10483
    d_model.reset(nullptr);
316
317
10483
    d_abductSolver.reset(nullptr);
318
10483
    d_interpolSolver.reset(nullptr);
319
10483
    d_quantElimSolver.reset(nullptr);
320
10483
    d_sygusSolver.reset(nullptr);
321
10483
    d_smtSolver.reset(nullptr);
322
323
10483
    d_stats.reset(nullptr);
324
10483
    getNodeManager()->unsubscribeEvents(d_snmListener.get());
325
10483
    d_snmListener.reset(nullptr);
326
10483
    d_routListener.reset(nullptr);
327
10483
    d_optm.reset(nullptr);
328
10483
    d_pp.reset(nullptr);
329
    // destroy the state
330
10483
    d_state.reset(nullptr);
331
    // destroy the environment
332
10483
    d_env.reset(nullptr);
333
  } catch(Exception& e) {
334
    Warning() << "cvc5 threw an exception during cleanup." << endl << e << endl;
335
  }
336
10483
}
337
338
8350
void SmtEngine::setLogic(const LogicInfo& logic)
339
{
340
16700
  SmtScope smts(this);
341
8350
  if (d_state->isFullyInited())
342
  {
343
    throw ModalException("Cannot set logic in SmtEngine after the engine has "
344
                         "finished initializing.");
345
  }
346
8350
  d_env->d_logic = logic;
347
8350
  d_userLogic = logic;
348
8350
  setLogicInternal();
349
8350
}
350
351
2
void SmtEngine::setLogic(const std::string& s)
352
{
353
4
  SmtScope smts(this);
354
  try
355
  {
356
2
    setLogic(LogicInfo(s));
357
    // dump out a set-logic command
358
2
    if (Dump.isOn("raw-benchmark"))
359
    {
360
      getPrinter().toStreamCmdSetBenchmarkLogic(
361
          d_env->getDumpOut(), getLogicInfo().getLogicString());
362
    }
363
  }
364
  catch (IllegalArgumentException& e)
365
  {
366
    throw LogicException(e.what());
367
  }
368
2
}
369
370
2
void SmtEngine::setLogic(const char* logic) { setLogic(string(logic)); }
371
372
46441
const LogicInfo& SmtEngine::getLogicInfo() const
373
{
374
46441
  return d_env->getLogicInfo();
375
}
376
377
395
LogicInfo SmtEngine::getUserLogicInfo() const
378
{
379
  // Lock the logic to make sure that this logic can be queried. We create a
380
  // copy of the user logic here to keep this method const.
381
395
  LogicInfo res = d_userLogic;
382
395
  res.lock();
383
395
  return res;
384
}
385
386
6121
void SmtEngine::notifyStartParsing(const std::string& filename)
387
{
388
6121
  d_state->setFilename(filename);
389
12242
  d_env->getStatisticsRegistry().registerValue<std::string>("driver::filename",
390
12242
                                                            filename);
391
  // Copy the original options. This is called prior to beginning parsing.
392
  // Hence reset should revert to these options, which note is after reading
393
  // the command line.
394
6121
}
395
396
const std::string& SmtEngine::getFilename() const
397
{
398
  return d_state->getFilename();
399
}
400
401
void SmtEngine::setResultStatistic(const std::string& result) {
402
  d_env->getStatisticsRegistry().registerValue<std::string>("driver::sat/unsat",
403
                                                            result);
404
}
405
6121
void SmtEngine::setTotalTimeStatistic(double seconds) {
406
12242
  d_env->getStatisticsRegistry().registerValue<double>("driver::totalTime",
407
12242
                                                       seconds);
408
6121
}
409
410
9920
void SmtEngine::setLogicInternal()
411
{
412
9920
  Assert(!d_state->isFullyInited())
413
      << "setting logic in SmtEngine but the engine has already"
414
         " finished initializing for this run";
415
9920
  d_env->d_logic.lock();
416
9920
  d_userLogic.lock();
417
9920
}
418
419
5703
void SmtEngine::setInfo(const std::string& key, const std::string& value)
420
{
421
11406
  SmtScope smts(this);
422
423
5703
  Trace("smt") << "SMT setInfo(" << key << ", " << value << ")" << endl;
424
425
5703
  if (Dump.isOn("benchmark"))
426
  {
427
    if (key == "status")
428
    {
429
      Result::Sat status =
430
          (value == "sat")
431
              ? Result::SAT
432
              : ((value == "unsat") ? Result::UNSAT : Result::SAT_UNKNOWN);
433
      getPrinter().toStreamCmdSetBenchmarkStatus(d_env->getDumpOut(), status);
434
    }
435
    else
436
    {
437
      getPrinter().toStreamCmdSetInfo(d_env->getDumpOut(), key, value);
438
    }
439
  }
440
441
5703
  if (key == "filename")
442
  {
443
52
    d_state->setFilename(value);
444
  }
445
5651
  else if (key == "smt-lib-version" && !getOptions().base.inputLanguageWasSetByUser)
446
  {
447
699
    language::input::Language ilang = language::input::LANG_SMTLIB_V2_6;
448
449
699
    if (value != "2" && value != "2.6")
450
    {
451
8
      Warning() << "SMT-LIB version " << value
452
                << " unsupported, defaulting to language (and semantics of) "
453
4
                   "SMT-LIB 2.6\n";
454
    }
455
699
    getOptions().base.inputLanguage = ilang;
456
    // also update the output language
457
699
    if (!getOptions().base.outputLanguageWasSetByUser)
458
    {
459
699
      language::output::Language olang = language::toOutputLanguage(ilang);
460
699
      if (d_env->getOptions().base.outputLanguage != olang)
461
      {
462
2
        getOptions().base.outputLanguage = olang;
463
2
        *d_env->getOptions().base.out << language::SetLanguage(olang);
464
      }
465
    }
466
  }
467
4952
  else if (key == "status")
468
  {
469
3661
    d_state->notifyExpectedStatus(value);
470
  }
471
5703
}
472
473
24
bool SmtEngine::isValidGetInfoFlag(const std::string& key) const
474
{
475
71
  if (key == "all-statistics" || key == "error-behavior" || key == "name"
476
19
      || key == "version" || key == "authors" || key == "status"
477
15
      || key == "reason-unknown" || key == "assertion-stack-levels"
478
30
      || key == "all-options" || key == "time")
479
  {
480
18
    return true;
481
  }
482
6
  return false;
483
}
484
485
18
std::string SmtEngine::getInfo(const std::string& key) const
486
{
487
36
  SmtScope smts(this);
488
489
18
  Trace("smt") << "SMT getInfo(" << key << ")" << endl;
490
18
  if (key == "all-statistics")
491
  {
492
1
    return toSExpr(d_env->getStatisticsRegistry().begin(), d_env->getStatisticsRegistry().end());
493
  }
494
17
  if (key == "error-behavior")
495
  {
496
1
    return "immediate-exit";
497
  }
498
16
  if (key == "name")
499
  {
500
3
    return toSExpr(Configuration::getName());
501
  }
502
13
  if (key == "version")
503
  {
504
1
    return toSExpr(Configuration::getVersionString());
505
  }
506
12
  if (key == "authors")
507
  {
508
1
    return toSExpr(Configuration::about());
509
  }
510
11
  if (key == "status")
511
  {
512
    // sat | unsat | unknown
513
4
    Result status = d_state->getStatus();
514
2
    switch (status.asSatisfiabilityResult().isSat())
515
    {
516
      case Result::SAT: return "sat";
517
      case Result::UNSAT: return "unsat";
518
2
      default: return "unknown";
519
    }
520
  }
521
9
  if (key == "time")
522
  {
523
    return toSExpr(std::clock());
524
  }
525
9
  if (key == "reason-unknown")
526
  {
527
18
    Result status = d_state->getStatus();
528
9
    if (!status.isNull() && status.isUnknown())
529
    {
530
12
      std::stringstream ss;
531
6
      ss << status.whyUnknown();
532
12
      std::string s = ss.str();
533
6
      transform(s.begin(), s.end(), s.begin(), ::tolower);
534
6
      return s;
535
    }
536
    else
537
    {
538
      throw RecoverableModalException(
539
          "Can't get-info :reason-unknown when the "
540
3
          "last result wasn't unknown!");
541
    }
542
  }
543
  if (key == "assertion-stack-levels")
544
  {
545
    size_t ulevel = d_state->getNumUserLevels();
546
    AlwaysAssert(ulevel <= std::numeric_limits<unsigned long int>::max());
547
    return toSExpr(ulevel);
548
  }
549
  Assert(key == "all-options");
550
  // get the options, like all-statistics
551
  return toSExpr(options::getAll(getOptions()));
552
}
553
554
2461
void SmtEngine::debugCheckFormals(const std::vector<Node>& formals, Node func)
555
{
556
5739
  for (std::vector<Node>::const_iterator i = formals.begin();
557
5739
       i != formals.end();
558
       ++i)
559
  {
560
3278
    if((*i).getKind() != kind::BOUND_VARIABLE) {
561
      stringstream ss;
562
      ss << "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
563
         << "definition of function " << func << ", formal\n"
564
         << "  " << *i << "\n"
565
         << "has kind " << (*i).getKind();
566
      throw TypeCheckingExceptionPrivate(func, ss.str());
567
    }
568
  }
569
2461
}
570
571
2461
void SmtEngine::debugCheckFunctionBody(Node formula,
572
                                       const std::vector<Node>& formals,
573
                                       Node func)
574
{
575
  TypeNode formulaType =
576
4922
      formula.getType(d_env->getOptions().expr.typeChecking);
577
4922
  TypeNode funcType = func.getType();
578
  // We distinguish here between definitions of constants and functions,
579
  // because the type checking for them is subtly different.  Perhaps we
580
  // should instead have SmtEngine::defineFunction() and
581
  // SmtEngine::defineConstant() for better clarity, although then that
582
  // doesn't match the SMT-LIBv2 standard...
583
2461
  if(formals.size() > 0) {
584
2764
    TypeNode rangeType = funcType.getRangeType();
585
1382
    if(! formulaType.isComparableTo(rangeType)) {
586
      stringstream ss;
587
      ss << "Type of defined function does not match its declaration\n"
588
         << "The function  : " << func << "\n"
589
         << "Declared type : " << rangeType << "\n"
590
         << "The body      : " << formula << "\n"
591
         << "Body type     : " << formulaType;
592
      throw TypeCheckingExceptionPrivate(func, ss.str());
593
    }
594
  } else {
595
1079
    if(! formulaType.isComparableTo(funcType)) {
596
      stringstream ss;
597
      ss << "Declared type of defined constant does not match its definition\n"
598
         << "The constant   : " << func << "\n"
599
         << "Declared type  : " << funcType << "\n"
600
         << "The definition : " << formula << "\n"
601
         << "Definition type: " << formulaType;
602
      throw TypeCheckingExceptionPrivate(func, ss.str());
603
    }
604
  }
605
2461
}
606
607
2269
void SmtEngine::defineFunction(Node func,
608
                               const std::vector<Node>& formals,
609
                               Node formula,
610
                               bool global)
611
{
612
4538
  SmtScope smts(this);
613
2269
  finishInit();
614
2269
  d_state->doPendingPops();
615
2269
  Trace("smt") << "SMT defineFunction(" << func << ")" << endl;
616
2269
  debugCheckFormals(formals, func);
617
618
4538
  stringstream ss;
619
  ss << language::SetLanguage(
620
            language::SetLanguage::getLanguage(Dump.getStream()))
621
2269
     << func;
622
623
4538
  DefineFunctionNodeCommand nc(ss.str(), func, formals, formula);
624
2269
  getDumpManager()->addToDump(nc, "declarations");
625
626
  // type check body
627
2269
  debugCheckFunctionBody(formula, formals, func);
628
629
  // Substitute out any abstract values in formula
630
4538
  Node def = d_absValues->substituteAbstractValues(formula);
631
2269
  if (!formals.empty())
632
  {
633
1211
    NodeManager* nm = NodeManager::currentNM();
634
3633
    def = nm->mkNode(
635
2422
        kind::LAMBDA, nm->mkNode(kind::BOUND_VAR_LIST, formals), def);
636
  }
637
  // A define-fun is treated as a (higher-order) assertion. It is provided
638
  // to the assertions object. It will be added as a top-level substitution
639
  // within this class, possibly multiple times if global is true.
640
4538
  Node feq = func.eqNode(def);
641
2269
  d_asserts->addDefineFunDefinition(feq, global);
642
2269
}
643
644
141
void SmtEngine::defineFunctionsRec(
645
    const std::vector<Node>& funcs,
646
    const std::vector<std::vector<Node>>& formals,
647
    const std::vector<Node>& formulas,
648
    bool global)
649
{
650
282
  SmtScope smts(this);
651
141
  finishInit();
652
141
  d_state->doPendingPops();
653
141
  Trace("smt") << "SMT defineFunctionsRec(...)" << endl;
654
655
141
  if (funcs.size() != formals.size() && funcs.size() != formulas.size())
656
  {
657
    stringstream ss;
658
    ss << "Number of functions, formals, and function bodies passed to "
659
          "defineFunctionsRec do not match:"
660
       << "\n"
661
       << "        #functions : " << funcs.size() << "\n"
662
       << "        #arg lists : " << formals.size() << "\n"
663
       << "  #function bodies : " << formulas.size() << "\n";
664
    throw ModalException(ss.str());
665
  }
666
333
  for (unsigned i = 0, size = funcs.size(); i < size; i++)
667
  {
668
    // check formal argument list
669
192
    debugCheckFormals(formals[i], funcs[i]);
670
    // type check body
671
192
    debugCheckFunctionBody(formulas[i], formals[i], funcs[i]);
672
  }
673
674
141
  if (Dump.isOn("raw-benchmark"))
675
  {
676
    getPrinter().toStreamCmdDefineFunctionRec(
677
        d_env->getDumpOut(), funcs, formals, formulas);
678
  }
679
680
141
  NodeManager* nm = getNodeManager();
681
333
  for (unsigned i = 0, size = funcs.size(); i < size; i++)
682
  {
683
    // we assert a quantified formula
684
384
    Node func_app;
685
    // make the function application
686
192
    if (formals[i].empty())
687
    {
688
      // it has no arguments
689
21
      func_app = funcs[i];
690
    }
691
    else
692
    {
693
342
      std::vector<Node> children;
694
171
      children.push_back(funcs[i]);
695
171
      children.insert(children.end(), formals[i].begin(), formals[i].end());
696
171
      func_app = nm->mkNode(kind::APPLY_UF, children);
697
    }
698
384
    Node lem = nm->mkNode(kind::EQUAL, func_app, formulas[i]);
699
192
    if (!formals[i].empty())
700
    {
701
      // set the attribute to denote this is a function definition
702
342
      Node aexpr = nm->mkNode(kind::INST_ATTRIBUTE, func_app);
703
171
      aexpr = nm->mkNode(kind::INST_PATTERN_LIST, aexpr);
704
      FunDefAttribute fda;
705
171
      func_app.setAttribute(fda, true);
706
      // make the quantified formula
707
342
      Node boundVars = nm->mkNode(kind::BOUND_VAR_LIST, formals[i]);
708
171
      lem = nm->mkNode(kind::FORALL, boundVars, lem, aexpr);
709
    }
710
    // assert the quantified formula
711
    //   notice we don't call assertFormula directly, since this would
712
    //   duplicate the output on raw-benchmark.
713
    // add define recursive definition to the assertions
714
192
    d_asserts->addDefineFunDefinition(lem, global);
715
  }
716
141
}
717
718
16
void SmtEngine::defineFunctionRec(Node func,
719
                                  const std::vector<Node>& formals,
720
                                  Node formula,
721
                                  bool global)
722
{
723
32
  std::vector<Node> funcs;
724
16
  funcs.push_back(func);
725
32
  std::vector<std::vector<Node>> formals_multi;
726
16
  formals_multi.push_back(formals);
727
32
  std::vector<Node> formulas;
728
16
  formulas.push_back(formula);
729
16
  defineFunctionsRec(funcs, formals_multi, formulas, global);
730
16
}
731
732
89574
Result SmtEngine::quickCheck() {
733
89574
  Assert(d_state->isFullyInited());
734
89574
  Trace("smt") << "SMT quickCheck()" << endl;
735
89574
  const std::string& filename = d_state->getFilename();
736
  return Result(
737
89574
      Result::ENTAILMENT_UNKNOWN, Result::REQUIRES_FULL_CHECK, filename);
738
}
739
740
5135
Model* SmtEngine::getAvailableModel(const char* c) const
741
{
742
5135
  if (!d_env->getOptions().theory.assignFunctionValues)
743
  {
744
    std::stringstream ss;
745
    ss << "Cannot " << c << " when --assign-function-values is false.";
746
    throw RecoverableModalException(ss.str().c_str());
747
  }
748
749
10270
  if (d_state->getMode() != SmtMode::SAT
750
5135
      && d_state->getMode() != SmtMode::SAT_UNKNOWN)
751
  {
752
18
    std::stringstream ss;
753
    ss << "Cannot " << c
754
9
       << " unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN "
755
9
          "response.";
756
9
    throw RecoverableModalException(ss.str().c_str());
757
  }
758
759
5126
  if (!d_env->getOptions().smt.produceModels)
760
  {
761
4
    std::stringstream ss;
762
2
    ss << "Cannot " << c << " when produce-models options is off.";
763
2
    throw ModalException(ss.str().c_str());
764
  }
765
766
5124
  TheoryEngine* te = d_smtSolver->getTheoryEngine();
767
5124
  Assert(te != nullptr);
768
5124
  TheoryModel* m = te->getBuiltModel();
769
770
5123
  if (m == nullptr)
771
  {
772
    std::stringstream ss;
773
    ss << "Cannot " << c
774
       << " since model is not available. Perhaps the most recent call to "
775
          "check-sat was interrupted?";
776
    throw RecoverableModalException(ss.str().c_str());
777
  }
778
779
5123
  return d_model.get();
780
}
781
782
117
QuantifiersEngine* SmtEngine::getAvailableQuantifiersEngine(const char* c) const
783
{
784
117
  QuantifiersEngine* qe = d_smtSolver->getQuantifiersEngine();
785
117
  if (qe == nullptr)
786
  {
787
    std::stringstream ss;
788
    ss << "Cannot " << c << " when quantifiers are not present.";
789
    throw ModalException(ss.str().c_str());
790
  }
791
117
  return qe;
792
}
793
794
4869
void SmtEngine::notifyPushPre() { d_smtSolver->processAssertions(*d_asserts); }
795
796
4869
void SmtEngine::notifyPushPost()
797
{
798
9738
  TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
799
4869
  Assert(getPropEngine() != nullptr);
800
4869
  getPropEngine()->push();
801
4869
}
802
803
4869
void SmtEngine::notifyPopPre()
804
{
805
9738
  TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
806
4869
  PropEngine* pe = getPropEngine();
807
4869
  Assert(pe != nullptr);
808
4869
  pe->pop();
809
4869
}
810
811
15176
void SmtEngine::notifyPostSolvePre()
812
{
813
15176
  PropEngine* pe = getPropEngine();
814
15176
  Assert(pe != nullptr);
815
15176
  pe->resetTrail();
816
15176
}
817
818
15176
void SmtEngine::notifyPostSolvePost()
819
{
820
15176
  TheoryEngine* te = getTheoryEngine();
821
15176
  Assert(te != nullptr);
822
15176
  te->postsolve();
823
15176
}
824
825
12754
Result SmtEngine::checkSat()
826
{
827
25508
  Node nullNode;
828
25490
  return checkSat(nullNode);
829
}
830
831
13341
Result SmtEngine::checkSat(const Node& assumption)
832
{
833
13341
  if (Dump.isOn("benchmark"))
834
  {
835
2
    getPrinter().toStreamCmdCheckSat(d_env->getDumpOut(), assumption);
836
  }
837
26682
  std::vector<Node> assump;
838
13341
  if (!assumption.isNull())
839
  {
840
587
    assump.push_back(assumption);
841
  }
842
26663
  return checkSatInternal(assump, false);
843
}
844
845
996
Result SmtEngine::checkSat(const std::vector<Node>& assumptions)
846
{
847
996
  if (Dump.isOn("benchmark"))
848
  {
849
    if (assumptions.empty())
850
    {
851
      getPrinter().toStreamCmdCheckSat(d_env->getDumpOut());
852
    }
853
    else
854
    {
855
      getPrinter().toStreamCmdCheckSatAssuming(d_env->getDumpOut(),
856
                                               assumptions);
857
    }
858
  }
859
996
  return checkSatInternal(assumptions, false);
860
}
861
862
631
Result SmtEngine::checkEntailed(const Node& node)
863
{
864
631
  if (Dump.isOn("benchmark"))
865
  {
866
    getPrinter().toStreamCmdQuery(d_env->getDumpOut(), node);
867
  }
868
1258
  return checkSatInternal(
869
1262
             node.isNull() ? std::vector<Node>() : std::vector<Node>{node},
870
             true)
871
1254
      .asEntailmentResult();
872
}
873
874
2
Result SmtEngine::checkEntailed(const std::vector<Node>& nodes)
875
{
876
2
  return checkSatInternal(nodes, true).asEntailmentResult();
877
}
878
879
14970
Result SmtEngine::checkSatInternal(const std::vector<Node>& assumptions,
880
                                   bool isEntailmentCheck)
881
{
882
  try
883
  {
884
29940
    SmtScope smts(this);
885
14970
    finishInit();
886
887
29940
    Trace("smt") << "SmtEngine::"
888
29940
                 << (isEntailmentCheck ? "checkEntailed" : "checkSat") << "("
889
14970
                 << assumptions << ")" << endl;
890
    // check the satisfiability with the solver object
891
    Result r = d_smtSolver->checkSatisfiability(
892
29919
        *d_asserts.get(), assumptions, isEntailmentCheck);
893
894
29898
    Trace("smt") << "SmtEngine::" << (isEntailmentCheck ? "query" : "checkSat")
895
14949
                 << "(" << assumptions << ") => " << r << endl;
896
897
    // Check that SAT results generate a model correctly.
898
14949
    if (d_env->getOptions().smt.checkModels)
899
    {
900
2551
      if (r.asSatisfiabilityResult().isSat() == Result::SAT)
901
      {
902
2152
        checkModel();
903
      }
904
    }
905
    // Check that UNSAT results generate a proof correctly.
906
29894
    if (d_env->getOptions().smt.checkProofs
907
14947
        || d_env->getOptions().proof.proofEagerChecking)
908
    {
909
2256
      if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
910
      {
911
2732
        if ((d_env->getOptions().smt.checkProofs
912
             || d_env->getOptions().proof.proofEagerChecking)
913
2732
            && !d_env->getOptions().smt.produceProofs)
914
        {
915
          throw ModalException(
916
              "Cannot check-proofs because proofs were disabled.");
917
        }
918
1366
        checkProof();
919
      }
920
    }
921
    // Check that UNSAT results generate an unsat core correctly.
922
14947
    if (d_env->getOptions().smt.checkUnsatCores)
923
    {
924
2366
      if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
925
      {
926
2728
        TimerStat::CodeTimer checkUnsatCoreTimer(d_stats->d_checkUnsatCoreTime);
927
1364
        checkUnsatCore();
928
      }
929
    }
930
14947
    if (d_env->getOptions().base.statisticsEveryQuery)
931
    {
932
      printStatisticsDiff();
933
    }
934
14947
    return r;
935
  }
936
  catch (UnsafeInterruptException& e)
937
  {
938
    AlwaysAssert(getResourceManager()->out());
939
    // Notice that we do not notify the state of this result. If we wanted to
940
    // make the solver resume a working state after an interupt, then we would
941
    // implement a different callback and use it here, e.g.
942
    // d_state.notifyCheckSatInterupt.
943
    Result::UnknownExplanation why = getResourceManager()->outOfResources()
944
                                         ? Result::RESOURCEOUT
945
                                         : Result::TIMEOUT;
946
947
    if (d_env->getOptions().base.statisticsEveryQuery)
948
    {
949
      printStatisticsDiff();
950
    }
951
    return Result(Result::SAT_UNKNOWN, why, d_state->getFilename());
952
  }
953
}
954
955
13
std::vector<Node> SmtEngine::getUnsatAssumptions(void)
956
{
957
13
  Trace("smt") << "SMT getUnsatAssumptions()" << endl;
958
26
  SmtScope smts(this);
959
13
  if (!d_env->getOptions().smt.unsatAssumptions)
960
  {
961
    throw ModalException(
962
        "Cannot get unsat assumptions when produce-unsat-assumptions option "
963
        "is off.");
964
  }
965
13
  if (d_state->getMode() != SmtMode::UNSAT)
966
  {
967
    throw RecoverableModalException(
968
        "Cannot get unsat assumptions unless immediately preceded by "
969
        "UNSAT/ENTAILED.");
970
  }
971
13
  finishInit();
972
13
  if (Dump.isOn("benchmark"))
973
  {
974
    getPrinter().toStreamCmdGetUnsatAssumptions(d_env->getDumpOut());
975
  }
976
26
  UnsatCore core = getUnsatCoreInternal();
977
13
  std::vector<Node> res;
978
13
  std::vector<Node>& assumps = d_asserts->getAssumptions();
979
37
  for (const Node& e : assumps)
980
  {
981
24
    if (std::find(core.begin(), core.end(), e) != core.end())
982
    {
983
16
      res.push_back(e);
984
    }
985
  }
986
26
  return res;
987
}
988
989
89575
Result SmtEngine::assertFormula(const Node& formula)
990
{
991
179150
  SmtScope smts(this);
992
89575
  finishInit();
993
89574
  d_state->doPendingPops();
994
995
89574
  Trace("smt") << "SmtEngine::assertFormula(" << formula << ")" << endl;
996
997
89574
  if (Dump.isOn("raw-benchmark"))
998
  {
999
3
    getPrinter().toStreamCmdAssert(d_env->getDumpOut(), formula);
1000
  }
1001
1002
  // Substitute out any abstract values in ex
1003
179148
  Node n = d_absValues->substituteAbstractValues(formula);
1004
1005
89574
  d_asserts->assertFormula(n);
1006
179148
  return quickCheck().asEntailmentResult();
1007
}/* SmtEngine::assertFormula() */
1008
1009
/*
1010
   --------------------------------------------------------------------------
1011
    Handling SyGuS commands
1012
   --------------------------------------------------------------------------
1013
*/
1014
1015
413
void SmtEngine::declareSygusVar(Node var)
1016
{
1017
826
  SmtScope smts(this);
1018
413
  d_sygusSolver->declareSygusVar(var);
1019
413
  if (Dump.isOn("raw-benchmark"))
1020
  {
1021
    getPrinter().toStreamCmdDeclareVar(d_env->getDumpOut(), var, var.getType());
1022
  }
1023
  // don't need to set that the conjecture is stale
1024
413
}
1025
1026
321
void SmtEngine::declareSynthFun(Node func,
1027
                                TypeNode sygusType,
1028
                                bool isInv,
1029
                                const std::vector<Node>& vars)
1030
{
1031
642
  SmtScope smts(this);
1032
321
  d_state->doPendingPops();
1033
321
  d_sygusSolver->declareSynthFun(func, sygusType, isInv, vars);
1034
1035
  // !!! TEMPORARY: We cannot construct a SynthFunCommand since we cannot
1036
  // construct a Term-level Grammar from a Node-level sygus TypeNode. Thus we
1037
  // must print the command using the Node-level utility method for now.
1038
1039
321
  if (Dump.isOn("raw-benchmark"))
1040
  {
1041
    getPrinter().toStreamCmdSynthFun(
1042
        d_env->getDumpOut(), func, vars, isInv, sygusType);
1043
  }
1044
321
}
1045
void SmtEngine::declareSynthFun(Node func,
1046
                                bool isInv,
1047
                                const std::vector<Node>& vars)
1048
{
1049
  // use a null sygus type
1050
  TypeNode sygusType;
1051
  declareSynthFun(func, sygusType, isInv, vars);
1052
}
1053
1054
616
void SmtEngine::assertSygusConstraint(Node constraint)
1055
{
1056
1232
  SmtScope smts(this);
1057
616
  finishInit();
1058
616
  d_sygusSolver->assertSygusConstraint(constraint);
1059
616
  if (Dump.isOn("raw-benchmark"))
1060
  {
1061
    getPrinter().toStreamCmdConstraint(d_env->getDumpOut(), constraint);
1062
  }
1063
616
}
1064
1065
18
void SmtEngine::assertSygusInvConstraint(Node inv,
1066
                                         Node pre,
1067
                                         Node trans,
1068
                                         Node post)
1069
{
1070
36
  SmtScope smts(this);
1071
18
  finishInit();
1072
18
  d_sygusSolver->assertSygusInvConstraint(inv, pre, trans, post);
1073
18
  if (Dump.isOn("raw-benchmark"))
1074
  {
1075
    getPrinter().toStreamCmdInvConstraint(
1076
        d_env->getDumpOut(), inv, pre, trans, post);
1077
  }
1078
18
}
1079
1080
206
Result SmtEngine::checkSynth()
1081
{
1082
412
  SmtScope smts(this);
1083
206
  finishInit();
1084
403
  return d_sygusSolver->checkSynth(*d_asserts);
1085
}
1086
1087
/*
1088
   --------------------------------------------------------------------------
1089
    End of Handling SyGuS commands
1090
   --------------------------------------------------------------------------
1091
*/
1092
1093
5
void SmtEngine::declarePool(const Node& p, const std::vector<Node>& initValue)
1094
{
1095
5
  Assert(p.isVar() && p.getType().isSet());
1096
5
  finishInit();
1097
5
  QuantifiersEngine* qe = getAvailableQuantifiersEngine("declareTermPool");
1098
5
  qe->declarePool(p, initValue);
1099
5
}
1100
1101
68
Node SmtEngine::simplify(const Node& ex)
1102
{
1103
136
  SmtScope smts(this);
1104
68
  finishInit();
1105
68
  d_state->doPendingPops();
1106
  // ensure we've processed assertions
1107
68
  d_smtSolver->processAssertions(*d_asserts);
1108
136
  return d_pp->simplify(ex);
1109
}
1110
1111
1913
Node SmtEngine::expandDefinitions(const Node& ex)
1112
{
1113
1913
  getResourceManager()->spendResource(Resource::PreprocessStep);
1114
3826
  SmtScope smts(this);
1115
1913
  finishInit();
1116
1913
  d_state->doPendingPops();
1117
3826
  return d_pp->expandDefinitions(ex);
1118
}
1119
1120
// TODO(#1108): Simplify the error reporting of this method.
1121
2913
Node SmtEngine::getValue(const Node& ex) const
1122
{
1123
5826
  SmtScope smts(this);
1124
1125
2913
  Trace("smt") << "SMT getValue(" << ex << ")" << endl;
1126
2913
  if (Dump.isOn("benchmark"))
1127
  {
1128
    getPrinter().toStreamCmdGetValue(d_outMgr.getDumpOut(), {ex});
1129
  }
1130
5826
  TypeNode expectedType = ex.getType();
1131
1132
  // Substitute out any abstract values in ex and expand
1133
5826
  Node n = d_pp->expandDefinitions(ex);
1134
1135
2913
  Trace("smt") << "--- getting value of " << n << endl;
1136
  // There are two ways model values for terms are computed (for historical
1137
  // reasons).  One way is that used in check-model; the other is that
1138
  // used by the Model classes.  It's not clear to me exactly how these
1139
  // two are different, but they need to be unified.  This ugly hack here
1140
  // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
1141
1142
  //AJR : necessary?
1143
2913
  if(!n.getType().isFunction()) {
1144
2906
    n = Rewriter::rewrite(n);
1145
  }
1146
1147
2913
  Trace("smt") << "--- getting value of " << n << endl;
1148
2913
  Model* m = getAvailableModel("get-value");
1149
2907
  Assert(m != nullptr);
1150
2907
  Node resultNode = m->getValue(n);
1151
2907
  Trace("smt") << "--- got value " << n << " = " << resultNode << endl;
1152
2907
  Trace("smt") << "--- type " << resultNode.getType() << endl;
1153
2907
  Trace("smt") << "--- expected type " << expectedType << endl;
1154
1155
  // type-check the result we got
1156
  // Notice that lambdas have function type, which does not respect the subtype
1157
  // relation, so we ignore them here.
1158
2907
  Assert(resultNode.isNull() || resultNode.getKind() == kind::LAMBDA
1159
         || resultNode.getType().isSubtypeOf(expectedType))
1160
      << "Run with -t smt for details.";
1161
1162
  // Ensure it's a constant, or a lambda (for uninterpreted functions). This
1163
  // assertion only holds for models that do not have approximate values.
1164
2907
  Assert(m->hasApproximations() || resultNode.getKind() == kind::LAMBDA
1165
         || resultNode.isConst());
1166
1167
5814
  if (d_env->getOptions().smt.abstractValues
1168
5814
      && resultNode.getType().isArray())
1169
  {
1170
8
    resultNode = d_absValues->mkAbstractValue(resultNode);
1171
8
    Trace("smt") << "--- abstract value >> " << resultNode << endl;
1172
  }
1173
1174
5814
  return resultNode;
1175
}
1176
1177
std::vector<Node> SmtEngine::getValues(const std::vector<Node>& exprs)
1178
{
1179
  std::vector<Node> result;
1180
  for (const Node& e : exprs)
1181
  {
1182
    result.push_back(getValue(e));
1183
  }
1184
  return result;
1185
}
1186
1187
// TODO(#1108): Simplify the error reporting of this method.
1188
30
Model* SmtEngine::getModel() {
1189
30
  Trace("smt") << "SMT getModel()" << endl;
1190
60
  SmtScope smts(this);
1191
1192
30
  finishInit();
1193
1194
30
  if (Dump.isOn("benchmark"))
1195
  {
1196
    getPrinter().toStreamCmdGetModel(d_env->getDumpOut());
1197
  }
1198
1199
30
  Model* m = getAvailableModel("get model");
1200
1201
  // Since model m is being returned to the user, we must ensure that this
1202
  // model object remains valid with future check-sat calls. Hence, we set
1203
  // the theory engine into "eager model building" mode. TODO #2648: revisit.
1204
25
  TheoryEngine* te = getTheoryEngine();
1205
25
  Assert(te != nullptr);
1206
25
  te->setEagerModelBuilding();
1207
1208
50
  if (d_env->getOptions().smt.modelCoresMode
1209
25
      != options::ModelCoresMode::NONE)
1210
  {
1211
    // If we enabled model cores, we compute a model core for m based on our
1212
    // (expanded) assertions using the model core builder utility
1213
    std::vector<Node> eassertsProc = getExpandedAssertions();
1214
    ModelCoreBuilder::setModelCore(eassertsProc,
1215
                                   m->getTheoryModel(),
1216
                                   d_env->getOptions().smt.modelCoresMode);
1217
  }
1218
  // set the information on the SMT-level model
1219
25
  Assert(m != nullptr);
1220
25
  m->d_inputName = d_state->getFilename();
1221
25
  m->d_isKnownSat = (d_state->getMode() == SmtMode::SAT);
1222
50
  return m;
1223
}
1224
1225
18
Result SmtEngine::blockModel()
1226
{
1227
18
  Trace("smt") << "SMT blockModel()" << endl;
1228
36
  SmtScope smts(this);
1229
1230
18
  finishInit();
1231
1232
18
  if (Dump.isOn("benchmark"))
1233
  {
1234
    getPrinter().toStreamCmdBlockModel(d_env->getDumpOut());
1235
  }
1236
1237
18
  Model* m = getAvailableModel("block model");
1238
1239
36
  if (d_env->getOptions().smt.blockModelsMode
1240
18
      == options::BlockModelsMode::NONE)
1241
  {
1242
4
    std::stringstream ss;
1243
2
    ss << "Cannot block model when block-models is set to none.";
1244
2
    throw RecoverableModalException(ss.str().c_str());
1245
  }
1246
1247
  // get expanded assertions
1248
32
  std::vector<Node> eassertsProc = getExpandedAssertions();
1249
  Node eblocker =
1250
      ModelBlocker::getModelBlocker(eassertsProc,
1251
                                    m->getTheoryModel(),
1252
32
                                    d_env->getOptions().smt.blockModelsMode);
1253
16
  Trace("smt") << "Block formula: " << eblocker << std::endl;
1254
32
  return assertFormula(eblocker);
1255
}
1256
1257
12
Result SmtEngine::blockModelValues(const std::vector<Node>& exprs)
1258
{
1259
12
  Trace("smt") << "SMT blockModelValues()" << endl;
1260
24
  SmtScope smts(this);
1261
1262
12
  finishInit();
1263
1264
12
  if (Dump.isOn("benchmark"))
1265
  {
1266
    getPrinter().toStreamCmdBlockModelValues(d_env->getDumpOut(), exprs);
1267
  }
1268
1269
12
  Model* m = getAvailableModel("block model values");
1270
1271
  // get expanded assertions
1272
22
  std::vector<Node> eassertsProc = getExpandedAssertions();
1273
  // we always do block model values mode here
1274
  Node eblocker =
1275
      ModelBlocker::getModelBlocker(eassertsProc,
1276
                                    m->getTheoryModel(),
1277
                                    options::BlockModelsMode::VALUES,
1278
20
                                    exprs);
1279
20
  return assertFormula(eblocker);
1280
}
1281
1282
10
std::pair<Node, Node> SmtEngine::getSepHeapAndNilExpr(void)
1283
{
1284
10
  if (!getLogicInfo().isTheoryEnabled(THEORY_SEP))
1285
  {
1286
    const char* msg =
1287
        "Cannot obtain separation logic expressions if not using the "
1288
        "separation logic theory.";
1289
    throw RecoverableModalException(msg);
1290
  }
1291
20
  NodeManagerScope nms(getNodeManager());
1292
20
  Node heap;
1293
20
  Node nil;
1294
10
  Model* m = getAvailableModel("get separation logic heap and nil");
1295
10
  TheoryModel* tm = m->getTheoryModel();
1296
10
  if (!tm->getHeapModel(heap, nil))
1297
  {
1298
4
    const char* msg =
1299
        "Failed to obtain heap/nil "
1300
        "expressions from theory model.";
1301
4
    throw RecoverableModalException(msg);
1302
  }
1303
12
  return std::make_pair(heap, nil);
1304
}
1305
1306
94
std::vector<Node> SmtEngine::getExpandedAssertions()
1307
{
1308
186
  std::vector<Node> easserts = getAssertions();
1309
  // must expand definitions
1310
92
  std::vector<Node> eassertsProc;
1311
184
  std::unordered_map<Node, Node> cache;
1312
382
  for (const Node& e : easserts)
1313
  {
1314
580
    Node eae = d_pp->expandDefinitions(e, cache);
1315
290
    eassertsProc.push_back(eae);
1316
  }
1317
184
  return eassertsProc;
1318
}
1319
48
Env& SmtEngine::getEnv() { return *d_env.get(); }
1320
1321
121
void SmtEngine::declareSepHeap(TypeNode locT, TypeNode dataT)
1322
{
1323
121
  if (!getLogicInfo().isTheoryEnabled(THEORY_SEP))
1324
  {
1325
    const char* msg =
1326
        "Cannot declare heap if not using the separation logic theory.";
1327
    throw RecoverableModalException(msg);
1328
  }
1329
242
  SmtScope smts(this);
1330
121
  finishInit();
1331
121
  TheoryEngine* te = getTheoryEngine();
1332
123
  te->declareSepHeap(locT, dataT);
1333
119
}
1334
1335
1364
bool SmtEngine::getSepHeapTypes(TypeNode& locT, TypeNode& dataT)
1336
{
1337
2728
  SmtScope smts(this);
1338
1364
  finishInit();
1339
1364
  TheoryEngine* te = getTheoryEngine();
1340
2728
  return te->getSepHeapTypes(locT, dataT);
1341
}
1342
1343
5
Node SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
1344
1345
5
Node SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
1346
1347
1366
void SmtEngine::checkProof()
1348
{
1349
1366
  Assert(d_env->getOptions().smt.produceProofs);
1350
  // internal check the proof
1351
1366
  PropEngine* pe = getPropEngine();
1352
1366
  Assert(pe != nullptr);
1353
1366
  if (d_env->getOptions().proof.proofEagerChecking)
1354
  {
1355
    pe->checkProof(d_asserts->getAssertionList());
1356
  }
1357
1366
  Assert(pe->getProof() != nullptr);
1358
2732
  std::shared_ptr<ProofNode> pePfn = pe->getProof();
1359
1366
  if (d_env->getOptions().smt.checkProofs)
1360
  {
1361
1366
    d_pfManager->checkProof(pePfn, *d_asserts);
1362
  }
1363
1366
}
1364
1365
4673263
StatisticsRegistry& SmtEngine::getStatisticsRegistry()
1366
{
1367
4673263
  return d_env->getStatisticsRegistry();
1368
}
1369
1370
1420
UnsatCore SmtEngine::getUnsatCoreInternal()
1371
{
1372
1420
  if (!d_env->getOptions().smt.unsatCores)
1373
  {
1374
    throw ModalException(
1375
        "Cannot get an unsat core when produce-unsat-cores or produce-proofs "
1376
        "option is off.");
1377
  }
1378
1420
  if (d_state->getMode() != SmtMode::UNSAT)
1379
  {
1380
    throw RecoverableModalException(
1381
        "Cannot get an unsat core unless immediately preceded by "
1382
        "UNSAT/ENTAILED response.");
1383
  }
1384
  // generate with new proofs
1385
1420
  PropEngine* pe = getPropEngine();
1386
1420
  Assert(pe != nullptr);
1387
1388
2840
  std::shared_ptr<ProofNode> pepf;
1389
1420
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
1390
  {
1391
1369
    pepf = pe->getRefutation();
1392
  }
1393
  else
1394
  {
1395
51
    pepf = pe->getProof();
1396
  }
1397
1420
  Assert(pepf != nullptr);
1398
2840
  std::shared_ptr<ProofNode> pfn = d_pfManager->getFinalProof(pepf, *d_asserts);
1399
2840
  std::vector<Node> core;
1400
1420
  d_ucManager->getUnsatCore(pfn, *d_asserts, core);
1401
1420
  if (options::minimalUnsatCores())
1402
  {
1403
1
    core = reduceUnsatCore(core);
1404
  }
1405
2840
  return UnsatCore(core);
1406
}
1407
1408
1
std::vector<Node> SmtEngine::reduceUnsatCore(const std::vector<Node>& core)
1409
{
1410
1
  Assert(options::unsatCores())
1411
      << "cannot reduce unsat core if unsat cores are turned off";
1412
1413
1
  Notice() << "SmtEngine::reduceUnsatCore(): reducing unsat core" << endl;
1414
2
  std::unordered_set<Node> removed;
1415
4
  for (const Node& skip : core)
1416
  {
1417
6
    std::unique_ptr<SmtEngine> coreChecker;
1418
3
    initializeSubsolver(coreChecker);
1419
3
    coreChecker->setLogic(getLogicInfo());
1420
3
    coreChecker->getOptions().smt.checkUnsatCores = false;
1421
    // disable all proof options
1422
3
    coreChecker->getOptions().smt.produceProofs = false;
1423
3
    coreChecker->getOptions().smt.checkProofs = false;
1424
3
    coreChecker->getOptions().proof.proofEagerChecking = false;
1425
1426
12
    for (const Node& ucAssertion : core)
1427
    {
1428
9
      if (ucAssertion != skip && removed.find(ucAssertion) == removed.end())
1429
      {
1430
8
        Node assertionAfterExpansion = expandDefinitions(ucAssertion);
1431
4
        coreChecker->assertFormula(assertionAfterExpansion);
1432
      }
1433
    }
1434
6
    Result r;
1435
    try
1436
    {
1437
3
      r = coreChecker->checkSat();
1438
    }
1439
    catch (...)
1440
    {
1441
      throw;
1442
    }
1443
1444
3
    if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
1445
    {
1446
1
      removed.insert(skip);
1447
    }
1448
2
    else if (r.asSatisfiabilityResult().isUnknown())
1449
    {
1450
      Warning() << "SmtEngine::reduceUnsatCore(): could not reduce unsat core "
1451
                   "due to "
1452
                   "unknown result.";
1453
    }
1454
  }
1455
1456
1
  if (removed.empty())
1457
  {
1458
    return core;
1459
  }
1460
  else
1461
  {
1462
2
    std::vector<Node> newUcAssertions;
1463
4
    for (const Node& n : core)
1464
    {
1465
3
      if (removed.find(n) == removed.end())
1466
      {
1467
2
        newUcAssertions.push_back(n);
1468
      }
1469
    }
1470
1471
1
    return newUcAssertions;
1472
  }
1473
}
1474
1475
1364
void SmtEngine::checkUnsatCore() {
1476
1364
  Assert(d_env->getOptions().smt.unsatCores)
1477
      << "cannot check unsat core if unsat cores are turned off";
1478
1479
1364
  Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl;
1480
2728
  UnsatCore core = getUnsatCore();
1481
1482
  // initialize the core checker
1483
2728
  std::unique_ptr<SmtEngine> coreChecker;
1484
1364
  initializeSubsolver(coreChecker);
1485
1364
  coreChecker->getOptions().smt.checkUnsatCores = false;
1486
  // disable all proof options
1487
1364
  coreChecker->getOptions().smt.produceProofs = false;
1488
1364
  coreChecker->getOptions().smt.checkProofs = false;
1489
1364
  coreChecker->getOptions().proof.proofEagerChecking = false;
1490
1491
  // set up separation logic heap if necessary
1492
2728
  TypeNode sepLocType, sepDataType;
1493
1364
  if (getSepHeapTypes(sepLocType, sepDataType))
1494
  {
1495
21
    coreChecker->declareSepHeap(sepLocType, sepDataType);
1496
  }
1497
1498
1364
  Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
1499
           << std::endl;
1500
1364
  theory::TrustSubstitutionMap& tls = d_env->getTopLevelSubstitutions();
1501
7316
  for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
1502
11904
    Node assertionAfterExpansion = tls.apply(*i, false);
1503
5952
    Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
1504
             << ", expanded to " << assertionAfterExpansion << "\n";
1505
5952
    coreChecker->assertFormula(assertionAfterExpansion);
1506
  }
1507
2728
  Result r;
1508
  try {
1509
1364
    r = coreChecker->checkSat();
1510
  } catch(...) {
1511
    throw;
1512
  }
1513
1364
  Notice() << "SmtEngine::checkUnsatCore(): result is " << r << endl;
1514
1364
  if(r.asSatisfiabilityResult().isUnknown()) {
1515
1
    Warning()
1516
        << "SmtEngine::checkUnsatCore(): could not check core result unknown."
1517
        << std::endl;
1518
  }
1519
1363
  else if (r.asSatisfiabilityResult().isSat())
1520
  {
1521
    InternalError()
1522
        << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
1523
  }
1524
1364
}
1525
1526
2152
void SmtEngine::checkModel(bool hardFailure) {
1527
2152
  context::CDList<Node>* al = d_asserts->getAssertionList();
1528
  // --check-model implies --produce-assertions, which enables the
1529
  // assertion list, so we should be ok.
1530
2152
  Assert(al != nullptr)
1531
      << "don't have an assertion list to check in SmtEngine::checkModel()";
1532
1533
4304
  TimerStat::CodeTimer checkModelTimer(d_stats->d_checkModelTime);
1534
1535
2152
  Notice() << "SmtEngine::checkModel(): generating model" << endl;
1536
2152
  Model* m = getAvailableModel("check model");
1537
2151
  Assert(m != nullptr);
1538
1539
  // check the model with the theory engine for debugging
1540
2151
  if (options::debugCheckModels())
1541
  {
1542
2137
    TheoryEngine* te = getTheoryEngine();
1543
2137
    Assert(te != nullptr);
1544
2137
    te->checkTheoryAssertionsWithModel(hardFailure);
1545
  }
1546
1547
  // check the model with the check models utility
1548
2151
  Assert(d_checkModels != nullptr);
1549
2151
  d_checkModels->checkModel(m, al, hardFailure);
1550
2150
}
1551
1552
1407
UnsatCore SmtEngine::getUnsatCore() {
1553
1407
  Trace("smt") << "SMT getUnsatCore()" << std::endl;
1554
2814
  SmtScope smts(this);
1555
1407
  finishInit();
1556
1407
  if (Dump.isOn("benchmark"))
1557
  {
1558
    getPrinter().toStreamCmdGetUnsatCore(d_env->getDumpOut());
1559
  }
1560
2814
  return getUnsatCoreInternal();
1561
}
1562
1563
7
void SmtEngine::getRelevantInstantiationTermVectors(
1564
    std::map<Node, std::vector<std::vector<Node>>>& insts)
1565
{
1566
7
  Assert(d_state->getMode() == SmtMode::UNSAT);
1567
  // generate with new proofs
1568
7
  PropEngine* pe = getPropEngine();
1569
7
  Assert(pe != nullptr);
1570
7
  Assert(pe->getProof() != nullptr);
1571
  std::shared_ptr<ProofNode> pfn =
1572
14
      d_pfManager->getFinalProof(pe->getProof(), *d_asserts);
1573
7
  d_ucManager->getRelevantInstantiations(pfn, insts);
1574
7
}
1575
1576
1
std::string SmtEngine::getProof()
1577
{
1578
1
  Trace("smt") << "SMT getProof()\n";
1579
2
  SmtScope smts(this);
1580
1
  finishInit();
1581
1
  if (Dump.isOn("benchmark"))
1582
  {
1583
    getPrinter().toStreamCmdGetProof(d_env->getDumpOut());
1584
  }
1585
1
  if (!d_env->getOptions().smt.produceProofs)
1586
  {
1587
    throw ModalException("Cannot get a proof when proof option is off.");
1588
  }
1589
1
  if (d_state->getMode() != SmtMode::UNSAT)
1590
  {
1591
    throw RecoverableModalException(
1592
        "Cannot get a proof unless immediately preceded by "
1593
        "UNSAT/ENTAILED response.");
1594
  }
1595
  // the prop engine has the proof of false
1596
1
  PropEngine* pe = getPropEngine();
1597
1
  Assert(pe != nullptr);
1598
1
  Assert(pe->getProof() != nullptr);
1599
1
  Assert(d_pfManager);
1600
2
  std::ostringstream ss;
1601
1
  d_pfManager->printProof(ss, pe->getProof(), *d_asserts);
1602
2
  return ss.str();
1603
}
1604
1605
15
void SmtEngine::printInstantiations( std::ostream& out ) {
1606
30
  SmtScope smts(this);
1607
15
  finishInit();
1608
15
  if (d_env->getOptions().printer.instFormatMode == options::InstFormatMode::SZS)
1609
  {
1610
    out << "% SZS output start Proof for " << d_state->getFilename()
1611
        << std::endl;
1612
  }
1613
15
  QuantifiersEngine* qe = getAvailableQuantifiersEngine("printInstantiations");
1614
1615
  // First, extract and print the skolemizations
1616
15
  bool printed = false;
1617
15
  bool reqNames = !d_env->getOptions().printer.printInstFull;
1618
  // only print when in list mode
1619
15
  if (d_env->getOptions().printer.printInstMode == options::PrintInstMode::LIST)
1620
  {
1621
24
    std::map<Node, std::vector<Node>> sks;
1622
12
    qe->getSkolemTermVectors(sks);
1623
21
    for (const std::pair<const Node, std::vector<Node>>& s : sks)
1624
    {
1625
18
      Node name;
1626
9
      if (!qe->getNameForQuant(s.first, name, reqNames))
1627
      {
1628
        // did not have a name and we are only printing formulas with names
1629
        continue;
1630
      }
1631
18
      SkolemList slist(name, s.second);
1632
9
      out << slist;
1633
9
      printed = true;
1634
    }
1635
  }
1636
1637
  // Second, extract and print the instantiations
1638
30
  std::map<Node, std::vector<std::vector<Node>>> insts;
1639
15
  getInstantiationTermVectors(insts);
1640
36
  for (const std::pair<const Node, std::vector<std::vector<Node>>>& i : insts)
1641
  {
1642
21
    if (i.second.empty())
1643
    {
1644
      // no instantiations, skip
1645
      continue;
1646
    }
1647
42
    Node name;
1648
21
    if (!qe->getNameForQuant(i.first, name, reqNames))
1649
    {
1650
      // did not have a name and we are only printing formulas with names
1651
      continue;
1652
    }
1653
    // must have a name
1654
21
    if (d_env->getOptions().printer.printInstMode == options::PrintInstMode::NUM)
1655
    {
1656
12
      out << "(num-instantiations " << name << " " << i.second.size() << ")"
1657
6
          << std::endl;
1658
    }
1659
    else
1660
    {
1661
15
      Assert(d_env->getOptions().printer.printInstMode
1662
             == options::PrintInstMode::LIST);
1663
30
      InstantiationList ilist(name, i.second);
1664
15
      out << ilist;
1665
    }
1666
21
    printed = true;
1667
  }
1668
  // if we did not print anything, we indicate this
1669
15
  if (!printed)
1670
  {
1671
    out << "No instantiations" << std::endl;
1672
  }
1673
15
  if (d_env->getOptions().printer.instFormatMode == options::InstFormatMode::SZS)
1674
  {
1675
    out << "% SZS output end Proof for " << d_state->getFilename() << std::endl;
1676
  }
1677
15
}
1678
1679
15
void SmtEngine::getInstantiationTermVectors(
1680
    std::map<Node, std::vector<std::vector<Node>>>& insts)
1681
{
1682
30
  SmtScope smts(this);
1683
15
  finishInit();
1684
30
  if (d_env->getOptions().smt.produceProofs
1685
11
      && (!d_env->getOptions().smt.unsatCores
1686
11
          || d_env->getOptions().smt.unsatCoresMode == options::UnsatCoresMode::FULL_PROOF)
1687
22
      && getSmtMode() == SmtMode::UNSAT)
1688
  {
1689
    // minimize instantiations based on proof manager
1690
7
    getRelevantInstantiationTermVectors(insts);
1691
  }
1692
  else
1693
  {
1694
    QuantifiersEngine* qe =
1695
8
        getAvailableQuantifiersEngine("getInstantiationTermVectors");
1696
    // otherwise, just get the list of all instantiations
1697
8
    qe->getInstantiationTermVectors(insts);
1698
  }
1699
15
}
1700
1701
86
bool SmtEngine::getSynthSolutions(std::map<Node, Node>& solMap)
1702
{
1703
172
  SmtScope smts(this);
1704
86
  finishInit();
1705
172
  return d_sygusSolver->getSynthSolutions(solMap);
1706
}
1707
1708
30
Node SmtEngine::getQuantifierElimination(Node q, bool doFull, bool strict)
1709
{
1710
60
  SmtScope smts(this);
1711
30
  finishInit();
1712
30
  const LogicInfo& logic = getLogicInfo();
1713
30
  if (!logic.isPure(THEORY_ARITH) && strict)
1714
  {
1715
10
    Warning() << "Unexpected logic for quantifier elimination " << logic
1716
4
              << endl;
1717
  }
1718
  return d_quantElimSolver->getQuantifierElimination(
1719
60
      *d_asserts, q, doFull, d_isInternalSubsolver);
1720
}
1721
1722
10
bool SmtEngine::getInterpol(const Node& conj,
1723
                            const TypeNode& grammarType,
1724
                            Node& interpol)
1725
{
1726
20
  SmtScope smts(this);
1727
10
  finishInit();
1728
10
  bool success = d_interpolSolver->getInterpol(conj, grammarType, interpol);
1729
  // notify the state of whether the get-interpol call was successfuly, which
1730
  // impacts the SMT mode.
1731
10
  d_state->notifyGetInterpol(success);
1732
20
  return success;
1733
}
1734
1735
9
bool SmtEngine::getInterpol(const Node& conj, Node& interpol)
1736
{
1737
18
  TypeNode grammarType;
1738
18
  return getInterpol(conj, grammarType, interpol);
1739
}
1740
1741
16
bool SmtEngine::getAbduct(const Node& conj,
1742
                          const TypeNode& grammarType,
1743
                          Node& abd)
1744
{
1745
32
  SmtScope smts(this);
1746
16
  finishInit();
1747
16
  bool success = d_abductSolver->getAbduct(conj, grammarType, abd);
1748
  // notify the state of whether the get-abduct call was successfuly, which
1749
  // impacts the SMT mode.
1750
14
  d_state->notifyGetAbduct(success);
1751
28
  return success;
1752
}
1753
1754
10
bool SmtEngine::getAbduct(const Node& conj, Node& abd)
1755
{
1756
20
  TypeNode grammarType;
1757
19
  return getAbduct(conj, grammarType, abd);
1758
}
1759
1760
47
void SmtEngine::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
1761
{
1762
94
  SmtScope smts(this);
1763
  QuantifiersEngine* qe =
1764
47
      getAvailableQuantifiersEngine("getInstantiatedQuantifiedFormulas");
1765
47
  qe->getInstantiatedQuantifiedFormulas(qs);
1766
47
}
1767
1768
42
void SmtEngine::getInstantiationTermVectors(
1769
    Node q, std::vector<std::vector<Node>>& tvecs)
1770
{
1771
84
  SmtScope smts(this);
1772
  QuantifiersEngine* qe =
1773
42
      getAvailableQuantifiersEngine("getInstantiationTermVectors");
1774
42
  qe->getInstantiationTermVectors(q, tvecs);
1775
42
}
1776
1777
94
std::vector<Node> SmtEngine::getAssertions()
1778
{
1779
188
  SmtScope smts(this);
1780
94
  finishInit();
1781
94
  d_state->doPendingPops();
1782
94
  if (Dump.isOn("benchmark"))
1783
  {
1784
    getPrinter().toStreamCmdGetAssertions(d_env->getDumpOut());
1785
  }
1786
94
  Trace("smt") << "SMT getAssertions()" << endl;
1787
94
  if (!d_env->getOptions().smt.produceAssertions)
1788
  {
1789
2
    const char* msg =
1790
      "Cannot query the current assertion list when not in produce-assertions mode.";
1791
2
    throw ModalException(msg);
1792
  }
1793
92
  context::CDList<Node>* al = d_asserts->getAssertionList();
1794
92
  Assert(al != nullptr);
1795
92
  std::vector<Node> res;
1796
382
  for (const Node& n : *al)
1797
  {
1798
290
    res.emplace_back(n);
1799
  }
1800
  // copy the result out
1801
184
  return res;
1802
}
1803
1804
4036
void SmtEngine::push()
1805
{
1806
8072
  SmtScope smts(this);
1807
4036
  finishInit();
1808
4036
  d_state->doPendingPops();
1809
4036
  Trace("smt") << "SMT push()" << endl;
1810
4036
  d_smtSolver->processAssertions(*d_asserts);
1811
4036
  if(Dump.isOn("benchmark")) {
1812
    getPrinter().toStreamCmdPush(d_env->getDumpOut());
1813
  }
1814
4036
  d_state->userPush();
1815
4036
}
1816
1817
3497
void SmtEngine::pop() {
1818
6994
  SmtScope smts(this);
1819
3497
  finishInit();
1820
3497
  Trace("smt") << "SMT pop()" << endl;
1821
3497
  if (Dump.isOn("benchmark"))
1822
  {
1823
    getPrinter().toStreamCmdPop(d_env->getDumpOut());
1824
  }
1825
3497
  d_state->userPop();
1826
1827
  // Clear out assertion queues etc., in case anything is still in there
1828
3497
  d_asserts->clearCurrent();
1829
  // clear the learned literals from the preprocessor
1830
3497
  d_pp->clearLearnedLiterals();
1831
1832
6994
  Trace("userpushpop") << "SmtEngine: popped to level "
1833
3497
                       << getUserContext()->getLevel() << endl;
1834
  // should we reset d_status here?
1835
  // SMT-LIBv2 spec seems to imply no, but it would make sense to..
1836
3497
}
1837
1838
71
void SmtEngine::resetAssertions()
1839
{
1840
138
  SmtScope smts(this);
1841
1842
71
  if (!d_state->isFullyInited())
1843
  {
1844
    // We're still in Start Mode, nothing asserted yet, do nothing.
1845
    // (see solver execution modes in the SMT-LIB standard)
1846
4
    Assert(getContext()->getLevel() == 0);
1847
4
    Assert(getUserContext()->getLevel() == 0);
1848
4
    getDumpManager()->resetAssertions();
1849
4
    return;
1850
  }
1851
1852
1853
67
  Trace("smt") << "SMT resetAssertions()" << endl;
1854
67
  if (Dump.isOn("benchmark"))
1855
  {
1856
    getPrinter().toStreamCmdResetAssertions(d_env->getDumpOut());
1857
  }
1858
1859
67
  d_asserts->clearCurrent();
1860
67
  d_state->notifyResetAssertions();
1861
67
  getDumpManager()->resetAssertions();
1862
  // push the state to maintain global context around everything
1863
67
  d_state->setup();
1864
1865
  // reset SmtSolver, which will construct a new prop engine
1866
67
  d_smtSolver->resetAssertions();
1867
}
1868
1869
void SmtEngine::interrupt()
1870
{
1871
  if (!d_state->isFullyInited())
1872
  {
1873
    return;
1874
  }
1875
  d_smtSolver->interrupt();
1876
}
1877
1878
void SmtEngine::setResourceLimit(uint64_t units, bool cumulative)
1879
{
1880
  if (cumulative)
1881
  {
1882
    d_env->d_options.base.cumulativeResourceLimit = units;
1883
  }
1884
  else
1885
  {
1886
    d_env->d_options.base.perCallResourceLimit = units;
1887
  }
1888
}
1889
void SmtEngine::setTimeLimit(uint64_t millis)
1890
{
1891
  d_env->d_options.base.perCallMillisecondLimit = millis;
1892
}
1893
1894
unsigned long SmtEngine::getResourceUsage() const
1895
{
1896
  return getResourceManager()->getResourceUsage();
1897
}
1898
1899
unsigned long SmtEngine::getTimeUsage() const
1900
{
1901
  return getResourceManager()->getTimeUsage();
1902
}
1903
1904
unsigned long SmtEngine::getResourceRemaining() const
1905
{
1906
  return getResourceManager()->getResourceRemaining();
1907
}
1908
1909
801782
NodeManager* SmtEngine::getNodeManager() const
1910
{
1911
801782
  return d_env->getNodeManager();
1912
}
1913
1914
void SmtEngine::printStatisticsSafe(int fd) const
1915
{
1916
  d_env->getStatisticsRegistry().printSafe(fd);
1917
}
1918
1919
void SmtEngine::printStatisticsDiff() const
1920
{
1921
  d_env->getStatisticsRegistry().printDiff(*d_env->getOptions().base.err);
1922
  d_env->getStatisticsRegistry().storeSnapshot();
1923
}
1924
1925
208
void SmtEngine::setUserAttribute(const std::string& attr,
1926
                                 Node expr,
1927
                                 const std::vector<Node>& expr_values,
1928
                                 const std::string& str_value)
1929
{
1930
416
  SmtScope smts(this);
1931
208
  finishInit();
1932
208
  TheoryEngine* te = getTheoryEngine();
1933
208
  Assert(te != nullptr);
1934
208
  te->setUserAttribute(attr, expr, expr_values, str_value);
1935
208
}
1936
1937
9534
void SmtEngine::setOption(const std::string& key, const std::string& value)
1938
{
1939
19064
  NodeManagerScope nms(getNodeManager());
1940
9534
  Trace("smt") << "SMT setOption(" << key << ", " << value << ")" << endl;
1941
1942
9534
  if (Dump.isOn("benchmark"))
1943
  {
1944
2
    getPrinter().toStreamCmdSetOption(d_env->getDumpOut(), key, value);
1945
  }
1946
1947
9534
  if (key == "command-verbosity")
1948
  {
1949
4
    size_t fstIndex = value.find(" ");
1950
4
    size_t sndIndex = value.find(" ", fstIndex + 1);
1951
4
    if (sndIndex == std::string::npos)
1952
    {
1953
8
      string c = value.substr(1, fstIndex - 1);
1954
      int v =
1955
4
          std::stoi(value.substr(fstIndex + 1, value.length() - fstIndex - 1));
1956
4
      if (v < 0 || v > 2)
1957
      {
1958
        throw OptionException("command-verbosity must be 0, 1, or 2");
1959
      }
1960
4
      d_commandVerbosity[c] = v;
1961
4
      return;
1962
    }
1963
    throw OptionException(
1964
        "command-verbosity value must be a tuple (command-name integer)");
1965
  }
1966
1967
9530
  if (value.find(" ") != std::string::npos)
1968
  {
1969
    throw OptionException("bad value for :" + key);
1970
  }
1971
1972
19060
  std::string optionarg = value;
1973
9530
  options::set(getOptions(), key, optionarg);
1974
}
1975
1976
2681
void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver = true; }
1977
1978
13735
bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver; }
1979
1980
597216
std::string SmtEngine::getOption(const std::string& key) const
1981
{
1982
1194432
  NodeManagerScope nms(getNodeManager());
1983
597216
  NodeManager* nm = d_env->getNodeManager();
1984
1985
597216
  Trace("smt") << "SMT getOption(" << key << ")" << endl;
1986
1987
597216
  if (key.find("command-verbosity:") == 0)
1988
  {
1989
597154
    auto it = d_commandVerbosity.find(key.substr(std::strlen("command-verbosity:")));
1990
597154
    if (it != d_commandVerbosity.end())
1991
    {
1992
      return std::to_string(it->second);
1993
    }
1994
597154
    it = d_commandVerbosity.find("*");
1995
597154
    if (it != d_commandVerbosity.end())
1996
    {
1997
32
      return std::to_string(it->second);
1998
    }
1999
597122
    return "2";
2000
  }
2001
2002
62
  if (Dump.isOn("benchmark"))
2003
  {
2004
    getPrinter().toStreamCmdGetOption(d_outMgr.getDumpOut(), key);
2005
  }
2006
2007
62
  if (key == "command-verbosity")
2008
  {
2009
6
    vector<Node> result;
2010
6
    Node defaultVerbosity;
2011
7
    for (const auto& verb: d_commandVerbosity)
2012
    {
2013
      // treat the command name as a variable name as opposed to a string
2014
      // constant to avoid printing double quotes around the name
2015
8
      Node name = nm->mkBoundVar(verb.first, nm->integerType());
2016
8
      Node value = nm->mkConst(Rational(verb.second));
2017
4
      if (verb.first == "*")
2018
      {
2019
        // put the default at the end of the SExpr
2020
2
        defaultVerbosity = nm->mkNode(Kind::SEXPR, name, value);
2021
      }
2022
      else
2023
      {
2024
2
        result.push_back(nm->mkNode(Kind::SEXPR, name, value));
2025
      }
2026
    }
2027
    // ensure the default is always listed
2028
3
    if (defaultVerbosity.isNull())
2029
    {
2030
3
      defaultVerbosity = nm->mkNode(Kind::SEXPR,
2031
2
                                    nm->mkBoundVar("*", nm->integerType()),
2032
2
                                    nm->mkConst(Rational(2)));
2033
    }
2034
3
    result.push_back(defaultVerbosity);
2035
3
    return nm->mkNode(Kind::SEXPR, result).toString();
2036
  }
2037
2038
116
  std::string atom = options::get(getOptions(), key);
2039
2040
57
  if (atom != "true" && atom != "false")
2041
  {
2042
    try
2043
    {
2044
13
      Integer z(atom);
2045
    }
2046
4
    catch (std::invalid_argument&)
2047
    {
2048
2
      atom = "\"" + atom + "\"";
2049
    }
2050
  }
2051
2052
57
  return atom;
2053
}
2054
2055
3752163
Options& SmtEngine::getOptions() { return d_env->d_options; }
2056
2057
59
const Options& SmtEngine::getOptions() const { return d_env->getOptions(); }
2058
2059
7252802
ResourceManager* SmtEngine::getResourceManager() const
2060
{
2061
7252802
  return d_env->getResourceManager();
2062
}
2063
2064
22685
DumpManager* SmtEngine::getDumpManager() { return d_env->getDumpManager(); }
2065
2066
10
const Printer& SmtEngine::getPrinter() const { return d_env->getPrinter(); }
2067
2068
1
OutputManager& SmtEngine::getOutputManager() { return d_outMgr; }
2069
2070
32206637
theory::Rewriter* SmtEngine::getRewriter() { return d_env->getRewriter(); }
2071
2072
29286
}  // namespace cvc5