GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/smt/solver_engine.cpp Lines: 806 956 84.3 %
Date: 2021-11-05 Branches: 1173 2995 39.2 %

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