GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 851 1024 83.1 %
Date: 2021-08-20 Branches: 1268 3285 38.6 %

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