GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 854 1038 82.3 %
Date: 2021-08-01 Branches: 1238 3301 37.5 %

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