GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 852 1012 84.2 %
Date: 2021-09-18 Branches: 1254 3243 38.7 %

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
13207
SmtEngine::SmtEngine(NodeManager* nm, const Options* optr)
88
13207
    : d_env(new Env(nm, optr)),
89
13207
      d_state(new SmtEngineState(*d_env.get(), *this)),
90
13207
      d_absValues(new AbstractValues(getNodeManager())),
91
13207
      d_asserts(new Assertions(*d_env.get(), *d_absValues.get())),
92
13207
      d_routListener(new ResourceOutListener(*this)),
93
13207
      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
92449
      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
13207
  d_scope.reset(new SmtScope(this));
121
  // listen to node manager events
122
13207
  getNodeManager()->subscribeEvents(d_snmListener.get());
123
  // listen to resource out
124
13207
  getResourceManager()->registerListener(d_routListener.get());
125
  // make statistics
126
13207
  d_stats.reset(new SmtEngineStatistics());
127
  // reset the preprocessor
128
39621
  d_pp.reset(
129
26414
      new smt::Preprocessor(*this, *d_env.get(), *d_absValues.get(), *d_stats));
130
  // make the SMT solver
131
13207
  d_smtSolver.reset(new SmtSolver(*d_env.get(), *d_state, *d_pp, *d_stats));
132
  // make the SyGuS solver
133
13207
  d_sygusSolver.reset(new SygusSolver(*d_env.get(), *d_smtSolver, *d_pp));
134
  // make the quantifier elimination solver
135
13207
  d_quantElimSolver.reset(new QuantElimSolver(*d_env.get(), *d_smtSolver));
136
13207
}
137
138
42192
bool SmtEngine::isFullyInited() const { return d_state->isFullyInited(); }
139
11004
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
344038
TheoryEngine* SmtEngine::getTheoryEngine()
161
{
162
344038
  return d_smtSolver->getTheoryEngine();
163
}
164
165
56410
prop::PropEngine* SmtEngine::getPropEngine()
166
{
167
56410
  return d_smtSolver->getPropEngine();
168
}
169
170
119620
void SmtEngine::finishInit()
171
{
172
119620
  if (d_state->isFullyInited())
173
  {
174
    // already initialized, return
175
109679
    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
9941
  const LogicInfo& logic = getLogicInfo();
184
9941
  if (!logic.isLocked())
185
  {
186
1613
    setLogicInternal();
187
  }
188
189
  // set the random seed
190
9941
  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
9941
  SetDefaults sdefaults(d_isInternalSubsolver);
195
9941
  sdefaults.setDefaults(d_env->d_logic, getOptions());
196
197
9940
  if (d_env->getOptions().smt.produceProofs)
198
  {
199
    // ensure bound variable uses canonical bound variables
200
3794
    getNodeManager()->getBoundVarManager()->enableKeepCacheValues();
201
    // make the proof manager
202
3794
    d_pfManager.reset(new PfManager(*d_env.get()));
203
3794
    PreprocessProofGenerator* pppg = d_pfManager->getPreprocessProofGenerator();
204
    // start the unsat core manager
205
3794
    d_ucManager.reset(new UnsatCoreManager());
206
    // enable it in the assertions pipeline
207
3794
    d_asserts->setProofGenerator(pppg);
208
    // enabled proofs in the preprocessor
209
3794
    d_pp->setProofGenerator(pppg);
210
  }
211
212
9940
  Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
213
9940
  d_smtSolver->finishInit(logic);
214
215
  // now can construct the SMT-level model object
216
9940
  TheoryEngine* te = d_smtSolver->getTheoryEngine();
217
9940
  Assert(te != nullptr);
218
9940
  TheoryModel* tm = te->getModel();
219
9940
  if (tm != nullptr)
220
  {
221
    // make the check models utility
222
9940
    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
9940
  d_state->setup();
228
229
9940
  Trace("smt-debug") << "Set up assertions..." << std::endl;
230
9940
  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
9940
  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
9940
  getDumpManager()->finishInit();
249
250
  // subsolvers
251
9940
  if (d_env->getOptions().smt.produceAbducts)
252
  {
253
317
    d_abductSolver.reset(new AbductionSolver(*d_env.get()));
254
  }
255
19880
  if (d_env->getOptions().smt.produceInterpols
256
9940
      != options::ProduceInterpols::NONE)
257
  {
258
120
    d_interpolSolver.reset(new InterpolationSolver(*d_env.get()));
259
  }
260
261
9940
  d_pp->finishInit();
262
263
9940
  AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
264
      << "The PropEngine has pushed but the SmtEngine "
265
         "hasn't finished initializing!";
266
267
9940
  Assert(getLogicInfo().isLocked());
268
269
  // store that we are finished initializing
270
9940
  d_state->finishInit();
271
9940
  Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
272
}
273
274
10560
void SmtEngine::shutdown() {
275
10560
  d_state->shutdown();
276
277
10560
  d_smtSolver->shutdown();
278
279
10560
  d_env->shutdown();
280
10560
}
281
282
21120
SmtEngine::~SmtEngine()
283
{
284
21120
  SmtScope smts(this);
285
286
  try {
287
10560
    shutdown();
288
289
    // global push/pop around everything, to ensure proper destruction
290
    // of context-dependent data structures
291
10560
    d_state->cleanup();
292
293
    //destroy all passes before destroying things that they refer to
294
10560
    d_pp->cleanup();
295
296
10560
    d_pfManager.reset(nullptr);
297
10560
    d_ucManager.reset(nullptr);
298
299
10560
    d_absValues.reset(nullptr);
300
10560
    d_asserts.reset(nullptr);
301
302
10560
    d_abductSolver.reset(nullptr);
303
10560
    d_interpolSolver.reset(nullptr);
304
10560
    d_quantElimSolver.reset(nullptr);
305
10560
    d_sygusSolver.reset(nullptr);
306
10560
    d_smtSolver.reset(nullptr);
307
308
10560
    d_stats.reset(nullptr);
309
10560
    getNodeManager()->unsubscribeEvents(d_snmListener.get());
310
10560
    d_snmListener.reset(nullptr);
311
10560
    d_routListener.reset(nullptr);
312
10560
    d_pp.reset(nullptr);
313
    // destroy the state
314
10560
    d_state.reset(nullptr);
315
    // destroy the environment
316
10560
    d_env.reset(nullptr);
317
  } catch(Exception& e) {
318
    Warning() << "cvc5 threw an exception during cleanup." << endl << e << endl;
319
  }
320
10560
}
321
322
8414
void SmtEngine::setLogic(const LogicInfo& logic)
323
{
324
16828
  SmtScope smts(this);
325
8414
  if (d_state->isFullyInited())
326
  {
327
    throw ModalException("Cannot set logic in SmtEngine after the engine has "
328
                         "finished initializing.");
329
  }
330
8414
  d_env->d_logic = logic;
331
8414
  d_userLogic = logic;
332
8414
  setLogicInternal();
333
8414
}
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
34000
const LogicInfo& SmtEngine::getLogicInfo() const
351
{
352
34000
  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
10027
void SmtEngine::setLogicInternal()
365
{
366
10027
  Assert(!d_state->isFullyInited())
367
      << "setting logic in SmtEngine but the engine has already"
368
         " finished initializing for this run";
369
10027
  d_env->d_logic.lock();
370
10027
  d_userLogic.lock();
371
10027
}
372
373
11889
void SmtEngine::setInfo(const std::string& key, const std::string& value)
374
{
375
23778
  SmtScope smts(this);
376
377
11889
  Trace("smt") << "SMT setInfo(" << key << ", " << value << ")" << endl;
378
379
11889
  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
11889
  if (key == "filename")
396
  {
397
6222
    d_env->d_options.driver.filename = value;
398
6222
    d_env->d_originalOptions->driver.filename = value;
399
12444
    d_env->getStatisticsRegistry().registerValue<std::string>(
400
12444
        "driver::filename", value);
401
  }
402
5667
  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
5659
  else if (key == "status")
425
  {
426
3693
    d_state->notifyExpectedStatus(value);
427
  }
428
11889
}
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
89166
Result SmtEngine::quickCheck() {
693
89166
  Assert(d_state->isFullyInited());
694
89166
  Trace("smt") << "SMT quickCheck()" << endl;
695
89166
  const std::string& filename = d_env->getOptions().driver.filename;
696
  return Result(
697
89166
      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
15246
void SmtEngine::notifyPostSolvePre()
772
{
773
15246
  PropEngine* pe = getPropEngine();
774
15246
  Assert(pe != nullptr);
775
15246
  pe->resetTrail();
776
15246
}
777
778
15246
void SmtEngine::notifyPostSolvePost()
779
{
780
15246
  TheoryEngine* te = getTheoryEngine();
781
15246
  Assert(te != nullptr);
782
15246
  te->postsolve();
783
15246
}
784
785
12819
Result SmtEngine::checkSat()
786
{
787
25638
  Node nullNode;
788
25620
  return checkSat(nullNode);
789
}
790
791
13406
Result SmtEngine::checkSat(const Node& assumption)
792
{
793
13406
  if (Dump.isOn("benchmark"))
794
  {
795
1
    getPrinter().toStreamCmdCheckSat(d_env->getDumpOut(), assumption);
796
  }
797
26812
  std::vector<Node> assump;
798
13406
  if (!assumption.isNull())
799
  {
800
587
    assump.push_back(assumption);
801
  }
802
26793
  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
15037
Result SmtEngine::checkSatInternal(const std::vector<Node>& assumptions,
840
                                   bool isEntailmentCheck)
841
{
842
  try
843
  {
844
30074
    SmtScope smts(this);
845
15037
    finishInit();
846
847
30074
    Trace("smt") << "SmtEngine::"
848
30074
                 << (isEntailmentCheck ? "checkEntailed" : "checkSat") << "("
849
15037
                 << assumptions << ")" << endl;
850
    // check the satisfiability with the solver object
851
    Result r = d_smtSolver->checkSatisfiability(
852
30053
        *d_asserts.get(), assumptions, isEntailmentCheck);
853
854
30032
    Trace("smt") << "SmtEngine::" << (isEntailmentCheck ? "query" : "checkSat")
855
15016
                 << "(" << assumptions << ") => " << r << endl;
856
857
    // Check that SAT results generate a model correctly.
858
15016
    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
30028
    if (d_env->getOptions().smt.checkProofs
867
15014
        || 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
15014
    if (d_env->getOptions().smt.checkUnsatCores)
885
    {
886
2377
      if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
887
      {
888
2750
        TimerStat::CodeTimer checkUnsatCoreTimer(d_stats->d_checkUnsatCoreTime);
889
1375
        checkUnsatCore();
890
      }
891
    }
892
15014
    if (d_env->getOptions().base.statisticsEveryQuery)
893
    {
894
      printStatisticsDiff();
895
    }
896
15014
    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
89167
Result SmtEngine::assertFormula(const Node& formula)
952
{
953
178334
  SmtScope smts(this);
954
89167
  finishInit();
955
89166
  d_state->doPendingPops();
956
957
89166
  Trace("smt") << "SmtEngine::assertFormula(" << formula << ")" << endl;
958
959
  // Substitute out any abstract values in ex
960
178332
  Node n = d_absValues->substituteAbstractValues(formula);
961
962
89166
  d_asserts->assertFormula(n);
963
178332
  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
  Node heap;
1260
20
  Node nil;
1261
10
  TheoryModel* tm = getAvailableModel("get separation logic heap and nil");
1262
10
  if (!tm->getHeapModel(heap, nil))
1263
  {
1264
4
    const char* msg =
1265
        "Failed to obtain heap/nil "
1266
        "expressions from theory model.";
1267
4
    throw RecoverableModalException(msg);
1268
  }
1269
12
  return std::make_pair(heap, nil);
1270
}
1271
1272
84
std::vector<Node> SmtEngine::getAssertionsInternal()
1273
{
1274
84
  Assert(d_state->isFullyInited());
1275
84
  context::CDList<Node>* al = d_asserts->getAssertionList();
1276
84
  Assert(al != nullptr);
1277
84
  std::vector<Node> res;
1278
312
  for (const Node& n : *al)
1279
  {
1280
228
    res.emplace_back(n);
1281
  }
1282
84
  return res;
1283
}
1284
1285
84
std::vector<Node> SmtEngine::getExpandedAssertions()
1286
{
1287
84
  std::vector<Node> easserts = getAssertions();
1288
  // must expand definitions
1289
82
  d_pp->expandDefinitions(easserts);
1290
82
  return easserts;
1291
}
1292
132
Env& SmtEngine::getEnv() { return *d_env.get(); }
1293
1294
121
void SmtEngine::declareSepHeap(TypeNode locT, TypeNode dataT)
1295
{
1296
121
  if (!getLogicInfo().isTheoryEnabled(THEORY_SEP))
1297
  {
1298
    const char* msg =
1299
        "Cannot declare heap if not using the separation logic theory.";
1300
    throw RecoverableModalException(msg);
1301
  }
1302
242
  SmtScope smts(this);
1303
121
  finishInit();
1304
121
  TheoryEngine* te = getTheoryEngine();
1305
123
  te->declareSepHeap(locT, dataT);
1306
119
}
1307
1308
1404
bool SmtEngine::getSepHeapTypes(TypeNode& locT, TypeNode& dataT)
1309
{
1310
2808
  SmtScope smts(this);
1311
1404
  finishInit();
1312
1404
  TheoryEngine* te = getTheoryEngine();
1313
2808
  return te->getSepHeapTypes(locT, dataT);
1314
}
1315
1316
5
Node SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
1317
1318
5
Node SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
1319
1320
1376
void SmtEngine::checkProof()
1321
{
1322
1376
  Assert(d_env->getOptions().smt.produceProofs);
1323
  // internal check the proof
1324
1376
  PropEngine* pe = getPropEngine();
1325
1376
  Assert(pe != nullptr);
1326
1376
  if (d_env->getOptions().proof.proofCheck == options::ProofCheckMode::EAGER)
1327
  {
1328
    pe->checkProof(d_asserts->getAssertionList());
1329
  }
1330
1376
  Assert(pe->getProof() != nullptr);
1331
2752
  std::shared_ptr<ProofNode> pePfn = pe->getProof();
1332
1376
  if (d_env->getOptions().smt.checkProofs)
1333
  {
1334
1376
    d_pfManager->checkProof(pePfn, *d_asserts);
1335
  }
1336
1376
}
1337
1338
2826178
StatisticsRegistry& SmtEngine::getStatisticsRegistry()
1339
{
1340
2826178
  return d_env->getStatisticsRegistry();
1341
}
1342
1343
1431
UnsatCore SmtEngine::getUnsatCoreInternal()
1344
{
1345
1431
  if (!d_env->getOptions().smt.unsatCores)
1346
  {
1347
    throw ModalException(
1348
        "Cannot get an unsat core when produce-unsat-cores or produce-proofs "
1349
        "option is off.");
1350
  }
1351
1431
  if (d_state->getMode() != SmtMode::UNSAT)
1352
  {
1353
    throw RecoverableModalException(
1354
        "Cannot get an unsat core unless immediately preceded by "
1355
        "UNSAT/ENTAILED response.");
1356
  }
1357
  // generate with new proofs
1358
1431
  PropEngine* pe = getPropEngine();
1359
1431
  Assert(pe != nullptr);
1360
1361
2862
  std::shared_ptr<ProofNode> pepf;
1362
1431
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
1363
  {
1364
1378
    pepf = pe->getRefutation();
1365
  }
1366
  else
1367
  {
1368
53
    pepf = pe->getProof();
1369
  }
1370
1431
  Assert(pepf != nullptr);
1371
2862
  std::shared_ptr<ProofNode> pfn = d_pfManager->getFinalProof(pepf, *d_asserts);
1372
2862
  std::vector<Node> core;
1373
1431
  d_ucManager->getUnsatCore(pfn, *d_asserts, core);
1374
1431
  if (options::minimalUnsatCores())
1375
  {
1376
1
    core = reduceUnsatCore(core);
1377
  }
1378
2862
  return UnsatCore(core);
1379
}
1380
1381
1
std::vector<Node> SmtEngine::reduceUnsatCore(const std::vector<Node>& core)
1382
{
1383
1
  Assert(options::unsatCores())
1384
      << "cannot reduce unsat core if unsat cores are turned off";
1385
1386
1
  Notice() << "SmtEngine::reduceUnsatCore(): reducing unsat core" << endl;
1387
2
  std::unordered_set<Node> removed;
1388
4
  for (const Node& skip : core)
1389
  {
1390
6
    std::unique_ptr<SmtEngine> coreChecker;
1391
3
    initializeSubsolver(coreChecker, *d_env.get());
1392
3
    coreChecker->setLogic(getLogicInfo());
1393
3
    coreChecker->getOptions().smt.checkUnsatCores = false;
1394
    // disable all proof options
1395
3
    coreChecker->getOptions().smt.produceProofs = false;
1396
3
    coreChecker->getOptions().smt.checkProofs = false;
1397
1398
12
    for (const Node& ucAssertion : core)
1399
    {
1400
9
      if (ucAssertion != skip && removed.find(ucAssertion) == removed.end())
1401
      {
1402
8
        Node assertionAfterExpansion = expandDefinitions(ucAssertion);
1403
4
        coreChecker->assertFormula(assertionAfterExpansion);
1404
      }
1405
    }
1406
6
    Result r;
1407
    try
1408
    {
1409
3
      r = coreChecker->checkSat();
1410
    }
1411
    catch (...)
1412
    {
1413
      throw;
1414
    }
1415
1416
3
    if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
1417
    {
1418
1
      removed.insert(skip);
1419
    }
1420
2
    else if (r.asSatisfiabilityResult().isUnknown())
1421
    {
1422
      Warning() << "SmtEngine::reduceUnsatCore(): could not reduce unsat core "
1423
                   "due to "
1424
                   "unknown result.";
1425
    }
1426
  }
1427
1428
1
  if (removed.empty())
1429
  {
1430
    return core;
1431
  }
1432
  else
1433
  {
1434
2
    std::vector<Node> newUcAssertions;
1435
4
    for (const Node& n : core)
1436
    {
1437
3
      if (removed.find(n) == removed.end())
1438
      {
1439
2
        newUcAssertions.push_back(n);
1440
      }
1441
    }
1442
1443
1
    return newUcAssertions;
1444
  }
1445
}
1446
1447
1375
void SmtEngine::checkUnsatCore() {
1448
1375
  Assert(d_env->getOptions().smt.unsatCores)
1449
      << "cannot check unsat core if unsat cores are turned off";
1450
1451
1375
  Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl;
1452
2750
  UnsatCore core = getUnsatCore();
1453
1454
  // initialize the core checker
1455
2750
  std::unique_ptr<SmtEngine> coreChecker;
1456
1375
  initializeSubsolver(coreChecker, *d_env.get());
1457
1375
  coreChecker->getOptions().smt.checkUnsatCores = false;
1458
  // disable all proof options
1459
1375
  coreChecker->getOptions().smt.produceProofs = false;
1460
1375
  coreChecker->getOptions().smt.checkProofs = false;
1461
1462
  // set up separation logic heap if necessary
1463
2750
  TypeNode sepLocType, sepDataType;
1464
1375
  if (getSepHeapTypes(sepLocType, sepDataType))
1465
  {
1466
21
    coreChecker->declareSepHeap(sepLocType, sepDataType);
1467
  }
1468
1469
1375
  Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
1470
           << std::endl;
1471
1375
  theory::TrustSubstitutionMap& tls = d_env->getTopLevelSubstitutions();
1472
7338
  for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
1473
11926
    Node assertionAfterExpansion = tls.apply(*i, false);
1474
5963
    Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
1475
             << ", expanded to " << assertionAfterExpansion << "\n";
1476
5963
    coreChecker->assertFormula(assertionAfterExpansion);
1477
  }
1478
2750
  Result r;
1479
  try {
1480
1375
    r = coreChecker->checkSat();
1481
  } catch(...) {
1482
    throw;
1483
  }
1484
1375
  Notice() << "SmtEngine::checkUnsatCore(): result is " << r << endl;
1485
1375
  if(r.asSatisfiabilityResult().isUnknown()) {
1486
1
    Warning()
1487
        << "SmtEngine::checkUnsatCore(): could not check core result unknown."
1488
        << std::endl;
1489
  }
1490
1374
  else if (r.asSatisfiabilityResult().isSat())
1491
  {
1492
    InternalError()
1493
        << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
1494
  }
1495
1375
}
1496
1497
2158
void SmtEngine::checkModel(bool hardFailure) {
1498
2158
  context::CDList<Node>* al = d_asserts->getAssertionList();
1499
  // --check-model implies --produce-assertions, which enables the
1500
  // assertion list, so we should be ok.
1501
2158
  Assert(al != nullptr)
1502
      << "don't have an assertion list to check in SmtEngine::checkModel()";
1503
1504
4316
  TimerStat::CodeTimer checkModelTimer(d_stats->d_checkModelTime);
1505
1506
2158
  Notice() << "SmtEngine::checkModel(): generating model" << endl;
1507
2158
  TheoryModel* m = getAvailableModel("check model");
1508
2157
  Assert(m != nullptr);
1509
1510
  // check the model with the theory engine for debugging
1511
2157
  if (options::debugCheckModels())
1512
  {
1513
2141
    TheoryEngine* te = getTheoryEngine();
1514
2141
    Assert(te != nullptr);
1515
2141
    te->checkTheoryAssertionsWithModel(hardFailure);
1516
  }
1517
1518
  // check the model with the check models utility
1519
2157
  Assert(d_checkModels != nullptr);
1520
2157
  d_checkModels->checkModel(m, al, hardFailure);
1521
2156
}
1522
1523
1418
UnsatCore SmtEngine::getUnsatCore() {
1524
1418
  Trace("smt") << "SMT getUnsatCore()" << std::endl;
1525
2836
  SmtScope smts(this);
1526
1418
  finishInit();
1527
1418
  if (Dump.isOn("benchmark"))
1528
  {
1529
    getPrinter().toStreamCmdGetUnsatCore(d_env->getDumpOut());
1530
  }
1531
2836
  return getUnsatCoreInternal();
1532
}
1533
1534
7
void SmtEngine::getRelevantInstantiationTermVectors(
1535
    std::map<Node, InstantiationList>& insts, bool getDebugInfo)
1536
{
1537
7
  Assert(d_state->getMode() == SmtMode::UNSAT);
1538
  // generate with new proofs
1539
7
  PropEngine* pe = getPropEngine();
1540
7
  Assert(pe != nullptr);
1541
7
  Assert(pe->getProof() != nullptr);
1542
  std::shared_ptr<ProofNode> pfn =
1543
14
      d_pfManager->getFinalProof(pe->getProof(), *d_asserts);
1544
7
  d_ucManager->getRelevantInstantiations(pfn, insts, getDebugInfo);
1545
7
}
1546
1547
5
std::string SmtEngine::getProof()
1548
{
1549
5
  Trace("smt") << "SMT getProof()\n";
1550
10
  SmtScope smts(this);
1551
5
  finishInit();
1552
5
  if (Dump.isOn("benchmark"))
1553
  {
1554
    getPrinter().toStreamCmdGetProof(d_env->getDumpOut());
1555
  }
1556
5
  if (!d_env->getOptions().smt.produceProofs)
1557
  {
1558
    throw ModalException("Cannot get a proof when proof option is off.");
1559
  }
1560
5
  if (d_state->getMode() != SmtMode::UNSAT)
1561
  {
1562
    throw RecoverableModalException(
1563
        "Cannot get a proof unless immediately preceded by "
1564
        "UNSAT/ENTAILED response.");
1565
  }
1566
  // the prop engine has the proof of false
1567
5
  PropEngine* pe = getPropEngine();
1568
5
  Assert(pe != nullptr);
1569
5
  Assert(pe->getProof() != nullptr);
1570
5
  Assert(d_pfManager);
1571
10
  std::ostringstream ss;
1572
5
  d_pfManager->printProof(ss, pe->getProof(), *d_asserts);
1573
10
  return ss.str();
1574
}
1575
1576
15
void SmtEngine::printInstantiations( std::ostream& out ) {
1577
30
  SmtScope smts(this);
1578
15
  finishInit();
1579
15
  QuantifiersEngine* qe = getAvailableQuantifiersEngine("printInstantiations");
1580
1581
  // First, extract and print the skolemizations
1582
15
  bool printed = false;
1583
15
  bool reqNames = !d_env->getOptions().printer.printInstFull;
1584
  // only print when in list mode
1585
15
  if (d_env->getOptions().printer.printInstMode == options::PrintInstMode::LIST)
1586
  {
1587
24
    std::map<Node, std::vector<Node>> sks;
1588
12
    qe->getSkolemTermVectors(sks);
1589
21
    for (const std::pair<const Node, std::vector<Node>>& s : sks)
1590
    {
1591
18
      Node name;
1592
9
      if (!qe->getNameForQuant(s.first, name, reqNames))
1593
      {
1594
        // did not have a name and we are only printing formulas with names
1595
        continue;
1596
      }
1597
18
      SkolemList slist(name, s.second);
1598
9
      out << slist;
1599
9
      printed = true;
1600
    }
1601
  }
1602
1603
  // Second, extract and print the instantiations
1604
30
  std::map<Node, InstantiationList> rinsts;
1605
30
  if (d_env->getOptions().smt.produceProofs
1606
11
      && (!d_env->getOptions().smt.unsatCores
1607
11
          || d_env->getOptions().smt.unsatCoresMode
1608
                 == options::UnsatCoresMode::FULL_PROOF)
1609
22
      && getSmtMode() == SmtMode::UNSAT)
1610
  {
1611
    // minimize instantiations based on proof manager
1612
7
    getRelevantInstantiationTermVectors(rinsts,
1613
7
                                        options::dumpInstantiationsDebug());
1614
  }
1615
  else
1616
  {
1617
16
    std::map<Node, std::vector<std::vector<Node>>> insts;
1618
8
    getInstantiationTermVectors(insts);
1619
18
    for (const std::pair<const Node, std::vector<std::vector<Node>>>& i : insts)
1620
    {
1621
      // convert to instantiation list
1622
20
      Node q = i.first;
1623
10
      InstantiationList& ilq = rinsts[q];
1624
10
      ilq.initialize(q);
1625
32
      for (const std::vector<Node>& ii : i.second)
1626
      {
1627
22
        ilq.d_inst.push_back(InstantiationVec(ii));
1628
      }
1629
    }
1630
  }
1631
36
  for (std::pair<const Node, InstantiationList>& i : rinsts)
1632
  {
1633
21
    if (i.second.d_inst.empty())
1634
    {
1635
      // no instantiations, skip
1636
      continue;
1637
    }
1638
42
    Node name;
1639
21
    if (!qe->getNameForQuant(i.first, name, reqNames))
1640
    {
1641
      // did not have a name and we are only printing formulas with names
1642
      continue;
1643
    }
1644
    // must have a name
1645
21
    if (d_env->getOptions().printer.printInstMode == options::PrintInstMode::NUM)
1646
    {
1647
12
      out << "(num-instantiations " << name << " " << i.second.d_inst.size()
1648
6
          << ")" << std::endl;
1649
    }
1650
    else
1651
    {
1652
      // take the name
1653
15
      i.second.d_quant = name;
1654
15
      Assert(d_env->getOptions().printer.printInstMode
1655
             == options::PrintInstMode::LIST);
1656
15
      out << i.second;
1657
    }
1658
21
    printed = true;
1659
  }
1660
  // if we did not print anything, we indicate this
1661
15
  if (!printed)
1662
  {
1663
    out << "none" << std::endl;
1664
  }
1665
15
}
1666
1667
8
void SmtEngine::getInstantiationTermVectors(
1668
    std::map<Node, std::vector<std::vector<Node>>>& insts)
1669
{
1670
16
  SmtScope smts(this);
1671
8
  finishInit();
1672
  QuantifiersEngine* qe =
1673
8
      getAvailableQuantifiersEngine("getInstantiationTermVectors");
1674
  // get the list of all instantiations
1675
8
  qe->getInstantiationTermVectors(insts);
1676
8
}
1677
1678
85
bool SmtEngine::getSynthSolutions(std::map<Node, Node>& solMap)
1679
{
1680
170
  SmtScope smts(this);
1681
85
  finishInit();
1682
170
  return d_sygusSolver->getSynthSolutions(solMap);
1683
}
1684
1685
30
Node SmtEngine::getQuantifierElimination(Node q, bool doFull, bool strict)
1686
{
1687
60
  SmtScope smts(this);
1688
30
  finishInit();
1689
30
  const LogicInfo& logic = getLogicInfo();
1690
30
  if (!logic.isPure(THEORY_ARITH) && strict)
1691
  {
1692
10
    Warning() << "Unexpected logic for quantifier elimination " << logic
1693
4
              << endl;
1694
  }
1695
  return d_quantElimSolver->getQuantifierElimination(
1696
60
      *d_asserts, q, doFull, d_isInternalSubsolver);
1697
}
1698
1699
10
bool SmtEngine::getInterpol(const Node& conj,
1700
                            const TypeNode& grammarType,
1701
                            Node& interpol)
1702
{
1703
20
  SmtScope smts(this);
1704
10
  finishInit();
1705
20
  std::vector<Node> axioms = getExpandedAssertions();
1706
  bool success =
1707
10
      d_interpolSolver->getInterpol(axioms, conj, grammarType, interpol);
1708
  // notify the state of whether the get-interpol call was successfuly, which
1709
  // impacts the SMT mode.
1710
10
  d_state->notifyGetInterpol(success);
1711
20
  return success;
1712
}
1713
1714
9
bool SmtEngine::getInterpol(const Node& conj, Node& interpol)
1715
{
1716
18
  TypeNode grammarType;
1717
18
  return getInterpol(conj, grammarType, interpol);
1718
}
1719
1720
16
bool SmtEngine::getAbduct(const Node& conj,
1721
                          const TypeNode& grammarType,
1722
                          Node& abd)
1723
{
1724
32
  SmtScope smts(this);
1725
16
  finishInit();
1726
32
  std::vector<Node> axioms = getExpandedAssertions();
1727
16
  bool success = d_abductSolver->getAbduct(axioms, conj, grammarType, abd);
1728
  // notify the state of whether the get-abduct call was successfuly, which
1729
  // impacts the SMT mode.
1730
14
  d_state->notifyGetAbduct(success);
1731
28
  return success;
1732
}
1733
1734
10
bool SmtEngine::getAbduct(const Node& conj, Node& abd)
1735
{
1736
20
  TypeNode grammarType;
1737
19
  return getAbduct(conj, grammarType, abd);
1738
}
1739
1740
48
void SmtEngine::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
1741
{
1742
96
  SmtScope smts(this);
1743
  QuantifiersEngine* qe =
1744
48
      getAvailableQuantifiersEngine("getInstantiatedQuantifiedFormulas");
1745
48
  qe->getInstantiatedQuantifiedFormulas(qs);
1746
48
}
1747
1748
43
void SmtEngine::getInstantiationTermVectors(
1749
    Node q, std::vector<std::vector<Node>>& tvecs)
1750
{
1751
86
  SmtScope smts(this);
1752
  QuantifiersEngine* qe =
1753
43
      getAvailableQuantifiersEngine("getInstantiationTermVectors");
1754
43
  qe->getInstantiationTermVectors(q, tvecs);
1755
43
}
1756
1757
84
std::vector<Node> SmtEngine::getAssertions()
1758
{
1759
168
  SmtScope smts(this);
1760
84
  finishInit();
1761
84
  d_state->doPendingPops();
1762
84
  if (Dump.isOn("benchmark"))
1763
  {
1764
    getPrinter().toStreamCmdGetAssertions(d_env->getDumpOut());
1765
  }
1766
84
  Trace("smt") << "SMT getAssertions()" << endl;
1767
84
  if (!d_env->getOptions().smt.produceAssertions)
1768
  {
1769
2
    const char* msg =
1770
      "Cannot query the current assertion list when not in produce-assertions mode.";
1771
2
    throw ModalException(msg);
1772
  }
1773
164
  return getAssertionsInternal();
1774
}
1775
1776
6
void SmtEngine::getDifficultyMap(std::map<Node, Node>& dmap)
1777
{
1778
6
  Trace("smt") << "SMT getDifficultyMap()\n";
1779
12
  SmtScope smts(this);
1780
6
  finishInit();
1781
6
  if (Dump.isOn("benchmark"))
1782
  {
1783
    getPrinter().toStreamCmdGetDifficulty(d_env->getDumpOut());
1784
  }
1785
6
  if (!d_env->getOptions().smt.produceDifficulty)
1786
  {
1787
    throw ModalException(
1788
2
        "Cannot get difficulty when difficulty option is off.");
1789
  }
1790
  // the prop engine has the proof of false
1791
4
  Assert(d_pfManager);
1792
  // get difficulty map from theory engine first
1793
4
  TheoryEngine* te = getTheoryEngine();
1794
4
  te->getDifficultyMap(dmap);
1795
  // then ask proof manager to translate dmap in terms of the input
1796
4
  d_pfManager->translateDifficultyMap(dmap, *d_asserts);
1797
4
}
1798
1799
4036
void SmtEngine::push()
1800
{
1801
8072
  SmtScope smts(this);
1802
4036
  finishInit();
1803
4036
  d_state->doPendingPops();
1804
4036
  Trace("smt") << "SMT push()" << endl;
1805
4036
  d_smtSolver->processAssertions(*d_asserts);
1806
4036
  if(Dump.isOn("benchmark")) {
1807
    getPrinter().toStreamCmdPush(d_env->getDumpOut());
1808
  }
1809
4036
  d_state->userPush();
1810
4036
}
1811
1812
3497
void SmtEngine::pop() {
1813
6994
  SmtScope smts(this);
1814
3497
  finishInit();
1815
3497
  Trace("smt") << "SMT pop()" << endl;
1816
3497
  if (Dump.isOn("benchmark"))
1817
  {
1818
    getPrinter().toStreamCmdPop(d_env->getDumpOut());
1819
  }
1820
3497
  d_state->userPop();
1821
1822
  // Clear out assertion queues etc., in case anything is still in there
1823
3497
  d_asserts->clearCurrent();
1824
  // clear the learned literals from the preprocessor
1825
3497
  d_pp->clearLearnedLiterals();
1826
1827
6994
  Trace("userpushpop") << "SmtEngine: popped to level "
1828
3497
                       << getUserContext()->getLevel() << endl;
1829
  // should we reset d_status here?
1830
  // SMT-LIBv2 spec seems to imply no, but it would make sense to..
1831
3497
}
1832
1833
71
void SmtEngine::resetAssertions()
1834
{
1835
138
  SmtScope smts(this);
1836
1837
71
  if (!d_state->isFullyInited())
1838
  {
1839
    // We're still in Start Mode, nothing asserted yet, do nothing.
1840
    // (see solver execution modes in the SMT-LIB standard)
1841
4
    Assert(getContext()->getLevel() == 0);
1842
4
    Assert(getUserContext()->getLevel() == 0);
1843
4
    getDumpManager()->resetAssertions();
1844
4
    return;
1845
  }
1846
1847
1848
67
  Trace("smt") << "SMT resetAssertions()" << endl;
1849
67
  if (Dump.isOn("benchmark"))
1850
  {
1851
    getPrinter().toStreamCmdResetAssertions(d_env->getDumpOut());
1852
  }
1853
1854
67
  d_asserts->clearCurrent();
1855
67
  d_state->notifyResetAssertions();
1856
67
  getDumpManager()->resetAssertions();
1857
  // push the state to maintain global context around everything
1858
67
  d_state->setup();
1859
1860
  // reset SmtSolver, which will construct a new prop engine
1861
67
  d_smtSolver->resetAssertions();
1862
}
1863
1864
void SmtEngine::interrupt()
1865
{
1866
  if (!d_state->isFullyInited())
1867
  {
1868
    return;
1869
  }
1870
  d_smtSolver->interrupt();
1871
}
1872
1873
void SmtEngine::setResourceLimit(uint64_t units, bool cumulative)
1874
{
1875
  if (cumulative)
1876
  {
1877
    d_env->d_options.base.cumulativeResourceLimit = units;
1878
  }
1879
  else
1880
  {
1881
    d_env->d_options.base.perCallResourceLimit = units;
1882
  }
1883
}
1884
void SmtEngine::setTimeLimit(uint64_t millis)
1885
{
1886
  d_env->d_options.base.perCallMillisecondLimit = millis;
1887
}
1888
1889
unsigned long SmtEngine::getResourceUsage() const
1890
{
1891
  return getResourceManager()->getResourceUsage();
1892
}
1893
1894
unsigned long SmtEngine::getTimeUsage() const
1895
{
1896
  return getResourceManager()->getTimeUsage();
1897
}
1898
1899
unsigned long SmtEngine::getResourceRemaining() const
1900
{
1901
  return getResourceManager()->getResourceRemaining();
1902
}
1903
1904
40985
NodeManager* SmtEngine::getNodeManager() const
1905
{
1906
40985
  return d_env->getNodeManager();
1907
}
1908
1909
void SmtEngine::printStatisticsSafe(int fd) const
1910
{
1911
  d_env->getStatisticsRegistry().printSafe(fd);
1912
}
1913
1914
void SmtEngine::printStatisticsDiff() const
1915
{
1916
  d_env->getStatisticsRegistry().printDiff(*d_env->getOptions().base.err);
1917
  d_env->getStatisticsRegistry().storeSnapshot();
1918
}
1919
1920
38666
void SmtEngine::setOption(const std::string& key, const std::string& value)
1921
{
1922
38666
  Trace("smt") << "SMT setOption(" << key << ", " << value << ")" << endl;
1923
1924
38666
  if (Dump.isOn("benchmark"))
1925
  {
1926
4
    getPrinter().toStreamCmdSetOption(d_env->getDumpOut(), key, value);
1927
  }
1928
1929
38666
  if (key == "command-verbosity")
1930
  {
1931
4
    size_t fstIndex = value.find(" ");
1932
4
    size_t sndIndex = value.find(" ", fstIndex + 1);
1933
4
    if (sndIndex == std::string::npos)
1934
    {
1935
8
      string c = value.substr(1, fstIndex - 1);
1936
      int v =
1937
4
          std::stoi(value.substr(fstIndex + 1, value.length() - fstIndex - 1));
1938
4
      if (v < 0 || v > 2)
1939
      {
1940
        throw OptionException("command-verbosity must be 0, 1, or 2");
1941
      }
1942
4
      d_commandVerbosity[c] = v;
1943
4
      return;
1944
    }
1945
    throw OptionException(
1946
        "command-verbosity value must be a tuple (command-name integer)");
1947
  }
1948
1949
38662
  if (value.find(" ") != std::string::npos)
1950
  {
1951
    throw OptionException("bad value for :" + key);
1952
  }
1953
1954
74698
  std::string optionarg = value;
1955
38662
  options::set(getOptions(), key, optionarg);
1956
}
1957
1958
2687
void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver = true; }
1959
1960
13797
bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver; }
1961
1962
1413213
std::string SmtEngine::getOption(const std::string& key) const
1963
{
1964
1413213
  NodeManager* nm = d_env->getNodeManager();
1965
1966
1413213
  Trace("smt") << "SMT getOption(" << key << ")" << endl;
1967
1968
1413213
  if (key.find("command-verbosity:") == 0)
1969
  {
1970
591493
    auto it = d_commandVerbosity.find(key.substr(std::strlen("command-verbosity:")));
1971
591493
    if (it != d_commandVerbosity.end())
1972
    {
1973
      return std::to_string(it->second);
1974
    }
1975
591493
    it = d_commandVerbosity.find("*");
1976
591493
    if (it != d_commandVerbosity.end())
1977
    {
1978
32
      return std::to_string(it->second);
1979
    }
1980
591461
    return "2";
1981
  }
1982
1983
821720
  if (Dump.isOn("benchmark"))
1984
  {
1985
18
    getPrinter().toStreamCmdGetOption(d_env->getDumpOut(), key);
1986
  }
1987
1988
821720
  if (key == "command-verbosity")
1989
  {
1990
6
    vector<Node> result;
1991
6
    Node defaultVerbosity;
1992
7
    for (const auto& verb: d_commandVerbosity)
1993
    {
1994
      // treat the command name as a variable name as opposed to a string
1995
      // constant to avoid printing double quotes around the name
1996
8
      Node name = nm->mkBoundVar(verb.first, nm->integerType());
1997
8
      Node value = nm->mkConst(Rational(verb.second));
1998
4
      if (verb.first == "*")
1999
      {
2000
        // put the default at the end of the SExpr
2001
2
        defaultVerbosity = nm->mkNode(Kind::SEXPR, name, value);
2002
      }
2003
      else
2004
      {
2005
2
        result.push_back(nm->mkNode(Kind::SEXPR, name, value));
2006
      }
2007
    }
2008
    // ensure the default is always listed
2009
3
    if (defaultVerbosity.isNull())
2010
    {
2011
3
      defaultVerbosity = nm->mkNode(Kind::SEXPR,
2012
2
                                    nm->mkBoundVar("*", nm->integerType()),
2013
2
                                    nm->mkConst(Rational(2)));
2014
    }
2015
3
    result.push_back(defaultVerbosity);
2016
3
    return nm->mkNode(Kind::SEXPR, result).toString();
2017
  }
2018
2019
821717
  return options::get(getOptions(), key);
2020
}
2021
2022
3350612
Options& SmtEngine::getOptions() { return d_env->d_options; }
2023
2024
821717
const Options& SmtEngine::getOptions() const { return d_env->getOptions(); }
2025
2026
7431749
ResourceManager* SmtEngine::getResourceManager() const
2027
{
2028
7431749
  return d_env->getResourceManager();
2029
}
2030
2031
25493
DumpManager* SmtEngine::getDumpManager() { return d_env->getDumpManager(); }
2032
2033
26
const Printer& SmtEngine::getPrinter() const { return d_env->getPrinter(); }
2034
2035
OutputManager& SmtEngine::getOutputManager() { return d_outMgr; }
2036
2037
34443581
theory::Rewriter* SmtEngine::getRewriter() { return d_env->getRewriter(); }
2038
2039
29574
}  // namespace cvc5