1 /******************************************************************************
2 * Top contributors (to current version):
3 * Andrew Reynolds, Morgan Deters, Abdalrhman Mohamed
5 * This file is part of the cvc5 project.
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 * ****************************************************************************
13 * The main entry point into the cvc5 library's SMT interface.
16 #include "smt/smt_engine.h"
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"
44 #include "smt/dump_manager.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"
74 // required for hacks related to old proofs for unsat cores
75 #include "base/configuration.h"
76 #include "base/configuration_private.h"
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
;
87 SmtEngine::SmtEngine(NodeManager
* nm
, const Options
* optr
)
88 : d_env(new Env(nm
, optr
)),
89 d_state(new SmtEngineState(*d_env
.get(), *this)),
90 d_absValues(new AbstractValues(getNodeManager())),
91 d_asserts(new Assertions(*d_env
.get(), *d_absValues
.get())),
92 d_routListener(new ResourceOutListener(*this)),
93 d_snmListener(new SmtNodeManagerListener(*getDumpManager(), d_outMgr
)),
95 d_checkModels(nullptr),
98 d_sygusSolver(nullptr),
99 d_abductSolver(nullptr),
100 d_interpolSolver(nullptr),
101 d_quantElimSolver(nullptr),
102 d_isInternalSubsolver(false),
108 // !!!!!!!!!!!!!!!!!!!!!! temporary hack: this makes the current SmtEngine
109 // we are constructing the current SmtEngine in scope for the lifetime of
110 // this SmtEngine, or until another SmtEngine is constructed (that SmtEngine
111 // is then in scope during its lifetime). This is mostly to ensure that
112 // options are always in scope, for e.g. printing expressions, which rely
113 // on knowing the output language.
114 // Notice that the SmtEngine may spawn new SmtEngine "subsolvers" internally.
115 // These are created, used, and deleted in a modular fashion while not
116 // interleaving calls to the master SmtEngine. Thus the hack here does not
117 // break this use case.
118 // On the other hand, this hack breaks use cases where multiple SmtEngine
119 // objects are created by the user.
120 d_scope
.reset(new SmtScope(this));
121 // listen to node manager events
122 getNodeManager()->subscribeEvents(d_snmListener
.get());
123 // listen to resource out
124 getResourceManager()->registerListener(d_routListener
.get());
126 d_stats
.reset(new SmtEngineStatistics());
127 // reset the preprocessor
129 new smt::Preprocessor(*this, *d_env
.get(), *d_absValues
.get(), *d_stats
));
130 // make the SMT solver
131 d_smtSolver
.reset(new SmtSolver(*d_env
.get(), *d_state
, *d_pp
, *d_stats
));
132 // make the SyGuS solver
133 d_sygusSolver
.reset(new SygusSolver(*d_env
.get(), *d_smtSolver
, *d_pp
));
134 // make the quantifier elimination solver
135 d_quantElimSolver
.reset(new QuantElimSolver(*d_env
.get(), *d_smtSolver
));
138 bool SmtEngine::isFullyInited() const { return d_state
->isFullyInited(); }
139 bool SmtEngine::isQueryMade() const { return d_state
->isQueryMade(); }
140 size_t SmtEngine::getNumUserLevels() const
142 return d_state
->getNumUserLevels();
144 SmtMode
SmtEngine::getSmtMode() const { return d_state
->getMode(); }
145 bool SmtEngine::isSmtModeSat() const
147 SmtMode mode
= getSmtMode();
148 return mode
== SmtMode::SAT
|| mode
== SmtMode::SAT_UNKNOWN
;
150 Result
SmtEngine::getStatusOfLastCommand() const
152 return d_state
->getStatus();
154 context::UserContext
* SmtEngine::getUserContext()
156 return d_env
->getUserContext();
158 context::Context
* SmtEngine::getContext() { return d_env
->getContext(); }
160 TheoryEngine
* SmtEngine::getTheoryEngine()
162 return d_smtSolver
->getTheoryEngine();
165 prop::PropEngine
* SmtEngine::getPropEngine()
167 return d_smtSolver
->getPropEngine();
170 void SmtEngine::finishInit()
172 if (d_state
->isFullyInited())
174 // already initialized, return
178 // Notice that finishInitInternal is called when options are finalized. If we
179 // are parsing smt2, this occurs at the moment we enter "Assert mode", page 52
180 // of SMT-LIB 2.6 standard.
183 const LogicInfo
& logic
= getLogicInfo();
184 if (!logic
.isLocked())
189 // set the random seed
190 Random::getRandom().setSeed(d_env
->getOptions().driver
.seed
);
192 // Call finish init on the set defaults module. This inializes the logic
193 // and the best default options based on our heuristics.
194 SetDefaults
sdefaults(d_isInternalSubsolver
);
195 sdefaults
.setDefaults(d_env
->d_logic
, getOptions());
197 if (d_env
->getOptions().smt
.produceProofs
)
199 // ensure bound variable uses canonical bound variables
200 getNodeManager()->getBoundVarManager()->enableKeepCacheValues();
201 // make the proof manager
202 d_pfManager
.reset(new PfManager(*d_env
.get()));
203 PreprocessProofGenerator
* pppg
= d_pfManager
->getPreprocessProofGenerator();
204 // start the unsat core manager
205 d_ucManager
.reset(new UnsatCoreManager());
206 // enable it in the assertions pipeline
207 d_asserts
->setProofGenerator(pppg
);
208 // enabled proofs in the preprocessor
209 d_pp
->setProofGenerator(pppg
);
212 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl
;
213 d_smtSolver
->finishInit(logic
);
215 // now can construct the SMT-level model object
216 TheoryEngine
* te
= d_smtSolver
->getTheoryEngine();
217 Assert(te
!= nullptr);
218 TheoryModel
* tm
= te
->getModel();
221 // make the check models utility
222 d_checkModels
.reset(new CheckModels(*d_env
.get()));
225 // global push/pop around everything, to ensure proper destruction
226 // of context-dependent data structures
229 Trace("smt-debug") << "Set up assertions..." << std::endl
;
230 d_asserts
->finishInit();
232 // dump out a set-logic command only when raw-benchmark is disabled to avoid
233 // dumping the command twice.
234 if (Dump
.isOn("benchmark") && !Dump
.isOn("raw-benchmark"))
236 LogicInfo everything
;
238 getPrinter().toStreamCmdComment(
240 "cvc5 always dumps the most general, all-supported logic (below), as "
241 "some internals might require the use of a logic more general than "
243 getPrinter().toStreamCmdSetBenchmarkLogic(d_env
->getDumpOut(),
244 everything
.getLogicString());
247 // initialize the dump manager
248 getDumpManager()->finishInit();
251 if (d_env
->getOptions().smt
.produceAbducts
)
253 d_abductSolver
.reset(new AbductionSolver(*d_env
.get()));
255 if (d_env
->getOptions().smt
.produceInterpols
256 != options::ProduceInterpols::NONE
)
258 d_interpolSolver
.reset(new InterpolationSolver(*d_env
.get()));
263 AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
264 << "The PropEngine has pushed but the SmtEngine "
265 "hasn't finished initializing!";
267 Assert(getLogicInfo().isLocked());
269 // store that we are finished initializing
270 d_state
->finishInit();
271 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl
;
274 void SmtEngine::shutdown() {
277 d_smtSolver
->shutdown();
282 SmtEngine::~SmtEngine()
289 // global push/pop around everything, to ensure proper destruction
290 // of context-dependent data structures
293 //destroy all passes before destroying things that they refer to
296 d_pfManager
.reset(nullptr);
297 d_ucManager
.reset(nullptr);
299 d_absValues
.reset(nullptr);
300 d_asserts
.reset(nullptr);
302 d_abductSolver
.reset(nullptr);
303 d_interpolSolver
.reset(nullptr);
304 d_quantElimSolver
.reset(nullptr);
305 d_sygusSolver
.reset(nullptr);
306 d_smtSolver
.reset(nullptr);
308 d_stats
.reset(nullptr);
309 getNodeManager()->unsubscribeEvents(d_snmListener
.get());
310 d_snmListener
.reset(nullptr);
311 d_routListener
.reset(nullptr);
314 d_state
.reset(nullptr);
315 // destroy the environment
316 d_env
.reset(nullptr);
317 } catch(Exception
& e
) {
318 Warning() << "cvc5 threw an exception during cleanup." << endl
<< e
<< endl
;
322 void SmtEngine::setLogic(const LogicInfo
& logic
)
325 if (d_state
->isFullyInited())
327 throw ModalException("Cannot set logic in SmtEngine after the engine has "
328 "finished initializing.");
330 d_env
->d_logic
= logic
;
335 void SmtEngine::setLogic(const std::string
& s
)
340 setLogic(LogicInfo(s
));
341 // dump out a set-logic command
342 if (Dump
.isOn("raw-benchmark"))
344 getPrinter().toStreamCmdSetBenchmarkLogic(
345 d_env
->getDumpOut(), getLogicInfo().getLogicString());
348 catch (IllegalArgumentException
& e
)
350 throw LogicException(e
.what());
354 void SmtEngine::setLogic(const char* logic
) { setLogic(string(logic
)); }
356 const LogicInfo
& SmtEngine::getLogicInfo() const
358 return d_env
->getLogicInfo();
361 LogicInfo
SmtEngine::getUserLogicInfo() const
363 // Lock the logic to make sure that this logic can be queried. We create a
364 // copy of the user logic here to keep this method const.
365 LogicInfo res
= d_userLogic
;
370 void SmtEngine::setLogicInternal()
372 Assert(!d_state
->isFullyInited())
373 << "setting logic in SmtEngine but the engine has already"
374 " finished initializing for this run";
375 d_env
->d_logic
.lock();
379 void SmtEngine::setInfo(const std::string
& key
, const std::string
& value
)
383 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
385 if (Dump
.isOn("benchmark"))
392 : ((value
== "unsat") ? Result::UNSAT
: Result::SAT_UNKNOWN
);
393 getPrinter().toStreamCmdSetBenchmarkStatus(d_env
->getDumpOut(), status
);
397 getPrinter().toStreamCmdSetInfo(d_env
->getDumpOut(), key
, value
);
401 if (key
== "filename")
403 d_env
->d_options
.driver
.filename
= value
;
404 d_env
->d_originalOptions
->driver
.filename
= value
;
405 d_env
->getStatisticsRegistry().registerValue
<std::string
>(
406 "driver::filename", value
);
408 else if (key
== "smt-lib-version" && !getOptions().base
.inputLanguageWasSetByUser
)
410 Language ilang
= Language::LANG_SMTLIB_V2_6
;
412 if (value
!= "2" && value
!= "2.6")
414 Warning() << "SMT-LIB version " << value
415 << " unsupported, defaulting to language (and semantics of) "
418 getOptions().base
.inputLanguage
= ilang
;
419 // also update the output language
420 if (!getOptions().base
.outputLanguageWasSetByUser
)
422 Language olang
= ilang
;
423 if (d_env
->getOptions().base
.outputLanguage
!= olang
)
425 getOptions().base
.outputLanguage
= olang
;
426 *d_env
->getOptions().base
.out
<< language::SetLanguage(olang
);
430 else if (key
== "status")
432 d_state
->notifyExpectedStatus(value
);
436 bool SmtEngine::isValidGetInfoFlag(const std::string
& key
) const
438 if (key
== "all-statistics" || key
== "error-behavior" || key
== "name"
439 || key
== "version" || key
== "authors" || key
== "status"
440 || key
== "reason-unknown" || key
== "assertion-stack-levels"
441 || key
== "all-options" || key
== "time")
448 std::string
SmtEngine::getInfo(const std::string
& key
) const
452 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
453 if (key
== "all-statistics")
455 return toSExpr(d_env
->getStatisticsRegistry().begin(), d_env
->getStatisticsRegistry().end());
457 if (key
== "error-behavior")
459 return "immediate-exit";
461 if (key
== "filename")
463 return d_env
->getOptions().driver
.filename
;
467 return toSExpr(Configuration::getName());
469 if (key
== "version")
471 return toSExpr(Configuration::getVersionString());
473 if (key
== "authors")
475 return toSExpr(Configuration::about());
479 // sat | unsat | unknown
480 Result status
= d_state
->getStatus();
481 switch (status
.asSatisfiabilityResult().isSat())
483 case Result::SAT
: return "sat";
484 case Result::UNSAT
: return "unsat";
485 default: return "unknown";
490 return toSExpr(std::clock());
492 if (key
== "reason-unknown")
494 Result status
= d_state
->getStatus();
495 if (!status
.isNull() && status
.isUnknown())
497 std::stringstream ss
;
498 ss
<< status
.whyUnknown();
499 std::string s
= ss
.str();
500 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
505 throw RecoverableModalException(
506 "Can't get-info :reason-unknown when the "
507 "last result wasn't unknown!");
510 if (key
== "assertion-stack-levels")
512 size_t ulevel
= d_state
->getNumUserLevels();
513 AlwaysAssert(ulevel
<= std::numeric_limits
<unsigned long int>::max());
514 return toSExpr(ulevel
);
516 Assert(key
== "all-options");
517 // get the options, like all-statistics
518 std::vector
<std::vector
<std::string
>> res
;
519 for (const auto& opt
: options::getNames())
521 res
.emplace_back(std::vector
<std::string
>{opt
, options::get(getOptions(), opt
)});
526 void SmtEngine::debugCheckFormals(const std::vector
<Node
>& formals
, Node func
)
528 for (std::vector
<Node
>::const_iterator i
= formals
.begin();
532 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
534 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
535 << "definition of function " << func
<< ", formal\n"
537 << "has kind " << (*i
).getKind();
538 throw TypeCheckingExceptionPrivate(func
, ss
.str());
543 void SmtEngine::debugCheckFunctionBody(Node formula
,
544 const std::vector
<Node
>& formals
,
547 TypeNode formulaType
=
548 formula
.getType(d_env
->getOptions().expr
.typeChecking
);
549 TypeNode funcType
= func
.getType();
550 // We distinguish here between definitions of constants and functions,
551 // because the type checking for them is subtly different. Perhaps we
552 // should instead have SmtEngine::defineFunction() and
553 // SmtEngine::defineConstant() for better clarity, although then that
554 // doesn't match the SMT-LIBv2 standard...
555 if(formals
.size() > 0) {
556 TypeNode rangeType
= funcType
.getRangeType();
557 if(! formulaType
.isComparableTo(rangeType
)) {
559 ss
<< "Type of defined function does not match its declaration\n"
560 << "The function : " << func
<< "\n"
561 << "Declared type : " << rangeType
<< "\n"
562 << "The body : " << formula
<< "\n"
563 << "Body type : " << formulaType
;
564 throw TypeCheckingExceptionPrivate(func
, ss
.str());
567 if(! formulaType
.isComparableTo(funcType
)) {
569 ss
<< "Declared type of defined constant does not match its definition\n"
570 << "The constant : " << func
<< "\n"
571 << "Declared type : " << funcType
<< "\n"
572 << "The definition : " << formula
<< "\n"
573 << "Definition type: " << formulaType
;
574 throw TypeCheckingExceptionPrivate(func
, ss
.str());
579 void SmtEngine::defineFunction(Node func
,
580 const std::vector
<Node
>& formals
,
586 d_state
->doPendingPops();
587 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
588 debugCheckFormals(formals
, func
);
591 ss
<< language::SetLanguage(
592 language::SetLanguage::getLanguage(Dump
.getStream()))
595 DefineFunctionNodeCommand
nc(ss
.str(), func
, formals
, formula
);
596 getDumpManager()->addToDump(nc
, "declarations");
599 debugCheckFunctionBody(formula
, formals
, func
);
601 // Substitute out any abstract values in formula
602 Node def
= d_absValues
->substituteAbstractValues(formula
);
603 if (!formals
.empty())
605 NodeManager
* nm
= NodeManager::currentNM();
607 kind::LAMBDA
, nm
->mkNode(kind::BOUND_VAR_LIST
, formals
), def
);
609 // A define-fun is treated as a (higher-order) assertion. It is provided
610 // to the assertions object. It will be added as a top-level substitution
611 // within this class, possibly multiple times if global is true.
612 Node feq
= func
.eqNode(def
);
613 d_asserts
->addDefineFunDefinition(feq
, global
);
616 void SmtEngine::defineFunctionsRec(
617 const std::vector
<Node
>& funcs
,
618 const std::vector
<std::vector
<Node
>>& formals
,
619 const std::vector
<Node
>& formulas
,
624 d_state
->doPendingPops();
625 Trace("smt") << "SMT defineFunctionsRec(...)" << endl
;
627 if (funcs
.size() != formals
.size() && funcs
.size() != formulas
.size())
630 ss
<< "Number of functions, formals, and function bodies passed to "
631 "defineFunctionsRec do not match:"
633 << " #functions : " << funcs
.size() << "\n"
634 << " #arg lists : " << formals
.size() << "\n"
635 << " #function bodies : " << formulas
.size() << "\n";
636 throw ModalException(ss
.str());
638 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
640 // check formal argument list
641 debugCheckFormals(formals
[i
], funcs
[i
]);
643 debugCheckFunctionBody(formulas
[i
], formals
[i
], funcs
[i
]);
646 if (Dump
.isOn("raw-benchmark"))
648 getPrinter().toStreamCmdDefineFunctionRec(
649 d_env
->getDumpOut(), funcs
, formals
, formulas
);
652 NodeManager
* nm
= getNodeManager();
653 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
655 // we assert a quantified formula
657 // make the function application
658 if (formals
[i
].empty())
660 // it has no arguments
665 std::vector
<Node
> children
;
666 children
.push_back(funcs
[i
]);
667 children
.insert(children
.end(), formals
[i
].begin(), formals
[i
].end());
668 func_app
= nm
->mkNode(kind::APPLY_UF
, children
);
670 Node lem
= nm
->mkNode(kind::EQUAL
, func_app
, formulas
[i
]);
671 if (!formals
[i
].empty())
673 // set the attribute to denote this is a function definition
674 Node aexpr
= nm
->mkNode(kind::INST_ATTRIBUTE
, func_app
);
675 aexpr
= nm
->mkNode(kind::INST_PATTERN_LIST
, aexpr
);
677 func_app
.setAttribute(fda
, true);
678 // make the quantified formula
679 Node boundVars
= nm
->mkNode(kind::BOUND_VAR_LIST
, formals
[i
]);
680 lem
= nm
->mkNode(kind::FORALL
, boundVars
, lem
, aexpr
);
682 // assert the quantified formula
683 // notice we don't call assertFormula directly, since this would
684 // duplicate the output on raw-benchmark.
685 // add define recursive definition to the assertions
686 d_asserts
->addDefineFunDefinition(lem
, global
);
690 void SmtEngine::defineFunctionRec(Node func
,
691 const std::vector
<Node
>& formals
,
695 std::vector
<Node
> funcs
;
696 funcs
.push_back(func
);
697 std::vector
<std::vector
<Node
>> formals_multi
;
698 formals_multi
.push_back(formals
);
699 std::vector
<Node
> formulas
;
700 formulas
.push_back(formula
);
701 defineFunctionsRec(funcs
, formals_multi
, formulas
, global
);
704 Result
SmtEngine::quickCheck() {
705 Assert(d_state
->isFullyInited());
706 Trace("smt") << "SMT quickCheck()" << endl
;
707 const std::string
& filename
= d_env
->getOptions().driver
.filename
;
709 Result::ENTAILMENT_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, filename
);
712 TheoryModel
* SmtEngine::getAvailableModel(const char* c
) const
714 if (!d_env
->getOptions().theory
.assignFunctionValues
)
716 std::stringstream ss
;
717 ss
<< "Cannot " << c
<< " when --assign-function-values is false.";
718 throw RecoverableModalException(ss
.str().c_str());
721 if (d_state
->getMode() != SmtMode::SAT
722 && d_state
->getMode() != SmtMode::SAT_UNKNOWN
)
724 std::stringstream ss
;
726 << " unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN "
728 throw RecoverableModalException(ss
.str().c_str());
731 if (!d_env
->getOptions().smt
.produceModels
)
733 std::stringstream ss
;
734 ss
<< "Cannot " << c
<< " when produce-models options is off.";
735 throw ModalException(ss
.str().c_str());
738 TheoryEngine
* te
= d_smtSolver
->getTheoryEngine();
739 Assert(te
!= nullptr);
740 TheoryModel
* m
= te
->getBuiltModel();
744 std::stringstream ss
;
746 << " since model is not available. Perhaps the most recent call to "
747 "check-sat was interrupted?";
748 throw RecoverableModalException(ss
.str().c_str());
754 QuantifiersEngine
* SmtEngine::getAvailableQuantifiersEngine(const char* c
) const
756 QuantifiersEngine
* qe
= d_smtSolver
->getQuantifiersEngine();
759 std::stringstream ss
;
760 ss
<< "Cannot " << c
<< " when quantifiers are not present.";
761 throw ModalException(ss
.str().c_str());
766 void SmtEngine::notifyPushPre() { d_smtSolver
->processAssertions(*d_asserts
); }
768 void SmtEngine::notifyPushPost()
770 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
771 Assert(getPropEngine() != nullptr);
772 getPropEngine()->push();
775 void SmtEngine::notifyPopPre()
777 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
778 PropEngine
* pe
= getPropEngine();
779 Assert(pe
!= nullptr);
783 void SmtEngine::notifyPostSolvePre()
785 PropEngine
* pe
= getPropEngine();
786 Assert(pe
!= nullptr);
790 void SmtEngine::notifyPostSolvePost()
792 TheoryEngine
* te
= getTheoryEngine();
793 Assert(te
!= nullptr);
797 Result
SmtEngine::checkSat()
800 return checkSat(nullNode
);
803 Result
SmtEngine::checkSat(const Node
& assumption
)
805 if (Dump
.isOn("benchmark"))
807 getPrinter().toStreamCmdCheckSat(d_env
->getDumpOut(), assumption
);
809 std::vector
<Node
> assump
;
810 if (!assumption
.isNull())
812 assump
.push_back(assumption
);
814 return checkSatInternal(assump
, false);
817 Result
SmtEngine::checkSat(const std::vector
<Node
>& assumptions
)
819 if (Dump
.isOn("benchmark"))
821 if (assumptions
.empty())
823 getPrinter().toStreamCmdCheckSat(d_env
->getDumpOut());
827 getPrinter().toStreamCmdCheckSatAssuming(d_env
->getDumpOut(),
831 return checkSatInternal(assumptions
, false);
834 Result
SmtEngine::checkEntailed(const Node
& node
)
836 if (Dump
.isOn("benchmark"))
838 getPrinter().toStreamCmdQuery(d_env
->getDumpOut(), node
);
840 return checkSatInternal(
841 node
.isNull() ? std::vector
<Node
>() : std::vector
<Node
>{node
},
843 .asEntailmentResult();
846 Result
SmtEngine::checkEntailed(const std::vector
<Node
>& nodes
)
848 return checkSatInternal(nodes
, true).asEntailmentResult();
851 Result
SmtEngine::checkSatInternal(const std::vector
<Node
>& assumptions
,
852 bool isEntailmentCheck
)
859 Trace("smt") << "SmtEngine::"
860 << (isEntailmentCheck
? "checkEntailed" : "checkSat") << "("
861 << assumptions
<< ")" << endl
;
862 // check the satisfiability with the solver object
863 Result r
= d_smtSolver
->checkSatisfiability(
864 *d_asserts
.get(), assumptions
, isEntailmentCheck
);
866 Trace("smt") << "SmtEngine::" << (isEntailmentCheck
? "query" : "checkSat")
867 << "(" << assumptions
<< ") => " << r
<< endl
;
869 // Check that SAT results generate a model correctly.
870 if (d_env
->getOptions().smt
.checkModels
)
872 if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
877 // Check that UNSAT results generate a proof correctly.
878 if (d_env
->getOptions().smt
.checkProofs
879 || d_env
->getOptions().proof
.proofCheck
880 == options::ProofCheckMode::EAGER
)
882 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
884 if ((d_env
->getOptions().smt
.checkProofs
885 || d_env
->getOptions().proof
.proofCheck
886 == options::ProofCheckMode::EAGER
)
887 && !d_env
->getOptions().smt
.produceProofs
)
889 throw ModalException(
890 "Cannot check-proofs because proofs were disabled.");
895 // Check that UNSAT results generate an unsat core correctly.
896 if (d_env
->getOptions().smt
.checkUnsatCores
)
898 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
900 TimerStat::CodeTimer
checkUnsatCoreTimer(d_stats
->d_checkUnsatCoreTime
);
904 if (d_env
->getOptions().base
.statisticsEveryQuery
)
906 printStatisticsDiff();
910 catch (UnsafeInterruptException
& e
)
912 AlwaysAssert(getResourceManager()->out());
913 // Notice that we do not notify the state of this result. If we wanted to
914 // make the solver resume a working state after an interupt, then we would
915 // implement a different callback and use it here, e.g.
916 // d_state.notifyCheckSatInterupt.
917 Result::UnknownExplanation why
= getResourceManager()->outOfResources()
918 ? Result::RESOURCEOUT
921 if (d_env
->getOptions().base
.statisticsEveryQuery
)
923 printStatisticsDiff();
925 return Result(Result::SAT_UNKNOWN
, why
, d_env
->getOptions().driver
.filename
);
929 std::vector
<Node
> SmtEngine::getUnsatAssumptions(void)
931 Trace("smt") << "SMT getUnsatAssumptions()" << endl
;
933 if (!d_env
->getOptions().smt
.unsatAssumptions
)
935 throw ModalException(
936 "Cannot get unsat assumptions when produce-unsat-assumptions option "
939 if (d_state
->getMode() != SmtMode::UNSAT
)
941 throw RecoverableModalException(
942 "Cannot get unsat assumptions unless immediately preceded by "
946 if (Dump
.isOn("benchmark"))
948 getPrinter().toStreamCmdGetUnsatAssumptions(d_env
->getDumpOut());
950 UnsatCore core
= getUnsatCoreInternal();
951 std::vector
<Node
> res
;
952 std::vector
<Node
>& assumps
= d_asserts
->getAssumptions();
953 for (const Node
& e
: assumps
)
955 if (std::find(core
.begin(), core
.end(), e
) != core
.end())
963 Result
SmtEngine::assertFormula(const Node
& formula
)
967 d_state
->doPendingPops();
969 Trace("smt") << "SmtEngine::assertFormula(" << formula
<< ")" << endl
;
971 if (Dump
.isOn("raw-benchmark"))
973 getPrinter().toStreamCmdAssert(d_env
->getDumpOut(), formula
);
976 // Substitute out any abstract values in ex
977 Node n
= d_absValues
->substituteAbstractValues(formula
);
979 d_asserts
->assertFormula(n
);
980 return quickCheck().asEntailmentResult();
981 }/* SmtEngine::assertFormula() */
984 --------------------------------------------------------------------------
985 Handling SyGuS commands
986 --------------------------------------------------------------------------
989 void SmtEngine::declareSygusVar(Node var
)
992 d_sygusSolver
->declareSygusVar(var
);
993 if (Dump
.isOn("raw-benchmark"))
995 getPrinter().toStreamCmdDeclareVar(d_env
->getDumpOut(), var
, var
.getType());
997 // don't need to set that the conjecture is stale
1000 void SmtEngine::declareSynthFun(Node func
,
1003 const std::vector
<Node
>& vars
)
1005 SmtScope
smts(this);
1007 d_state
->doPendingPops();
1008 d_sygusSolver
->declareSynthFun(func
, sygusType
, isInv
, vars
);
1010 // !!! TEMPORARY: We cannot construct a SynthFunCommand since we cannot
1011 // construct a Term-level Grammar from a Node-level sygus TypeNode. Thus we
1012 // must print the command using the Node-level utility method for now.
1014 if (Dump
.isOn("raw-benchmark"))
1016 getPrinter().toStreamCmdSynthFun(
1017 d_env
->getDumpOut(), func
, vars
, isInv
, sygusType
);
1020 void SmtEngine::declareSynthFun(Node func
,
1022 const std::vector
<Node
>& vars
)
1024 // use a null sygus type
1026 declareSynthFun(func
, sygusType
, isInv
, vars
);
1029 void SmtEngine::assertSygusConstraint(Node constraint
)
1031 SmtScope
smts(this);
1033 d_sygusSolver
->assertSygusConstraint(constraint
);
1034 if (Dump
.isOn("raw-benchmark"))
1036 getPrinter().toStreamCmdConstraint(d_env
->getDumpOut(), constraint
);
1040 void SmtEngine::assertSygusInvConstraint(Node inv
,
1045 SmtScope
smts(this);
1047 d_sygusSolver
->assertSygusInvConstraint(inv
, pre
, trans
, post
);
1048 if (Dump
.isOn("raw-benchmark"))
1050 getPrinter().toStreamCmdInvConstraint(
1051 d_env
->getDumpOut(), inv
, pre
, trans
, post
);
1055 Result
SmtEngine::checkSynth()
1057 SmtScope
smts(this);
1059 return d_sygusSolver
->checkSynth(*d_asserts
);
1063 --------------------------------------------------------------------------
1064 End of Handling SyGuS commands
1065 --------------------------------------------------------------------------
1068 void SmtEngine::declarePool(const Node
& p
, const std::vector
<Node
>& initValue
)
1070 Assert(p
.isVar() && p
.getType().isSet());
1072 QuantifiersEngine
* qe
= getAvailableQuantifiersEngine("declareTermPool");
1073 qe
->declarePool(p
, initValue
);
1076 Node
SmtEngine::simplify(const Node
& ex
)
1078 SmtScope
smts(this);
1080 d_state
->doPendingPops();
1081 // ensure we've processed assertions
1082 d_smtSolver
->processAssertions(*d_asserts
);
1083 return d_pp
->simplify(ex
);
1086 Node
SmtEngine::expandDefinitions(const Node
& ex
)
1088 getResourceManager()->spendResource(Resource::PreprocessStep
);
1089 SmtScope
smts(this);
1091 d_state
->doPendingPops();
1092 return d_pp
->expandDefinitions(ex
);
1095 // TODO(#1108): Simplify the error reporting of this method.
1096 Node
SmtEngine::getValue(const Node
& ex
) const
1098 SmtScope
smts(this);
1100 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
1101 if (Dump
.isOn("benchmark"))
1103 getPrinter().toStreamCmdGetValue(d_env
->getDumpOut(), {ex
});
1105 TypeNode expectedType
= ex
.getType();
1107 // Substitute out any abstract values in ex and expand
1108 Node n
= d_pp
->expandDefinitions(ex
);
1110 Trace("smt") << "--- getting value of " << n
<< endl
;
1111 // There are two ways model values for terms are computed (for historical
1112 // reasons). One way is that used in check-model; the other is that
1113 // used by the Model classes. It's not clear to me exactly how these
1114 // two are different, but they need to be unified. This ugly hack here
1115 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
1118 if(!n
.getType().isFunction()) {
1119 n
= Rewriter::rewrite(n
);
1122 Trace("smt") << "--- getting value of " << n
<< endl
;
1123 TheoryModel
* m
= getAvailableModel("get-value");
1124 Assert(m
!= nullptr);
1125 Node resultNode
= m
->getValue(n
);
1126 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
1127 Trace("smt") << "--- type " << resultNode
.getType() << endl
;
1128 Trace("smt") << "--- expected type " << expectedType
<< endl
;
1130 // type-check the result we got
1131 // Notice that lambdas have function type, which does not respect the subtype
1132 // relation, so we ignore them here.
1133 Assert(resultNode
.isNull() || resultNode
.getKind() == kind::LAMBDA
1134 || resultNode
.getType().isSubtypeOf(expectedType
))
1135 << "Run with -t smt for details.";
1137 // Ensure it's a constant, or a lambda (for uninterpreted functions). This
1138 // assertion only holds for models that do not have approximate values.
1139 Assert(m
->hasApproximations() || resultNode
.getKind() == kind::LAMBDA
1140 || resultNode
.isConst());
1142 if (d_env
->getOptions().smt
.abstractValues
1143 && resultNode
.getType().isArray())
1145 resultNode
= d_absValues
->mkAbstractValue(resultNode
);
1146 Trace("smt") << "--- abstract value >> " << resultNode
<< endl
;
1152 std::vector
<Node
> SmtEngine::getValues(const std::vector
<Node
>& exprs
) const
1154 std::vector
<Node
> result
;
1155 for (const Node
& e
: exprs
)
1157 result
.push_back(getValue(e
));
1162 std::vector
<Node
> SmtEngine::getModelDomainElements(TypeNode tn
) const
1164 Assert(tn
.isSort());
1165 TheoryModel
* m
= getAvailableModel("getModelDomainElements");
1166 return m
->getDomainElements(tn
);
1169 bool SmtEngine::isModelCoreSymbol(Node n
)
1171 SmtScope
smts(this);
1173 const Options
& opts
= d_env
->getOptions();
1174 if (opts
.smt
.modelCoresMode
== options::ModelCoresMode::NONE
)
1176 // if the model core mode is none, we are always a model core symbol
1179 TheoryModel
* tm
= getAvailableModel("isModelCoreSymbol");
1180 // compute the model core if not done so already
1181 if (!tm
->isUsingModelCore())
1183 // If we enabled model cores, we compute a model core for m based on our
1184 // (expanded) assertions using the model core builder utility. Notice that
1185 // we get the assertions using the getAssertionsInternal, which does not
1186 // impact whether we are in "sat" mode
1187 std::vector
<Node
> asserts
= getAssertionsInternal();
1188 d_pp
->expandDefinitions(asserts
);
1189 ModelCoreBuilder::setModelCore(asserts
, tm
, opts
.smt
.modelCoresMode
);
1191 return tm
->isModelCoreSymbol(n
);
1194 std::string
SmtEngine::getModel(const std::vector
<TypeNode
>& declaredSorts
,
1195 const std::vector
<Node
>& declaredFuns
)
1197 SmtScope
smts(this);
1198 // !!! Note that all methods called here should have a version at the API
1199 // level. This is to ensure that the information associated with a model is
1200 // completely accessible by the user. This is currently not rigorously
1201 // enforced. An alternative design would be to have this method implemented
1202 // at the API level, but this makes exceptions in the text interface less
1203 // intuitive and makes it impossible to implement raw-benchmark at the
1205 if (Dump
.isOn("raw-benchmark"))
1207 getPrinter().toStreamCmdGetModel(d_env
->getDumpOut());
1209 TheoryModel
* tm
= getAvailableModel("get model");
1210 // use the smt::Model model utility for printing
1211 const Options
& opts
= d_env
->getOptions();
1212 bool isKnownSat
= (d_state
->getMode() == SmtMode::SAT
);
1213 Model
m(isKnownSat
, opts
.driver
.filename
);
1214 // set the model declarations, which determines what is printed in the model
1215 for (const TypeNode
& tn
: declaredSorts
)
1217 m
.addDeclarationSort(tn
, getModelDomainElements(tn
));
1219 bool usingModelCores
=
1220 (opts
.smt
.modelCoresMode
!= options::ModelCoresMode::NONE
);
1221 for (const Node
& n
: declaredFuns
)
1223 if (usingModelCores
&& !tm
->isModelCoreSymbol(n
))
1225 // skip if not in model core
1228 Node value
= tm
->getValue(n
);
1229 m
.addDeclarationTerm(n
, value
);
1231 // for separation logic
1232 TypeNode locT
, dataT
;
1233 if (getSepHeapTypes(locT
, dataT
))
1235 std::pair
<Node
, Node
> sh
= getSepHeapAndNilExpr();
1236 m
.setHeapModel(sh
.first
, sh
.second
);
1239 std::stringstream ssm
;
1244 Result
SmtEngine::blockModel()
1246 Trace("smt") << "SMT blockModel()" << endl
;
1247 SmtScope
smts(this);
1251 if (Dump
.isOn("benchmark"))
1253 getPrinter().toStreamCmdBlockModel(d_env
->getDumpOut());
1256 TheoryModel
* m
= getAvailableModel("block model");
1258 if (d_env
->getOptions().smt
.blockModelsMode
1259 == options::BlockModelsMode::NONE
)
1261 std::stringstream ss
;
1262 ss
<< "Cannot block model when block-models is set to none.";
1263 throw RecoverableModalException(ss
.str().c_str());
1266 // get expanded assertions
1267 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1268 Node eblocker
= ModelBlocker::getModelBlocker(
1269 eassertsProc
, m
, d_env
->getOptions().smt
.blockModelsMode
);
1270 Trace("smt") << "Block formula: " << eblocker
<< std::endl
;
1271 return assertFormula(eblocker
);
1274 Result
SmtEngine::blockModelValues(const std::vector
<Node
>& exprs
)
1276 Trace("smt") << "SMT blockModelValues()" << endl
;
1277 SmtScope
smts(this);
1281 if (Dump
.isOn("benchmark"))
1283 getPrinter().toStreamCmdBlockModelValues(d_env
->getDumpOut(), exprs
);
1286 TheoryModel
* m
= getAvailableModel("block model values");
1288 // get expanded assertions
1289 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1290 // we always do block model values mode here
1291 Node eblocker
= ModelBlocker::getModelBlocker(
1292 eassertsProc
, m
, options::BlockModelsMode::VALUES
, exprs
);
1293 return assertFormula(eblocker
);
1296 std::pair
<Node
, Node
> SmtEngine::getSepHeapAndNilExpr(void)
1298 if (!getLogicInfo().isTheoryEnabled(THEORY_SEP
))
1301 "Cannot obtain separation logic expressions if not using the "
1302 "separation logic theory.";
1303 throw RecoverableModalException(msg
);
1305 NodeManagerScope
nms(getNodeManager());
1308 TheoryModel
* tm
= getAvailableModel("get separation logic heap and nil");
1309 if (!tm
->getHeapModel(heap
, nil
))
1312 "Failed to obtain heap/nil "
1313 "expressions from theory model.";
1314 throw RecoverableModalException(msg
);
1316 return std::make_pair(heap
, nil
);
1319 std::vector
<Node
> SmtEngine::getAssertionsInternal()
1321 Assert(d_state
->isFullyInited());
1322 context::CDList
<Node
>* al
= d_asserts
->getAssertionList();
1323 Assert(al
!= nullptr);
1324 std::vector
<Node
> res
;
1325 for (const Node
& n
: *al
)
1327 res
.emplace_back(n
);
1332 std::vector
<Node
> SmtEngine::getExpandedAssertions()
1334 std::vector
<Node
> easserts
= getAssertions();
1335 // must expand definitions
1336 d_pp
->expandDefinitions(easserts
);
1339 Env
& SmtEngine::getEnv() { return *d_env
.get(); }
1341 void SmtEngine::declareSepHeap(TypeNode locT
, TypeNode dataT
)
1343 if (!getLogicInfo().isTheoryEnabled(THEORY_SEP
))
1346 "Cannot declare heap if not using the separation logic theory.";
1347 throw RecoverableModalException(msg
);
1349 SmtScope
smts(this);
1351 TheoryEngine
* te
= getTheoryEngine();
1352 te
->declareSepHeap(locT
, dataT
);
1355 bool SmtEngine::getSepHeapTypes(TypeNode
& locT
, TypeNode
& dataT
)
1357 SmtScope
smts(this);
1359 TheoryEngine
* te
= getTheoryEngine();
1360 return te
->getSepHeapTypes(locT
, dataT
);
1363 Node
SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first
; }
1365 Node
SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second
; }
1367 void SmtEngine::checkProof()
1369 Assert(d_env
->getOptions().smt
.produceProofs
);
1370 // internal check the proof
1371 PropEngine
* pe
= getPropEngine();
1372 Assert(pe
!= nullptr);
1373 if (d_env
->getOptions().proof
.proofCheck
== options::ProofCheckMode::EAGER
)
1375 pe
->checkProof(d_asserts
->getAssertionList());
1377 Assert(pe
->getProof() != nullptr);
1378 std::shared_ptr
<ProofNode
> pePfn
= pe
->getProof();
1379 if (d_env
->getOptions().smt
.checkProofs
)
1381 d_pfManager
->checkProof(pePfn
, *d_asserts
);
1385 StatisticsRegistry
& SmtEngine::getStatisticsRegistry()
1387 return d_env
->getStatisticsRegistry();
1390 UnsatCore
SmtEngine::getUnsatCoreInternal()
1392 if (!d_env
->getOptions().smt
.unsatCores
)
1394 throw ModalException(
1395 "Cannot get an unsat core when produce-unsat-cores or produce-proofs "
1398 if (d_state
->getMode() != SmtMode::UNSAT
)
1400 throw RecoverableModalException(
1401 "Cannot get an unsat core unless immediately preceded by "
1402 "UNSAT/ENTAILED response.");
1404 // generate with new proofs
1405 PropEngine
* pe
= getPropEngine();
1406 Assert(pe
!= nullptr);
1408 std::shared_ptr
<ProofNode
> pepf
;
1409 if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS
)
1411 pepf
= pe
->getRefutation();
1415 pepf
= pe
->getProof();
1417 Assert(pepf
!= nullptr);
1418 std::shared_ptr
<ProofNode
> pfn
= d_pfManager
->getFinalProof(pepf
, *d_asserts
);
1419 std::vector
<Node
> core
;
1420 d_ucManager
->getUnsatCore(pfn
, *d_asserts
, core
);
1421 if (options::minimalUnsatCores())
1423 core
= reduceUnsatCore(core
);
1425 return UnsatCore(core
);
1428 std::vector
<Node
> SmtEngine::reduceUnsatCore(const std::vector
<Node
>& core
)
1430 Assert(options::unsatCores())
1431 << "cannot reduce unsat core if unsat cores are turned off";
1433 Notice() << "SmtEngine::reduceUnsatCore(): reducing unsat core" << endl
;
1434 std::unordered_set
<Node
> removed
;
1435 for (const Node
& skip
: core
)
1437 std::unique_ptr
<SmtEngine
> coreChecker
;
1438 initializeSubsolver(coreChecker
, *d_env
.get());
1439 coreChecker
->setLogic(getLogicInfo());
1440 coreChecker
->getOptions().smt
.checkUnsatCores
= false;
1441 // disable all proof options
1442 coreChecker
->getOptions().smt
.produceProofs
= false;
1443 coreChecker
->getOptions().smt
.checkProofs
= false;
1445 for (const Node
& ucAssertion
: core
)
1447 if (ucAssertion
!= skip
&& removed
.find(ucAssertion
) == removed
.end())
1449 Node assertionAfterExpansion
= expandDefinitions(ucAssertion
);
1450 coreChecker
->assertFormula(assertionAfterExpansion
);
1456 r
= coreChecker
->checkSat();
1463 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
1465 removed
.insert(skip
);
1467 else if (r
.asSatisfiabilityResult().isUnknown())
1469 Warning() << "SmtEngine::reduceUnsatCore(): could not reduce unsat core "
1475 if (removed
.empty())
1481 std::vector
<Node
> newUcAssertions
;
1482 for (const Node
& n
: core
)
1484 if (removed
.find(n
) == removed
.end())
1486 newUcAssertions
.push_back(n
);
1490 return newUcAssertions
;
1494 void SmtEngine::checkUnsatCore() {
1495 Assert(d_env
->getOptions().smt
.unsatCores
)
1496 << "cannot check unsat core if unsat cores are turned off";
1498 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl
;
1499 UnsatCore core
= getUnsatCore();
1501 // initialize the core checker
1502 std::unique_ptr
<SmtEngine
> coreChecker
;
1503 initializeSubsolver(coreChecker
, *d_env
.get());
1504 coreChecker
->getOptions().smt
.checkUnsatCores
= false;
1505 // disable all proof options
1506 coreChecker
->getOptions().smt
.produceProofs
= false;
1507 coreChecker
->getOptions().smt
.checkProofs
= false;
1509 // set up separation logic heap if necessary
1510 TypeNode sepLocType
, sepDataType
;
1511 if (getSepHeapTypes(sepLocType
, sepDataType
))
1513 coreChecker
->declareSepHeap(sepLocType
, sepDataType
);
1516 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
1518 theory::TrustSubstitutionMap
& tls
= d_env
->getTopLevelSubstitutions();
1519 for(UnsatCore::iterator i
= core
.begin(); i
!= core
.end(); ++i
) {
1520 Node assertionAfterExpansion
= tls
.apply(*i
, false);
1521 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
1522 << ", expanded to " << assertionAfterExpansion
<< "\n";
1523 coreChecker
->assertFormula(assertionAfterExpansion
);
1527 r
= coreChecker
->checkSat();
1531 Notice() << "SmtEngine::checkUnsatCore(): result is " << r
<< endl
;
1532 if(r
.asSatisfiabilityResult().isUnknown()) {
1534 << "SmtEngine::checkUnsatCore(): could not check core result unknown."
1537 else if (r
.asSatisfiabilityResult().isSat())
1540 << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
1544 void SmtEngine::checkModel(bool hardFailure
) {
1545 context::CDList
<Node
>* al
= d_asserts
->getAssertionList();
1546 // --check-model implies --produce-assertions, which enables the
1547 // assertion list, so we should be ok.
1548 Assert(al
!= nullptr)
1549 << "don't have an assertion list to check in SmtEngine::checkModel()";
1551 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
1553 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
1554 TheoryModel
* m
= getAvailableModel("check model");
1555 Assert(m
!= nullptr);
1557 // check the model with the theory engine for debugging
1558 if (options::debugCheckModels())
1560 TheoryEngine
* te
= getTheoryEngine();
1561 Assert(te
!= nullptr);
1562 te
->checkTheoryAssertionsWithModel(hardFailure
);
1565 // check the model with the check models utility
1566 Assert(d_checkModels
!= nullptr);
1567 d_checkModels
->checkModel(m
, al
, hardFailure
);
1570 UnsatCore
SmtEngine::getUnsatCore() {
1571 Trace("smt") << "SMT getUnsatCore()" << std::endl
;
1572 SmtScope
smts(this);
1574 if (Dump
.isOn("benchmark"))
1576 getPrinter().toStreamCmdGetUnsatCore(d_env
->getDumpOut());
1578 return getUnsatCoreInternal();
1581 void SmtEngine::getRelevantInstantiationTermVectors(
1582 std::map
<Node
, InstantiationList
>& insts
, bool getDebugInfo
)
1584 Assert(d_state
->getMode() == SmtMode::UNSAT
);
1585 // generate with new proofs
1586 PropEngine
* pe
= getPropEngine();
1587 Assert(pe
!= nullptr);
1588 Assert(pe
->getProof() != nullptr);
1589 std::shared_ptr
<ProofNode
> pfn
=
1590 d_pfManager
->getFinalProof(pe
->getProof(), *d_asserts
);
1591 d_ucManager
->getRelevantInstantiations(pfn
, insts
, getDebugInfo
);
1594 std::string
SmtEngine::getProof()
1596 Trace("smt") << "SMT getProof()\n";
1597 SmtScope
smts(this);
1599 if (Dump
.isOn("benchmark"))
1601 getPrinter().toStreamCmdGetProof(d_env
->getDumpOut());
1603 if (!d_env
->getOptions().smt
.produceProofs
)
1605 throw ModalException("Cannot get a proof when proof option is off.");
1607 if (d_state
->getMode() != SmtMode::UNSAT
)
1609 throw RecoverableModalException(
1610 "Cannot get a proof unless immediately preceded by "
1611 "UNSAT/ENTAILED response.");
1613 // the prop engine has the proof of false
1614 PropEngine
* pe
= getPropEngine();
1615 Assert(pe
!= nullptr);
1616 Assert(pe
->getProof() != nullptr);
1617 Assert(d_pfManager
);
1618 std::ostringstream ss
;
1619 d_pfManager
->printProof(ss
, pe
->getProof(), *d_asserts
);
1623 void SmtEngine::printInstantiations( std::ostream
& out
) {
1624 SmtScope
smts(this);
1626 QuantifiersEngine
* qe
= getAvailableQuantifiersEngine("printInstantiations");
1628 // First, extract and print the skolemizations
1629 bool printed
= false;
1630 bool reqNames
= !d_env
->getOptions().printer
.printInstFull
;
1631 // only print when in list mode
1632 if (d_env
->getOptions().printer
.printInstMode
== options::PrintInstMode::LIST
)
1634 std::map
<Node
, std::vector
<Node
>> sks
;
1635 qe
->getSkolemTermVectors(sks
);
1636 for (const std::pair
<const Node
, std::vector
<Node
>>& s
: sks
)
1639 if (!qe
->getNameForQuant(s
.first
, name
, reqNames
))
1641 // did not have a name and we are only printing formulas with names
1644 SkolemList
slist(name
, s
.second
);
1650 // Second, extract and print the instantiations
1651 std::map
<Node
, InstantiationList
> rinsts
;
1652 if (d_env
->getOptions().smt
.produceProofs
1653 && (!d_env
->getOptions().smt
.unsatCores
1654 || d_env
->getOptions().smt
.unsatCoresMode
1655 == options::UnsatCoresMode::FULL_PROOF
)
1656 && getSmtMode() == SmtMode::UNSAT
)
1658 // minimize instantiations based on proof manager
1659 getRelevantInstantiationTermVectors(rinsts
,
1660 options::dumpInstantiationsDebug());
1664 std::map
<Node
, std::vector
<std::vector
<Node
>>> insts
;
1665 getInstantiationTermVectors(insts
);
1666 for (const std::pair
<const Node
, std::vector
<std::vector
<Node
>>>& i
: insts
)
1668 // convert to instantiation list
1670 InstantiationList
& ilq
= rinsts
[q
];
1672 for (const std::vector
<Node
>& ii
: i
.second
)
1674 ilq
.d_inst
.push_back(InstantiationVec(ii
));
1678 for (std::pair
<const Node
, InstantiationList
>& i
: rinsts
)
1680 if (i
.second
.d_inst
.empty())
1682 // no instantiations, skip
1686 if (!qe
->getNameForQuant(i
.first
, name
, reqNames
))
1688 // did not have a name and we are only printing formulas with names
1692 if (d_env
->getOptions().printer
.printInstMode
== options::PrintInstMode::NUM
)
1694 out
<< "(num-instantiations " << name
<< " " << i
.second
.d_inst
.size()
1695 << ")" << std::endl
;
1700 i
.second
.d_quant
= name
;
1701 Assert(d_env
->getOptions().printer
.printInstMode
1702 == options::PrintInstMode::LIST
);
1707 // if we did not print anything, we indicate this
1710 out
<< "none" << std::endl
;
1714 void SmtEngine::getInstantiationTermVectors(
1715 std::map
<Node
, std::vector
<std::vector
<Node
>>>& insts
)
1717 SmtScope
smts(this);
1719 QuantifiersEngine
* qe
=
1720 getAvailableQuantifiersEngine("getInstantiationTermVectors");
1721 // get the list of all instantiations
1722 qe
->getInstantiationTermVectors(insts
);
1725 bool SmtEngine::getSynthSolutions(std::map
<Node
, Node
>& solMap
)
1727 SmtScope
smts(this);
1729 return d_sygusSolver
->getSynthSolutions(solMap
);
1732 Node
SmtEngine::getQuantifierElimination(Node q
, bool doFull
, bool strict
)
1734 SmtScope
smts(this);
1736 const LogicInfo
& logic
= getLogicInfo();
1737 if (!logic
.isPure(THEORY_ARITH
) && strict
)
1739 Warning() << "Unexpected logic for quantifier elimination " << logic
1742 return d_quantElimSolver
->getQuantifierElimination(
1743 *d_asserts
, q
, doFull
, d_isInternalSubsolver
);
1746 bool SmtEngine::getInterpol(const Node
& conj
,
1747 const TypeNode
& grammarType
,
1750 SmtScope
smts(this);
1752 std::vector
<Node
> axioms
= getExpandedAssertions();
1754 d_interpolSolver
->getInterpol(axioms
, conj
, grammarType
, interpol
);
1755 // notify the state of whether the get-interpol call was successfuly, which
1756 // impacts the SMT mode.
1757 d_state
->notifyGetInterpol(success
);
1761 bool SmtEngine::getInterpol(const Node
& conj
, Node
& interpol
)
1763 TypeNode grammarType
;
1764 return getInterpol(conj
, grammarType
, interpol
);
1767 bool SmtEngine::getAbduct(const Node
& conj
,
1768 const TypeNode
& grammarType
,
1771 SmtScope
smts(this);
1773 std::vector
<Node
> axioms
= getExpandedAssertions();
1774 bool success
= d_abductSolver
->getAbduct(axioms
, conj
, grammarType
, abd
);
1775 // notify the state of whether the get-abduct call was successfuly, which
1776 // impacts the SMT mode.
1777 d_state
->notifyGetAbduct(success
);
1781 bool SmtEngine::getAbduct(const Node
& conj
, Node
& abd
)
1783 TypeNode grammarType
;
1784 return getAbduct(conj
, grammarType
, abd
);
1787 void SmtEngine::getInstantiatedQuantifiedFormulas(std::vector
<Node
>& qs
)
1789 SmtScope
smts(this);
1790 QuantifiersEngine
* qe
=
1791 getAvailableQuantifiersEngine("getInstantiatedQuantifiedFormulas");
1792 qe
->getInstantiatedQuantifiedFormulas(qs
);
1795 void SmtEngine::getInstantiationTermVectors(
1796 Node q
, std::vector
<std::vector
<Node
>>& tvecs
)
1798 SmtScope
smts(this);
1799 QuantifiersEngine
* qe
=
1800 getAvailableQuantifiersEngine("getInstantiationTermVectors");
1801 qe
->getInstantiationTermVectors(q
, tvecs
);
1804 std::vector
<Node
> SmtEngine::getAssertions()
1806 SmtScope
smts(this);
1808 d_state
->doPendingPops();
1809 if (Dump
.isOn("benchmark"))
1811 getPrinter().toStreamCmdGetAssertions(d_env
->getDumpOut());
1813 Trace("smt") << "SMT getAssertions()" << endl
;
1814 if (!d_env
->getOptions().smt
.produceAssertions
)
1817 "Cannot query the current assertion list when not in produce-assertions mode.";
1818 throw ModalException(msg
);
1820 return getAssertionsInternal();
1823 void SmtEngine::push()
1825 SmtScope
smts(this);
1827 d_state
->doPendingPops();
1828 Trace("smt") << "SMT push()" << endl
;
1829 d_smtSolver
->processAssertions(*d_asserts
);
1830 if(Dump
.isOn("benchmark")) {
1831 getPrinter().toStreamCmdPush(d_env
->getDumpOut());
1833 d_state
->userPush();
1836 void SmtEngine::pop() {
1837 SmtScope
smts(this);
1839 Trace("smt") << "SMT pop()" << endl
;
1840 if (Dump
.isOn("benchmark"))
1842 getPrinter().toStreamCmdPop(d_env
->getDumpOut());
1846 // Clear out assertion queues etc., in case anything is still in there
1847 d_asserts
->clearCurrent();
1848 // clear the learned literals from the preprocessor
1849 d_pp
->clearLearnedLiterals();
1851 Trace("userpushpop") << "SmtEngine: popped to level "
1852 << getUserContext()->getLevel() << endl
;
1853 // should we reset d_status here?
1854 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
1857 void SmtEngine::resetAssertions()
1859 SmtScope
smts(this);
1861 if (!d_state
->isFullyInited())
1863 // We're still in Start Mode, nothing asserted yet, do nothing.
1864 // (see solver execution modes in the SMT-LIB standard)
1865 Assert(getContext()->getLevel() == 0);
1866 Assert(getUserContext()->getLevel() == 0);
1867 getDumpManager()->resetAssertions();
1872 Trace("smt") << "SMT resetAssertions()" << endl
;
1873 if (Dump
.isOn("benchmark"))
1875 getPrinter().toStreamCmdResetAssertions(d_env
->getDumpOut());
1878 d_asserts
->clearCurrent();
1879 d_state
->notifyResetAssertions();
1880 getDumpManager()->resetAssertions();
1881 // push the state to maintain global context around everything
1884 // reset SmtSolver, which will construct a new prop engine
1885 d_smtSolver
->resetAssertions();
1888 void SmtEngine::interrupt()
1890 if (!d_state
->isFullyInited())
1894 d_smtSolver
->interrupt();
1897 void SmtEngine::setResourceLimit(uint64_t units
, bool cumulative
)
1901 d_env
->d_options
.base
.cumulativeResourceLimit
= units
;
1905 d_env
->d_options
.base
.perCallResourceLimit
= units
;
1908 void SmtEngine::setTimeLimit(uint64_t millis
)
1910 d_env
->d_options
.base
.perCallMillisecondLimit
= millis
;
1913 unsigned long SmtEngine::getResourceUsage() const
1915 return getResourceManager()->getResourceUsage();
1918 unsigned long SmtEngine::getTimeUsage() const
1920 return getResourceManager()->getTimeUsage();
1923 unsigned long SmtEngine::getResourceRemaining() const
1925 return getResourceManager()->getResourceRemaining();
1928 NodeManager
* SmtEngine::getNodeManager() const
1930 return d_env
->getNodeManager();
1933 void SmtEngine::printStatisticsSafe(int fd
) const
1935 d_env
->getStatisticsRegistry().printSafe(fd
);
1938 void SmtEngine::printStatisticsDiff() const
1940 d_env
->getStatisticsRegistry().printDiff(*d_env
->getOptions().base
.err
);
1941 d_env
->getStatisticsRegistry().storeSnapshot();
1944 void SmtEngine::setOption(const std::string
& key
, const std::string
& value
)
1946 NodeManagerScope
nms(getNodeManager());
1947 Trace("smt") << "SMT setOption(" << key
<< ", " << value
<< ")" << endl
;
1949 if (Dump
.isOn("benchmark"))
1951 getPrinter().toStreamCmdSetOption(d_env
->getDumpOut(), key
, value
);
1954 if (key
== "command-verbosity")
1956 size_t fstIndex
= value
.find(" ");
1957 size_t sndIndex
= value
.find(" ", fstIndex
+ 1);
1958 if (sndIndex
== std::string::npos
)
1960 string c
= value
.substr(1, fstIndex
- 1);
1962 std::stoi(value
.substr(fstIndex
+ 1, value
.length() - fstIndex
- 1));
1965 throw OptionException("command-verbosity must be 0, 1, or 2");
1967 d_commandVerbosity
[c
] = v
;
1970 throw OptionException(
1971 "command-verbosity value must be a tuple (command-name integer)");
1974 if (value
.find(" ") != std::string::npos
)
1976 throw OptionException("bad value for :" + key
);
1979 std::string optionarg
= value
;
1980 options::set(getOptions(), key
, optionarg
);
1983 void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver
= true; }
1985 bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver
; }
1987 std::string
SmtEngine::getOption(const std::string
& key
) const
1989 NodeManagerScope
nms(getNodeManager());
1990 NodeManager
* nm
= d_env
->getNodeManager();
1992 Trace("smt") << "SMT getOption(" << key
<< ")" << endl
;
1994 if (key
.find("command-verbosity:") == 0)
1996 auto it
= d_commandVerbosity
.find(key
.substr(std::strlen("command-verbosity:")));
1997 if (it
!= d_commandVerbosity
.end())
1999 return std::to_string(it
->second
);
2001 it
= d_commandVerbosity
.find("*");
2002 if (it
!= d_commandVerbosity
.end())
2004 return std::to_string(it
->second
);
2009 if (Dump
.isOn("benchmark"))
2011 getPrinter().toStreamCmdGetOption(d_env
->getDumpOut(), key
);
2014 if (key
== "command-verbosity")
2016 vector
<Node
> result
;
2017 Node defaultVerbosity
;
2018 for (const auto& verb
: d_commandVerbosity
)
2020 // treat the command name as a variable name as opposed to a string
2021 // constant to avoid printing double quotes around the name
2022 Node name
= nm
->mkBoundVar(verb
.first
, nm
->integerType());
2023 Node value
= nm
->mkConst(Rational(verb
.second
));
2024 if (verb
.first
== "*")
2026 // put the default at the end of the SExpr
2027 defaultVerbosity
= nm
->mkNode(Kind::SEXPR
, name
, value
);
2031 result
.push_back(nm
->mkNode(Kind::SEXPR
, name
, value
));
2034 // ensure the default is always listed
2035 if (defaultVerbosity
.isNull())
2037 defaultVerbosity
= nm
->mkNode(Kind::SEXPR
,
2038 nm
->mkBoundVar("*", nm
->integerType()),
2039 nm
->mkConst(Rational(2)));
2041 result
.push_back(defaultVerbosity
);
2042 return nm
->mkNode(Kind::SEXPR
, result
).toString();
2045 return options::get(getOptions(), key
);
2048 Options
& SmtEngine::getOptions() { return d_env
->d_options
; }
2050 const Options
& SmtEngine::getOptions() const { return d_env
->getOptions(); }
2052 ResourceManager
* SmtEngine::getResourceManager() const
2054 return d_env
->getResourceManager();
2057 DumpManager
* SmtEngine::getDumpManager() { return d_env
->getDumpManager(); }
2059 const Printer
& SmtEngine::getPrinter() const { return d_env
->getPrinter(); }
2061 OutputManager
& SmtEngine::getOutputManager() { return d_outMgr
; }
2063 theory::Rewriter
* SmtEngine::getRewriter() { return d_env
->getRewriter(); }