GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 804 1008 79.8 %
Date: 2021-09-29 Branches: 1176 3235 36.4 %

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