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/printer_options.h"
31 #include "options/proof_options.h"
32 #include "options/resource_manager_options.h"
33 #include "options/smt_options.h"
34 #include "options/theory_options.h"
35 #include "printer/printer.h"
36 #include "proof/proof_manager.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/options_manager.h"
53 #include "smt/preprocessor.h"
54 #include "smt/proof_manager.h"
55 #include "smt/quant_elim_solver.h"
56 #include "smt/smt_engine_scope.h"
57 #include "smt/smt_engine_state.h"
58 #include "smt/smt_engine_stats.h"
59 #include "smt/smt_solver.h"
60 #include "smt/sygus_solver.h"
61 #include "smt/unsat_core_manager.h"
62 #include "theory/quantifiers/instantiation_list.h"
63 #include "theory/quantifiers/quantifiers_attributes.h"
64 #include "theory/quantifiers_engine.h"
65 #include "theory/rewriter.h"
66 #include "theory/smt_engine_subsolver.h"
67 #include "theory/theory_engine.h"
68 #include "util/random.h"
69 #include "util/resource_manager.h"
70 #include "util/sexpr.h"
71 #include "util/statistics_registry.h"
73 // required for hacks related to old proofs for unsat cores
74 #include "base/configuration.h"
75 #include "base/configuration_private.h"
78 using namespace cvc5::smt
;
79 using namespace cvc5::preprocessing
;
80 using namespace cvc5::prop
;
81 using namespace cvc5::context
;
82 using namespace cvc5::theory
;
86 SmtEngine::SmtEngine(NodeManager
* nm
, Options
* optr
)
87 : d_env(new Env(nm
, optr
)),
88 d_state(new SmtEngineState(getContext(), getUserContext(), *this)),
89 d_absValues(new AbstractValues(getNodeManager())),
90 d_asserts(new Assertions(*d_env
.get(), *d_absValues
.get())),
91 d_routListener(new ResourceOutListener(*this)),
92 d_snmListener(new SmtNodeManagerListener(*getDumpManager(), d_outMgr
)),
94 d_proofManager(nullptr),
96 d_checkModels(nullptr),
99 d_sygusSolver(nullptr),
100 d_abductSolver(nullptr),
101 d_interpolSolver(nullptr),
102 d_quantElimSolver(nullptr),
103 d_isInternalSubsolver(false),
110 // !!!!!!!!!!!!!!!!!!!!!! temporary hack: this makes the current SmtEngine
111 // we are constructing the current SmtEngine in scope for the lifetime of
112 // this SmtEngine, or until another SmtEngine is constructed (that SmtEngine
113 // is then in scope during its lifetime). This is mostly to ensure that
114 // options are always in scope, for e.g. printing expressions, which rely
115 // on knowing the output language.
116 // Notice that the SmtEngine may spawn new SmtEngine "subsolvers" internally.
117 // These are created, used, and deleted in a modular fashion while not
118 // interleaving calls to the master SmtEngine. Thus the hack here does not
119 // break this use case.
120 // On the other hand, this hack breaks use cases where multiple SmtEngine
121 // objects are created by the user.
122 d_scope
.reset(new SmtScope(this));
123 // set the options manager
124 d_optm
.reset(new smt::OptionsManager(&getOptions()));
125 // listen to node manager events
126 getNodeManager()->subscribeEvents(d_snmListener
.get());
127 // listen to resource out
128 getResourceManager()->registerListener(d_routListener
.get());
130 d_stats
.reset(new SmtEngineStatistics());
131 // reset the preprocessor
133 new smt::Preprocessor(*this, *d_env
.get(), *d_absValues
.get(), *d_stats
));
134 // make the SMT solver
136 new SmtSolver(*this, *d_env
.get(), *d_state
, *d_pp
, *d_stats
));
137 // make the SyGuS solver
139 new SygusSolver(*d_smtSolver
, *d_pp
, getUserContext(), d_outMgr
));
140 // make the quantifier elimination solver
141 d_quantElimSolver
.reset(new QuantElimSolver(*d_smtSolver
));
143 // The ProofManager is constructed before any other proof objects such as
144 // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
145 // initialized in TheoryEngine and PropEngine respectively.
146 Assert(d_proofManager
== nullptr);
148 // d_proofManager must be created before Options has been finished
149 // being parsed from the input file. Because of this, we cannot trust
150 // that d_env->getOption(options::unsatCores) is set correctly yet.
151 d_proofManager
.reset(new ProofManager(getUserContext()));
154 bool SmtEngine::isFullyInited() const { return d_state
->isFullyInited(); }
155 bool SmtEngine::isQueryMade() const { return d_state
->isQueryMade(); }
156 size_t SmtEngine::getNumUserLevels() const
158 return d_state
->getNumUserLevels();
160 SmtMode
SmtEngine::getSmtMode() const { return d_state
->getMode(); }
161 bool SmtEngine::isSmtModeSat() const
163 SmtMode mode
= getSmtMode();
164 return mode
== SmtMode::SAT
|| mode
== SmtMode::SAT_UNKNOWN
;
166 Result
SmtEngine::getStatusOfLastCommand() const
168 return d_state
->getStatus();
170 context::UserContext
* SmtEngine::getUserContext()
172 return d_env
->getUserContext();
174 context::Context
* SmtEngine::getContext() { return d_env
->getContext(); }
176 TheoryEngine
* SmtEngine::getTheoryEngine()
178 return d_smtSolver
->getTheoryEngine();
181 prop::PropEngine
* SmtEngine::getPropEngine()
183 return d_smtSolver
->getPropEngine();
186 void SmtEngine::finishInit()
188 if (d_state
->isFullyInited())
190 // already initialized, return
194 // Notice that finishInitInternal is called when options are finalized. If we
195 // are parsing smt2, this occurs at the moment we enter "Assert mode", page 52
196 // of SMT-LIB 2.6 standard.
199 const LogicInfo
& logic
= getLogicInfo();
200 if (!logic
.isLocked())
205 // set the random seed
206 Random::getRandom().setSeed(d_env
->getOption(options::seed
));
208 // Call finish init on the options manager. This inializes the resource
209 // manager based on the options, and sets up the best default options
210 // based on our heuristics.
211 d_optm
->finishInit(d_env
->d_logic
, d_isInternalSubsolver
);
213 ProofNodeManager
* pnm
= nullptr;
214 if (d_env
->getOption(options::produceProofs
))
216 // ensure bound variable uses canonical bound variables
217 getNodeManager()->getBoundVarManager()->enableKeepCacheValues();
218 // make the proof manager
219 d_pfManager
.reset(new PfManager(getUserContext(), this));
220 PreprocessProofGenerator
* pppg
= d_pfManager
->getPreprocessProofGenerator();
221 // start the unsat core manager
222 d_ucManager
.reset(new UnsatCoreManager());
223 // use this proof node manager
224 pnm
= d_pfManager
->getProofNodeManager();
225 // enable proof support in the environment/rewriter
226 d_env
->setProofNodeManager(pnm
);
227 // enable it in the assertions pipeline
228 d_asserts
->setProofGenerator(pppg
);
229 // enable it in the SmtSolver
230 d_smtSolver
->setProofNodeManager(pnm
);
231 // enabled proofs in the preprocessor
232 d_pp
->setProofGenerator(pppg
);
235 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl
;
236 d_smtSolver
->finishInit(logic
);
238 // now can construct the SMT-level model object
239 TheoryEngine
* te
= d_smtSolver
->getTheoryEngine();
240 Assert(te
!= nullptr);
241 TheoryModel
* tm
= te
->getModel();
244 d_model
.reset(new Model(tm
));
245 // make the check models utility
246 d_checkModels
.reset(new CheckModels(*d_env
.get()));
249 // global push/pop around everything, to ensure proper destruction
250 // of context-dependent data structures
253 Trace("smt-debug") << "Set up assertions..." << std::endl
;
254 d_asserts
->finishInit();
256 // dump out a set-logic command only when raw-benchmark is disabled to avoid
257 // dumping the command twice.
258 if (Dump
.isOn("benchmark") && !Dump
.isOn("raw-benchmark"))
260 LogicInfo everything
;
262 getPrinter().toStreamCmdComment(
263 getOutputManager().getDumpOut(),
264 "cvc5 always dumps the most general, all-supported logic (below), as "
265 "some internals might require the use of a logic more general than "
267 getPrinter().toStreamCmdSetBenchmarkLogic(getOutputManager().getDumpOut(),
268 everything
.getLogicString());
271 // initialize the dump manager
272 getDumpManager()->finishInit();
275 if (d_env
->getOption(options::produceAbducts
))
277 d_abductSolver
.reset(new AbductionSolver(this));
279 if (d_env
->getOption(options::produceInterpols
)
280 != options::ProduceInterpols::NONE
)
282 d_interpolSolver
.reset(new InterpolationSolver(this));
287 AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
288 << "The PropEngine has pushed but the SmtEngine "
289 "hasn't finished initializing!";
291 Assert(getLogicInfo().isLocked());
293 // store that we are finished initializing
294 d_state
->finishInit();
295 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl
;
298 void SmtEngine::shutdown() {
301 d_smtSolver
->shutdown();
306 SmtEngine::~SmtEngine()
313 // global push/pop around everything, to ensure proper destruction
314 // of context-dependent data structures
317 //destroy all passes before destroying things that they refer to
320 // d_proofManager is always created when proofs are enabled at configure
321 // time. Because of this, this code should not be wrapped in PROOF() which
322 // additionally checks flags such as
323 // d_env->getOption(options::produceProofs).
325 // Note: the proof manager must be destroyed before the theory engine.
326 // Because the destruction of the proofs depends on contexts owned be the
328 d_proofManager
.reset(nullptr);
329 d_pfManager
.reset(nullptr);
330 d_ucManager
.reset(nullptr);
332 d_absValues
.reset(nullptr);
333 d_asserts
.reset(nullptr);
334 d_model
.reset(nullptr);
336 d_abductSolver
.reset(nullptr);
337 d_interpolSolver
.reset(nullptr);
338 d_quantElimSolver
.reset(nullptr);
339 d_sygusSolver
.reset(nullptr);
340 d_smtSolver
.reset(nullptr);
342 d_stats
.reset(nullptr);
343 getNodeManager()->unsubscribeEvents(d_snmListener
.get());
344 d_snmListener
.reset(nullptr);
345 d_routListener
.reset(nullptr);
346 d_optm
.reset(nullptr);
349 d_state
.reset(nullptr);
350 // destroy the environment
351 d_env
.reset(nullptr);
352 } catch(Exception
& e
) {
353 Warning() << "cvc5 threw an exception during cleanup." << endl
<< e
<< endl
;
357 void SmtEngine::setLogic(const LogicInfo
& logic
)
360 if (d_state
->isFullyInited())
362 throw ModalException("Cannot set logic in SmtEngine after the engine has "
363 "finished initializing.");
365 d_env
->d_logic
= logic
;
370 void SmtEngine::setLogic(const std::string
& s
)
375 setLogic(LogicInfo(s
));
376 // dump out a set-logic command
377 if (Dump
.isOn("raw-benchmark"))
379 getPrinter().toStreamCmdSetBenchmarkLogic(
380 getOutputManager().getDumpOut(), getLogicInfo().getLogicString());
383 catch (IllegalArgumentException
& e
)
385 throw LogicException(e
.what());
389 void SmtEngine::setLogic(const char* logic
) { setLogic(string(logic
)); }
391 const LogicInfo
& SmtEngine::getLogicInfo() const
393 return d_env
->getLogicInfo();
396 LogicInfo
SmtEngine::getUserLogicInfo() const
398 // Lock the logic to make sure that this logic can be queried. We create a
399 // copy of the user logic here to keep this method const.
400 LogicInfo res
= d_userLogic
;
405 void SmtEngine::notifyStartParsing(const std::string
& filename
)
407 d_state
->setFilename(filename
);
408 d_env
->getStatisticsRegistry().registerValue
<std::string
>("driver::filename",
410 // Copy the original options. This is called prior to beginning parsing.
411 // Hence reset should revert to these options, which note is after reading
415 const std::string
& SmtEngine::getFilename() const
417 return d_state
->getFilename();
420 void SmtEngine::setResultStatistic(const std::string
& result
) {
421 d_env
->getStatisticsRegistry().registerValue
<std::string
>("driver::sat/unsat",
424 void SmtEngine::setTotalTimeStatistic(double seconds
) {
425 d_env
->getStatisticsRegistry().registerValue
<double>("driver::totalTime",
429 void SmtEngine::setLogicInternal()
431 Assert(!d_state
->isFullyInited())
432 << "setting logic in SmtEngine but the engine has already"
433 " finished initializing for this run";
434 d_env
->d_logic
.lock();
438 void SmtEngine::setInfo(const std::string
& key
, const std::string
& value
)
442 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
444 if (Dump
.isOn("benchmark"))
451 : ((value
== "unsat") ? Result::UNSAT
: Result::SAT_UNKNOWN
);
452 getPrinter().toStreamCmdSetBenchmarkStatus(
453 getOutputManager().getDumpOut(), status
);
457 getPrinter().toStreamCmdSetInfo(
458 getOutputManager().getDumpOut(), key
, value
);
462 if (key
== "filename")
464 d_state
->setFilename(value
);
466 else if (key
== "smt-lib-version" && !Options::current().wasSetByUser(options::inputLanguage
))
468 language::input::Language ilang
= language::input::LANG_SMTLIB_V2_6
;
470 if (value
!= "2" && value
!= "2.6")
472 Warning() << "SMT-LIB version " << value
473 << " unsupported, defaulting to language (and semantics of) "
476 Options::current().set(options::inputLanguage
, ilang
);
477 // also update the output language
478 if (!Options::current().wasSetByUser(options::outputLanguage
))
480 language::output::Language olang
= language::toOutputLanguage(ilang
);
481 if (d_env
->getOption(options::outputLanguage
) != olang
)
483 Options::current().set(options::outputLanguage
, olang
);
484 *d_env
->getOption(options::out
) << language::SetLanguage(olang
);
488 else if (key
== "status")
490 d_state
->notifyExpectedStatus(value
);
494 bool SmtEngine::isValidGetInfoFlag(const std::string
& key
) const
496 if (key
== "all-statistics" || key
== "error-behavior" || key
== "name"
497 || key
== "version" || key
== "authors" || key
== "status"
498 || key
== "reason-unknown" || key
== "assertion-stack-levels"
499 || key
== "all-options" || key
== "time")
506 std::string
SmtEngine::getInfo(const std::string
& key
) const
510 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
511 if (key
== "all-statistics")
513 return toSExpr(d_env
->getStatisticsRegistry().begin(), d_env
->getStatisticsRegistry().end());
515 if (key
== "error-behavior")
517 return "immediate-exit";
521 return toSExpr(Configuration::getName());
523 if (key
== "version")
525 return toSExpr(Configuration::getVersionString());
527 if (key
== "authors")
529 return toSExpr(Configuration::about());
533 // sat | unsat | unknown
534 Result status
= d_state
->getStatus();
535 switch (status
.asSatisfiabilityResult().isSat())
537 case Result::SAT
: return "sat";
538 case Result::UNSAT
: return "unsat";
539 default: return "unknown";
544 return toSExpr(std::clock());
546 if (key
== "reason-unknown")
548 Result status
= d_state
->getStatus();
549 if (!status
.isNull() && status
.isUnknown())
551 std::stringstream ss
;
552 ss
<< status
.whyUnknown();
553 std::string s
= ss
.str();
554 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
559 throw RecoverableModalException(
560 "Can't get-info :reason-unknown when the "
561 "last result wasn't unknown!");
564 if (key
== "assertion-stack-levels")
566 size_t ulevel
= d_state
->getNumUserLevels();
567 AlwaysAssert(ulevel
<= std::numeric_limits
<unsigned long int>::max());
568 return toSExpr(ulevel
);
570 Assert(key
== "all-options");
571 // get the options, like all-statistics
572 return toSExpr(Options::current().getOptions());
575 void SmtEngine::debugCheckFormals(const std::vector
<Node
>& formals
, Node func
)
577 for (std::vector
<Node
>::const_iterator i
= formals
.begin();
581 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
583 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
584 << "definition of function " << func
<< ", formal\n"
586 << "has kind " << (*i
).getKind();
587 throw TypeCheckingExceptionPrivate(func
, ss
.str());
592 void SmtEngine::debugCheckFunctionBody(Node formula
,
593 const std::vector
<Node
>& formals
,
596 TypeNode formulaType
=
597 formula
.getType(d_env
->getOption(options::typeChecking
));
598 TypeNode funcType
= func
.getType();
599 // We distinguish here between definitions of constants and functions,
600 // because the type checking for them is subtly different. Perhaps we
601 // should instead have SmtEngine::defineFunction() and
602 // SmtEngine::defineConstant() for better clarity, although then that
603 // doesn't match the SMT-LIBv2 standard...
604 if(formals
.size() > 0) {
605 TypeNode rangeType
= funcType
.getRangeType();
606 if(! formulaType
.isComparableTo(rangeType
)) {
608 ss
<< "Type of defined function does not match its declaration\n"
609 << "The function : " << func
<< "\n"
610 << "Declared type : " << rangeType
<< "\n"
611 << "The body : " << formula
<< "\n"
612 << "Body type : " << formulaType
;
613 throw TypeCheckingExceptionPrivate(func
, ss
.str());
616 if(! formulaType
.isComparableTo(funcType
)) {
618 ss
<< "Declared type of defined constant does not match its definition\n"
619 << "The constant : " << func
<< "\n"
620 << "Declared type : " << funcType
<< "\n"
621 << "The definition : " << formula
<< "\n"
622 << "Definition type: " << formulaType
;
623 throw TypeCheckingExceptionPrivate(func
, ss
.str());
628 void SmtEngine::defineFunction(Node func
,
629 const std::vector
<Node
>& formals
,
635 d_state
->doPendingPops();
636 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
637 debugCheckFormals(formals
, func
);
640 ss
<< language::SetLanguage(
641 language::SetLanguage::getLanguage(Dump
.getStream()))
644 DefineFunctionNodeCommand
nc(ss
.str(), func
, formals
, formula
);
645 getDumpManager()->addToDump(nc
, "declarations");
648 debugCheckFunctionBody(formula
, formals
, func
);
650 // Substitute out any abstract values in formula
651 Node def
= d_absValues
->substituteAbstractValues(formula
);
652 if (!formals
.empty())
654 NodeManager
* nm
= NodeManager::currentNM();
656 kind::LAMBDA
, nm
->mkNode(kind::BOUND_VAR_LIST
, formals
), def
);
658 // A define-fun is treated as a (higher-order) assertion. It is provided
659 // to the assertions object. It will be added as a top-level substitution
660 // within this class, possibly multiple times if global is true.
661 Node feq
= func
.eqNode(def
);
662 d_asserts
->addDefineFunDefinition(feq
, global
);
665 void SmtEngine::defineFunctionsRec(
666 const std::vector
<Node
>& funcs
,
667 const std::vector
<std::vector
<Node
>>& formals
,
668 const std::vector
<Node
>& formulas
,
673 d_state
->doPendingPops();
674 Trace("smt") << "SMT defineFunctionsRec(...)" << endl
;
676 if (funcs
.size() != formals
.size() && funcs
.size() != formulas
.size())
679 ss
<< "Number of functions, formals, and function bodies passed to "
680 "defineFunctionsRec do not match:"
682 << " #functions : " << funcs
.size() << "\n"
683 << " #arg lists : " << formals
.size() << "\n"
684 << " #function bodies : " << formulas
.size() << "\n";
685 throw ModalException(ss
.str());
687 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
689 // check formal argument list
690 debugCheckFormals(formals
[i
], funcs
[i
]);
692 debugCheckFunctionBody(formulas
[i
], formals
[i
], funcs
[i
]);
695 if (Dump
.isOn("raw-benchmark"))
697 getPrinter().toStreamCmdDefineFunctionRec(
698 getOutputManager().getDumpOut(), funcs
, formals
, formulas
);
701 NodeManager
* nm
= getNodeManager();
702 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
704 // we assert a quantified formula
706 // make the function application
707 if (formals
[i
].empty())
709 // it has no arguments
714 std::vector
<Node
> children
;
715 children
.push_back(funcs
[i
]);
716 children
.insert(children
.end(), formals
[i
].begin(), formals
[i
].end());
717 func_app
= nm
->mkNode(kind::APPLY_UF
, children
);
719 Node lem
= nm
->mkNode(kind::EQUAL
, func_app
, formulas
[i
]);
720 if (!formals
[i
].empty())
722 // set the attribute to denote this is a function definition
723 Node aexpr
= nm
->mkNode(kind::INST_ATTRIBUTE
, func_app
);
724 aexpr
= nm
->mkNode(kind::INST_PATTERN_LIST
, aexpr
);
726 func_app
.setAttribute(fda
, true);
727 // make the quantified formula
728 Node boundVars
= nm
->mkNode(kind::BOUND_VAR_LIST
, formals
[i
]);
729 lem
= nm
->mkNode(kind::FORALL
, boundVars
, lem
, aexpr
);
731 // assert the quantified formula
732 // notice we don't call assertFormula directly, since this would
733 // duplicate the output on raw-benchmark.
734 // add define recursive definition to the assertions
735 d_asserts
->addDefineFunDefinition(lem
, global
);
739 void SmtEngine::defineFunctionRec(Node func
,
740 const std::vector
<Node
>& formals
,
744 std::vector
<Node
> funcs
;
745 funcs
.push_back(func
);
746 std::vector
<std::vector
<Node
>> formals_multi
;
747 formals_multi
.push_back(formals
);
748 std::vector
<Node
> formulas
;
749 formulas
.push_back(formula
);
750 defineFunctionsRec(funcs
, formals_multi
, formulas
, global
);
753 Result
SmtEngine::quickCheck() {
754 Assert(d_state
->isFullyInited());
755 Trace("smt") << "SMT quickCheck()" << endl
;
756 const std::string
& filename
= d_state
->getFilename();
758 Result::ENTAILMENT_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, filename
);
761 Model
* SmtEngine::getAvailableModel(const char* c
) const
763 if (!d_env
->getOption(options::assignFunctionValues
))
765 std::stringstream ss
;
766 ss
<< "Cannot " << c
<< " when --assign-function-values is false.";
767 throw RecoverableModalException(ss
.str().c_str());
770 if (d_state
->getMode() != SmtMode::SAT
771 && d_state
->getMode() != SmtMode::SAT_UNKNOWN
)
773 std::stringstream ss
;
775 << " unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN "
777 throw RecoverableModalException(ss
.str().c_str());
780 if (!d_env
->getOption(options::produceModels
))
782 std::stringstream ss
;
783 ss
<< "Cannot " << c
<< " when produce-models options is off.";
784 throw ModalException(ss
.str().c_str());
787 TheoryEngine
* te
= d_smtSolver
->getTheoryEngine();
788 Assert(te
!= nullptr);
789 TheoryModel
* m
= te
->getBuiltModel();
793 std::stringstream ss
;
795 << " since model is not available. Perhaps the most recent call to "
796 "check-sat was interrupted?";
797 throw RecoverableModalException(ss
.str().c_str());
800 return d_model
.get();
803 QuantifiersEngine
* SmtEngine::getAvailableQuantifiersEngine(const char* c
) const
805 QuantifiersEngine
* qe
= d_smtSolver
->getQuantifiersEngine();
808 std::stringstream ss
;
809 ss
<< "Cannot " << c
<< " when quantifiers are not present.";
810 throw ModalException(ss
.str().c_str());
815 void SmtEngine::notifyPushPre() { d_smtSolver
->processAssertions(*d_asserts
); }
817 void SmtEngine::notifyPushPost()
819 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
820 Assert(getPropEngine() != nullptr);
821 getPropEngine()->push();
824 void SmtEngine::notifyPopPre()
826 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
827 PropEngine
* pe
= getPropEngine();
828 Assert(pe
!= nullptr);
832 void SmtEngine::notifyPostSolvePre()
834 PropEngine
* pe
= getPropEngine();
835 Assert(pe
!= nullptr);
839 void SmtEngine::notifyPostSolvePost()
841 TheoryEngine
* te
= getTheoryEngine();
842 Assert(te
!= nullptr);
846 Result
SmtEngine::checkSat()
849 return checkSat(nullNode
);
852 Result
SmtEngine::checkSat(const Node
& assumption
, bool inUnsatCore
)
854 if (Dump
.isOn("benchmark"))
856 getPrinter().toStreamCmdCheckSat(getOutputManager().getDumpOut(),
859 std::vector
<Node
> assump
;
860 if (!assumption
.isNull())
862 assump
.push_back(assumption
);
864 return checkSatInternal(assump
, inUnsatCore
, false);
867 Result
SmtEngine::checkSat(const std::vector
<Node
>& assumptions
,
870 if (Dump
.isOn("benchmark"))
872 if (assumptions
.empty())
874 getPrinter().toStreamCmdCheckSat(getOutputManager().getDumpOut());
878 getPrinter().toStreamCmdCheckSatAssuming(getOutputManager().getDumpOut(),
882 return checkSatInternal(assumptions
, inUnsatCore
, false);
885 Result
SmtEngine::checkEntailed(const Node
& node
, bool inUnsatCore
)
887 if (Dump
.isOn("benchmark"))
889 getPrinter().toStreamCmdQuery(getOutputManager().getDumpOut(), node
);
891 return checkSatInternal(
892 node
.isNull() ? std::vector
<Node
>() : std::vector
<Node
>{node
},
895 .asEntailmentResult();
898 Result
SmtEngine::checkEntailed(const std::vector
<Node
>& nodes
,
901 return checkSatInternal(nodes
, inUnsatCore
, true).asEntailmentResult();
904 Result
SmtEngine::checkSatInternal(const std::vector
<Node
>& assumptions
,
906 bool isEntailmentCheck
)
913 Trace("smt") << "SmtEngine::"
914 << (isEntailmentCheck
? "checkEntailed" : "checkSat") << "("
915 << assumptions
<< ")" << endl
;
916 // check the satisfiability with the solver object
917 Result r
= d_smtSolver
->checkSatisfiability(
918 *d_asserts
.get(), assumptions
, inUnsatCore
, isEntailmentCheck
);
920 Trace("smt") << "SmtEngine::" << (isEntailmentCheck
? "query" : "checkSat")
921 << "(" << assumptions
<< ") => " << r
<< endl
;
923 // Check that SAT results generate a model correctly.
924 if (d_env
->getOption(options::checkModels
))
926 if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
931 // Check that UNSAT results generate a proof correctly.
932 if (d_env
->getOption(options::checkProofs
)
933 || d_env
->getOption(options::proofEagerChecking
))
935 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
937 if ((d_env
->getOption(options::checkProofs
)
938 || d_env
->getOption(options::proofEagerChecking
))
939 && !d_env
->getOption(options::produceProofs
))
941 throw ModalException(
942 "Cannot check-proofs because proofs were disabled.");
947 // Check that UNSAT results generate an unsat core correctly.
948 if (d_env
->getOption(options::checkUnsatCores
))
950 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
952 TimerStat::CodeTimer
checkUnsatCoreTimer(d_stats
->d_checkUnsatCoreTime
);
959 catch (UnsafeInterruptException
& e
)
961 AlwaysAssert(getResourceManager()->out());
962 // Notice that we do not notify the state of this result. If we wanted to
963 // make the solver resume a working state after an interupt, then we would
964 // implement a different callback and use it here, e.g.
965 // d_state.notifyCheckSatInterupt.
966 Result::UnknownExplanation why
= getResourceManager()->outOfResources()
967 ? Result::RESOURCEOUT
969 return Result(Result::SAT_UNKNOWN
, why
, d_state
->getFilename());
973 std::vector
<Node
> SmtEngine::getUnsatAssumptions(void)
975 Trace("smt") << "SMT getUnsatAssumptions()" << endl
;
977 if (!d_env
->getOption(options::unsatAssumptions
))
979 throw ModalException(
980 "Cannot get unsat assumptions when produce-unsat-assumptions option "
983 if (d_state
->getMode() != SmtMode::UNSAT
)
985 throw RecoverableModalException(
986 "Cannot get unsat assumptions unless immediately preceded by "
990 if (Dump
.isOn("benchmark"))
992 getPrinter().toStreamCmdGetUnsatAssumptions(
993 getOutputManager().getDumpOut());
995 UnsatCore core
= getUnsatCoreInternal();
996 std::vector
<Node
> res
;
997 std::vector
<Node
>& assumps
= d_asserts
->getAssumptions();
998 for (const Node
& e
: assumps
)
1000 if (std::find(core
.begin(), core
.end(), e
) != core
.end())
1008 Result
SmtEngine::assertFormula(const Node
& formula
, bool inUnsatCore
)
1010 SmtScope
smts(this);
1012 d_state
->doPendingPops();
1014 Trace("smt") << "SmtEngine::assertFormula(" << formula
<< ")" << endl
;
1016 if (Dump
.isOn("raw-benchmark"))
1018 getPrinter().toStreamCmdAssert(getOutputManager().getDumpOut(), formula
);
1021 // Substitute out any abstract values in ex
1022 Node n
= d_absValues
->substituteAbstractValues(formula
);
1024 d_asserts
->assertFormula(n
, inUnsatCore
);
1025 return quickCheck().asEntailmentResult();
1026 }/* SmtEngine::assertFormula() */
1029 --------------------------------------------------------------------------
1030 Handling SyGuS commands
1031 --------------------------------------------------------------------------
1034 void SmtEngine::declareSygusVar(Node var
)
1036 SmtScope
smts(this);
1037 d_sygusSolver
->declareSygusVar(var
);
1038 if (Dump
.isOn("raw-benchmark"))
1040 getPrinter().toStreamCmdDeclareVar(
1041 getOutputManager().getDumpOut(), var
, var
.getType());
1043 // don't need to set that the conjecture is stale
1046 void SmtEngine::declareSynthFun(Node func
,
1049 const std::vector
<Node
>& vars
)
1051 SmtScope
smts(this);
1052 d_state
->doPendingPops();
1053 d_sygusSolver
->declareSynthFun(func
, sygusType
, isInv
, vars
);
1055 // !!! TEMPORARY: We cannot construct a SynthFunCommand since we cannot
1056 // construct a Term-level Grammar from a Node-level sygus TypeNode. Thus we
1057 // must print the command using the Node-level utility method for now.
1059 if (Dump
.isOn("raw-benchmark"))
1061 getPrinter().toStreamCmdSynthFun(
1062 getOutputManager().getDumpOut(), func
, vars
, isInv
, sygusType
);
1065 void SmtEngine::declareSynthFun(Node func
,
1067 const std::vector
<Node
>& vars
)
1069 // use a null sygus type
1071 declareSynthFun(func
, sygusType
, isInv
, vars
);
1074 void SmtEngine::assertSygusConstraint(Node constraint
)
1076 SmtScope
smts(this);
1078 d_sygusSolver
->assertSygusConstraint(constraint
);
1079 if (Dump
.isOn("raw-benchmark"))
1081 getPrinter().toStreamCmdConstraint(getOutputManager().getDumpOut(),
1086 void SmtEngine::assertSygusInvConstraint(Node inv
,
1091 SmtScope
smts(this);
1093 d_sygusSolver
->assertSygusInvConstraint(inv
, pre
, trans
, post
);
1094 if (Dump
.isOn("raw-benchmark"))
1096 getPrinter().toStreamCmdInvConstraint(
1097 getOutputManager().getDumpOut(), inv
, pre
, trans
, post
);
1101 Result
SmtEngine::checkSynth()
1103 SmtScope
smts(this);
1105 return d_sygusSolver
->checkSynth(*d_asserts
);
1109 --------------------------------------------------------------------------
1110 End of Handling SyGuS commands
1111 --------------------------------------------------------------------------
1114 void SmtEngine::declarePool(const Node
& p
, const std::vector
<Node
>& initValue
)
1116 Assert(p
.isVar() && p
.getType().isSet());
1118 QuantifiersEngine
* qe
= getAvailableQuantifiersEngine("declareTermPool");
1119 qe
->declarePool(p
, initValue
);
1122 Node
SmtEngine::simplify(const Node
& ex
)
1124 SmtScope
smts(this);
1126 d_state
->doPendingPops();
1127 // ensure we've processed assertions
1128 d_smtSolver
->processAssertions(*d_asserts
);
1129 return d_pp
->simplify(ex
);
1132 Node
SmtEngine::expandDefinitions(const Node
& ex
)
1134 getResourceManager()->spendResource(Resource::PreprocessStep
);
1135 SmtScope
smts(this);
1137 d_state
->doPendingPops();
1138 return d_pp
->expandDefinitions(ex
);
1141 // TODO(#1108): Simplify the error reporting of this method.
1142 Node
SmtEngine::getValue(const Node
& ex
) const
1144 SmtScope
smts(this);
1146 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
1147 if (Dump
.isOn("benchmark"))
1149 getPrinter().toStreamCmdGetValue(d_outMgr
.getDumpOut(), {ex
});
1151 TypeNode expectedType
= ex
.getType();
1153 // Substitute out any abstract values in ex and expand
1154 Node n
= d_pp
->expandDefinitions(ex
);
1156 Trace("smt") << "--- getting value of " << n
<< endl
;
1157 // There are two ways model values for terms are computed (for historical
1158 // reasons). One way is that used in check-model; the other is that
1159 // used by the Model classes. It's not clear to me exactly how these
1160 // two are different, but they need to be unified. This ugly hack here
1161 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
1164 if(!n
.getType().isFunction()) {
1165 n
= Rewriter::rewrite(n
);
1168 Trace("smt") << "--- getting value of " << n
<< endl
;
1169 Model
* m
= getAvailableModel("get-value");
1170 Assert(m
!= nullptr);
1171 Node resultNode
= m
->getValue(n
);
1172 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
1173 Trace("smt") << "--- type " << resultNode
.getType() << endl
;
1174 Trace("smt") << "--- expected type " << expectedType
<< endl
;
1176 // type-check the result we got
1177 // Notice that lambdas have function type, which does not respect the subtype
1178 // relation, so we ignore them here.
1179 Assert(resultNode
.isNull() || resultNode
.getKind() == kind::LAMBDA
1180 || resultNode
.getType().isSubtypeOf(expectedType
))
1181 << "Run with -t smt for details.";
1183 // Ensure it's a constant, or a lambda (for uninterpreted functions). This
1184 // assertion only holds for models that do not have approximate values.
1185 Assert(m
->hasApproximations() || resultNode
.getKind() == kind::LAMBDA
1186 || resultNode
.isConst());
1188 if (d_env
->getOption(options::abstractValues
)
1189 && resultNode
.getType().isArray())
1191 resultNode
= d_absValues
->mkAbstractValue(resultNode
);
1192 Trace("smt") << "--- abstract value >> " << resultNode
<< endl
;
1198 std::vector
<Node
> SmtEngine::getValues(const std::vector
<Node
>& exprs
)
1200 std::vector
<Node
> result
;
1201 for (const Node
& e
: exprs
)
1203 result
.push_back(getValue(e
));
1208 // TODO(#1108): Simplify the error reporting of this method.
1209 Model
* SmtEngine::getModel() {
1210 Trace("smt") << "SMT getModel()" << endl
;
1211 SmtScope
smts(this);
1215 if (Dump
.isOn("benchmark"))
1217 getPrinter().toStreamCmdGetModel(getOutputManager().getDumpOut());
1220 Model
* m
= getAvailableModel("get model");
1222 // Since model m is being returned to the user, we must ensure that this
1223 // model object remains valid with future check-sat calls. Hence, we set
1224 // the theory engine into "eager model building" mode. TODO #2648: revisit.
1225 TheoryEngine
* te
= getTheoryEngine();
1226 Assert(te
!= nullptr);
1227 te
->setEagerModelBuilding();
1229 if (d_env
->getOption(options::modelCoresMode
)
1230 != options::ModelCoresMode::NONE
)
1232 // If we enabled model cores, we compute a model core for m based on our
1233 // (expanded) assertions using the model core builder utility
1234 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1235 ModelCoreBuilder::setModelCore(eassertsProc
,
1236 m
->getTheoryModel(),
1237 d_env
->getOption(options::modelCoresMode
));
1239 // set the information on the SMT-level model
1240 Assert(m
!= nullptr);
1241 m
->d_inputName
= d_state
->getFilename();
1242 m
->d_isKnownSat
= (d_state
->getMode() == SmtMode::SAT
);
1246 Result
SmtEngine::blockModel()
1248 Trace("smt") << "SMT blockModel()" << endl
;
1249 SmtScope
smts(this);
1253 if (Dump
.isOn("benchmark"))
1255 getPrinter().toStreamCmdBlockModel(getOutputManager().getDumpOut());
1258 Model
* m
= getAvailableModel("block model");
1260 if (d_env
->getOption(options::blockModelsMode
)
1261 == options::BlockModelsMode::NONE
)
1263 std::stringstream ss
;
1264 ss
<< "Cannot block model when block-models is set to none.";
1265 throw RecoverableModalException(ss
.str().c_str());
1268 // get expanded assertions
1269 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1271 ModelBlocker::getModelBlocker(eassertsProc
,
1272 m
->getTheoryModel(),
1273 d_env
->getOption(options::blockModelsMode
));
1274 Trace("smt") << "Block formula: " << eblocker
<< std::endl
;
1275 return assertFormula(eblocker
);
1278 Result
SmtEngine::blockModelValues(const std::vector
<Node
>& exprs
)
1280 Trace("smt") << "SMT blockModelValues()" << endl
;
1281 SmtScope
smts(this);
1285 if (Dump
.isOn("benchmark"))
1287 getPrinter().toStreamCmdBlockModelValues(getOutputManager().getDumpOut(),
1291 Model
* m
= getAvailableModel("block model values");
1293 // get expanded assertions
1294 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1295 // we always do block model values mode here
1297 ModelBlocker::getModelBlocker(eassertsProc
,
1298 m
->getTheoryModel(),
1299 options::BlockModelsMode::VALUES
,
1301 return assertFormula(eblocker
);
1304 std::pair
<Node
, Node
> SmtEngine::getSepHeapAndNilExpr(void)
1306 if (!getLogicInfo().isTheoryEnabled(THEORY_SEP
))
1309 "Cannot obtain separation logic expressions if not using the "
1310 "separation logic theory.";
1311 throw RecoverableModalException(msg
);
1313 NodeManagerScope
nms(getNodeManager());
1316 Model
* m
= getAvailableModel("get separation logic heap and nil");
1317 TheoryModel
* tm
= m
->getTheoryModel();
1318 if (!tm
->getHeapModel(heap
, nil
))
1321 "Failed to obtain heap/nil "
1322 "expressions from theory model.";
1323 throw RecoverableModalException(msg
);
1325 return std::make_pair(heap
, nil
);
1328 std::vector
<Node
> SmtEngine::getExpandedAssertions()
1330 std::vector
<Node
> easserts
= getAssertions();
1331 // must expand definitions
1332 std::vector
<Node
> eassertsProc
;
1333 std::unordered_map
<Node
, Node
> cache
;
1334 for (const Node
& e
: easserts
)
1336 Node eae
= d_pp
->expandDefinitions(e
, cache
);
1337 eassertsProc
.push_back(eae
);
1339 return eassertsProc
;
1341 Env
& SmtEngine::getEnv() { return *d_env
.get(); }
1343 void SmtEngine::declareSepHeap(TypeNode locT
, TypeNode dataT
)
1345 if (!getLogicInfo().isTheoryEnabled(THEORY_SEP
))
1348 "Cannot declare heap if not using the separation logic theory.";
1349 throw RecoverableModalException(msg
);
1351 SmtScope
smts(this);
1353 TheoryEngine
* te
= getTheoryEngine();
1354 te
->declareSepHeap(locT
, dataT
);
1357 bool SmtEngine::getSepHeapTypes(TypeNode
& locT
, TypeNode
& dataT
)
1359 SmtScope
smts(this);
1361 TheoryEngine
* te
= getTheoryEngine();
1362 return te
->getSepHeapTypes(locT
, dataT
);
1365 Node
SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first
; }
1367 Node
SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second
; }
1369 void SmtEngine::checkProof()
1371 Assert(d_env
->getOption(options::produceProofs
));
1372 // internal check the proof
1373 PropEngine
* pe
= getPropEngine();
1374 Assert(pe
!= nullptr);
1375 if (d_env
->getOption(options::proofEagerChecking
))
1377 pe
->checkProof(d_asserts
->getAssertionList());
1379 Assert(pe
->getProof() != nullptr);
1380 std::shared_ptr
<ProofNode
> pePfn
= pe
->getProof();
1381 if (d_env
->getOption(options::checkProofs
))
1383 d_pfManager
->checkProof(pePfn
, *d_asserts
);
1387 StatisticsRegistry
& SmtEngine::getStatisticsRegistry()
1389 return d_env
->getStatisticsRegistry();
1392 UnsatCore
SmtEngine::getUnsatCoreInternal()
1394 if (!d_env
->getOption(options::unsatCores
))
1396 throw ModalException(
1397 "Cannot get an unsat core when produce-unsat-cores[-new] or "
1398 "produce-proofs option is off.");
1400 if (d_state
->getMode() != SmtMode::UNSAT
)
1402 throw RecoverableModalException(
1403 "Cannot get an unsat core unless immediately preceded by "
1404 "UNSAT/ENTAILED response.");
1406 // use old proof infrastructure
1409 d_proofManager
->traceUnsatCore(); // just to trigger core creation
1410 return UnsatCore(d_proofManager
->extractUnsatCore());
1412 // generate with new proofs
1413 PropEngine
* pe
= getPropEngine();
1414 Assert(pe
!= nullptr);
1416 std::shared_ptr
<ProofNode
> pepf
;
1417 if (options::unsatCoresMode() == options::UnsatCoresMode::ASSUMPTIONS
)
1419 pepf
= pe
->getRefutation();
1423 pepf
= pe
->getProof();
1425 Assert(pepf
!= nullptr);
1426 std::shared_ptr
<ProofNode
> pfn
= d_pfManager
->getFinalProof(pepf
, *d_asserts
);
1427 std::vector
<Node
> core
;
1428 d_ucManager
->getUnsatCore(pfn
, *d_asserts
, core
);
1429 return UnsatCore(core
);
1432 void SmtEngine::checkUnsatCore() {
1433 Assert(d_env
->getOption(options::unsatCores
))
1434 << "cannot check unsat core if unsat cores are turned off";
1436 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl
;
1437 UnsatCore core
= getUnsatCore();
1439 // initialize the core checker
1440 std::unique_ptr
<SmtEngine
> coreChecker
;
1441 initializeSubsolver(coreChecker
);
1442 coreChecker
->getOptions().set(options::checkUnsatCores
, false);
1443 // disable all proof options
1444 coreChecker
->getOptions().set(options::produceProofs
, false);
1445 coreChecker
->getOptions().set(options::checkProofs
, false);
1446 coreChecker
->getOptions().set(options::proofEagerChecking
, false);
1448 // set up separation logic heap if necessary
1449 TypeNode sepLocType
, sepDataType
;
1450 if (getSepHeapTypes(sepLocType
, sepDataType
))
1452 coreChecker
->declareSepHeap(sepLocType
, sepDataType
);
1455 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
1457 theory::TrustSubstitutionMap
& tls
= d_env
->getTopLevelSubstitutions();
1458 for(UnsatCore::iterator i
= core
.begin(); i
!= core
.end(); ++i
) {
1459 Node assertionAfterExpansion
= tls
.apply(*i
, false);
1460 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
1461 << ", expanded to " << assertionAfterExpansion
<< "\n";
1462 coreChecker
->assertFormula(assertionAfterExpansion
);
1466 r
= coreChecker
->checkSat();
1470 Notice() << "SmtEngine::checkUnsatCore(): result is " << r
<< endl
;
1471 if(r
.asSatisfiabilityResult().isUnknown()) {
1473 << "SmtEngine::checkUnsatCore(): could not check core result unknown."
1476 else if (r
.asSatisfiabilityResult().isSat())
1479 << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
1483 void SmtEngine::checkModel(bool hardFailure
) {
1484 context::CDList
<Node
>* al
= d_asserts
->getAssertionList();
1485 // --check-model implies --produce-assertions, which enables the
1486 // assertion list, so we should be ok.
1487 Assert(al
!= nullptr)
1488 << "don't have an assertion list to check in SmtEngine::checkModel()";
1490 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
1492 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
1493 Model
* m
= getAvailableModel("check model");
1494 Assert(m
!= nullptr);
1496 // check the model with the theory engine for debugging
1497 if (options::debugCheckModels())
1499 TheoryEngine
* te
= getTheoryEngine();
1500 Assert(te
!= nullptr);
1501 te
->checkTheoryAssertionsWithModel(hardFailure
);
1504 // check the model with the check models utility
1505 Assert(d_checkModels
!= nullptr);
1506 d_checkModels
->checkModel(m
, al
, hardFailure
);
1509 UnsatCore
SmtEngine::getUnsatCore() {
1510 Trace("smt") << "SMT getUnsatCore()" << std::endl
;
1511 SmtScope
smts(this);
1513 if (Dump
.isOn("benchmark"))
1515 getPrinter().toStreamCmdGetUnsatCore(getOutputManager().getDumpOut());
1517 return getUnsatCoreInternal();
1520 void SmtEngine::getRelevantInstantiationTermVectors(
1521 std::map
<Node
, std::vector
<std::vector
<Node
>>>& insts
)
1523 Assert(d_state
->getMode() == SmtMode::UNSAT
);
1524 // generate with new proofs
1525 PropEngine
* pe
= getPropEngine();
1526 Assert(pe
!= nullptr);
1527 Assert(pe
->getProof() != nullptr);
1528 std::shared_ptr
<ProofNode
> pfn
=
1529 d_pfManager
->getFinalProof(pe
->getProof(), *d_asserts
);
1530 d_ucManager
->getRelevantInstantiations(pfn
, insts
);
1533 std::string
SmtEngine::getProof()
1535 Trace("smt") << "SMT getProof()\n";
1536 SmtScope
smts(this);
1538 if (Dump
.isOn("benchmark"))
1540 getPrinter().toStreamCmdGetProof(getOutputManager().getDumpOut());
1542 if (!d_env
->getOption(options::produceProofs
))
1544 throw ModalException("Cannot get a proof when proof option is off.");
1546 if (d_state
->getMode() != SmtMode::UNSAT
)
1548 throw RecoverableModalException(
1549 "Cannot get a proof unless immediately preceded by "
1550 "UNSAT/ENTAILED response.");
1552 // the prop engine has the proof of false
1553 PropEngine
* pe
= getPropEngine();
1554 Assert(pe
!= nullptr);
1555 Assert(pe
->getProof() != nullptr);
1556 Assert(d_pfManager
);
1557 std::ostringstream ss
;
1558 d_pfManager
->printProof(ss
, pe
->getProof(), *d_asserts
);
1562 void SmtEngine::printInstantiations( std::ostream
& out
) {
1563 SmtScope
smts(this);
1565 if (d_env
->getOption(options::instFormatMode
) == options::InstFormatMode::SZS
)
1567 out
<< "% SZS output start Proof for " << d_state
->getFilename()
1570 QuantifiersEngine
* qe
= getAvailableQuantifiersEngine("printInstantiations");
1572 // First, extract and print the skolemizations
1573 bool printed
= false;
1574 bool reqNames
= !d_env
->getOption(options::printInstFull
);
1575 // only print when in list mode
1576 if (d_env
->getOption(options::printInstMode
) == options::PrintInstMode::LIST
)
1578 std::map
<Node
, std::vector
<Node
>> sks
;
1579 qe
->getSkolemTermVectors(sks
);
1580 for (const std::pair
<const Node
, std::vector
<Node
>>& s
: sks
)
1583 if (!qe
->getNameForQuant(s
.first
, name
, reqNames
))
1585 // did not have a name and we are only printing formulas with names
1588 SkolemList
slist(name
, s
.second
);
1594 // Second, extract and print the instantiations
1595 std::map
<Node
, std::vector
<std::vector
<Node
>>> insts
;
1596 getInstantiationTermVectors(insts
);
1597 for (const std::pair
<const Node
, std::vector
<std::vector
<Node
>>>& i
: insts
)
1599 if (i
.second
.empty())
1601 // no instantiations, skip
1605 if (!qe
->getNameForQuant(i
.first
, name
, reqNames
))
1607 // did not have a name and we are only printing formulas with names
1611 if (d_env
->getOption(options::printInstMode
) == options::PrintInstMode::NUM
)
1613 out
<< "(num-instantiations " << name
<< " " << i
.second
.size() << ")"
1618 Assert(d_env
->getOption(options::printInstMode
)
1619 == options::PrintInstMode::LIST
);
1620 InstantiationList
ilist(name
, i
.second
);
1625 // if we did not print anything, we indicate this
1628 out
<< "No instantiations" << std::endl
;
1630 if (d_env
->getOption(options::instFormatMode
) == options::InstFormatMode::SZS
)
1632 out
<< "% SZS output end Proof for " << d_state
->getFilename() << std::endl
;
1636 void SmtEngine::getInstantiationTermVectors(
1637 std::map
<Node
, std::vector
<std::vector
<Node
>>>& insts
)
1639 SmtScope
smts(this);
1641 if (d_env
->getOption(options::produceProofs
)
1642 && (!d_env
->getOption(options::unsatCores
)
1643 || d_env
->getOption(options::unsatCoresMode
) == options::UnsatCoresMode::FULL_PROOF
)
1644 && getSmtMode() == SmtMode::UNSAT
)
1646 // minimize instantiations based on proof manager
1647 getRelevantInstantiationTermVectors(insts
);
1651 QuantifiersEngine
* qe
=
1652 getAvailableQuantifiersEngine("getInstantiationTermVectors");
1653 // otherwise, just get the list of all instantiations
1654 qe
->getInstantiationTermVectors(insts
);
1658 void SmtEngine::printSynthSolution( std::ostream
& out
) {
1659 SmtScope
smts(this);
1661 d_sygusSolver
->printSynthSolution(out
);
1664 bool SmtEngine::getSynthSolutions(std::map
<Node
, Node
>& solMap
)
1666 SmtScope
smts(this);
1668 return d_sygusSolver
->getSynthSolutions(solMap
);
1671 Node
SmtEngine::getQuantifierElimination(Node q
, bool doFull
, bool strict
)
1673 SmtScope
smts(this);
1675 const LogicInfo
& logic
= getLogicInfo();
1676 if (!logic
.isPure(THEORY_ARITH
) && strict
)
1678 Warning() << "Unexpected logic for quantifier elimination " << logic
1681 return d_quantElimSolver
->getQuantifierElimination(
1682 *d_asserts
, q
, doFull
, d_isInternalSubsolver
);
1685 bool SmtEngine::getInterpol(const Node
& conj
,
1686 const TypeNode
& grammarType
,
1689 SmtScope
smts(this);
1691 bool success
= d_interpolSolver
->getInterpol(conj
, grammarType
, interpol
);
1692 // notify the state of whether the get-interpol call was successfuly, which
1693 // impacts the SMT mode.
1694 d_state
->notifyGetInterpol(success
);
1698 bool SmtEngine::getInterpol(const Node
& conj
, Node
& interpol
)
1700 TypeNode grammarType
;
1701 return getInterpol(conj
, grammarType
, interpol
);
1704 bool SmtEngine::getAbduct(const Node
& conj
,
1705 const TypeNode
& grammarType
,
1708 SmtScope
smts(this);
1710 bool success
= d_abductSolver
->getAbduct(conj
, grammarType
, abd
);
1711 // notify the state of whether the get-abduct call was successfuly, which
1712 // impacts the SMT mode.
1713 d_state
->notifyGetAbduct(success
);
1717 bool SmtEngine::getAbduct(const Node
& conj
, Node
& abd
)
1719 TypeNode grammarType
;
1720 return getAbduct(conj
, grammarType
, abd
);
1723 void SmtEngine::getInstantiatedQuantifiedFormulas(std::vector
<Node
>& qs
)
1725 SmtScope
smts(this);
1726 QuantifiersEngine
* qe
=
1727 getAvailableQuantifiersEngine("getInstantiatedQuantifiedFormulas");
1728 qe
->getInstantiatedQuantifiedFormulas(qs
);
1731 void SmtEngine::getInstantiationTermVectors(
1732 Node q
, std::vector
<std::vector
<Node
>>& tvecs
)
1734 SmtScope
smts(this);
1735 QuantifiersEngine
* qe
=
1736 getAvailableQuantifiersEngine("getInstantiationTermVectors");
1737 qe
->getInstantiationTermVectors(q
, tvecs
);
1740 std::vector
<Node
> SmtEngine::getAssertions()
1742 SmtScope
smts(this);
1744 d_state
->doPendingPops();
1745 if (Dump
.isOn("benchmark"))
1747 getPrinter().toStreamCmdGetAssertions(getOutputManager().getDumpOut());
1749 Trace("smt") << "SMT getAssertions()" << endl
;
1750 if (!d_env
->getOption(options::produceAssertions
))
1753 "Cannot query the current assertion list when not in produce-assertions mode.";
1754 throw ModalException(msg
);
1756 context::CDList
<Node
>* al
= d_asserts
->getAssertionList();
1757 Assert(al
!= nullptr);
1758 std::vector
<Node
> res
;
1759 for (const Node
& n
: *al
)
1761 res
.emplace_back(n
);
1763 // copy the result out
1767 void SmtEngine::push()
1769 SmtScope
smts(this);
1771 d_state
->doPendingPops();
1772 Trace("smt") << "SMT push()" << endl
;
1773 d_smtSolver
->processAssertions(*d_asserts
);
1774 if(Dump
.isOn("benchmark")) {
1775 getPrinter().toStreamCmdPush(getOutputManager().getDumpOut());
1777 d_state
->userPush();
1780 void SmtEngine::pop() {
1781 SmtScope
smts(this);
1783 Trace("smt") << "SMT pop()" << endl
;
1784 if (Dump
.isOn("benchmark"))
1786 getPrinter().toStreamCmdPop(getOutputManager().getDumpOut());
1790 // Clear out assertion queues etc., in case anything is still in there
1791 d_asserts
->clearCurrent();
1792 // clear the learned literals from the preprocessor
1793 d_pp
->clearLearnedLiterals();
1795 Trace("userpushpop") << "SmtEngine: popped to level "
1796 << getUserContext()->getLevel() << endl
;
1797 // should we reset d_status here?
1798 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
1801 void SmtEngine::resetAssertions()
1803 SmtScope
smts(this);
1805 if (!d_state
->isFullyInited())
1807 // We're still in Start Mode, nothing asserted yet, do nothing.
1808 // (see solver execution modes in the SMT-LIB standard)
1809 Assert(getContext()->getLevel() == 0);
1810 Assert(getUserContext()->getLevel() == 0);
1811 getDumpManager()->resetAssertions();
1816 Trace("smt") << "SMT resetAssertions()" << endl
;
1817 if (Dump
.isOn("benchmark"))
1819 getPrinter().toStreamCmdResetAssertions(getOutputManager().getDumpOut());
1822 d_asserts
->clearCurrent();
1823 d_state
->notifyResetAssertions();
1824 getDumpManager()->resetAssertions();
1825 // push the state to maintain global context around everything
1828 // reset SmtSolver, which will construct a new prop engine
1829 d_smtSolver
->resetAssertions();
1832 void SmtEngine::interrupt()
1834 if (!d_state
->isFullyInited())
1838 d_smtSolver
->interrupt();
1841 void SmtEngine::setResourceLimit(uint64_t units
, bool cumulative
)
1845 d_env
->d_options
.set(options::cumulativeResourceLimit__option_t(), units
);
1849 d_env
->d_options
.set(options::perCallResourceLimit__option_t(), units
);
1852 void SmtEngine::setTimeLimit(uint64_t millis
)
1854 d_env
->d_options
.set(options::perCallMillisecondLimit__option_t(), millis
);
1857 unsigned long SmtEngine::getResourceUsage() const
1859 return getResourceManager()->getResourceUsage();
1862 unsigned long SmtEngine::getTimeUsage() const
1864 return getResourceManager()->getTimeUsage();
1867 unsigned long SmtEngine::getResourceRemaining() const
1869 return getResourceManager()->getResourceRemaining();
1872 NodeManager
* SmtEngine::getNodeManager() const
1874 return d_env
->getNodeManager();
1877 void SmtEngine::printStatistics(std::ostream
& out
) const
1879 d_env
->getStatisticsRegistry().print(out
);
1882 void SmtEngine::printStatisticsSafe(int fd
) const
1884 d_env
->getStatisticsRegistry().printSafe(fd
);
1887 void SmtEngine::printStatisticsDiff(std::ostream
& out
) const
1889 d_env
->getStatisticsRegistry().printDiff(out
);
1890 d_env
->getStatisticsRegistry().storeSnapshot();
1893 void SmtEngine::setUserAttribute(const std::string
& attr
,
1895 const std::vector
<Node
>& expr_values
,
1896 const std::string
& str_value
)
1898 SmtScope
smts(this);
1900 TheoryEngine
* te
= getTheoryEngine();
1901 Assert(te
!= nullptr);
1902 te
->setUserAttribute(attr
, expr
, expr_values
, str_value
);
1905 void SmtEngine::setOption(const std::string
& key
, const std::string
& value
)
1907 NodeManagerScope
nms(getNodeManager());
1908 Trace("smt") << "SMT setOption(" << key
<< ", " << value
<< ")" << endl
;
1910 if (Dump
.isOn("benchmark"))
1912 getPrinter().toStreamCmdSetOption(
1913 getOutputManager().getDumpOut(), key
, value
);
1916 if (key
== "command-verbosity")
1918 size_t fstIndex
= value
.find(" ");
1919 size_t sndIndex
= value
.find(" ", fstIndex
+ 1);
1920 if (sndIndex
== std::string::npos
)
1922 string c
= value
.substr(1, fstIndex
- 1);
1924 std::stoi(value
.substr(fstIndex
+ 1, value
.length() - fstIndex
- 1));
1927 throw OptionException("command-verbosity must be 0, 1, or 2");
1929 d_commandVerbosity
[c
] = v
;
1932 throw OptionException(
1933 "command-verbosity value must be a tuple (command-name integer)");
1936 if (value
.find(" ") != std::string::npos
)
1938 throw OptionException("bad value for :" + key
);
1941 std::string optionarg
= value
;
1942 getOptions().setOption(key
, optionarg
);
1945 void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver
= true; }
1947 bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver
; }
1949 std::string
SmtEngine::getOption(const std::string
& key
) const
1951 NodeManagerScope
nms(getNodeManager());
1952 NodeManager
* nm
= d_env
->getNodeManager();
1954 Trace("smt") << "SMT getOption(" << key
<< ")" << endl
;
1956 if (key
.find("command-verbosity:") == 0)
1958 auto it
= d_commandVerbosity
.find(key
.substr(std::strlen("command-verbosity:")));
1959 if (it
!= d_commandVerbosity
.end())
1961 return std::to_string(it
->second
);
1963 it
= d_commandVerbosity
.find("*");
1964 if (it
!= d_commandVerbosity
.end())
1966 return std::to_string(it
->second
);
1971 if (Dump
.isOn("benchmark"))
1973 getPrinter().toStreamCmdGetOption(d_outMgr
.getDumpOut(), key
);
1976 if (key
== "command-verbosity")
1978 vector
<Node
> result
;
1979 Node defaultVerbosity
;
1980 for (const auto& verb
: d_commandVerbosity
)
1982 // treat the command name as a variable name as opposed to a string
1983 // constant to avoid printing double quotes around the name
1984 Node name
= nm
->mkBoundVar(verb
.first
, nm
->integerType());
1985 Node value
= nm
->mkConst(Rational(verb
.second
));
1986 if (verb
.first
== "*")
1988 // put the default at the end of the SExpr
1989 defaultVerbosity
= nm
->mkNode(Kind::SEXPR
, name
, value
);
1993 result
.push_back(nm
->mkNode(Kind::SEXPR
, name
, value
));
1996 // ensure the default is always listed
1997 if (defaultVerbosity
.isNull())
1999 defaultVerbosity
= nm
->mkNode(Kind::SEXPR
,
2000 nm
->mkBoundVar("*", nm
->integerType()),
2001 nm
->mkConst(Rational(2)));
2003 result
.push_back(defaultVerbosity
);
2004 return nm
->mkNode(Kind::SEXPR
, result
).toString();
2007 std::string atom
= getOptions().getOption(key
);
2009 if (atom
!= "true" && atom
!= "false")
2015 catch (std::invalid_argument
&)
2017 atom
= "\"" + atom
+ "\"";
2024 Options
& SmtEngine::getOptions() { return d_env
->d_options
; }
2026 const Options
& SmtEngine::getOptions() const { return d_env
->getOptions(); }
2028 ResourceManager
* SmtEngine::getResourceManager() const
2030 return d_env
->getResourceManager();
2033 DumpManager
* SmtEngine::getDumpManager() { return d_env
->getDumpManager(); }
2035 const Printer
& SmtEngine::getPrinter() const { return d_env
->getPrinter(); }
2037 OutputManager
& SmtEngine::getOutputManager() { return d_outMgr
; }
2039 theory::Rewriter
* SmtEngine::getRewriter() { return d_env
->getRewriter(); }