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