GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 855 1015 84.2 %
Date: 2021-09-15 Branches: 1270 3271 38.8 %

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