GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 856 1031 83.0 %
Date: 2021-08-19 Branches: 1276 3329 38.3 %

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
10498
SmtEngine::SmtEngine(NodeManager* nm, Options* optr)
88
10498
    : d_env(new Env(nm, optr)),
89
10498
      d_state(new SmtEngineState(*d_env.get(), *this)),
90
10498
      d_absValues(new AbstractValues(getNodeManager())),
91
10498
      d_asserts(new Assertions(*d_env.get(), *d_absValues.get())),
92
10498
      d_routListener(new ResourceOutListener(*this)),
93
10498
      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
73486
      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
10498
  d_scope.reset(new SmtScope(this));
122
  // listen to node manager events
123
10498
  getNodeManager()->subscribeEvents(d_snmListener.get());
124
  // listen to resource out
125
10498
  getResourceManager()->registerListener(d_routListener.get());
126
  // make statistics
127
10498
  d_stats.reset(new SmtEngineStatistics());
128
  // reset the preprocessor
129
31494
  d_pp.reset(
130
20996
      new smt::Preprocessor(*this, *d_env.get(), *d_absValues.get(), *d_stats));
131
  // make the SMT solver
132
10498
  d_smtSolver.reset(new SmtSolver(*d_env.get(), *d_state, *d_pp, *d_stats));
133
  // make the SyGuS solver
134
41992
  d_sygusSolver.reset(
135
31494
      new SygusSolver(*d_smtSolver, *d_pp, getUserContext(), d_outMgr));
136
  // make the quantifier elimination solver
137
10498
  d_quantElimSolver.reset(new QuantElimSolver(*d_smtSolver));
138
139
10498
}
140
141
13226
bool SmtEngine::isFullyInited() const { return d_state->isFullyInited(); }
142
10953
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
17800
context::UserContext* SmtEngine::getUserContext()
158
{
159
17800
  return d_env->getUserContext();
160
}
161
12
context::Context* SmtEngine::getContext() { return d_env->getContext(); }
162
163
343766
TheoryEngine* SmtEngine::getTheoryEngine()
164
{
165
343766
  return d_smtSolver->getTheoryEngine();
166
}
167
168
56204
prop::PropEngine* SmtEngine::getPropEngine()
169
{
170
56204
  return d_smtSolver->getPropEngine();
171
}
172
173
121139
void SmtEngine::finishInit()
174
{
175
121139
  if (d_state->isFullyInited())
176
  {
177
    // already initialized, return
178
111284
    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
9855
  const LogicInfo& logic = getLogicInfo();
187
9855
  if (!logic.isLocked())
188
  {
189
1569
    setLogicInternal();
190
  }
191
192
  // set the random seed
193
9855
  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
9855
  SetDefaults sdefaults(d_isInternalSubsolver);
198
9855
  sdefaults.setDefaults(d_env->d_logic, getOptions());
199
200
9854
  ProofNodeManager* pnm = nullptr;
201
9854
  if (d_env->getOptions().smt.produceProofs)
202
  {
203
    // ensure bound variable uses canonical bound variables
204
3769
    getNodeManager()->getBoundVarManager()->enableKeepCacheValues();
205
    // make the proof manager
206
3769
    d_pfManager.reset(new PfManager(getUserContext(), this));
207
3769
    PreprocessProofGenerator* pppg = d_pfManager->getPreprocessProofGenerator();
208
    // start the unsat core manager
209
3769
    d_ucManager.reset(new UnsatCoreManager());
210
    // use this proof node manager
211
3769
    pnm = d_pfManager->getProofNodeManager();
212
    // enable proof support in the environment/rewriter
213
3769
    d_env->setProofNodeManager(pnm);
214
    // enable it in the assertions pipeline
215
3769
    d_asserts->setProofGenerator(pppg);
216
    // enabled proofs in the preprocessor
217
3769
    d_pp->setProofGenerator(pppg);
218
  }
219
220
9854
  Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
221
9854
  d_smtSolver->finishInit(logic);
222
223
  // now can construct the SMT-level model object
224
9854
  TheoryEngine* te = d_smtSolver->getTheoryEngine();
225
9854
  Assert(te != nullptr);
226
9854
  TheoryModel* tm = te->getModel();
227
9854
  if (tm != nullptr)
228
  {
229
9854
    d_model.reset(new Model(tm));
230
    // make the check models utility
231
9854
    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
9854
  d_state->setup();
237
238
9854
  Trace("smt-debug") << "Set up assertions..." << std::endl;
239
9854
  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
9854
  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
9854
  getDumpManager()->finishInit();
258
259
  // subsolvers
260
9854
  if (d_env->getOptions().smt.produceAbducts)
261
  {
262
326
    d_abductSolver.reset(new AbductionSolver(this));
263
  }
264
19708
  if (d_env->getOptions().smt.produceInterpols
265
9854
      != options::ProduceInterpols::NONE)
266
  {
267
114
    d_interpolSolver.reset(new InterpolationSolver(this));
268
  }
269
270
9854
  d_pp->finishInit();
271
272
9854
  AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
273
      << "The PropEngine has pushed but the SmtEngine "
274
         "hasn't finished initializing!";
275
276
9854
  Assert(getLogicInfo().isLocked());
277
278
  // store that we are finished initializing
279
9854
  d_state->finishInit();
280
9854
  Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
281
}
282
283
10498
void SmtEngine::shutdown() {
284
10498
  d_state->shutdown();
285
286
10498
  d_smtSolver->shutdown();
287
288
10498
  d_env->shutdown();
289
10498
}
290
291
20996
SmtEngine::~SmtEngine()
292
{
293
20996
  SmtScope smts(this);
294
295
  try {
296
10498
    shutdown();
297
298
    // global push/pop around everything, to ensure proper destruction
299
    // of context-dependent data structures
300
10498
    d_state->cleanup();
301
302
    //destroy all passes before destroying things that they refer to
303
10498
    d_pp->cleanup();
304
305
10498
    d_pfManager.reset(nullptr);
306
10498
    d_ucManager.reset(nullptr);
307
308
10498
    d_absValues.reset(nullptr);
309
10498
    d_asserts.reset(nullptr);
310
10498
    d_model.reset(nullptr);
311
312
10498
    d_abductSolver.reset(nullptr);
313
10498
    d_interpolSolver.reset(nullptr);
314
10498
    d_quantElimSolver.reset(nullptr);
315
10498
    d_sygusSolver.reset(nullptr);
316
10498
    d_smtSolver.reset(nullptr);
317
318
10498
    d_stats.reset(nullptr);
319
10498
    getNodeManager()->unsubscribeEvents(d_snmListener.get());
320
10498
    d_snmListener.reset(nullptr);
321
10498
    d_routListener.reset(nullptr);
322
10498
    d_pp.reset(nullptr);
323
    // destroy the state
324
10498
    d_state.reset(nullptr);
325
    // destroy the environment
326
10498
    d_env.reset(nullptr);
327
  } catch(Exception& e) {
328
    Warning() << "cvc5 threw an exception during cleanup." << endl << e << endl;
329
  }
330
10498
}
331
332
8364
void SmtEngine::setLogic(const LogicInfo& logic)
333
{
334
16728
  SmtScope smts(this);
335
8364
  if (d_state->isFullyInited())
336
  {
337
    throw ModalException("Cannot set logic in SmtEngine after the engine has "
338
                         "finished initializing.");
339
  }
340
8364
  d_env->d_logic = logic;
341
8364
  d_userLogic = logic;
342
8364
  setLogicInternal();
343
8364
}
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
46496
const LogicInfo& SmtEngine::getLogicInfo() const
367
{
368
46496
  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
6131
void SmtEngine::notifyStartParsing(const std::string& filename)
381
{
382
6131
  d_env->setFilename(filename);
383
12262
  d_env->getStatisticsRegistry().registerValue<std::string>("driver::filename",
384
12262
                                                            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
6131
}
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
6131
void SmtEngine::setTotalTimeStatistic(double seconds) {
400
12262
  d_env->getStatisticsRegistry().registerValue<double>("driver::totalTime",
401
12262
                                                       seconds);
402
6131
}
403
404
9933
void SmtEngine::setLogicInternal()
405
{
406
9933
  Assert(!d_state->isFullyInited())
407
      << "setting logic in SmtEngine but the engine has already"
408
         " finished initializing for this run";
409
9933
  d_env->d_logic.lock();
410
9933
  d_userLogic.lock();
411
9933
}
412
413
5693
void SmtEngine::setInfo(const std::string& key, const std::string& value)
414
{
415
11386
  SmtScope smts(this);
416
417
5693
  Trace("smt") << "SMT setInfo(" << key << ", " << value << ")" << endl;
418
419
5693
  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
5693
  if (key == "filename")
436
  {
437
52
    d_env->setFilename(value);
438
  }
439
5641
  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
4945
  else if (key == "status")
462
  {
463
3663
    d_state->notifyExpectedStatus(value);
464
  }
465
5693
}
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
89036
Result SmtEngine::quickCheck() {
727
89036
  Assert(d_state->isFullyInited());
728
89036
  Trace("smt") << "SMT quickCheck()" << endl;
729
89036
  const std::string& filename = d_env->getFilename();
730
  return Result(
731
89036
      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
15189
void SmtEngine::notifyPostSolvePre()
806
{
807
15189
  PropEngine* pe = getPropEngine();
808
15189
  Assert(pe != nullptr);
809
15189
  pe->resetTrail();
810
15189
}
811
812
15189
void SmtEngine::notifyPostSolvePost()
813
{
814
15189
  TheoryEngine* te = getTheoryEngine();
815
15189
  Assert(te != nullptr);
816
15189
  te->postsolve();
817
15189
}
818
819
12769
Result SmtEngine::checkSat()
820
{
821
25538
  Node nullNode;
822
25520
  return checkSat(nullNode);
823
}
824
825
13356
Result SmtEngine::checkSat(const Node& assumption)
826
{
827
13356
  if (Dump.isOn("benchmark"))
828
  {
829
2
    getPrinter().toStreamCmdCheckSat(d_env->getDumpOut(), assumption);
830
  }
831
26712
  std::vector<Node> assump;
832
13356
  if (!assumption.isNull())
833
  {
834
587
    assump.push_back(assumption);
835
  }
836
26693
  return checkSatInternal(assump, false);
837
}
838
839
995
Result SmtEngine::checkSat(const std::vector<Node>& assumptions)
840
{
841
995
  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
995
  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
14983
Result SmtEngine::checkSatInternal(const std::vector<Node>& assumptions,
874
                                   bool isEntailmentCheck)
875
{
876
  try
877
  {
878
29966
    SmtScope smts(this);
879
14983
    finishInit();
880
881
29966
    Trace("smt") << "SmtEngine::"
882
29966
                 << (isEntailmentCheck ? "checkEntailed" : "checkSat") << "("
883
14983
                 << assumptions << ")" << endl;
884
    // check the satisfiability with the solver object
885
    Result r = d_smtSolver->checkSatisfiability(
886
29945
        *d_asserts.get(), assumptions, isEntailmentCheck);
887
888
29924
    Trace("smt") << "SmtEngine::" << (isEntailmentCheck ? "query" : "checkSat")
889
14962
                 << "(" << assumptions << ") => " << r << endl;
890
891
    // Check that SAT results generate a model correctly.
892
14962
    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
29920
    if (d_env->getOptions().smt.checkProofs
901
14960
        || 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
14960
    if (d_env->getOptions().smt.checkUnsatCores)
917
    {
918
2370
      if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
919
      {
920
2736
        TimerStat::CodeTimer checkUnsatCoreTimer(d_stats->d_checkUnsatCoreTime);
921
1368
        checkUnsatCore();
922
      }
923
    }
924
14960
    if (d_env->getOptions().base.statisticsEveryQuery)
925
    {
926
      printStatisticsDiff();
927
    }
928
14960
    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
89037
Result SmtEngine::assertFormula(const Node& formula)
984
{
985
178074
  SmtScope smts(this);
986
89037
  finishInit();
987
89036
  d_state->doPendingPops();
988
989
89036
  Trace("smt") << "SmtEngine::assertFormula(" << formula << ")" << endl;
990
991
89036
  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
178072
  Node n = d_absValues->substituteAbstractValues(formula);
998
999
89036
  d_asserts->assertFormula(n);
1000
178072
  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
  // Since model m is being returned to the user, we must ensure that this
1196
  // model object remains valid with future check-sat calls. Hence, we set
1197
  // the theory engine into "eager model building" mode. TODO #2648: revisit.
1198
25
  TheoryEngine* te = getTheoryEngine();
1199
25
  Assert(te != nullptr);
1200
25
  te->setEagerModelBuilding();
1201
1202
50
  if (d_env->getOptions().smt.modelCoresMode
1203
25
      != options::ModelCoresMode::NONE)
1204
  {
1205
    // If we enabled model cores, we compute a model core for m based on our
1206
    // (expanded) assertions using the model core builder utility
1207
    std::vector<Node> eassertsProc = getExpandedAssertions();
1208
    ModelCoreBuilder::setModelCore(eassertsProc,
1209
                                   m->getTheoryModel(),
1210
                                   d_env->getOptions().smt.modelCoresMode);
1211
  }
1212
  // set the information on the SMT-level model
1213
25
  Assert(m != nullptr);
1214
25
  m->d_inputName = d_env->getFilename();
1215
25
  m->d_isKnownSat = (d_state->getMode() == SmtMode::SAT);
1216
50
  return m;
1217
}
1218
1219
18
Result SmtEngine::blockModel()
1220
{
1221
18
  Trace("smt") << "SMT blockModel()" << endl;
1222
36
  SmtScope smts(this);
1223
1224
18
  finishInit();
1225
1226
18
  if (Dump.isOn("benchmark"))
1227
  {
1228
    getPrinter().toStreamCmdBlockModel(d_env->getDumpOut());
1229
  }
1230
1231
18
  Model* m = getAvailableModel("block model");
1232
1233
36
  if (d_env->getOptions().smt.blockModelsMode
1234
18
      == options::BlockModelsMode::NONE)
1235
  {
1236
4
    std::stringstream ss;
1237
2
    ss << "Cannot block model when block-models is set to none.";
1238
2
    throw RecoverableModalException(ss.str().c_str());
1239
  }
1240
1241
  // get expanded assertions
1242
32
  std::vector<Node> eassertsProc = getExpandedAssertions();
1243
  Node eblocker =
1244
      ModelBlocker::getModelBlocker(eassertsProc,
1245
                                    m->getTheoryModel(),
1246
32
                                    d_env->getOptions().smt.blockModelsMode);
1247
16
  Trace("smt") << "Block formula: " << eblocker << std::endl;
1248
32
  return assertFormula(eblocker);
1249
}
1250
1251
12
Result SmtEngine::blockModelValues(const std::vector<Node>& exprs)
1252
{
1253
12
  Trace("smt") << "SMT blockModelValues()" << endl;
1254
24
  SmtScope smts(this);
1255
1256
12
  finishInit();
1257
1258
12
  if (Dump.isOn("benchmark"))
1259
  {
1260
    getPrinter().toStreamCmdBlockModelValues(d_env->getDumpOut(), exprs);
1261
  }
1262
1263
12
  Model* m = getAvailableModel("block model values");
1264
1265
  // get expanded assertions
1266
22
  std::vector<Node> eassertsProc = getExpandedAssertions();
1267
  // we always do block model values mode here
1268
  Node eblocker =
1269
      ModelBlocker::getModelBlocker(eassertsProc,
1270
                                    m->getTheoryModel(),
1271
                                    options::BlockModelsMode::VALUES,
1272
20
                                    exprs);
1273
20
  return assertFormula(eblocker);
1274
}
1275
1276
10
std::pair<Node, Node> SmtEngine::getSepHeapAndNilExpr(void)
1277
{
1278
10
  if (!getLogicInfo().isTheoryEnabled(THEORY_SEP))
1279
  {
1280
    const char* msg =
1281
        "Cannot obtain separation logic expressions if not using the "
1282
        "separation logic theory.";
1283
    throw RecoverableModalException(msg);
1284
  }
1285
20
  NodeManagerScope nms(getNodeManager());
1286
20
  Node heap;
1287
20
  Node nil;
1288
10
  Model* m = getAvailableModel("get separation logic heap and nil");
1289
10
  TheoryModel* tm = m->getTheoryModel();
1290
10
  if (!tm->getHeapModel(heap, nil))
1291
  {
1292
4
    const char* msg =
1293
        "Failed to obtain heap/nil "
1294
        "expressions from theory model.";
1295
4
    throw RecoverableModalException(msg);
1296
  }
1297
12
  return std::make_pair(heap, nil);
1298
}
1299
1300
94
std::vector<Node> SmtEngine::getExpandedAssertions()
1301
{
1302
186
  std::vector<Node> easserts = getAssertions();
1303
  // must expand definitions
1304
92
  std::vector<Node> eassertsProc;
1305
184
  std::unordered_map<Node, Node> cache;
1306
382
  for (const Node& e : easserts)
1307
  {
1308
580
    Node eae = d_pp->expandDefinitions(e, cache);
1309
290
    eassertsProc.push_back(eae);
1310
  }
1311
184
  return eassertsProc;
1312
}
1313
54
Env& SmtEngine::getEnv() { return *d_env.get(); }
1314
1315
121
void SmtEngine::declareSepHeap(TypeNode locT, TypeNode dataT)
1316
{
1317
121
  if (!getLogicInfo().isTheoryEnabled(THEORY_SEP))
1318
  {
1319
    const char* msg =
1320
        "Cannot declare heap if not using the separation logic theory.";
1321
    throw RecoverableModalException(msg);
1322
  }
1323
242
  SmtScope smts(this);
1324
121
  finishInit();
1325
121
  TheoryEngine* te = getTheoryEngine();
1326
123
  te->declareSepHeap(locT, dataT);
1327
119
}
1328
1329
1368
bool SmtEngine::getSepHeapTypes(TypeNode& locT, TypeNode& dataT)
1330
{
1331
2736
  SmtScope smts(this);
1332
1368
  finishInit();
1333
1368
  TheoryEngine* te = getTheoryEngine();
1334
2736
  return te->getSepHeapTypes(locT, dataT);
1335
}
1336
1337
5
Node SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
1338
1339
5
Node SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
1340
1341
1368
void SmtEngine::checkProof()
1342
{
1343
1368
  Assert(d_env->getOptions().smt.produceProofs);
1344
  // internal check the proof
1345
1368
  PropEngine* pe = getPropEngine();
1346
1368
  Assert(pe != nullptr);
1347
1368
  if (d_env->getOptions().proof.proofEagerChecking)
1348
  {
1349
    pe->checkProof(d_asserts->getAssertionList());
1350
  }
1351
1368
  Assert(pe->getProof() != nullptr);
1352
2736
  std::shared_ptr<ProofNode> pePfn = pe->getProof();
1353
1368
  if (d_env->getOptions().smt.checkProofs)
1354
  {
1355
1368
    d_pfManager->checkProof(pePfn, *d_asserts);
1356
  }
1357
1368
}
1358
1359
4679571
StatisticsRegistry& SmtEngine::getStatisticsRegistry()
1360
{
1361
4679571
  return d_env->getStatisticsRegistry();
1362
}
1363
1364
1424
UnsatCore SmtEngine::getUnsatCoreInternal()
1365
{
1366
1424
  if (!d_env->getOptions().smt.unsatCores)
1367
  {
1368
    throw ModalException(
1369
        "Cannot get an unsat core when produce-unsat-cores or produce-proofs "
1370
        "option is off.");
1371
  }
1372
1424
  if (d_state->getMode() != SmtMode::UNSAT)
1373
  {
1374
    throw RecoverableModalException(
1375
        "Cannot get an unsat core unless immediately preceded by "
1376
        "UNSAT/ENTAILED response.");
1377
  }
1378
  // generate with new proofs
1379
1424
  PropEngine* pe = getPropEngine();
1380
1424
  Assert(pe != nullptr);
1381
1382
2848
  std::shared_ptr<ProofNode> pepf;
1383
1424
  if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS)
1384
  {
1385
1371
    pepf = pe->getRefutation();
1386
  }
1387
  else
1388
  {
1389
53
    pepf = pe->getProof();
1390
  }
1391
1424
  Assert(pepf != nullptr);
1392
2848
  std::shared_ptr<ProofNode> pfn = d_pfManager->getFinalProof(pepf, *d_asserts);
1393
2848
  std::vector<Node> core;
1394
1424
  d_ucManager->getUnsatCore(pfn, *d_asserts, core);
1395
1424
  if (options::minimalUnsatCores())
1396
  {
1397
1
    core = reduceUnsatCore(core);
1398
  }
1399
2848
  return UnsatCore(core);
1400
}
1401
1402
1
std::vector<Node> SmtEngine::reduceUnsatCore(const std::vector<Node>& core)
1403
{
1404
1
  Assert(options::unsatCores())
1405
      << "cannot reduce unsat core if unsat cores are turned off";
1406
1407
1
  Notice() << "SmtEngine::reduceUnsatCore(): reducing unsat core" << endl;
1408
2
  std::unordered_set<Node> removed;
1409
4
  for (const Node& skip : core)
1410
  {
1411
6
    std::unique_ptr<SmtEngine> coreChecker;
1412
3
    initializeSubsolver(coreChecker);
1413
3
    coreChecker->setLogic(getLogicInfo());
1414
3
    coreChecker->getOptions().smt.checkUnsatCores = false;
1415
    // disable all proof options
1416
3
    coreChecker->getOptions().smt.produceProofs = false;
1417
3
    coreChecker->getOptions().smt.checkProofs = false;
1418
3
    coreChecker->getOptions().proof.proofEagerChecking = false;
1419
1420
12
    for (const Node& ucAssertion : core)
1421
    {
1422
9
      if (ucAssertion != skip && removed.find(ucAssertion) == removed.end())
1423
      {
1424
8
        Node assertionAfterExpansion = expandDefinitions(ucAssertion);
1425
4
        coreChecker->assertFormula(assertionAfterExpansion);
1426
      }
1427
    }
1428
6
    Result r;
1429
    try
1430
    {
1431
3
      r = coreChecker->checkSat();
1432
    }
1433
    catch (...)
1434
    {
1435
      throw;
1436
    }
1437
1438
3
    if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
1439
    {
1440
1
      removed.insert(skip);
1441
    }
1442
2
    else if (r.asSatisfiabilityResult().isUnknown())
1443
    {
1444
      Warning() << "SmtEngine::reduceUnsatCore(): could not reduce unsat core "
1445
                   "due to "
1446
                   "unknown result.";
1447
    }
1448
  }
1449
1450
1
  if (removed.empty())
1451
  {
1452
    return core;
1453
  }
1454
  else
1455
  {
1456
2
    std::vector<Node> newUcAssertions;
1457
4
    for (const Node& n : core)
1458
    {
1459
3
      if (removed.find(n) == removed.end())
1460
      {
1461
2
        newUcAssertions.push_back(n);
1462
      }
1463
    }
1464
1465
1
    return newUcAssertions;
1466
  }
1467
}
1468
1469
1368
void SmtEngine::checkUnsatCore() {
1470
1368
  Assert(d_env->getOptions().smt.unsatCores)
1471
      << "cannot check unsat core if unsat cores are turned off";
1472
1473
1368
  Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl;
1474
2736
  UnsatCore core = getUnsatCore();
1475
1476
  // initialize the core checker
1477
2736
  std::unique_ptr<SmtEngine> coreChecker;
1478
1368
  initializeSubsolver(coreChecker);
1479
1368
  coreChecker->getOptions().smt.checkUnsatCores = false;
1480
  // disable all proof options
1481
1368
  coreChecker->getOptions().smt.produceProofs = false;
1482
1368
  coreChecker->getOptions().smt.checkProofs = false;
1483
1368
  coreChecker->getOptions().proof.proofEagerChecking = false;
1484
1485
  // set up separation logic heap if necessary
1486
2736
  TypeNode sepLocType, sepDataType;
1487
1368
  if (getSepHeapTypes(sepLocType, sepDataType))
1488
  {
1489
21
    coreChecker->declareSepHeap(sepLocType, sepDataType);
1490
  }
1491
1492
1368
  Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
1493
           << std::endl;
1494
1368
  theory::TrustSubstitutionMap& tls = d_env->getTopLevelSubstitutions();
1495
7326
  for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
1496
11916
    Node assertionAfterExpansion = tls.apply(*i, false);
1497
5958
    Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
1498
             << ", expanded to " << assertionAfterExpansion << "\n";
1499
5958
    coreChecker->assertFormula(assertionAfterExpansion);
1500
  }
1501
2736
  Result r;
1502
  try {
1503
1368
    r = coreChecker->checkSat();
1504
  } catch(...) {
1505
    throw;
1506
  }
1507
1368
  Notice() << "SmtEngine::checkUnsatCore(): result is " << r << endl;
1508
1368
  if(r.asSatisfiabilityResult().isUnknown()) {
1509
1
    Warning()
1510
        << "SmtEngine::checkUnsatCore(): could not check core result unknown."
1511
        << std::endl;
1512
  }
1513
1367
  else if (r.asSatisfiabilityResult().isSat())
1514
  {
1515
    InternalError()
1516
        << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
1517
  }
1518
1368
}
1519
1520
2152
void SmtEngine::checkModel(bool hardFailure) {
1521
2152
  context::CDList<Node>* al = d_asserts->getAssertionList();
1522
  // --check-model implies --produce-assertions, which enables the
1523
  // assertion list, so we should be ok.
1524
2152
  Assert(al != nullptr)
1525
      << "don't have an assertion list to check in SmtEngine::checkModel()";
1526
1527
4304
  TimerStat::CodeTimer checkModelTimer(d_stats->d_checkModelTime);
1528
1529
2152
  Notice() << "SmtEngine::checkModel(): generating model" << endl;
1530
2152
  Model* m = getAvailableModel("check model");
1531
2151
  Assert(m != nullptr);
1532
1533
  // check the model with the theory engine for debugging
1534
2151
  if (options::debugCheckModels())
1535
  {
1536
2137
    TheoryEngine* te = getTheoryEngine();
1537
2137
    Assert(te != nullptr);
1538
2137
    te->checkTheoryAssertionsWithModel(hardFailure);
1539
  }
1540
1541
  // check the model with the check models utility
1542
2151
  Assert(d_checkModels != nullptr);
1543
2151
  d_checkModels->checkModel(m, al, hardFailure);
1544
2150
}
1545
1546
1411
UnsatCore SmtEngine::getUnsatCore() {
1547
1411
  Trace("smt") << "SMT getUnsatCore()" << std::endl;
1548
2822
  SmtScope smts(this);
1549
1411
  finishInit();
1550
1411
  if (Dump.isOn("benchmark"))
1551
  {
1552
    getPrinter().toStreamCmdGetUnsatCore(d_env->getDumpOut());
1553
  }
1554
2822
  return getUnsatCoreInternal();
1555
}
1556
1557
7
void SmtEngine::getRelevantInstantiationTermVectors(
1558
    std::map<Node, InstantiationList>& insts, bool getDebugInfo)
1559
{
1560
7
  Assert(d_state->getMode() == SmtMode::UNSAT);
1561
  // generate with new proofs
1562
7
  PropEngine* pe = getPropEngine();
1563
7
  Assert(pe != nullptr);
1564
7
  Assert(pe->getProof() != nullptr);
1565
  std::shared_ptr<ProofNode> pfn =
1566
14
      d_pfManager->getFinalProof(pe->getProof(), *d_asserts);
1567
7
  d_ucManager->getRelevantInstantiations(pfn, insts, getDebugInfo);
1568
7
}
1569
1570
5
std::string SmtEngine::getProof()
1571
{
1572
5
  Trace("smt") << "SMT getProof()\n";
1573
10
  SmtScope smts(this);
1574
5
  finishInit();
1575
5
  if (Dump.isOn("benchmark"))
1576
  {
1577
    getPrinter().toStreamCmdGetProof(d_env->getDumpOut());
1578
  }
1579
5
  if (!d_env->getOptions().smt.produceProofs)
1580
  {
1581
    throw ModalException("Cannot get a proof when proof option is off.");
1582
  }
1583
5
  if (d_state->getMode() != SmtMode::UNSAT)
1584
  {
1585
    throw RecoverableModalException(
1586
        "Cannot get a proof unless immediately preceded by "
1587
        "UNSAT/ENTAILED response.");
1588
  }
1589
  // the prop engine has the proof of false
1590
5
  PropEngine* pe = getPropEngine();
1591
5
  Assert(pe != nullptr);
1592
5
  Assert(pe->getProof() != nullptr);
1593
5
  Assert(d_pfManager);
1594
10
  std::ostringstream ss;
1595
5
  d_pfManager->printProof(ss, pe->getProof(), *d_asserts);
1596
10
  return ss.str();
1597
}
1598
1599
15
void SmtEngine::printInstantiations( std::ostream& out ) {
1600
30
  SmtScope smts(this);
1601
15
  finishInit();
1602
15
  if (d_env->getOptions().printer.instFormatMode == options::InstFormatMode::SZS)
1603
  {
1604
    out << "% SZS output start Proof for " << d_env->getFilename() << std::endl;
1605
  }
1606
15
  QuantifiersEngine* qe = getAvailableQuantifiersEngine("printInstantiations");
1607
1608
  // First, extract and print the skolemizations
1609
15
  bool printed = false;
1610
15
  bool reqNames = !d_env->getOptions().printer.printInstFull;
1611
  // only print when in list mode
1612
15
  if (d_env->getOptions().printer.printInstMode == options::PrintInstMode::LIST)
1613
  {
1614
24
    std::map<Node, std::vector<Node>> sks;
1615
12
    qe->getSkolemTermVectors(sks);
1616
21
    for (const std::pair<const Node, std::vector<Node>>& s : sks)
1617
    {
1618
18
      Node name;
1619
9
      if (!qe->getNameForQuant(s.first, name, reqNames))
1620
      {
1621
        // did not have a name and we are only printing formulas with names
1622
        continue;
1623
      }
1624
18
      SkolemList slist(name, s.second);
1625
9
      out << slist;
1626
9
      printed = true;
1627
    }
1628
  }
1629
1630
  // Second, extract and print the instantiations
1631
30
  std::map<Node, InstantiationList> rinsts;
1632
30
  if (d_env->getOptions().smt.produceProofs
1633
11
      && (!d_env->getOptions().smt.unsatCores
1634
11
          || d_env->getOptions().smt.unsatCoresMode
1635
                 == options::UnsatCoresMode::FULL_PROOF)
1636
22
      && getSmtMode() == SmtMode::UNSAT)
1637
  {
1638
    // minimize instantiations based on proof manager
1639
7
    getRelevantInstantiationTermVectors(rinsts,
1640
7
                                        options::dumpInstantiationsDebug());
1641
  }
1642
  else
1643
  {
1644
16
    std::map<Node, std::vector<std::vector<Node>>> insts;
1645
8
    getInstantiationTermVectors(insts);
1646
18
    for (const std::pair<const Node, std::vector<std::vector<Node>>>& i : insts)
1647
    {
1648
      // convert to instantiation list
1649
20
      Node q = i.first;
1650
10
      InstantiationList& ilq = rinsts[q];
1651
10
      ilq.initialize(q);
1652
32
      for (const std::vector<Node>& ii : i.second)
1653
      {
1654
22
        ilq.d_inst.push_back(InstantiationVec(ii));
1655
      }
1656
    }
1657
  }
1658
36
  for (std::pair<const Node, InstantiationList>& i : rinsts)
1659
  {
1660
21
    if (i.second.d_inst.empty())
1661
    {
1662
      // no instantiations, skip
1663
      continue;
1664
    }
1665
42
    Node name;
1666
21
    if (!qe->getNameForQuant(i.first, name, reqNames))
1667
    {
1668
      // did not have a name and we are only printing formulas with names
1669
      continue;
1670
    }
1671
    // must have a name
1672
21
    if (d_env->getOptions().printer.printInstMode == options::PrintInstMode::NUM)
1673
    {
1674
12
      out << "(num-instantiations " << name << " " << i.second.d_inst.size()
1675
6
          << ")" << std::endl;
1676
    }
1677
    else
1678
    {
1679
      // take the name
1680
15
      i.second.d_quant = name;
1681
15
      Assert(d_env->getOptions().printer.printInstMode
1682
             == options::PrintInstMode::LIST);
1683
15
      out << i.second;
1684
    }
1685
21
    printed = true;
1686
  }
1687
  // if we did not print anything, we indicate this
1688
15
  if (!printed)
1689
  {
1690
    out << "none" << std::endl;
1691
  }
1692
15
  if (d_env->getOptions().printer.instFormatMode == options::InstFormatMode::SZS)
1693
  {
1694
    out << "% SZS output end Proof for " << d_env->getFilename() << std::endl;
1695
  }
1696
15
}
1697
1698
8
void SmtEngine::getInstantiationTermVectors(
1699
    std::map<Node, std::vector<std::vector<Node>>>& insts)
1700
{
1701
16
  SmtScope smts(this);
1702
8
  finishInit();
1703
  QuantifiersEngine* qe =
1704
8
      getAvailableQuantifiersEngine("getInstantiationTermVectors");
1705
  // get the list of all instantiations
1706
8
  qe->getInstantiationTermVectors(insts);
1707
8
}
1708
1709
86
bool SmtEngine::getSynthSolutions(std::map<Node, Node>& solMap)
1710
{
1711
172
  SmtScope smts(this);
1712
86
  finishInit();
1713
172
  return d_sygusSolver->getSynthSolutions(solMap);
1714
}
1715
1716
30
Node SmtEngine::getQuantifierElimination(Node q, bool doFull, bool strict)
1717
{
1718
60
  SmtScope smts(this);
1719
30
  finishInit();
1720
30
  const LogicInfo& logic = getLogicInfo();
1721
30
  if (!logic.isPure(THEORY_ARITH) && strict)
1722
  {
1723
10
    Warning() << "Unexpected logic for quantifier elimination " << logic
1724
4
              << endl;
1725
  }
1726
  return d_quantElimSolver->getQuantifierElimination(
1727
60
      *d_asserts, q, doFull, d_isInternalSubsolver);
1728
}
1729
1730
10
bool SmtEngine::getInterpol(const Node& conj,
1731
                            const TypeNode& grammarType,
1732
                            Node& interpol)
1733
{
1734
20
  SmtScope smts(this);
1735
10
  finishInit();
1736
10
  bool success = d_interpolSolver->getInterpol(conj, grammarType, interpol);
1737
  // notify the state of whether the get-interpol call was successfuly, which
1738
  // impacts the SMT mode.
1739
10
  d_state->notifyGetInterpol(success);
1740
20
  return success;
1741
}
1742
1743
9
bool SmtEngine::getInterpol(const Node& conj, Node& interpol)
1744
{
1745
18
  TypeNode grammarType;
1746
18
  return getInterpol(conj, grammarType, interpol);
1747
}
1748
1749
16
bool SmtEngine::getAbduct(const Node& conj,
1750
                          const TypeNode& grammarType,
1751
                          Node& abd)
1752
{
1753
32
  SmtScope smts(this);
1754
16
  finishInit();
1755
16
  bool success = d_abductSolver->getAbduct(conj, grammarType, abd);
1756
  // notify the state of whether the get-abduct call was successfuly, which
1757
  // impacts the SMT mode.
1758
14
  d_state->notifyGetAbduct(success);
1759
28
  return success;
1760
}
1761
1762
10
bool SmtEngine::getAbduct(const Node& conj, Node& abd)
1763
{
1764
20
  TypeNode grammarType;
1765
19
  return getAbduct(conj, grammarType, abd);
1766
}
1767
1768
47
void SmtEngine::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
1769
{
1770
94
  SmtScope smts(this);
1771
  QuantifiersEngine* qe =
1772
47
      getAvailableQuantifiersEngine("getInstantiatedQuantifiedFormulas");
1773
47
  qe->getInstantiatedQuantifiedFormulas(qs);
1774
47
}
1775
1776
42
void SmtEngine::getInstantiationTermVectors(
1777
    Node q, std::vector<std::vector<Node>>& tvecs)
1778
{
1779
84
  SmtScope smts(this);
1780
  QuantifiersEngine* qe =
1781
42
      getAvailableQuantifiersEngine("getInstantiationTermVectors");
1782
42
  qe->getInstantiationTermVectors(q, tvecs);
1783
42
}
1784
1785
94
std::vector<Node> SmtEngine::getAssertions()
1786
{
1787
188
  SmtScope smts(this);
1788
94
  finishInit();
1789
94
  d_state->doPendingPops();
1790
94
  if (Dump.isOn("benchmark"))
1791
  {
1792
    getPrinter().toStreamCmdGetAssertions(d_env->getDumpOut());
1793
  }
1794
94
  Trace("smt") << "SMT getAssertions()" << endl;
1795
94
  if (!d_env->getOptions().smt.produceAssertions)
1796
  {
1797
2
    const char* msg =
1798
      "Cannot query the current assertion list when not in produce-assertions mode.";
1799
2
    throw ModalException(msg);
1800
  }
1801
92
  context::CDList<Node>* al = d_asserts->getAssertionList();
1802
92
  Assert(al != nullptr);
1803
92
  std::vector<Node> res;
1804
382
  for (const Node& n : *al)
1805
  {
1806
290
    res.emplace_back(n);
1807
  }
1808
  // copy the result out
1809
184
  return res;
1810
}
1811
1812
4036
void SmtEngine::push()
1813
{
1814
8072
  SmtScope smts(this);
1815
4036
  finishInit();
1816
4036
  d_state->doPendingPops();
1817
4036
  Trace("smt") << "SMT push()" << endl;
1818
4036
  d_smtSolver->processAssertions(*d_asserts);
1819
4036
  if(Dump.isOn("benchmark")) {
1820
    getPrinter().toStreamCmdPush(d_env->getDumpOut());
1821
  }
1822
4036
  d_state->userPush();
1823
4036
}
1824
1825
3497
void SmtEngine::pop() {
1826
6994
  SmtScope smts(this);
1827
3497
  finishInit();
1828
3497
  Trace("smt") << "SMT pop()" << endl;
1829
3497
  if (Dump.isOn("benchmark"))
1830
  {
1831
    getPrinter().toStreamCmdPop(d_env->getDumpOut());
1832
  }
1833
3497
  d_state->userPop();
1834
1835
  // Clear out assertion queues etc., in case anything is still in there
1836
3497
  d_asserts->clearCurrent();
1837
  // clear the learned literals from the preprocessor
1838
3497
  d_pp->clearLearnedLiterals();
1839
1840
6994
  Trace("userpushpop") << "SmtEngine: popped to level "
1841
3497
                       << getUserContext()->getLevel() << endl;
1842
  // should we reset d_status here?
1843
  // SMT-LIBv2 spec seems to imply no, but it would make sense to..
1844
3497
}
1845
1846
71
void SmtEngine::resetAssertions()
1847
{
1848
138
  SmtScope smts(this);
1849
1850
71
  if (!d_state->isFullyInited())
1851
  {
1852
    // We're still in Start Mode, nothing asserted yet, do nothing.
1853
    // (see solver execution modes in the SMT-LIB standard)
1854
4
    Assert(getContext()->getLevel() == 0);
1855
4
    Assert(getUserContext()->getLevel() == 0);
1856
4
    getDumpManager()->resetAssertions();
1857
4
    return;
1858
  }
1859
1860
1861
67
  Trace("smt") << "SMT resetAssertions()" << endl;
1862
67
  if (Dump.isOn("benchmark"))
1863
  {
1864
    getPrinter().toStreamCmdResetAssertions(d_env->getDumpOut());
1865
  }
1866
1867
67
  d_asserts->clearCurrent();
1868
67
  d_state->notifyResetAssertions();
1869
67
  getDumpManager()->resetAssertions();
1870
  // push the state to maintain global context around everything
1871
67
  d_state->setup();
1872
1873
  // reset SmtSolver, which will construct a new prop engine
1874
67
  d_smtSolver->resetAssertions();
1875
}
1876
1877
void SmtEngine::interrupt()
1878
{
1879
  if (!d_state->isFullyInited())
1880
  {
1881
    return;
1882
  }
1883
  d_smtSolver->interrupt();
1884
}
1885
1886
void SmtEngine::setResourceLimit(uint64_t units, bool cumulative)
1887
{
1888
  if (cumulative)
1889
  {
1890
    d_env->d_options.base.cumulativeResourceLimit = units;
1891
  }
1892
  else
1893
  {
1894
    d_env->d_options.base.perCallResourceLimit = units;
1895
  }
1896
}
1897
void SmtEngine::setTimeLimit(uint64_t millis)
1898
{
1899
  d_env->d_options.base.perCallMillisecondLimit = millis;
1900
}
1901
1902
unsigned long SmtEngine::getResourceUsage() const
1903
{
1904
  return getResourceManager()->getResourceUsage();
1905
}
1906
1907
unsigned long SmtEngine::getTimeUsage() const
1908
{
1909
  return getResourceManager()->getTimeUsage();
1910
}
1911
1912
unsigned long SmtEngine::getResourceRemaining() const
1913
{
1914
  return getResourceManager()->getResourceRemaining();
1915
}
1916
1917
796301
NodeManager* SmtEngine::getNodeManager() const
1918
{
1919
796301
  return d_env->getNodeManager();
1920
}
1921
1922
void SmtEngine::printStatisticsSafe(int fd) const
1923
{
1924
  d_env->getStatisticsRegistry().printSafe(fd);
1925
}
1926
1927
void SmtEngine::printStatisticsDiff() const
1928
{
1929
  d_env->getStatisticsRegistry().printDiff(*d_env->getOptions().base.err);
1930
  d_env->getStatisticsRegistry().storeSnapshot();
1931
}
1932
1933
211
void SmtEngine::setUserAttribute(const std::string& attr,
1934
                                 Node expr,
1935
                                 const std::vector<Node>& expr_values,
1936
                                 const std::string& str_value)
1937
{
1938
422
  SmtScope smts(this);
1939
211
  finishInit();
1940
211
  TheoryEngine* te = getTheoryEngine();
1941
211
  Assert(te != nullptr);
1942
211
  te->setUserAttribute(attr, expr, expr_values, str_value);
1943
211
}
1944
1945
9573
void SmtEngine::setOption(const std::string& key, const std::string& value)
1946
{
1947
19142
  NodeManagerScope nms(getNodeManager());
1948
9573
  Trace("smt") << "SMT setOption(" << key << ", " << value << ")" << endl;
1949
1950
9573
  if (Dump.isOn("benchmark"))
1951
  {
1952
2
    getPrinter().toStreamCmdSetOption(d_env->getDumpOut(), key, value);
1953
  }
1954
1955
9573
  if (key == "command-verbosity")
1956
  {
1957
4
    size_t fstIndex = value.find(" ");
1958
4
    size_t sndIndex = value.find(" ", fstIndex + 1);
1959
4
    if (sndIndex == std::string::npos)
1960
    {
1961
8
      string c = value.substr(1, fstIndex - 1);
1962
      int v =
1963
4
          std::stoi(value.substr(fstIndex + 1, value.length() - fstIndex - 1));
1964
4
      if (v < 0 || v > 2)
1965
      {
1966
        throw OptionException("command-verbosity must be 0, 1, or 2");
1967
      }
1968
4
      d_commandVerbosity[c] = v;
1969
4
      return;
1970
    }
1971
    throw OptionException(
1972
        "command-verbosity value must be a tuple (command-name integer)");
1973
  }
1974
1975
9569
  if (value.find(" ") != std::string::npos)
1976
  {
1977
    throw OptionException("bad value for :" + key);
1978
  }
1979
1980
19138
  std::string optionarg = value;
1981
9569
  options::set(getOptions(), key, optionarg);
1982
}
1983
1984
2684
void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver = true; }
1985
1986
13748
bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver; }
1987
1988
592045
std::string SmtEngine::getOption(const std::string& key) const
1989
{
1990
1184090
  NodeManagerScope nms(getNodeManager());
1991
592045
  NodeManager* nm = d_env->getNodeManager();
1992
1993
592045
  Trace("smt") << "SMT getOption(" << key << ")" << endl;
1994
1995
592045
  if (key.find("command-verbosity:") == 0)
1996
  {
1997
591983
    auto it = d_commandVerbosity.find(key.substr(std::strlen("command-verbosity:")));
1998
591983
    if (it != d_commandVerbosity.end())
1999
    {
2000
      return std::to_string(it->second);
2001
    }
2002
591983
    it = d_commandVerbosity.find("*");
2003
591983
    if (it != d_commandVerbosity.end())
2004
    {
2005
32
      return std::to_string(it->second);
2006
    }
2007
591951
    return "2";
2008
  }
2009
2010
62
  if (Dump.isOn("benchmark"))
2011
  {
2012
    getPrinter().toStreamCmdGetOption(d_outMgr.getDumpOut(), key);
2013
  }
2014
2015
62
  if (key == "command-verbosity")
2016
  {
2017
6
    vector<Node> result;
2018
6
    Node defaultVerbosity;
2019
7
    for (const auto& verb: d_commandVerbosity)
2020
    {
2021
      // treat the command name as a variable name as opposed to a string
2022
      // constant to avoid printing double quotes around the name
2023
8
      Node name = nm->mkBoundVar(verb.first, nm->integerType());
2024
8
      Node value = nm->mkConst(Rational(verb.second));
2025
4
      if (verb.first == "*")
2026
      {
2027
        // put the default at the end of the SExpr
2028
2
        defaultVerbosity = nm->mkNode(Kind::SEXPR, name, value);
2029
      }
2030
      else
2031
      {
2032
2
        result.push_back(nm->mkNode(Kind::SEXPR, name, value));
2033
      }
2034
    }
2035
    // ensure the default is always listed
2036
3
    if (defaultVerbosity.isNull())
2037
    {
2038
3
      defaultVerbosity = nm->mkNode(Kind::SEXPR,
2039
2
                                    nm->mkBoundVar("*", nm->integerType()),
2040
2
                                    nm->mkConst(Rational(2)));
2041
    }
2042
3
    result.push_back(defaultVerbosity);
2043
3
    return nm->mkNode(Kind::SEXPR, result).toString();
2044
  }
2045
2046
116
  std::string atom = options::get(getOptions(), key);
2047
2048
57
  if (atom != "true" && atom != "false")
2049
  {
2050
    try
2051
    {
2052
13
      Integer z(atom);
2053
    }
2054
4
    catch (std::invalid_argument&)
2055
    {
2056
2
      atom = "\"" + atom + "\"";
2057
    }
2058
  }
2059
2060
57
  return atom;
2061
}
2062
2063
4024940
Options& SmtEngine::getOptions() { return d_env->d_options; }
2064
2065
59
const Options& SmtEngine::getOptions() const { return d_env->getOptions(); }
2066
2067
6808582
ResourceManager* SmtEngine::getResourceManager() const
2068
{
2069
6808582
  return d_env->getResourceManager();
2070
}
2071
2072
22712
DumpManager* SmtEngine::getDumpManager() { return d_env->getDumpManager(); }
2073
2074
10
const Printer& SmtEngine::getPrinter() const { return d_env->getPrinter(); }
2075
2076
1
OutputManager& SmtEngine::getOutputManager() { return d_outMgr; }
2077
2078
31868808
theory::Rewriter* SmtEngine::getRewriter() { return d_env->getRewriter(); }
2079
2080
29349
}  // namespace cvc5