1 /********************* */
2 /*! \file smt_engine.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Morgan Deters, Abdalrhman Mohamed
6 ** This file is part of the CVC4 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.\endverbatim
12 ** \brief The main entry point into the CVC4 library's SMT interface
14 ** The main entry point into the CVC4 library's SMT interface.
17 #include "smt/smt_engine.h"
19 #include "api/cvc4cpp.h"
20 #include "base/check.h"
21 #include "base/exception.h"
22 #include "base/modal_exception.h"
23 #include "base/output.h"
24 #include "decision/decision_engine.h"
25 #include "expr/bound_var_manager.h"
26 #include "expr/node.h"
27 #include "options/base_options.h"
28 #include "options/language.h"
29 #include "options/main_options.h"
30 #include "options/printer_options.h"
31 #include "options/proof_options.h"
32 #include "options/smt_options.h"
33 #include "options/theory_options.h"
34 #include "printer/printer.h"
35 #include "proof/proof_manager.h"
36 #include "proof/unsat_core.h"
37 #include "prop/prop_engine.h"
38 #include "smt/abduction_solver.h"
39 #include "smt/abstract_values.h"
40 #include "smt/assertions.h"
41 #include "smt/check_models.h"
42 #include "smt/defined_function.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"
71 // required for hacks related to old proofs for unsat cores
72 #include "base/configuration.h"
73 #include "base/configuration_private.h"
76 using namespace CVC4::smt
;
77 using namespace CVC4::preprocessing
;
78 using namespace CVC4::prop
;
79 using namespace CVC4::context
;
80 using namespace CVC4::theory
;
84 SmtEngine::SmtEngine(NodeManager
* nm
, Options
* optr
)
86 d_state(new SmtEngineState(getContext(), getUserContext(), *this)),
87 d_absValues(new AbstractValues(getNodeManager())),
88 d_asserts(new Assertions(getUserContext(), *d_absValues
.get())),
89 d_routListener(new ResourceOutListener(*this)),
90 d_snmListener(new SmtNodeManagerListener(*getDumpManager(), d_outMgr
)),
92 d_proofManager(nullptr),
94 d_checkModels(nullptr),
97 d_definedFunctions(nullptr),
98 d_sygusSolver(nullptr),
99 d_abductSolver(nullptr),
100 d_interpolSolver(nullptr),
101 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 options in the environment, which makes a deep copy of optr if
124 // non-null. This may throw an options exception.
125 d_env
->setOptions(optr
);
126 // set the options manager
127 d_optm
.reset(new smt::OptionsManager(&getOptions(), getResourceManager()));
128 // listen to node manager events
129 getNodeManager()->subscribeEvents(d_snmListener
.get());
130 // listen to resource out
131 getResourceManager()->registerListener(d_routListener
.get());
133 d_stats
.reset(new SmtEngineStatistics());
134 // reset the preprocessor
135 d_pp
.reset(new smt::Preprocessor(
136 *this, getUserContext(), *d_absValues
.get(), *d_stats
));
137 // make the SMT solver
139 new SmtSolver(*this, *d_state
, getResourceManager(), *d_pp
, *d_stats
));
140 // make the SyGuS solver
142 new SygusSolver(*d_smtSolver
, *d_pp
, getUserContext(), d_outMgr
));
143 // make the quantifier elimination solver
144 d_quantElimSolver
.reset(new QuantElimSolver(*d_smtSolver
));
146 // The ProofManager is constructed before any other proof objects such as
147 // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
148 // initialized in TheoryEngine and PropEngine respectively.
149 Assert(d_proofManager
== nullptr);
151 // d_proofManager must be created before Options has been finished
152 // being parsed from the input file. Because of this, we cannot trust
153 // that options::unsatCores() is set correctly yet.
155 d_proofManager
.reset(new ProofManager(getUserContext()));
158 d_definedFunctions
= new (true) DefinedFunctionMap(getUserContext());
161 bool SmtEngine::isFullyInited() const { return d_state
->isFullyInited(); }
162 bool SmtEngine::isQueryMade() const { return d_state
->isQueryMade(); }
163 size_t SmtEngine::getNumUserLevels() const
165 return d_state
->getNumUserLevels();
167 SmtMode
SmtEngine::getSmtMode() const { return d_state
->getMode(); }
168 bool SmtEngine::isSmtModeSat() const
170 SmtMode mode
= getSmtMode();
171 return mode
== SmtMode::SAT
|| mode
== SmtMode::SAT_UNKNOWN
;
173 Result
SmtEngine::getStatusOfLastCommand() const
175 return d_state
->getStatus();
177 context::UserContext
* SmtEngine::getUserContext()
179 return d_env
->getUserContext();
181 context::Context
* SmtEngine::getContext() { return d_env
->getContext(); }
183 TheoryEngine
* SmtEngine::getTheoryEngine()
185 return d_smtSolver
->getTheoryEngine();
188 prop::PropEngine
* SmtEngine::getPropEngine()
190 return d_smtSolver
->getPropEngine();
193 void SmtEngine::finishInit()
195 if (d_state
->isFullyInited())
197 // already initialized, return
201 // Notice that finishInitInternal is called when options are finalized. If we
202 // are parsing smt2, this occurs at the moment we enter "Assert mode", page 52
203 // of SMT-LIB 2.6 standard.
206 const LogicInfo
& logic
= getLogicInfo();
207 if (!logic
.isLocked())
212 // set the random seed
213 Random::getRandom().setSeed(options::seed());
215 // Call finish init on the options manager. This inializes the resource
216 // manager based on the options, and sets up the best default options
217 // based on our heuristics.
218 d_optm
->finishInit(d_env
->d_logic
, d_isInternalSubsolver
);
220 ProofNodeManager
* pnm
= nullptr;
221 if (options::produceProofs())
223 // ensure bound variable uses canonical bound variables
224 getNodeManager()->getBoundVarManager()->enableKeepCacheValues();
225 // make the proof manager
226 d_pfManager
.reset(new PfManager(getUserContext(), this));
227 PreprocessProofGenerator
* pppg
= d_pfManager
->getPreprocessProofGenerator();
228 // start the unsat core manager
229 d_ucManager
.reset(new UnsatCoreManager());
230 // use this proof node manager
231 pnm
= d_pfManager
->getProofNodeManager();
232 // enable proof support in the environment/rewriter
233 d_env
->setProofNodeManager(pnm
);
234 // enable it in the assertions pipeline
235 d_asserts
->setProofGenerator(pppg
);
236 // enable it in the SmtSolver
237 d_smtSolver
->setProofNodeManager(pnm
);
238 // enabled proofs in the preprocessor
239 d_pp
->setProofGenerator(pppg
);
242 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl
;
243 d_smtSolver
->finishInit(logic
);
245 // now can construct the SMT-level model object
246 TheoryEngine
* te
= d_smtSolver
->getTheoryEngine();
247 Assert(te
!= nullptr);
248 TheoryModel
* tm
= te
->getModel();
251 d_model
.reset(new Model(tm
));
252 // make the check models utility
253 d_checkModels
.reset(new CheckModels(*d_smtSolver
.get()));
256 // global push/pop around everything, to ensure proper destruction
257 // of context-dependent data structures
260 Trace("smt-debug") << "Set up assertions..." << std::endl
;
261 d_asserts
->finishInit();
263 // dump out a set-logic command only when raw-benchmark is disabled to avoid
264 // dumping the command twice.
265 if (Dump
.isOn("benchmark") && !Dump
.isOn("raw-benchmark"))
267 LogicInfo everything
;
269 getPrinter().toStreamCmdComment(
270 getOutputManager().getDumpOut(),
271 "CVC4 always dumps the most general, all-supported logic (below), as "
272 "some internals might require the use of a logic more general than "
274 getPrinter().toStreamCmdSetBenchmarkLogic(getOutputManager().getDumpOut(),
275 everything
.getLogicString());
278 // initialize the dump manager
279 getDumpManager()->finishInit();
282 if (options::produceAbducts())
284 d_abductSolver
.reset(new AbductionSolver(this));
286 if (options::produceInterpols() != options::ProduceInterpols::NONE
)
288 d_interpolSolver
.reset(new InterpolationSolver(this));
293 AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
294 << "The PropEngine has pushed but the SmtEngine "
295 "hasn't finished initializing!";
297 Assert(getLogicInfo().isLocked());
299 // store that we are finished initializing
300 d_state
->finishInit();
301 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl
;
304 void SmtEngine::shutdown() {
307 d_smtSolver
->shutdown();
312 SmtEngine::~SmtEngine()
319 // global push/pop around everything, to ensure proper destruction
320 // of context-dependent data structures
323 d_definedFunctions
->deleteSelf();
325 //destroy all passes before destroying things that they refer to
328 // d_proofManager is always created when proofs are enabled at configure
329 // time. Because of this, this code should not be wrapped in PROOF() which
330 // additionally checks flags such as options::produceProofs().
332 // Note: the proof manager must be destroyed before the theory engine.
333 // Because the destruction of the proofs depends on contexts owned be the
336 d_proofManager
.reset(nullptr);
338 d_pfManager
.reset(nullptr);
339 d_ucManager
.reset(nullptr);
341 d_absValues
.reset(nullptr);
342 d_asserts
.reset(nullptr);
343 d_model
.reset(nullptr);
345 d_sygusSolver
.reset(nullptr);
347 d_smtSolver
.reset(nullptr);
349 d_stats
.reset(nullptr);
350 getNodeManager()->unsubscribeEvents(d_snmListener
.get());
351 d_snmListener
.reset(nullptr);
352 d_routListener
.reset(nullptr);
353 d_optm
.reset(nullptr);
356 d_state
.reset(nullptr);
357 // destroy the environment
358 d_env
.reset(nullptr);
359 } catch(Exception
& e
) {
360 Warning() << "CVC4 threw an exception during cleanup." << endl
365 void SmtEngine::setLogic(const LogicInfo
& logic
)
368 if (d_state
->isFullyInited())
370 throw ModalException("Cannot set logic in SmtEngine after the engine has "
371 "finished initializing.");
373 d_env
->d_logic
= logic
;
378 void SmtEngine::setLogic(const std::string
& s
)
383 setLogic(LogicInfo(s
));
384 // dump out a set-logic command
385 if (Dump
.isOn("raw-benchmark"))
387 getPrinter().toStreamCmdSetBenchmarkLogic(
388 getOutputManager().getDumpOut(), getLogicInfo().getLogicString());
391 catch (IllegalArgumentException
& e
)
393 throw LogicException(e
.what());
397 void SmtEngine::setLogic(const char* logic
) { setLogic(string(logic
)); }
399 const LogicInfo
& SmtEngine::getLogicInfo() const
401 return d_env
->getLogicInfo();
404 LogicInfo
SmtEngine::getUserLogicInfo() const
406 // Lock the logic to make sure that this logic can be queried. We create a
407 // copy of the user logic here to keep this method const.
408 LogicInfo res
= d_userLogic
;
413 void SmtEngine::notifyStartParsing(std::string filename
)
415 d_state
->setFilename(filename
);
416 // Copy the original options. This is called prior to beginning parsing.
417 // Hence reset should revert to these options, which note is after reading
419 d_originalOptions
.copyValues(getOptions());
422 const std::string
& SmtEngine::getFilename() const
424 return d_state
->getFilename();
426 void SmtEngine::setLogicInternal()
428 Assert(!d_state
->isFullyInited())
429 << "setting logic in SmtEngine but the engine has already"
430 " finished initializing for this run";
431 d_env
->d_logic
.lock();
435 void SmtEngine::setInfo(const std::string
& key
, const std::string
& value
)
439 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
441 if (Dump
.isOn("benchmark"))
448 : ((value
== "unsat") ? Result::UNSAT
: Result::SAT_UNKNOWN
);
449 getPrinter().toStreamCmdSetBenchmarkStatus(
450 getOutputManager().getDumpOut(), status
);
454 getPrinter().toStreamCmdSetInfo(
455 getOutputManager().getDumpOut(), key
, value
);
459 if (key
== "filename")
461 d_state
->setFilename(value
);
463 else if (key
== "smt-lib-version" && !options::inputLanguage
.wasSetByUser())
465 language::input::Language ilang
= language::input::LANG_SMTLIB_V2_6
;
467 if (value
!= "2" && value
!= "2.6")
469 Warning() << "SMT-LIB version " << value
470 << " unsupported, defaulting to language (and semantics of) "
473 options::inputLanguage
.set(ilang
);
474 // also update the output language
475 if (!options::outputLanguage
.wasSetByUser())
477 language::output::Language olang
= language::toOutputLanguage(ilang
);
478 if (options::outputLanguage() != olang
)
480 options::outputLanguage
.set(olang
);
481 *options::out() << language::SetLanguage(olang
);
485 else if (key
== "status")
487 d_state
->notifyExpectedStatus(value
);
491 bool SmtEngine::isValidGetInfoFlag(const std::string
& key
) const
493 if (key
== "all-statistics" || key
== "error-behavior" || key
== "name"
494 || key
== "version" || key
== "authors" || key
== "status"
495 || key
== "reason-unknown" || key
== "assertion-stack-levels"
496 || key
== "all-options" || key
== "time")
503 CVC4::SExpr
SmtEngine::getInfo(const std::string
& key
) const
507 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
508 if (key
== "all-statistics")
511 StatisticsRegistry
* sr
= getNodeManager()->getStatisticsRegistry();
512 for (StatisticsRegistry::const_iterator i
= sr
->begin(); i
!= sr
->end();
516 v
.push_back((*i
).first
);
517 v
.push_back((*i
).second
);
520 for (StatisticsRegistry::const_iterator i
= d_env
->getStatisticsRegistry()->begin();
521 i
!= d_env
->getStatisticsRegistry()->end();
525 v
.push_back((*i
).first
);
526 v
.push_back((*i
).second
);
531 if (key
== "error-behavior")
533 return SExpr(SExpr::Keyword("immediate-exit"));
537 return SExpr(Configuration::getName());
539 if (key
== "version")
541 return SExpr(Configuration::getVersionString());
543 if (key
== "authors")
545 return SExpr(Configuration::about());
549 // sat | unsat | unknown
550 Result status
= d_state
->getStatus();
551 switch (status
.asSatisfiabilityResult().isSat())
553 case Result::SAT
: return SExpr(SExpr::Keyword("sat"));
554 case Result::UNSAT
: return SExpr(SExpr::Keyword("unsat"));
555 default: return SExpr(SExpr::Keyword("unknown"));
560 return SExpr(std::clock());
562 if (key
== "reason-unknown")
564 Result status
= d_state
->getStatus();
565 if (!status
.isNull() && status
.isUnknown())
567 std::stringstream ss
;
568 ss
<< status
.whyUnknown();
570 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
571 return SExpr(SExpr::Keyword(s
));
575 throw RecoverableModalException(
576 "Can't get-info :reason-unknown when the "
577 "last result wasn't unknown!");
580 if (key
== "assertion-stack-levels")
582 size_t ulevel
= d_state
->getNumUserLevels();
583 AlwaysAssert(ulevel
<= std::numeric_limits
<unsigned long int>::max());
584 return SExpr(static_cast<unsigned long int>(ulevel
));
586 Assert(key
== "all-options");
587 // get the options, like all-statistics
588 std::vector
<std::vector
<std::string
>> current_options
=
589 Options::current()->getOptions();
590 return SExpr::parseListOfListOfAtoms(current_options
);
593 void SmtEngine::debugCheckFormals(const std::vector
<Node
>& formals
, Node func
)
595 for (std::vector
<Node
>::const_iterator i
= formals
.begin();
599 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
601 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
602 << "definition of function " << func
<< ", formal\n"
604 << "has kind " << (*i
).getKind();
605 throw TypeCheckingExceptionPrivate(func
, ss
.str());
610 void SmtEngine::debugCheckFunctionBody(Node formula
,
611 const std::vector
<Node
>& formals
,
614 TypeNode formulaType
= formula
.getType(options::typeChecking());
615 TypeNode funcType
= func
.getType();
616 // We distinguish here between definitions of constants and functions,
617 // because the type checking for them is subtly different. Perhaps we
618 // should instead have SmtEngine::defineFunction() and
619 // SmtEngine::defineConstant() for better clarity, although then that
620 // doesn't match the SMT-LIBv2 standard...
621 if(formals
.size() > 0) {
622 TypeNode rangeType
= funcType
.getRangeType();
623 if(! formulaType
.isComparableTo(rangeType
)) {
625 ss
<< "Type of defined function does not match its declaration\n"
626 << "The function : " << func
<< "\n"
627 << "Declared type : " << rangeType
<< "\n"
628 << "The body : " << formula
<< "\n"
629 << "Body type : " << formulaType
;
630 throw TypeCheckingExceptionPrivate(func
, ss
.str());
633 if(! formulaType
.isComparableTo(funcType
)) {
635 ss
<< "Declared type of defined constant does not match its definition\n"
636 << "The constant : " << func
<< "\n"
637 << "Declared type : " << funcType
<< "\n"
638 << "The definition : " << formula
<< "\n"
639 << "Definition type: " << formulaType
;
640 throw TypeCheckingExceptionPrivate(func
, ss
.str());
645 void SmtEngine::defineFunction(Node func
,
646 const std::vector
<Node
>& formals
,
652 d_state
->doPendingPops();
653 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
654 debugCheckFormals(formals
, func
);
657 ss
<< language::SetLanguage(
658 language::SetLanguage::getLanguage(Dump
.getStream()))
660 std::vector
<Node
> nFormals
;
661 nFormals
.reserve(formals
.size());
663 for (const Node
& formal
: formals
)
665 nFormals
.push_back(formal
);
668 DefineFunctionNodeCommand
nc(ss
.str(), func
, nFormals
, formula
);
669 getDumpManager()->addToDump(nc
, "declarations");
672 debugCheckFunctionBody(formula
, formals
, func
);
674 // Substitute out any abstract values in formula
675 Node formNode
= d_absValues
->substituteAbstractValues(formula
);
676 DefinedFunction
def(func
, formals
, formNode
);
677 // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
678 // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
679 // d_haveAdditions = true;
680 Debug("smt") << "definedFunctions insert " << func
<< " " << formNode
<< endl
;
684 d_definedFunctions
->insertAtContextLevelZero(func
, def
);
688 d_definedFunctions
->insert(func
, def
);
692 void SmtEngine::defineFunctionsRec(
693 const std::vector
<Node
>& funcs
,
694 const std::vector
<std::vector
<Node
>>& formals
,
695 const std::vector
<Node
>& formulas
,
700 d_state
->doPendingPops();
701 Trace("smt") << "SMT defineFunctionsRec(...)" << endl
;
703 if (funcs
.size() != formals
.size() && funcs
.size() != formulas
.size())
706 ss
<< "Number of functions, formals, and function bodies passed to "
707 "defineFunctionsRec do not match:"
709 << " #functions : " << funcs
.size() << "\n"
710 << " #arg lists : " << formals
.size() << "\n"
711 << " #function bodies : " << formulas
.size() << "\n";
712 throw ModalException(ss
.str());
714 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
716 // check formal argument list
717 debugCheckFormals(formals
[i
], funcs
[i
]);
719 debugCheckFunctionBody(formulas
[i
], formals
[i
], funcs
[i
]);
722 if (Dump
.isOn("raw-benchmark"))
724 getPrinter().toStreamCmdDefineFunctionRec(
725 getOutputManager().getDumpOut(), funcs
, formals
, formulas
);
728 NodeManager
* nm
= getNodeManager();
729 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
731 // we assert a quantified formula
733 // make the function application
734 if (formals
[i
].empty())
736 // it has no arguments
741 std::vector
<Node
> children
;
742 children
.push_back(funcs
[i
]);
743 children
.insert(children
.end(), formals
[i
].begin(), formals
[i
].end());
744 func_app
= nm
->mkNode(kind::APPLY_UF
, children
);
746 Node lem
= nm
->mkNode(kind::EQUAL
, func_app
, formulas
[i
]);
747 if (!formals
[i
].empty())
749 // set the attribute to denote this is a function definition
750 Node aexpr
= nm
->mkNode(kind::INST_ATTRIBUTE
, func_app
);
751 aexpr
= nm
->mkNode(kind::INST_PATTERN_LIST
, aexpr
);
753 func_app
.setAttribute(fda
, true);
754 // make the quantified formula
755 Node boundVars
= nm
->mkNode(kind::BOUND_VAR_LIST
, formals
[i
]);
756 lem
= nm
->mkNode(kind::FORALL
, boundVars
, lem
, aexpr
);
758 // assert the quantified formula
759 // notice we don't call assertFormula directly, since this would
760 // duplicate the output on raw-benchmark.
761 // add define recursive definition to the assertions
762 d_asserts
->addDefineFunRecDefinition(lem
, global
);
766 void SmtEngine::defineFunctionRec(Node func
,
767 const std::vector
<Node
>& formals
,
771 std::vector
<Node
> funcs
;
772 funcs
.push_back(func
);
773 std::vector
<std::vector
<Node
>> formals_multi
;
774 formals_multi
.push_back(formals
);
775 std::vector
<Node
> formulas
;
776 formulas
.push_back(formula
);
777 defineFunctionsRec(funcs
, formals_multi
, formulas
, global
);
780 bool SmtEngine::isDefinedFunction(Node func
)
782 Debug("smt") << "isDefined function " << func
<< "?" << std::endl
;
783 return d_definedFunctions
->find(func
) != d_definedFunctions
->end();
786 Result
SmtEngine::quickCheck() {
787 Assert(d_state
->isFullyInited());
788 Trace("smt") << "SMT quickCheck()" << endl
;
789 const std::string
& filename
= d_state
->getFilename();
791 Result::ENTAILMENT_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, filename
);
794 Model
* SmtEngine::getAvailableModel(const char* c
) const
796 if (!options::assignFunctionValues())
798 std::stringstream ss
;
799 ss
<< "Cannot " << c
<< " when --assign-function-values is false.";
800 throw RecoverableModalException(ss
.str().c_str());
803 if (d_state
->getMode() != SmtMode::SAT
804 && d_state
->getMode() != SmtMode::SAT_UNKNOWN
)
806 std::stringstream ss
;
808 << " unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN "
810 throw RecoverableModalException(ss
.str().c_str());
813 if (!options::produceModels())
815 std::stringstream ss
;
816 ss
<< "Cannot " << c
<< " when produce-models options is off.";
817 throw ModalException(ss
.str().c_str());
820 TheoryEngine
* te
= d_smtSolver
->getTheoryEngine();
821 Assert(te
!= nullptr);
822 TheoryModel
* m
= te
->getBuiltModel();
826 std::stringstream ss
;
828 << " since model is not available. Perhaps the most recent call to "
829 "check-sat was interrupted?";
830 throw RecoverableModalException(ss
.str().c_str());
833 return d_model
.get();
836 QuantifiersEngine
* SmtEngine::getAvailableQuantifiersEngine(const char* c
) const
838 QuantifiersEngine
* qe
= d_smtSolver
->getQuantifiersEngine();
841 std::stringstream ss
;
842 ss
<< "Cannot " << c
<< " when quantifiers are not present.";
843 throw ModalException(ss
.str().c_str());
848 void SmtEngine::notifyPushPre() { d_smtSolver
->processAssertions(*d_asserts
); }
850 void SmtEngine::notifyPushPost()
852 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
853 Assert(getPropEngine() != nullptr);
854 getPropEngine()->push();
857 void SmtEngine::notifyPopPre()
859 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
860 PropEngine
* pe
= getPropEngine();
861 Assert(pe
!= nullptr);
865 void SmtEngine::notifyPostSolvePre()
867 PropEngine
* pe
= getPropEngine();
868 Assert(pe
!= nullptr);
872 void SmtEngine::notifyPostSolvePost()
874 TheoryEngine
* te
= getTheoryEngine();
875 Assert(te
!= nullptr);
879 Result
SmtEngine::checkSat()
882 return checkSat(nullNode
);
885 Result
SmtEngine::checkSat(const Node
& assumption
, bool inUnsatCore
)
887 if (Dump
.isOn("benchmark"))
889 getPrinter().toStreamCmdCheckSat(getOutputManager().getDumpOut(),
892 std::vector
<Node
> assump
;
893 if (!assumption
.isNull())
895 assump
.push_back(assumption
);
897 return checkSatInternal(assump
, inUnsatCore
, false);
900 Result
SmtEngine::checkSat(const std::vector
<Node
>& assumptions
,
903 if (Dump
.isOn("benchmark"))
905 if (assumptions
.empty())
907 getPrinter().toStreamCmdCheckSat(getOutputManager().getDumpOut());
911 getPrinter().toStreamCmdCheckSatAssuming(getOutputManager().getDumpOut(),
915 return checkSatInternal(assumptions
, inUnsatCore
, false);
918 Result
SmtEngine::checkEntailed(const Node
& node
, bool inUnsatCore
)
920 if (Dump
.isOn("benchmark"))
922 getPrinter().toStreamCmdQuery(getOutputManager().getDumpOut(), node
);
924 return checkSatInternal(
925 node
.isNull() ? std::vector
<Node
>() : std::vector
<Node
>{node
},
928 .asEntailmentResult();
931 Result
SmtEngine::checkEntailed(const std::vector
<Node
>& nodes
,
934 return checkSatInternal(nodes
, inUnsatCore
, true).asEntailmentResult();
937 Result
SmtEngine::checkSatInternal(const std::vector
<Node
>& assumptions
,
939 bool isEntailmentCheck
)
946 Trace("smt") << "SmtEngine::"
947 << (isEntailmentCheck
? "checkEntailed" : "checkSat") << "("
948 << assumptions
<< ")" << endl
;
949 // check the satisfiability with the solver object
950 Result r
= d_smtSolver
->checkSatisfiability(
951 *d_asserts
.get(), assumptions
, inUnsatCore
, isEntailmentCheck
);
953 Trace("smt") << "SmtEngine::" << (isEntailmentCheck
? "query" : "checkSat")
954 << "(" << assumptions
<< ") => " << r
<< endl
;
956 // Check that SAT results generate a model correctly.
957 if(options::checkModels()) {
958 if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
963 // Check that UNSAT results generate a proof correctly.
964 if (options::checkProofs() || options::proofEagerChecking())
966 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
968 if ((options::checkProofs() || options::proofEagerChecking())
969 && !options::produceProofs())
971 throw ModalException(
972 "Cannot check-proofs because proofs were disabled.");
977 // Check that UNSAT results generate an unsat core correctly.
978 if (options::checkUnsatCores() || options::checkUnsatCoresNew())
980 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
982 TimerStat::CodeTimer
checkUnsatCoreTimer(d_stats
->d_checkUnsatCoreTime
);
989 catch (UnsafeInterruptException
& e
)
991 AlwaysAssert(getResourceManager()->out());
992 // Notice that we do not notify the state of this result. If we wanted to
993 // make the solver resume a working state after an interupt, then we would
994 // implement a different callback and use it here, e.g.
995 // d_state.notifyCheckSatInterupt.
996 Result::UnknownExplanation why
= getResourceManager()->outOfResources()
997 ? Result::RESOURCEOUT
999 return Result(Result::SAT_UNKNOWN
, why
, d_state
->getFilename());
1003 std::vector
<Node
> SmtEngine::getUnsatAssumptions(void)
1005 Trace("smt") << "SMT getUnsatAssumptions()" << endl
;
1006 SmtScope
smts(this);
1007 if (!options::unsatAssumptions())
1009 throw ModalException(
1010 "Cannot get unsat assumptions when produce-unsat-assumptions option "
1013 if (d_state
->getMode() != SmtMode::UNSAT
)
1015 throw RecoverableModalException(
1016 "Cannot get unsat assumptions unless immediately preceded by "
1020 if (Dump
.isOn("benchmark"))
1022 getPrinter().toStreamCmdGetUnsatAssumptions(
1023 getOutputManager().getDumpOut());
1025 UnsatCore core
= getUnsatCoreInternal();
1026 std::vector
<Node
> res
;
1027 std::vector
<Node
>& assumps
= d_asserts
->getAssumptions();
1028 for (const Node
& e
: assumps
)
1030 if (std::find(core
.begin(), core
.end(), e
) != core
.end())
1038 Result
SmtEngine::assertFormula(const Node
& formula
, bool inUnsatCore
)
1040 SmtScope
smts(this);
1042 d_state
->doPendingPops();
1044 Trace("smt") << "SmtEngine::assertFormula(" << formula
<< ")" << endl
;
1046 if (Dump
.isOn("raw-benchmark"))
1048 getPrinter().toStreamCmdAssert(getOutputManager().getDumpOut(), formula
);
1051 // Substitute out any abstract values in ex
1052 Node n
= d_absValues
->substituteAbstractValues(formula
);
1054 d_asserts
->assertFormula(n
, inUnsatCore
);
1055 return quickCheck().asEntailmentResult();
1056 }/* SmtEngine::assertFormula() */
1059 --------------------------------------------------------------------------
1060 Handling SyGuS commands
1061 --------------------------------------------------------------------------
1064 void SmtEngine::declareSygusVar(Node var
)
1066 SmtScope
smts(this);
1067 d_sygusSolver
->declareSygusVar(var
);
1068 if (Dump
.isOn("raw-benchmark"))
1070 getPrinter().toStreamCmdDeclareVar(
1071 getOutputManager().getDumpOut(), var
, var
.getType());
1073 // don't need to set that the conjecture is stale
1076 void SmtEngine::declareSynthFun(Node func
,
1079 const std::vector
<Node
>& vars
)
1081 SmtScope
smts(this);
1082 d_state
->doPendingPops();
1083 d_sygusSolver
->declareSynthFun(func
, sygusType
, isInv
, vars
);
1085 // !!! TEMPORARY: We cannot construct a SynthFunCommand since we cannot
1086 // construct a Term-level Grammar from a Node-level sygus TypeNode. Thus we
1087 // must print the command using the Node-level utility method for now.
1089 if (Dump
.isOn("raw-benchmark"))
1091 getPrinter().toStreamCmdSynthFun(
1092 getOutputManager().getDumpOut(), func
, vars
, isInv
, sygusType
);
1095 void SmtEngine::declareSynthFun(Node func
,
1097 const std::vector
<Node
>& vars
)
1099 // use a null sygus type
1101 declareSynthFun(func
, sygusType
, isInv
, vars
);
1104 void SmtEngine::assertSygusConstraint(Node constraint
)
1106 SmtScope
smts(this);
1108 d_sygusSolver
->assertSygusConstraint(constraint
);
1109 if (Dump
.isOn("raw-benchmark"))
1111 getPrinter().toStreamCmdConstraint(getOutputManager().getDumpOut(),
1116 void SmtEngine::assertSygusInvConstraint(Node inv
,
1121 SmtScope
smts(this);
1123 d_sygusSolver
->assertSygusInvConstraint(inv
, pre
, trans
, post
);
1124 if (Dump
.isOn("raw-benchmark"))
1126 getPrinter().toStreamCmdInvConstraint(
1127 getOutputManager().getDumpOut(), inv
, pre
, trans
, post
);
1131 Result
SmtEngine::checkSynth()
1133 SmtScope
smts(this);
1135 return d_sygusSolver
->checkSynth(*d_asserts
);
1139 --------------------------------------------------------------------------
1140 End of Handling SyGuS commands
1141 --------------------------------------------------------------------------
1144 Node
SmtEngine::simplify(const Node
& ex
)
1146 SmtScope
smts(this);
1148 d_state
->doPendingPops();
1149 // ensure we've processed assertions
1150 d_smtSolver
->processAssertions(*d_asserts
);
1151 return d_pp
->simplify(ex
);
1154 Node
SmtEngine::expandDefinitions(const Node
& ex
, bool expandOnly
)
1156 getResourceManager()->spendResource(
1157 ResourceManager::Resource::PreprocessStep
);
1159 SmtScope
smts(this);
1161 d_state
->doPendingPops();
1162 return d_pp
->expandDefinitions(ex
, expandOnly
);
1165 // TODO(#1108): Simplify the error reporting of this method.
1166 Node
SmtEngine::getValue(const Node
& ex
) const
1168 SmtScope
smts(this);
1170 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
1171 if (Dump
.isOn("benchmark"))
1173 getPrinter().toStreamCmdGetValue(d_outMgr
.getDumpOut(), {ex
});
1175 TypeNode expectedType
= ex
.getType();
1177 // Substitute out any abstract values in ex and expand
1178 Node n
= d_pp
->expandDefinitions(ex
);
1180 Trace("smt") << "--- getting value of " << n
<< endl
;
1181 // There are two ways model values for terms are computed (for historical
1182 // reasons). One way is that used in check-model; the other is that
1183 // used by the Model classes. It's not clear to me exactly how these
1184 // two are different, but they need to be unified. This ugly hack here
1185 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
1188 if(!n
.getType().isFunction()) {
1189 n
= Rewriter::rewrite(n
);
1192 Trace("smt") << "--- getting value of " << n
<< endl
;
1193 Model
* m
= getAvailableModel("get-value");
1194 Assert(m
!= nullptr);
1195 Node resultNode
= m
->getValue(n
);
1196 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
1197 Trace("smt") << "--- type " << resultNode
.getType() << endl
;
1198 Trace("smt") << "--- expected type " << expectedType
<< endl
;
1200 // type-check the result we got
1201 // Notice that lambdas have function type, which does not respect the subtype
1202 // relation, so we ignore them here.
1203 Assert(resultNode
.isNull() || resultNode
.getKind() == kind::LAMBDA
1204 || resultNode
.getType().isSubtypeOf(expectedType
))
1205 << "Run with -t smt for details.";
1207 // Ensure it's a constant, or a lambda (for uninterpreted functions). This
1208 // assertion only holds for models that do not have approximate values.
1209 Assert(m
->hasApproximations() || resultNode
.getKind() == kind::LAMBDA
1210 || resultNode
.isConst());
1212 if(options::abstractValues() && resultNode
.getType().isArray()) {
1213 resultNode
= d_absValues
->mkAbstractValue(resultNode
);
1214 Trace("smt") << "--- abstract value >> " << resultNode
<< endl
;
1220 std::vector
<Node
> SmtEngine::getValues(const std::vector
<Node
>& exprs
)
1222 std::vector
<Node
> result
;
1223 for (const Node
& e
: exprs
)
1225 result
.push_back(getValue(e
));
1230 // TODO(#1108): Simplify the error reporting of this method.
1231 Model
* SmtEngine::getModel() {
1232 Trace("smt") << "SMT getModel()" << endl
;
1233 SmtScope
smts(this);
1237 if (Dump
.isOn("benchmark"))
1239 getPrinter().toStreamCmdGetModel(getOutputManager().getDumpOut());
1242 Model
* m
= getAvailableModel("get model");
1244 // Since model m is being returned to the user, we must ensure that this
1245 // model object remains valid with future check-sat calls. Hence, we set
1246 // the theory engine into "eager model building" mode. TODO #2648: revisit.
1247 TheoryEngine
* te
= getTheoryEngine();
1248 Assert(te
!= nullptr);
1249 te
->setEagerModelBuilding();
1251 if (options::modelCoresMode() != options::ModelCoresMode::NONE
)
1253 // If we enabled model cores, we compute a model core for m based on our
1254 // (expanded) assertions using the model core builder utility
1255 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1256 ModelCoreBuilder::setModelCore(
1257 eassertsProc
, m
->getTheoryModel(), options::modelCoresMode());
1259 // set the information on the SMT-level model
1260 Assert(m
!= nullptr);
1261 m
->d_inputName
= d_state
->getFilename();
1262 m
->d_isKnownSat
= (d_state
->getMode() == SmtMode::SAT
);
1266 Result
SmtEngine::blockModel()
1268 Trace("smt") << "SMT blockModel()" << endl
;
1269 SmtScope
smts(this);
1273 if (Dump
.isOn("benchmark"))
1275 getPrinter().toStreamCmdBlockModel(getOutputManager().getDumpOut());
1278 Model
* m
= getAvailableModel("block model");
1280 if (options::blockModelsMode() == options::BlockModelsMode::NONE
)
1282 std::stringstream ss
;
1283 ss
<< "Cannot block model when block-models is set to none.";
1284 throw RecoverableModalException(ss
.str().c_str());
1287 // get expanded assertions
1288 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1289 Node eblocker
= ModelBlocker::getModelBlocker(
1290 eassertsProc
, m
->getTheoryModel(), options::blockModelsMode());
1291 return assertFormula(eblocker
);
1294 Result
SmtEngine::blockModelValues(const std::vector
<Node
>& exprs
)
1296 Trace("smt") << "SMT blockModelValues()" << endl
;
1297 SmtScope
smts(this);
1301 if (Dump
.isOn("benchmark"))
1303 getPrinter().toStreamCmdBlockModelValues(getOutputManager().getDumpOut(),
1307 Model
* m
= getAvailableModel("block model values");
1309 // get expanded assertions
1310 std::vector
<Node
> eassertsProc
= getExpandedAssertions();
1311 // we always do block model values mode here
1313 ModelBlocker::getModelBlocker(eassertsProc
,
1314 m
->getTheoryModel(),
1315 options::BlockModelsMode::VALUES
,
1317 return assertFormula(eblocker
);
1320 std::pair
<Node
, Node
> SmtEngine::getSepHeapAndNilExpr(void)
1322 if (!getLogicInfo().isTheoryEnabled(THEORY_SEP
))
1325 "Cannot obtain separation logic expressions if not using the "
1326 "separation logic theory.";
1327 throw RecoverableModalException(msg
);
1329 NodeManagerScope
nms(getNodeManager());
1332 Model
* m
= getAvailableModel("get separation logic heap and nil");
1333 TheoryModel
* tm
= m
->getTheoryModel();
1334 if (!tm
->getHeapModel(heap
, nil
))
1337 "Failed to obtain heap/nil "
1338 "expressions from theory model.";
1339 throw RecoverableModalException(msg
);
1341 return std::make_pair(heap
, nil
);
1344 std::vector
<Node
> SmtEngine::getExpandedAssertions()
1346 std::vector
<Node
> easserts
= getAssertions();
1347 // must expand definitions
1348 std::vector
<Node
> eassertsProc
;
1349 std::unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
1350 for (const Node
& e
: easserts
)
1352 Node eae
= d_pp
->expandDefinitions(e
, cache
);
1353 eassertsProc
.push_back(eae
);
1355 return eassertsProc
;
1358 void SmtEngine::declareSepHeap(TypeNode locT
, TypeNode dataT
)
1360 if (!getLogicInfo().isTheoryEnabled(THEORY_SEP
))
1363 "Cannot declare heap if not using the separation logic theory.";
1364 throw RecoverableModalException(msg
);
1366 SmtScope
smts(this);
1368 TheoryEngine
* te
= getTheoryEngine();
1369 te
->declareSepHeap(locT
, dataT
);
1372 bool SmtEngine::getSepHeapTypes(TypeNode
& locT
, TypeNode
& dataT
)
1374 SmtScope
smts(this);
1376 TheoryEngine
* te
= getTheoryEngine();
1377 return te
->getSepHeapTypes(locT
, dataT
);
1380 Node
SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first
; }
1382 Node
SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second
; }
1384 void SmtEngine::checkProof()
1386 Assert(options::produceProofs());
1387 // internal check the proof
1388 PropEngine
* pe
= getPropEngine();
1389 Assert(pe
!= nullptr);
1390 if (options::proofEagerChecking())
1392 pe
->checkProof(d_asserts
->getAssertionList());
1394 Assert(pe
->getProof() != nullptr);
1395 std::shared_ptr
<ProofNode
> pePfn
= pe
->getProof();
1396 if (options::checkProofs())
1398 d_pfManager
->checkProof(pePfn
, *d_asserts
, *d_definedFunctions
);
1402 StatisticsRegistry
* SmtEngine::getStatisticsRegistry()
1404 return d_env
->getStatisticsRegistry();
1407 UnsatCore
SmtEngine::getUnsatCoreInternal()
1410 if (!options::unsatCores())
1412 throw ModalException(
1413 "Cannot get an unsat core when produce-unsat-cores option is off.");
1415 if (d_state
->getMode() != SmtMode::UNSAT
)
1417 throw RecoverableModalException(
1418 "Cannot get an unsat core unless immediately preceded by "
1419 "UNSAT/ENTAILED response.");
1421 // use old proof infrastructure
1424 d_proofManager
->traceUnsatCore(); // just to trigger core creation
1425 return UnsatCore(d_proofManager
->extractUnsatCore());
1427 // generate with new proofs
1428 PropEngine
* pe
= getPropEngine();
1429 Assert(pe
!= nullptr);
1430 Assert(pe
->getProof() != nullptr);
1431 std::shared_ptr
<ProofNode
> pfn
= d_pfManager
->getFinalProof(
1432 pe
->getProof(), *d_asserts
, *d_definedFunctions
);
1433 std::vector
<Node
> core
;
1434 d_ucManager
->getUnsatCore(pfn
, *d_asserts
, core
);
1435 return UnsatCore(core
);
1436 #else /* IS_PROOFS_BUILD */
1437 throw ModalException(
1438 "This build of CVC4 doesn't have proof support (required for unsat "
1440 #endif /* IS_PROOFS_BUILD */
1443 void SmtEngine::checkUnsatCore() {
1444 Assert(options::unsatCores())
1445 << "cannot check unsat core if unsat cores are turned off";
1447 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl
;
1448 UnsatCore core
= getUnsatCore();
1450 // initialize the core checker
1451 std::unique_ptr
<SmtEngine
> coreChecker
;
1452 initializeSubsolver(coreChecker
);
1453 coreChecker
->getOptions().set(options::checkUnsatCores
, false);
1454 // disable all proof options
1455 coreChecker
->getOptions().set(options::produceProofs
, false);
1456 coreChecker
->getOptions().set(options::checkUnsatCoresNew
, false);
1457 // set up separation logic heap if necessary
1458 TypeNode sepLocType
, sepDataType
;
1459 if (getSepHeapTypes(sepLocType
, sepDataType
))
1461 coreChecker
->declareSepHeap(sepLocType
, sepDataType
);
1464 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
1466 for(UnsatCore::iterator i
= core
.begin(); i
!= core
.end(); ++i
) {
1467 Node assertionAfterExpansion
= expandDefinitions(*i
);
1468 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
1469 << ", expanded to " << assertionAfterExpansion
<< "\n";
1470 coreChecker
->assertFormula(assertionAfterExpansion
);
1474 r
= coreChecker
->checkSat();
1478 Notice() << "SmtEngine::checkUnsatCore(): result is " << r
<< endl
;
1479 if(r
.asSatisfiabilityResult().isUnknown()) {
1481 << "SmtEngine::checkUnsatCore(): could not check core result unknown."
1484 else if (r
.asSatisfiabilityResult().isSat())
1487 << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
1491 void SmtEngine::checkModel(bool hardFailure
) {
1492 context::CDList
<Node
>* al
= d_asserts
->getAssertionList();
1493 // --check-model implies --produce-assertions, which enables the
1494 // assertion list, so we should be ok.
1495 Assert(al
!= nullptr)
1496 << "don't have an assertion list to check in SmtEngine::checkModel()";
1498 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
1500 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
1501 Model
* m
= getAvailableModel("check model");
1502 Assert(m
!= nullptr);
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
= d_pfManager
->getFinalProof(
1529 pe
->getProof(), *d_asserts
, *d_definedFunctions
);
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());
1543 if (!options::produceProofs())
1545 throw ModalException("Cannot get a proof when proof option is off.");
1547 if (d_state
->getMode() != SmtMode::UNSAT
)
1549 throw RecoverableModalException(
1550 "Cannot get a proof unless immediately preceded by "
1551 "UNSAT/ENTAILED response.");
1553 // the prop engine has the proof of false
1554 PropEngine
* pe
= getPropEngine();
1555 Assert(pe
!= nullptr);
1556 Assert(pe
->getProof() != nullptr);
1557 Assert(d_pfManager
);
1558 std::ostringstream ss
;
1559 d_pfManager
->printProof(ss
, pe
->getProof(), *d_asserts
, *d_definedFunctions
);
1561 #else /* IS_PROOFS_BUILD */
1562 throw ModalException("This build of CVC4 doesn't have proof support.");
1563 #endif /* IS_PROOFS_BUILD */
1566 void SmtEngine::printInstantiations( std::ostream
& out
) {
1567 SmtScope
smts(this);
1569 if (options::instFormatMode() == options::InstFormatMode::SZS
)
1571 out
<< "% SZS output start Proof for " << d_state
->getFilename()
1574 QuantifiersEngine
* qe
= getAvailableQuantifiersEngine("printInstantiations");
1576 // First, extract and print the skolemizations
1577 bool printed
= false;
1578 bool reqNames
= !options::printInstFull();
1579 // only print when in list mode
1580 if (options::printInstMode() == options::PrintInstMode::LIST
)
1582 std::map
<Node
, std::vector
<Node
>> sks
;
1583 qe
->getSkolemTermVectors(sks
);
1584 for (const std::pair
<const Node
, std::vector
<Node
>>& s
: sks
)
1587 if (!qe
->getNameForQuant(s
.first
, name
, reqNames
))
1589 // did not have a name and we are only printing formulas with names
1592 SkolemList
slist(name
, s
.second
);
1598 // Second, extract and print the instantiations
1599 std::map
<Node
, std::vector
<std::vector
<Node
>>> insts
;
1600 getInstantiationTermVectors(insts
);
1601 for (const std::pair
<const Node
, std::vector
<std::vector
<Node
>>>& i
: insts
)
1603 if (i
.second
.empty())
1605 // no instantiations, skip
1609 if (!qe
->getNameForQuant(i
.first
, name
, reqNames
))
1611 // did not have a name and we are only printing formulas with names
1615 if (options::printInstMode() == options::PrintInstMode::NUM
)
1617 out
<< "(num-instantiations " << name
<< " " << i
.second
.size() << ")"
1622 Assert(options::printInstMode() == options::PrintInstMode::LIST
);
1623 InstantiationList
ilist(name
, i
.second
);
1628 // if we did not print anything, we indicate this
1631 out
<< "No instantiations" << std::endl
;
1633 if (options::instFormatMode() == options::InstFormatMode::SZS
)
1635 out
<< "% SZS output end Proof for " << d_state
->getFilename() << std::endl
;
1639 void SmtEngine::getInstantiationTermVectors(
1640 std::map
<Node
, std::vector
<std::vector
<Node
>>>& insts
)
1642 SmtScope
smts(this);
1644 if (options::produceProofs() && 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(!options::produceAssertions()) {
1752 "Cannot query the current assertion list when not in produce-assertions mode.";
1753 throw ModalException(msg
);
1755 context::CDList
<Node
>* al
= d_asserts
->getAssertionList();
1756 Assert(al
!= nullptr);
1757 std::vector
<Node
> res
;
1758 for (const Node
& n
: *al
)
1760 res
.emplace_back(n
);
1762 // copy the result out
1766 void SmtEngine::push()
1768 SmtScope
smts(this);
1770 d_state
->doPendingPops();
1771 Trace("smt") << "SMT push()" << endl
;
1772 d_smtSolver
->processAssertions(*d_asserts
);
1773 if(Dump
.isOn("benchmark")) {
1774 getPrinter().toStreamCmdPush(getOutputManager().getDumpOut());
1776 d_state
->userPush();
1779 void SmtEngine::pop() {
1780 SmtScope
smts(this);
1782 Trace("smt") << "SMT pop()" << endl
;
1783 if (Dump
.isOn("benchmark"))
1785 getPrinter().toStreamCmdPop(getOutputManager().getDumpOut());
1789 // Clear out assertion queues etc., in case anything is still in there
1790 d_asserts
->clearCurrent();
1791 // clear the learned literals from the preprocessor
1792 d_pp
->clearLearnedLiterals();
1794 Trace("userpushpop") << "SmtEngine: popped to level "
1795 << getUserContext()->getLevel() << endl
;
1796 // should we reset d_status here?
1797 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
1800 void SmtEngine::reset()
1802 // save pointer to the current node manager
1803 NodeManager
* nm
= getNodeManager();
1804 Trace("smt") << "SMT reset()" << endl
;
1805 if (Dump
.isOn("benchmark"))
1807 getPrinter().toStreamCmdReset(getOutputManager().getDumpOut());
1809 std::string filename
= d_state
->getFilename();
1811 opts
.copyValues(d_originalOptions
);
1813 new (this) SmtEngine(nm
, &opts
);
1814 // Restore data set after creation
1815 notifyStartParsing(filename
);
1818 void SmtEngine::resetAssertions()
1820 SmtScope
smts(this);
1822 if (!d_state
->isFullyInited())
1824 // We're still in Start Mode, nothing asserted yet, do nothing.
1825 // (see solver execution modes in the SMT-LIB standard)
1826 Assert(getContext()->getLevel() == 0);
1827 Assert(getUserContext()->getLevel() == 0);
1828 getDumpManager()->resetAssertions();
1833 Trace("smt") << "SMT resetAssertions()" << endl
;
1834 if (Dump
.isOn("benchmark"))
1836 getPrinter().toStreamCmdResetAssertions(getOutputManager().getDumpOut());
1839 d_asserts
->clearCurrent();
1840 d_state
->notifyResetAssertions();
1841 getDumpManager()->resetAssertions();
1842 // push the state to maintain global context around everything
1845 // reset SmtSolver, which will construct a new prop engine
1846 d_smtSolver
->resetAssertions();
1849 void SmtEngine::interrupt()
1851 if (!d_state
->isFullyInited())
1855 d_smtSolver
->interrupt();
1858 void SmtEngine::setResourceLimit(unsigned long units
, bool cumulative
)
1860 getResourceManager()->setResourceLimit(units
, cumulative
);
1862 void SmtEngine::setTimeLimit(unsigned long milis
)
1864 getResourceManager()->setTimeLimit(milis
);
1867 unsigned long SmtEngine::getResourceUsage() const
1869 return getResourceManager()->getResourceUsage();
1872 unsigned long SmtEngine::getTimeUsage() const
1874 return getResourceManager()->getTimeUsage();
1877 unsigned long SmtEngine::getResourceRemaining() const
1879 return getResourceManager()->getResourceRemaining();
1882 NodeManager
* SmtEngine::getNodeManager() const
1884 return d_env
->getNodeManager();
1887 Statistics
SmtEngine::getStatistics() const
1889 return Statistics(*d_env
->getStatisticsRegistry());
1892 SExpr
SmtEngine::getStatistic(std::string name
) const
1894 return d_env
->getStatisticsRegistry()->getStatistic(name
);
1897 void SmtEngine::flushStatistics(std::ostream
& out
) const
1899 getNodeManager()->getStatisticsRegistry()->flushInformation(out
);
1900 d_env
->getStatisticsRegistry()->flushInformation(out
);
1903 void SmtEngine::safeFlushStatistics(int fd
) const
1905 getNodeManager()->getStatisticsRegistry()->safeFlushInformation(fd
);
1906 d_env
->getStatisticsRegistry()->safeFlushInformation(fd
);
1909 void SmtEngine::setUserAttribute(const std::string
& attr
,
1911 const std::vector
<Node
>& expr_values
,
1912 const std::string
& str_value
)
1914 SmtScope
smts(this);
1916 TheoryEngine
* te
= getTheoryEngine();
1917 Assert(te
!= nullptr);
1918 te
->setUserAttribute(attr
, expr
, expr_values
, str_value
);
1921 void SmtEngine::setOption(const std::string
& key
, const std::string
& value
)
1923 NodeManagerScope
nms(getNodeManager());
1924 Trace("smt") << "SMT setOption(" << key
<< ", " << value
<< ")" << endl
;
1926 if (Dump
.isOn("benchmark"))
1928 getPrinter().toStreamCmdSetOption(
1929 getOutputManager().getDumpOut(), key
, value
);
1932 if (key
== "command-verbosity")
1934 size_t fstIndex
= value
.find(" ");
1935 size_t sndIndex
= value
.find(" ", fstIndex
+ 1);
1936 if (sndIndex
== std::string::npos
)
1938 string c
= value
.substr(1, fstIndex
- 1);
1940 std::stoi(value
.substr(fstIndex
+ 1, value
.length() - fstIndex
- 1));
1943 throw OptionException("command-verbosity must be 0, 1, or 2");
1945 d_commandVerbosity
[c
] = v
;
1948 throw OptionException(
1949 "command-verbosity value must be a tuple (command-name integer)");
1952 if (value
.find(" ") != std::string::npos
)
1954 throw OptionException("bad value for :" + key
);
1957 std::string optionarg
= value
;
1958 getOptions().setOption(key
, optionarg
);
1961 void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver
= true; }
1963 bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver
; }
1965 Node
SmtEngine::getOption(const std::string
& key
) const
1967 NodeManagerScope
nms(getNodeManager());
1968 NodeManager
* nm
= d_env
->getNodeManager();
1970 Trace("smt") << "SMT getOption(" << key
<< ")" << endl
;
1972 if (key
.length() >= 18 && key
.compare(0, 18, "command-verbosity:") == 0)
1974 map
<string
, Integer
>::const_iterator i
=
1975 d_commandVerbosity
.find(key
.c_str() + 18);
1976 if (i
!= d_commandVerbosity
.end())
1978 return nm
->mkConst(Rational(i
->second
));
1980 i
= d_commandVerbosity
.find("*");
1981 if (i
!= d_commandVerbosity
.end())
1983 return nm
->mkConst(Rational(i
->second
));
1985 return nm
->mkConst(Rational(2));
1988 if (Dump
.isOn("benchmark"))
1990 getPrinter().toStreamCmdGetOption(d_outMgr
.getDumpOut(), key
);
1993 if (key
== "command-verbosity")
1995 vector
<Node
> result
;
1996 Node defaultVerbosity
;
1997 for (map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.begin();
1998 i
!= d_commandVerbosity
.end();
2001 // treat the command name as a variable name as opposed to a string
2002 // constant to avoid printing double quotes around the name
2003 Node name
= nm
->mkBoundVar(i
->first
, nm
->integerType());
2004 Node value
= nm
->mkConst(Rational(i
->second
));
2005 if ((*i
).first
== "*")
2007 // put the default at the end of the SExpr
2008 defaultVerbosity
= nm
->mkNode(Kind::SEXPR
, name
, value
);
2012 result
.push_back(nm
->mkNode(Kind::SEXPR
, name
, value
));
2015 // ensure the default is always listed
2016 if (defaultVerbosity
.isNull())
2018 defaultVerbosity
= nm
->mkNode(Kind::SEXPR
,
2019 nm
->mkBoundVar("*", nm
->integerType()),
2020 nm
->mkConst(Rational(2)));
2022 result
.push_back(defaultVerbosity
);
2023 return nm
->mkNode(Kind::SEXPR
, result
);
2026 // parse atom string
2027 std::string atom
= getOptions().getOption(key
);
2031 return nm
->mkConst
<bool>(true);
2033 else if (atom
== "false")
2035 return nm
->mkConst
<bool>(false);
2040 return nm
->mkConst(Rational(z
));
2042 catch (std::invalid_argument
&)
2044 // Fall through to the next case
2046 return nm
->mkConst(String(atom
));
2049 Options
& SmtEngine::getOptions() { return d_env
->d_options
; }
2051 const Options
& SmtEngine::getOptions() const { return d_env
->getOptions(); }
2053 ResourceManager
* SmtEngine::getResourceManager() const
2055 return d_env
->getResourceManager();
2058 DumpManager
* SmtEngine::getDumpManager() { return d_env
->getDumpManager(); }
2060 const Printer
& SmtEngine::getPrinter() const { return d_env
->getPrinter(); }
2062 OutputManager
& SmtEngine::getOutputManager() { return d_outMgr
; }
2064 theory::Rewriter
* SmtEngine::getRewriter() { return d_env
->getRewriter(); }
2066 }/* CVC4 namespace */