GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/smt_engine.cpp Lines: 857 1033 83.0 %
Date: 2021-08-17 Branches: 1279 3335 38.4 %

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