GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 829 1004 82.6 %
Date: 2021-05-21 Branches: 1238 3309 37.4 %

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