GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 858 1034 83.0 %
Date: 2021-08-14 Branches: 1240 3259 38.0 %

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