1 /********************* */
2 /*! \file smt_engine.cpp
4 ** Top contributors (to current version):
5 ** Morgan Deters, Andrew Reynolds, Tim King
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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"
27 #include <unordered_map>
28 #include <unordered_set>
32 #include "base/check.h"
33 #include "base/configuration.h"
34 #include "base/configuration_private.h"
35 #include "base/exception.h"
36 #include "base/listener.h"
37 #include "base/modal_exception.h"
38 #include "base/output.h"
39 #include "context/cdhashmap.h"
40 #include "context/cdhashset.h"
41 #include "context/cdlist.h"
42 #include "context/context.h"
43 #include "decision/decision_engine.h"
44 #include "expr/attribute.h"
45 #include "expr/expr.h"
46 #include "expr/kind.h"
47 #include "expr/metakind.h"
48 #include "expr/node.h"
49 #include "expr/node_algorithm.h"
50 #include "expr/node_builder.h"
51 #include "expr/node_self_iterator.h"
52 #include "expr/node_visitor.h"
53 #include "options/arith_options.h"
54 #include "options/arrays_options.h"
55 #include "options/base_options.h"
56 #include "options/booleans_options.h"
57 #include "options/bv_options.h"
58 #include "options/datatypes_options.h"
59 #include "options/decision_options.h"
60 #include "options/language.h"
61 #include "options/main_options.h"
62 #include "options/open_ostream.h"
63 #include "options/option_exception.h"
64 #include "options/printer_options.h"
65 #include "options/proof_options.h"
66 #include "options/prop_options.h"
67 #include "options/quantifiers_options.h"
68 #include "options/sep_options.h"
69 #include "options/set_language.h"
70 #include "options/smt_options.h"
71 #include "options/strings_options.h"
72 #include "options/theory_options.h"
73 #include "options/uf_options.h"
74 #include "preprocessing/preprocessing_pass.h"
75 #include "preprocessing/preprocessing_pass_context.h"
76 #include "preprocessing/preprocessing_pass_registry.h"
77 #include "printer/printer.h"
78 #include "proof/proof.h"
79 #include "proof/proof_manager.h"
80 #include "proof/theory_proof.h"
81 #include "proof/unsat_core.h"
82 #include "prop/prop_engine.h"
83 #include "smt/command.h"
84 #include "smt/command_list.h"
85 #include "smt/defined_function.h"
86 #include "smt/logic_request.h"
87 #include "smt/managed_ostreams.h"
88 #include "smt/model_blocker.h"
89 #include "smt/model_core_builder.h"
90 #include "smt/process_assertions.h"
91 #include "smt/set_defaults.h"
92 #include "smt/smt_engine_scope.h"
93 #include "smt/smt_engine_stats.h"
94 #include "smt/term_formula_removal.h"
95 #include "smt/update_ostream.h"
96 #include "smt_util/boolean_simplification.h"
97 #include "smt_util/nary_builder.h"
98 #include "theory/booleans/circuit_propagator.h"
99 #include "theory/bv/theory_bv_rewriter.h"
100 #include "theory/logic_info.h"
101 #include "theory/quantifiers/fun_def_process.h"
102 #include "theory/quantifiers/single_inv_partition.h"
103 #include "theory/quantifiers/sygus/sygus_abduct.h"
104 #include "theory/quantifiers/sygus/synth_engine.h"
105 #include "theory/quantifiers/term_util.h"
106 #include "theory/quantifiers_engine.h"
107 #include "theory/rewriter.h"
108 #include "theory/sort_inference.h"
109 #include "theory/strings/theory_strings.h"
110 #include "theory/substitutions.h"
111 #include "theory/theory_engine.h"
112 #include "theory/theory_model.h"
113 #include "theory/theory_traits.h"
114 #include "util/hash.h"
115 #include "util/proof.h"
116 #include "util/random.h"
117 #include "util/resource_manager.h"
119 #if (IS_LFSC_BUILD && IS_PROOFS_BUILD)
124 using namespace CVC4
;
125 using namespace CVC4::smt
;
126 using namespace CVC4::preprocessing
;
127 using namespace CVC4::prop
;
128 using namespace CVC4::context
;
129 using namespace CVC4::theory
;
134 extern const char* const plf_signatures
;
139 struct DeleteCommandFunction
: public std::unary_function
<const Command
*, void>
141 void operator()(const Command
* command
) { delete command
; }
144 void DeleteAndClearCommandVector(std::vector
<Command
*>& commands
) {
145 std::for_each(commands
.begin(), commands
.end(), DeleteCommandFunction());
149 class SoftResourceOutListener
: public Listener
{
151 SoftResourceOutListener(SmtEngine
& smt
) : d_smt(&smt
) {}
152 void notify() override
154 SmtScope
scope(d_smt
);
155 Assert(smt::smtEngineInScope());
160 }; /* class SoftResourceOutListener */
163 class HardResourceOutListener
: public Listener
{
165 HardResourceOutListener(SmtEngine
& smt
) : d_smt(&smt
) {}
166 void notify() override
168 SmtScope
scope(d_smt
);
169 theory::Rewriter::clearCaches();
173 }; /* class HardResourceOutListener */
175 class BeforeSearchListener
: public Listener
{
177 BeforeSearchListener(SmtEngine
& smt
) : d_smt(&smt
) {}
178 void notify() override
{ d_smt
->beforeSearch(); }
182 }; /* class BeforeSearchListener */
184 class SetDefaultExprDepthListener
: public Listener
{
186 void notify() override
188 int depth
= options::defaultExprDepth();
189 Debug
.getStream() << expr::ExprSetDepth(depth
);
190 Trace
.getStream() << expr::ExprSetDepth(depth
);
191 Notice
.getStream() << expr::ExprSetDepth(depth
);
192 Chat
.getStream() << expr::ExprSetDepth(depth
);
193 Message
.getStream() << expr::ExprSetDepth(depth
);
194 Warning
.getStream() << expr::ExprSetDepth(depth
);
195 // intentionally exclude Dump stream from this list
199 class SetDefaultExprDagListener
: public Listener
{
201 void notify() override
203 int dag
= options::defaultDagThresh();
204 Debug
.getStream() << expr::ExprDag(dag
);
205 Trace
.getStream() << expr::ExprDag(dag
);
206 Notice
.getStream() << expr::ExprDag(dag
);
207 Chat
.getStream() << expr::ExprDag(dag
);
208 Message
.getStream() << expr::ExprDag(dag
);
209 Warning
.getStream() << expr::ExprDag(dag
);
210 Dump
.getStream() << expr::ExprDag(dag
);
214 class SetPrintExprTypesListener
: public Listener
{
216 void notify() override
218 bool value
= options::printExprTypes();
219 Debug
.getStream() << expr::ExprPrintTypes(value
);
220 Trace
.getStream() << expr::ExprPrintTypes(value
);
221 Notice
.getStream() << expr::ExprPrintTypes(value
);
222 Chat
.getStream() << expr::ExprPrintTypes(value
);
223 Message
.getStream() << expr::ExprPrintTypes(value
);
224 Warning
.getStream() << expr::ExprPrintTypes(value
);
225 // intentionally exclude Dump stream from this list
229 class DumpModeListener
: public Listener
{
231 void notify() override
233 const std::string
& value
= options::dumpModeString();
234 Dump
.setDumpFromString(value
);
238 class PrintSuccessListener
: public Listener
{
240 void notify() override
242 bool value
= options::printSuccess();
243 Debug
.getStream() << Command::printsuccess(value
);
244 Trace
.getStream() << Command::printsuccess(value
);
245 Notice
.getStream() << Command::printsuccess(value
);
246 Chat
.getStream() << Command::printsuccess(value
);
247 Message
.getStream() << Command::printsuccess(value
);
248 Warning
.getStream() << Command::printsuccess(value
);
249 *options::out() << Command::printsuccess(value
);
256 * This is an inelegant solution, but for the present, it will work.
257 * The point of this is to separate the public and private portions of
258 * the SmtEngine class, so that smt_engine.h doesn't
259 * include "expr/node.h", which is a private CVC4 header (and can lead
260 * to linking errors due to the improper inlining of non-visible symbols
263 * The "real" solution (that which is usually implemented) is to move
264 * ALL the implementation to SmtEnginePrivate and maintain a
265 * heap-allocated instance of it in SmtEngine. SmtEngine (the public
266 * one) becomes an "interface shell" which simply acts as a forwarder
269 class SmtEnginePrivate
: public NodeManagerListener
{
272 typedef unordered_map
<Node
, Node
, NodeHashFunction
> NodeToNodeHashMap
;
273 typedef unordered_map
<Node
, bool, NodeHashFunction
> NodeToBoolHashMap
;
276 * Manager for limiting time and abstract resource usage.
278 ResourceManager
* d_resourceManager
;
280 /** Manager for the memory of regular-output-channel. */
281 ManagedRegularOutputChannel d_managedRegularChannel
;
283 /** Manager for the memory of diagnostic-output-channel. */
284 ManagedDiagnosticOutputChannel d_managedDiagnosticChannel
;
286 /** Manager for the memory of --dump-to. */
287 ManagedDumpOStream d_managedDumpChannel
;
290 * This list contains:
293 * beforeSearchListener
295 * This needs to be deleted before both NodeManager's Options,
296 * SmtEngine, d_resourceManager, and TheoryEngine.
298 ListenerRegistrationList
* d_listenerRegistrations
;
300 /** A circuit propagator for non-clausal propositional deduction */
301 booleans::CircuitPropagator d_propagator
;
303 /** Assertions in the preprocessing pipeline */
304 AssertionPipeline d_assertions
;
306 /** Whether any assertions have been processed */
307 CDO
<bool> d_assertionsProcessed
;
313 * A context that never pushes/pops, for use by CD structures (like
314 * SubstitutionMaps) that should be "global".
316 context::Context d_fakeContext
;
319 * A map of AbsractValues to their actual constants. Only used if
320 * options::abstractValues() is on.
322 SubstitutionMap d_abstractValueMap
;
325 * A mapping of all abstract values (actual value |-> abstract) that
326 * we've handed out. This is necessary to ensure that we give the
327 * same AbstractValues for the same real constants. Only used if
328 * options::abstractValues() is on.
330 NodeToNodeHashMap d_abstractValues
;
332 /** TODO: whether certain preprocess steps are necessary */
333 //bool d_needsExpandDefs;
335 /** The preprocessing pass context */
336 std::unique_ptr
<PreprocessingPassContext
> d_preprocessingPassContext
;
338 /** Process assertions module */
339 ProcessAssertions d_processor
;
341 //------------------------------- expression names
342 /** mapping from expressions to name */
343 context::CDHashMap
< Node
, std::string
, NodeHashFunction
> d_exprNames
;
344 //------------------------------- end expression names
346 IteSkolemMap
& getIteSkolemMap() { return d_assertions
.getIteSkolemMap(); }
348 /** Instance of the ITE remover */
349 RemoveTermFormulas d_iteRemover
;
351 /* Finishes the initialization of the private portion of SMTEngine. */
354 /*------------------- sygus utils ------------------*/
356 * sygus variables declared (from "declare-var" and "declare-fun" commands)
358 * The SyGuS semantics for declared variables is that they are implicitly
359 * universally quantified in the constraints.
361 std::vector
<Node
> d_sygusVars
;
362 /** sygus constraints */
363 std::vector
<Node
> d_sygusConstraints
;
364 /** functions-to-synthesize */
365 std::vector
<Node
> d_sygusFunSymbols
;
367 * Whether we need to reconstruct the sygus conjecture.
369 CDO
<bool> d_sygusConjectureStale
;
370 /*------------------- end of sygus utils ------------------*/
373 SmtEnginePrivate(SmtEngine
& smt
)
375 d_resourceManager(NodeManager::currentResourceManager()),
376 d_managedRegularChannel(),
377 d_managedDiagnosticChannel(),
378 d_managedDumpChannel(),
379 d_listenerRegistrations(new ListenerRegistrationList()),
380 d_propagator(true, true),
382 d_assertionsProcessed(smt
.getUserContext(), false),
384 d_abstractValueMap(&d_fakeContext
),
386 d_processor(smt
, *d_resourceManager
),
387 // d_needsExpandDefs(true), //TODO?
388 d_exprNames(smt
.getUserContext()),
389 d_iteRemover(smt
.getUserContext()),
390 d_sygusConjectureStale(smt
.getUserContext(), true)
392 d_smt
.d_nodeManager
->subscribeEvents(this);
393 d_true
= NodeManager::currentNM()->mkConst(true);
395 d_listenerRegistrations
->add(d_resourceManager
->registerSoftListener(
396 new SoftResourceOutListener(d_smt
)));
398 d_listenerRegistrations
->add(d_resourceManager
->registerHardListener(
399 new HardResourceOutListener(d_smt
)));
403 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
405 // Multiple options reuse BeforeSearchListener so registration requires an
406 // extra bit of care.
407 // We can safely not call notify on this before search listener at
408 // registration time. This d_smt cannot be beforeSearch at construction
409 // time. Therefore the BeforeSearchListener is a no-op. Therefore it does
410 // not have to be called.
411 d_listenerRegistrations
->add(
412 nodeManagerOptions
.registerBeforeSearchListener(
413 new BeforeSearchListener(d_smt
)));
415 // These do need registration calls.
416 d_listenerRegistrations
->add(
417 nodeManagerOptions
.registerSetDefaultExprDepthListener(
418 new SetDefaultExprDepthListener(), true));
419 d_listenerRegistrations
->add(
420 nodeManagerOptions
.registerSetDefaultExprDagListener(
421 new SetDefaultExprDagListener(), true));
422 d_listenerRegistrations
->add(
423 nodeManagerOptions
.registerSetPrintExprTypesListener(
424 new SetPrintExprTypesListener(), true));
425 d_listenerRegistrations
->add(
426 nodeManagerOptions
.registerSetDumpModeListener(new DumpModeListener(),
428 d_listenerRegistrations
->add(
429 nodeManagerOptions
.registerSetPrintSuccessListener(
430 new PrintSuccessListener(), true));
431 d_listenerRegistrations
->add(
432 nodeManagerOptions
.registerSetRegularOutputChannelListener(
433 new SetToDefaultSourceListener(&d_managedRegularChannel
), true));
434 d_listenerRegistrations
->add(
435 nodeManagerOptions
.registerSetDiagnosticOutputChannelListener(
436 new SetToDefaultSourceListener(&d_managedDiagnosticChannel
),
438 d_listenerRegistrations
->add(
439 nodeManagerOptions
.registerDumpToFileNameListener(
440 new SetToDefaultSourceListener(&d_managedDumpChannel
), true));
442 catch (OptionException
& e
)
444 // Registering the option listeners can lead to OptionExceptions, e.g.
445 // when the user chooses a dump tag that does not exist. In that case, we
446 // have to make sure that we delete existing listener registrations and
447 // that we unsubscribe from NodeManager events. Otherwise we will have
448 // errors in the deconstructors of the NodeManager (because the
449 // NodeManager tries to notify an SmtEnginePrivate that does not exist)
450 // and the ListenerCollection (because not all registrations have been
451 // removed before calling the deconstructor).
452 delete d_listenerRegistrations
;
453 d_smt
.d_nodeManager
->unsubscribeEvents(this);
454 throw OptionException(e
.getRawMessage());
460 delete d_listenerRegistrations
;
462 if(d_propagator
.getNeedsFinish()) {
463 d_propagator
.finish();
464 d_propagator
.setNeedsFinish(false);
466 d_smt
.d_nodeManager
->unsubscribeEvents(this);
469 ResourceManager
* getResourceManager() { return d_resourceManager
; }
471 void spendResource(ResourceManager::Resource r
)
473 d_resourceManager
->spendResource(r
);
476 ProcessAssertions
* getProcessAssertions() { return &d_processor
; }
478 void nmNotifyNewSort(TypeNode tn
, uint32_t flags
) override
480 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
483 if((flags
& ExprManager::SORT_FLAG_PLACEHOLDER
) == 0) {
484 d_smt
.addToModelCommandAndDump(c
, flags
);
488 void nmNotifyNewSortConstructor(TypeNode tn
, uint32_t flags
) override
490 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
491 tn
.getAttribute(expr::SortArityAttr()),
493 if ((flags
& ExprManager::SORT_FLAG_PLACEHOLDER
) == 0)
495 d_smt
.addToModelCommandAndDump(c
);
499 void nmNotifyNewDatatypes(const std::vector
<DatatypeType
>& dtts
,
500 uint32_t flags
) override
502 if ((flags
& ExprManager::DATATYPE_FLAG_PLACEHOLDER
) == 0)
504 std::vector
<Type
> types(dtts
.begin(), dtts
.end());
505 DatatypeDeclarationCommand
c(types
);
506 d_smt
.addToModelCommandAndDump(c
);
510 void nmNotifyNewVar(TNode n
, uint32_t flags
) override
512 DeclareFunctionCommand
c(n
.getAttribute(expr::VarNameAttr()),
514 n
.getType().toType());
515 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
516 d_smt
.addToModelCommandAndDump(c
, flags
);
520 void nmNotifyNewSkolem(TNode n
,
521 const std::string
& comment
,
522 uint32_t flags
) override
524 string id
= n
.getAttribute(expr::VarNameAttr());
525 DeclareFunctionCommand
c(id
, n
.toExpr(), n
.getType().toType());
526 if(Dump
.isOn("skolems") && comment
!= "") {
527 Dump("skolems") << CommentCommand(id
+ " is " + comment
);
529 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
530 d_smt
.addToModelCommandAndDump(c
, flags
, false, "skolems");
534 void nmNotifyDeleteNode(TNode n
) override
{}
536 Node
applySubstitutions(TNode node
)
538 return Rewriter::rewrite(
539 d_preprocessingPassContext
->getTopLevelSubstitutions().apply(node
));
543 * Process the assertions that have been asserted.
545 void processAssertions();
547 /** Process a user push.
554 * Process a user pop. Clears out the non-context-dependent stuff in this
555 * SmtEnginePrivate. Necessary to clear out our assertion vectors in case
556 * someone does a push-assert-pop without a check-sat. It also pops the
557 * last map of expression names from notifyPush.
560 d_assertions
.clear();
561 d_propagator
.getLearnedLiterals().clear();
562 getIteSkolemMap().clear();
566 * Adds a formula to the current context. Action here depends on
567 * the SimplificationMode (in the current Options scope); the
568 * formula might be pushed out to the propositional layer
569 * immediately, or it might be simplified and kept, or it might not
570 * even be simplified.
571 * The arguments isInput and isAssumption are used for bookkeeping for proofs.
572 * The argument maybeHasFv should be set to true if the assertion may have
573 * free variables. By construction, assertions from the smt2 parser are
574 * guaranteed not to have free variables. However, other cases such as
575 * assertions from the SyGuS parser may have free variables (say if the
576 * input contains an assert or define-fun-rec command).
578 * @param isAssumption If true, the formula is considered to be an assumption
579 * (this is used to distinguish assertions and assumptions)
581 void addFormula(TNode n
,
584 bool isAssumption
= false,
585 bool maybeHasFv
= false);
587 * Simplify node "in" by expanding definitions and applying any
588 * substitutions learned from preprocessing.
590 Node
simplify(TNode in
) {
591 // Substitute out any abstract values in ex.
592 // Expand definitions.
593 NodeToNodeHashMap cache
;
594 Node n
= d_processor
.expandDefinitions(in
, cache
).toExpr();
595 // Make sure we've done all preprocessing, etc.
596 Assert(d_assertions
.size() == 0);
597 return applySubstitutions(n
).toExpr();
601 * Substitute away all AbstractValues in a node.
603 Node
substituteAbstractValues(TNode n
) {
604 // We need to do this even if options::abstractValues() is off,
605 // since the setting might have changed after we already gave out
606 // some abstract values.
607 return d_abstractValueMap
.apply(n
);
611 * Make a new (or return an existing) abstract value for a node.
612 * Can only use this if options::abstractValues() is on.
614 Node
mkAbstractValue(TNode n
) {
615 Assert(options::abstractValues());
616 Node
& val
= d_abstractValues
[n
];
618 val
= d_smt
.d_nodeManager
->mkAbstractValue(n
.getType());
619 d_abstractValueMap
.addSubstitution(val
, n
);
621 // We are supposed to ascribe types to all abstract values that go out.
622 NodeManager
* current
= d_smt
.d_nodeManager
;
623 Node ascription
= current
->mkConst(AscriptionType(n
.getType().toType()));
624 Node retval
= current
->mkNode(kind::APPLY_TYPE_ASCRIPTION
, ascription
, val
);
628 //------------------------------- expression names
629 // implements setExpressionName, as described in smt_engine.h
630 void setExpressionName(Expr e
, std::string name
) {
631 d_exprNames
[Node::fromExpr(e
)] = name
;
634 // implements getExpressionName, as described in smt_engine.h
635 bool getExpressionName(Expr e
, std::string
& name
) const {
636 context::CDHashMap
< Node
, std::string
, NodeHashFunction
>::const_iterator it
= d_exprNames
.find(e
);
637 if(it
!=d_exprNames
.end()) {
644 //------------------------------- end expression names
645 };/* class SmtEnginePrivate */
647 }/* namespace CVC4::smt */
649 SmtEngine::SmtEngine(ExprManager
* em
)
650 : d_context(new Context()),
651 d_userContext(new UserContext()),
654 d_nodeManager(d_exprManager
->getNodeManager()),
655 d_theoryEngine(nullptr),
656 d_propEngine(nullptr),
657 d_proofManager(nullptr),
658 d_rewriter(new theory::Rewriter()),
659 d_definedFunctions(nullptr),
660 d_assertionList(nullptr),
661 d_assignments(nullptr),
662 d_modelGlobalCommands(),
663 d_modelCommands(nullptr),
668 d_isInternalSubsolver(false),
670 d_fullyInited(false),
672 d_needPostsolve(false),
673 d_globalNegation(false),
676 d_smtMode(SMT_MODE_START
),
678 d_statisticsRegistry(nullptr),
682 d_originalOptions
.copyValues(em
->getOptions());
683 d_private
.reset(new smt::SmtEnginePrivate(*this));
684 d_statisticsRegistry
.reset(new StatisticsRegistry());
685 d_stats
.reset(new SmtEngineStatistics());
686 d_stats
->d_resourceUnitsUsed
.setData(
687 d_private
->getResourceManager()->getResourceUsage());
689 // The ProofManager is constructed before any other proof objects such as
690 // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
691 // initialized in TheoryEngine and PropEngine respectively.
692 Assert(d_proofManager
== nullptr);
694 // d_proofManager must be created before Options has been finished
695 // being parsed from the input file. Because of this, we cannot trust
696 // that options::proof() is set correctly yet.
698 d_proofManager
.reset(new ProofManager(getUserContext()));
701 d_definedFunctions
= new (true) DefinedFunctionMap(getUserContext());
702 d_modelCommands
= new (true) smt::CommandList(getUserContext());
705 void SmtEngine::finishInit()
707 // set the random seed
708 Random::getRandom().setSeed(options::seed());
710 // ensure that our heuristics are properly set up
711 setDefaults(*this, d_logic
);
713 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl
;
714 // We have mutual dependency here, so we add the prop engine to the theory
715 // engine later (it is non-essential there)
716 d_theoryEngine
.reset(new TheoryEngine(getContext(),
718 d_private
->d_iteRemover
,
719 const_cast<const LogicInfo
&>(d_logic
)));
722 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
723 TheoryConstructor::addTheory(getTheoryEngine(), id
);
724 //register with proof engine if applicable
726 ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine
->theoryOf(id
));
730 Trace("smt-debug") << "Making decision engine..." << std::endl
;
732 Trace("smt-debug") << "Making prop engine..." << std::endl
;
733 /* force destruction of referenced PropEngine to enforce that statistics
734 * are unregistered by the obsolete PropEngine object before registered
735 * again by the new PropEngine object */
736 d_propEngine
.reset(nullptr);
737 d_propEngine
.reset(new PropEngine(getTheoryEngine(),
740 d_private
->getResourceManager()));
742 Trace("smt-debug") << "Setting up theory engine..." << std::endl
;
743 d_theoryEngine
->setPropEngine(getPropEngine());
744 Trace("smt-debug") << "Finishing init for theory engine..." << std::endl
;
745 d_theoryEngine
->finishInit();
747 // global push/pop around everything, to ensure proper destruction
748 // of context-dependent data structures
749 d_userContext
->push();
752 Trace("smt-debug") << "Set up assertion list..." << std::endl
;
753 // [MGD 10/20/2011] keep around in incremental mode, due to a
754 // cleanup ordering issue and Nodes/TNodes. If SAT is popped
755 // first, some user-context-dependent TNodes might still exist
757 if(options::produceAssertions() ||
758 options::incrementalSolving()) {
759 // In the case of incremental solving, we appear to need these to
760 // ensure the relevant Nodes remain live.
761 d_assertionList
= new (true) AssertionList(getUserContext());
764 // dump out a set-logic command only when raw-benchmark is disabled to avoid
765 // dumping the command twice.
766 if (Dump
.isOn("benchmark") && !Dump
.isOn("raw-benchmark"))
768 LogicInfo everything
;
770 Dump("benchmark") << CommentCommand(
771 "CVC4 always dumps the most general, all-supported logic (below), as "
772 "some internals might require the use of a logic more general than "
774 << SetBenchmarkLogicCommand(
775 everything
.getLogicString());
778 Trace("smt-debug") << "Dump declaration commands..." << std::endl
;
779 // dump out any pending declaration commands
780 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
781 Dump("declarations") << *d_dumpCommands
[i
];
782 delete d_dumpCommands
[i
];
784 d_dumpCommands
.clear();
786 PROOF( ProofManager::currentPM()->setLogic(d_logic
); );
788 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
789 ProofManager::currentPM()->getTheoryProofEngine()->
790 finishRegisterTheory(d_theoryEngine
->theoryOf(id
));
793 d_private
->finishInit();
794 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl
;
797 void SmtEngine::finalOptionsAreSet() {
802 if(! d_logic
.isLocked()) {
806 // finish initialization, create the prop engine, etc.
809 AlwaysAssert(d_propEngine
->getAssertionLevel() == 0)
810 << "The PropEngine has pushed but the SmtEngine "
811 "hasn't finished initializing!";
813 d_fullyInited
= true;
814 Assert(d_logic
.isLocked());
817 void SmtEngine::shutdown() {
820 while(options::incrementalSolving() && d_userContext
->getLevel() > 1) {
824 if (d_propEngine
!= nullptr)
826 d_propEngine
->shutdown();
828 if (d_theoryEngine
!= nullptr)
830 d_theoryEngine
->shutdown();
834 SmtEngine::~SmtEngine()
841 // global push/pop around everything, to ensure proper destruction
842 // of context-dependent data structures
844 d_userContext
->popto(0);
846 if(d_assignments
!= NULL
) {
847 d_assignments
->deleteSelf();
850 if(d_assertionList
!= NULL
) {
851 d_assertionList
->deleteSelf();
854 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
855 delete d_dumpCommands
[i
];
856 d_dumpCommands
[i
] = NULL
;
858 d_dumpCommands
.clear();
860 DeleteAndClearCommandVector(d_modelGlobalCommands
);
862 if(d_modelCommands
!= NULL
) {
863 d_modelCommands
->deleteSelf();
866 d_definedFunctions
->deleteSelf();
868 //destroy all passes before destroying things that they refer to
869 d_private
->getProcessAssertions()->cleanup();
871 // d_proofManager is always created when proofs are enabled at configure
872 // time. Because of this, this code should not be wrapped in PROOF() which
873 // additionally checks flags such as options::proof().
875 // Note: the proof manager must be destroyed before the theory engine.
876 // Because the destruction of the proofs depends on contexts owned be the
879 d_proofManager
.reset(nullptr);
882 d_theoryEngine
.reset(nullptr);
883 d_propEngine
.reset(nullptr);
885 d_stats
.reset(nullptr);
886 d_statisticsRegistry
.reset(nullptr);
888 d_private
.reset(nullptr);
890 d_userContext
.reset(nullptr);
891 d_context
.reset(nullptr);
892 } catch(Exception
& e
) {
893 Warning() << "CVC4 threw an exception during cleanup." << endl
898 void SmtEngine::setLogic(const LogicInfo
& logic
)
902 throw ModalException("Cannot set logic in SmtEngine after the engine has "
903 "finished initializing.");
909 void SmtEngine::setLogic(const std::string
& s
)
914 setLogic(LogicInfo(s
));
915 // dump out a set-logic command
916 if (Dump
.isOn("raw-benchmark"))
918 Dump("raw-benchmark")
919 << SetBenchmarkLogicCommand(d_logic
.getLogicString());
922 catch (IllegalArgumentException
& e
)
924 throw LogicException(e
.what());
928 void SmtEngine::setLogic(const char* logic
) { setLogic(string(logic
)); }
929 LogicInfo
SmtEngine::getLogicInfo() const {
932 void SmtEngine::setFilename(std::string filename
) { d_filename
= filename
; }
933 std::string
SmtEngine::getFilename() const { return d_filename
; }
934 void SmtEngine::setLogicInternal()
936 Assert(!d_fullyInited
)
937 << "setting logic in SmtEngine but the engine has already"
938 " finished initializing for this run";
942 void SmtEngine::setProblemExtended()
944 d_smtMode
= SMT_MODE_ASSERT
;
945 d_assumptions
.clear();
948 void SmtEngine::setInfo(const std::string
& key
, const CVC4::SExpr
& value
)
952 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
954 if(Dump
.isOn("benchmark")) {
955 if(key
== "status") {
956 string s
= value
.getValue();
957 BenchmarkStatus status
=
958 (s
== "sat") ? SMT_SATISFIABLE
:
959 ((s
== "unsat") ? SMT_UNSATISFIABLE
: SMT_UNKNOWN
);
960 Dump("benchmark") << SetBenchmarkStatusCommand(status
);
962 Dump("benchmark") << SetInfoCommand(key
, value
);
966 // Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
967 if (key
== "source" || key
== "category" || key
== "difficulty"
968 || key
== "notes" || key
== "name" || key
== "license")
973 else if (key
== "filename")
975 d_filename
= value
.getValue();
978 else if (key
== "smt-lib-version" && !options::inputLanguage
.wasSetByUser())
980 language::input::Language ilang
= language::input::LANG_AUTO
;
981 if( (value
.isInteger() && value
.getIntegerValue() == Integer(2)) ||
982 (value
.isRational() && value
.getRationalValue() == Rational(2)) ||
983 value
.getValue() == "2" ||
984 value
.getValue() == "2.0" ) {
985 ilang
= language::input::LANG_SMTLIB_V2_0
;
986 } else if( (value
.isRational() && value
.getRationalValue() == Rational(5, 2)) ||
987 value
.getValue() == "2.5" ) {
988 ilang
= language::input::LANG_SMTLIB_V2_5
;
989 } else if( (value
.isRational() && value
.getRationalValue() == Rational(13, 5)) ||
990 value
.getValue() == "2.6" ) {
991 ilang
= language::input::LANG_SMTLIB_V2_6
;
995 Warning() << "Warning: unsupported smt-lib-version: " << value
<< endl
;
996 throw UnrecognizedOptionException();
998 options::inputLanguage
.set(ilang
);
999 // also update the output language
1000 if (!options::outputLanguage
.wasSetByUser())
1002 language::output::Language olang
= language::toOutputLanguage(ilang
);
1003 if (options::outputLanguage() != olang
)
1005 options::outputLanguage
.set(olang
);
1006 *options::out() << language::SetLanguage(olang
);
1010 } else if(key
== "status") {
1012 if(value
.isAtom()) {
1013 s
= value
.getValue();
1015 if(s
!= "sat" && s
!= "unsat" && s
!= "unknown") {
1016 throw OptionException("argument to (set-info :status ..) must be "
1017 "`sat' or `unsat' or `unknown'");
1019 d_expectedStatus
= Result(s
, d_filename
);
1022 throw UnrecognizedOptionException();
1025 bool SmtEngine::isValidGetInfoFlag(const std::string
& key
) const
1027 if (key
== "all-statistics" || key
== "error-behavior" || key
== "name"
1028 || key
== "version" || key
== "authors" || key
== "status"
1029 || key
== "reason-unknown" || key
== "assertion-stack-levels"
1030 || key
== "all-options")
1037 CVC4::SExpr
SmtEngine::getInfo(const std::string
& key
) const
1039 SmtScope
smts(this);
1041 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
1042 if (!isValidGetInfoFlag(key
))
1044 throw UnrecognizedOptionException();
1046 if (key
== "all-statistics")
1048 vector
<SExpr
> stats
;
1049 for (StatisticsRegistry::const_iterator i
=
1050 NodeManager::fromExprManager(d_exprManager
)
1051 ->getStatisticsRegistry()
1054 != NodeManager::fromExprManager(d_exprManager
)
1055 ->getStatisticsRegistry()
1060 v
.push_back((*i
).first
);
1061 v
.push_back((*i
).second
);
1064 for (StatisticsRegistry::const_iterator i
= d_statisticsRegistry
->begin();
1065 i
!= d_statisticsRegistry
->end();
1069 v
.push_back((*i
).first
);
1070 v
.push_back((*i
).second
);
1073 return SExpr(stats
);
1075 if (key
== "error-behavior")
1077 return SExpr(SExpr::Keyword("immediate-exit"));
1081 return SExpr(Configuration::getName());
1083 if (key
== "version")
1085 return SExpr(Configuration::getVersionString());
1087 if (key
== "authors")
1089 return SExpr(Configuration::about());
1091 if (key
== "status")
1093 // sat | unsat | unknown
1094 switch (d_status
.asSatisfiabilityResult().isSat())
1096 case Result::SAT
: return SExpr(SExpr::Keyword("sat"));
1097 case Result::UNSAT
: return SExpr(SExpr::Keyword("unsat"));
1098 default: return SExpr(SExpr::Keyword("unknown"));
1101 if (key
== "reason-unknown")
1103 if (!d_status
.isNull() && d_status
.isUnknown())
1106 ss
<< d_status
.whyUnknown();
1107 string s
= ss
.str();
1108 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
1109 return SExpr(SExpr::Keyword(s
));
1113 throw RecoverableModalException(
1114 "Can't get-info :reason-unknown when the "
1115 "last result wasn't unknown!");
1118 if (key
== "assertion-stack-levels")
1120 AlwaysAssert(d_userLevels
.size()
1121 <= std::numeric_limits
<unsigned long int>::max());
1122 return SExpr(static_cast<unsigned long int>(d_userLevels
.size()));
1124 Assert(key
== "all-options");
1125 // get the options, like all-statistics
1126 std::vector
<std::vector
<std::string
>> current_options
=
1127 Options::current()->getOptions();
1128 return SExpr::parseListOfListOfAtoms(current_options
);
1131 void SmtEngine::debugCheckFormals(const std::vector
<Expr
>& formals
, Expr func
)
1133 for(std::vector
<Expr
>::const_iterator i
= formals
.begin(); i
!= formals
.end(); ++i
) {
1134 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
1136 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
1137 << "definition of function " << func
<< ", formal\n"
1138 << " " << *i
<< "\n"
1139 << "has kind " << (*i
).getKind();
1140 throw TypeCheckingException(func
, ss
.str());
1145 void SmtEngine::debugCheckFunctionBody(Expr formula
,
1146 const std::vector
<Expr
>& formals
,
1149 Type formulaType
= formula
.getType(options::typeChecking());
1150 Type funcType
= func
.getType();
1151 // We distinguish here between definitions of constants and functions,
1152 // because the type checking for them is subtly different. Perhaps we
1153 // should instead have SmtEngine::defineFunction() and
1154 // SmtEngine::defineConstant() for better clarity, although then that
1155 // doesn't match the SMT-LIBv2 standard...
1156 if(formals
.size() > 0) {
1157 Type rangeType
= FunctionType(funcType
).getRangeType();
1158 if(! formulaType
.isComparableTo(rangeType
)) {
1160 ss
<< "Type of defined function does not match its declaration\n"
1161 << "The function : " << func
<< "\n"
1162 << "Declared type : " << rangeType
<< "\n"
1163 << "The body : " << formula
<< "\n"
1164 << "Body type : " << formulaType
;
1165 throw TypeCheckingException(func
, ss
.str());
1168 if(! formulaType
.isComparableTo(funcType
)) {
1170 ss
<< "Declared type of defined constant does not match its definition\n"
1171 << "The constant : " << func
<< "\n"
1172 << "Declared type : " << funcType
<< " " << Type::getTypeNode(funcType
)->getId() << "\n"
1173 << "The definition : " << formula
<< "\n"
1174 << "Definition type: " << formulaType
<< " " << Type::getTypeNode(formulaType
)->getId();
1175 throw TypeCheckingException(func
, ss
.str());
1180 void SmtEngine::defineFunction(Expr func
,
1181 const std::vector
<Expr
>& formals
,
1184 SmtScope
smts(this);
1185 finalOptionsAreSet();
1187 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
1188 debugCheckFormals(formals
, func
);
1191 ss
<< language::SetLanguage(
1192 language::SetLanguage::getLanguage(Dump
.getStream()))
1194 DefineFunctionCommand
c(ss
.str(), func
, formals
, formula
);
1195 addToModelCommandAndDump(
1196 c
, ExprManager::VAR_FLAG_DEFINED
, true, "declarations");
1198 PROOF(if (options::checkUnsatCores()) {
1199 d_defineCommands
.push_back(c
.clone());
1203 debugCheckFunctionBody(formula
, formals
, func
);
1205 // Substitute out any abstract values in formula
1207 d_private
->substituteAbstractValues(Node::fromExpr(formula
)).toExpr();
1209 TNode funcNode
= func
.getTNode();
1210 vector
<Node
> formalsNodes
;
1211 for(vector
<Expr
>::const_iterator i
= formals
.begin(),
1212 iend
= formals
.end();
1215 formalsNodes
.push_back((*i
).getNode());
1217 TNode formNode
= form
.getTNode();
1218 DefinedFunction
def(funcNode
, formalsNodes
, formNode
);
1219 // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
1220 // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
1221 // d_haveAdditions = true;
1222 Debug("smt") << "definedFunctions insert " << funcNode
<< " " << formNode
<< endl
;
1223 d_definedFunctions
->insert(funcNode
, def
);
1226 void SmtEngine::defineFunctionsRec(
1227 const std::vector
<Expr
>& funcs
,
1228 const std::vector
<std::vector
<Expr
> >& formals
,
1229 const std::vector
<Expr
>& formulas
)
1231 SmtScope
smts(this);
1232 finalOptionsAreSet();
1234 Trace("smt") << "SMT defineFunctionsRec(...)" << endl
;
1236 if (funcs
.size() != formals
.size() && funcs
.size() != formulas
.size())
1239 ss
<< "Number of functions, formals, and function bodies passed to "
1240 "defineFunctionsRec do not match:"
1242 << " #functions : " << funcs
.size() << "\n"
1243 << " #arg lists : " << formals
.size() << "\n"
1244 << " #function bodies : " << formulas
.size() << "\n";
1245 throw ModalException(ss
.str());
1247 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
1249 // check formal argument list
1250 debugCheckFormals(formals
[i
], funcs
[i
]);
1252 debugCheckFunctionBody(formulas
[i
], formals
[i
], funcs
[i
]);
1255 if (Dump
.isOn("raw-benchmark"))
1257 Dump("raw-benchmark") << DefineFunctionRecCommand(funcs
, formals
, formulas
);
1260 ExprManager
* em
= getExprManager();
1261 bool maybeHasFv
= language::isInputLangSygus(options::inputLanguage());
1262 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
1264 // we assert a quantified formula
1266 // make the function application
1267 if (formals
[i
].empty())
1269 // it has no arguments
1270 func_app
= funcs
[i
];
1274 std::vector
<Expr
> children
;
1275 children
.push_back(funcs
[i
]);
1276 children
.insert(children
.end(), formals
[i
].begin(), formals
[i
].end());
1277 func_app
= em
->mkExpr(kind::APPLY_UF
, children
);
1279 Expr lem
= em
->mkExpr(kind::EQUAL
, func_app
, formulas
[i
]);
1280 if (!formals
[i
].empty())
1282 // set the attribute to denote this is a function definition
1283 std::string
attr_name("fun-def");
1284 Expr aexpr
= em
->mkExpr(kind::INST_ATTRIBUTE
, func_app
);
1285 aexpr
= em
->mkExpr(kind::INST_PATTERN_LIST
, aexpr
);
1286 std::vector
<Expr
> expr_values
;
1287 std::string str_value
;
1288 setUserAttribute(attr_name
, func_app
, expr_values
, str_value
);
1289 // make the quantified formula
1290 Expr boundVars
= em
->mkExpr(kind::BOUND_VAR_LIST
, formals
[i
]);
1291 lem
= em
->mkExpr(kind::FORALL
, boundVars
, lem
, aexpr
);
1293 // assert the quantified formula
1294 // notice we don't call assertFormula directly, since this would
1295 // duplicate the output on raw-benchmark.
1296 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(lem
)).toExpr();
1297 if (d_assertionList
!= NULL
)
1299 d_assertionList
->push_back(e
);
1301 d_private
->addFormula(e
.getNode(), false, true, false, maybeHasFv
);
1305 void SmtEngine::defineFunctionRec(Expr func
,
1306 const std::vector
<Expr
>& formals
,
1309 std::vector
<Expr
> funcs
;
1310 funcs
.push_back(func
);
1311 std::vector
<std::vector
<Expr
> > formals_multi
;
1312 formals_multi
.push_back(formals
);
1313 std::vector
<Expr
> formulas
;
1314 formulas
.push_back(formula
);
1315 defineFunctionsRec(funcs
, formals_multi
, formulas
);
1318 bool SmtEngine::isDefinedFunction( Expr func
){
1319 Node nf
= Node::fromExpr( func
);
1320 Debug("smt") << "isDefined function " << nf
<< "?" << std::endl
;
1321 return d_definedFunctions
->find(nf
) != d_definedFunctions
->end();
1324 void SmtEnginePrivate::finishInit()
1326 d_preprocessingPassContext
.reset(new PreprocessingPassContext(
1327 &d_smt
, d_resourceManager
, &d_iteRemover
, &d_propagator
));
1329 // initialize the preprocessing passes
1330 d_processor
.finishInit(d_preprocessingPassContext
.get());
1333 Result
SmtEngine::check() {
1334 Assert(d_fullyInited
);
1335 Assert(d_pendingPops
== 0);
1337 Trace("smt") << "SmtEngine::check()" << endl
;
1339 ResourceManager
* resourceManager
= d_private
->getResourceManager();
1341 resourceManager
->beginCall();
1343 // Only way we can be out of resource is if cumulative budget is on
1344 if (resourceManager
->cumulativeLimitOn() &&
1345 resourceManager
->out()) {
1346 Result::UnknownExplanation why
= resourceManager
->outOfResources() ?
1347 Result::RESOURCEOUT
: Result::TIMEOUT
;
1348 return Result(Result::ENTAILMENT_UNKNOWN
, why
, d_filename
);
1351 // Make sure the prop layer has all of the assertions
1352 Trace("smt") << "SmtEngine::check(): processing assertions" << endl
;
1353 d_private
->processAssertions();
1354 Trace("smt") << "SmtEngine::check(): done processing assertions" << endl
;
1356 TimerStat::CodeTimer
solveTimer(d_stats
->d_solveTime
);
1358 Chat() << "solving..." << endl
;
1359 Trace("smt") << "SmtEngine::check(): running check" << endl
;
1360 Result result
= d_propEngine
->checkSat();
1362 resourceManager
->endCall();
1363 Trace("limit") << "SmtEngine::check(): cumulative millis " << resourceManager
->getTimeUsage()
1364 << ", resources " << resourceManager
->getResourceUsage() << endl
;
1367 return Result(result
, d_filename
);
1370 Result
SmtEngine::quickCheck() {
1371 Assert(d_fullyInited
);
1372 Trace("smt") << "SMT quickCheck()" << endl
;
1374 Result::ENTAILMENT_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, d_filename
);
1377 theory::TheoryModel
* SmtEngine::getAvailableModel(const char* c
) const
1379 if (!options::assignFunctionValues())
1381 std::stringstream ss
;
1382 ss
<< "Cannot " << c
<< " when --assign-function-values is false.";
1383 throw RecoverableModalException(ss
.str().c_str());
1386 if (d_smtMode
!= SMT_MODE_SAT
&& d_smtMode
!= SMT_MODE_SAT_UNKNOWN
)
1388 std::stringstream ss
;
1389 ss
<< "Cannot " << c
1390 << " unless immediately preceded by SAT/NOT_ENTAILED or UNKNOWN "
1392 throw RecoverableModalException(ss
.str().c_str());
1395 if (!options::produceModels())
1397 std::stringstream ss
;
1398 ss
<< "Cannot " << c
<< " when produce-models options is off.";
1399 throw ModalException(ss
.str().c_str());
1402 TheoryModel
* m
= d_theoryEngine
->getBuiltModel();
1406 std::stringstream ss
;
1407 ss
<< "Cannot " << c
1408 << " since model is not available. Perhaps the most recent call to "
1409 "check-sat was interupted?";
1410 throw RecoverableModalException(ss
.str().c_str());
1416 void SmtEnginePrivate::processAssertions() {
1417 TimerStat::CodeTimer
paTimer(d_smt
.d_stats
->d_processAssertionsTime
);
1418 spendResource(ResourceManager::Resource::PreprocessStep
);
1419 Assert(d_smt
.d_fullyInited
);
1420 Assert(d_smt
.d_pendingPops
== 0);
1422 if (d_assertions
.size() == 0) {
1426 if (d_assertionsProcessed
&& options::incrementalSolving()) {
1427 // TODO(b/1255): Substitutions in incremental mode should be managed with a
1428 // proper data structure.
1430 d_assertions
.enableStoreSubstsInAsserts();
1434 d_assertions
.disableStoreSubstsInAsserts();
1437 // process the assertions
1438 bool noConflict
= d_processor
.apply(d_assertions
);
1440 //notify theory engine new preprocessed assertions
1441 d_smt
.d_theoryEngine
->notifyPreprocessedAssertions( d_assertions
.ref() );
1443 // Push the formula to decision engine
1446 Chat() << "pushing to decision engine..." << endl
;
1447 d_smt
.d_propEngine
->addAssertionsToDecisionEngine(d_assertions
);
1450 // end: INVARIANT to maintain: no reordering of assertions or
1451 // introducing new ones
1453 // if incremental, compute which variables are assigned
1454 if (options::incrementalSolving())
1456 d_preprocessingPassContext
->recordSymbolsInAssertions(d_assertions
.ref());
1459 // Push the formula to SAT
1461 Chat() << "converting to CNF..." << endl
;
1462 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_cnfConversionTime
);
1463 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
1464 Chat() << "+ " << d_assertions
[i
] << std::endl
;
1465 d_smt
.d_propEngine
->assertFormula(d_assertions
[i
]);
1469 d_assertionsProcessed
= true;
1471 d_assertions
.clear();
1472 getIteSkolemMap().clear();
1475 void SmtEnginePrivate::addFormula(
1476 TNode n
, bool inUnsatCore
, bool inInput
, bool isAssumption
, bool maybeHasFv
)
1483 Trace("smt") << "SmtEnginePrivate::addFormula(" << n
1484 << "), inUnsatCore = " << inUnsatCore
1485 << ", inInput = " << inInput
1486 << ", isAssumption = " << isAssumption
<< endl
;
1488 // Ensure that it does not contain free variables
1491 if (expr::hasFreeVar(n
))
1493 std::stringstream se
;
1494 se
<< "Cannot process assertion with free variable.";
1495 if (language::isInputLangSygus(options::inputLanguage()))
1497 // Common misuse of SyGuS is to use top-level assert instead of
1498 // constraint when defining the synthesis conjecture.
1499 se
<< " Perhaps you meant `constraint` instead of `assert`?";
1501 throw ModalException(se
.str().c_str());
1505 // Give it to proof manager
1508 // n is an input assertion
1509 if (inUnsatCore
|| options::unsatCores() || options::dumpUnsatCores() || options::checkUnsatCores() || options::fewerPreprocessingHoles()) {
1511 ProofManager::currentPM()->addCoreAssertion(n
.toExpr());
1514 // n is the result of an unknown preprocessing step, add it to dependency map to null
1515 ProofManager::currentPM()->addDependence(n
, Node::null());
1519 // Add the normalized formula to the queue
1520 d_assertions
.push_back(n
, isAssumption
);
1521 //d_assertions.push_back(Rewriter::rewrite(n));
1524 void SmtEngine::ensureBoolean(const Expr
& e
)
1526 Type type
= e
.getType(options::typeChecking());
1527 Type boolType
= d_exprManager
->booleanType();
1528 if(type
!= boolType
) {
1530 ss
<< "Expected " << boolType
<< "\n"
1531 << "The assertion : " << e
<< "\n"
1532 << "Its type : " << type
;
1533 throw TypeCheckingException(e
, ss
.str());
1537 Result
SmtEngine::checkSat(const Expr
& assumption
, bool inUnsatCore
)
1539 Dump("benchmark") << CheckSatCommand(assumption
);
1540 return checkSatisfiability(assumption
, inUnsatCore
, false);
1543 Result
SmtEngine::checkSat(const vector
<Expr
>& assumptions
, bool inUnsatCore
)
1545 if (assumptions
.empty())
1547 Dump("benchmark") << CheckSatCommand();
1551 Dump("benchmark") << CheckSatAssumingCommand(assumptions
);
1554 return checkSatisfiability(assumptions
, inUnsatCore
, false);
1557 Result
SmtEngine::checkEntailed(const Expr
& expr
, bool inUnsatCore
)
1559 Dump("benchmark") << QueryCommand(expr
, inUnsatCore
);
1560 return checkSatisfiability(
1561 expr
.isNull() ? std::vector
<Expr
>() : std::vector
<Expr
>{expr
},
1564 .asEntailmentResult();
1567 Result
SmtEngine::checkEntailed(const vector
<Expr
>& exprs
, bool inUnsatCore
)
1569 return checkSatisfiability(exprs
, inUnsatCore
, true).asEntailmentResult();
1572 Result
SmtEngine::checkSatisfiability(const Expr
& expr
,
1574 bool isEntailmentCheck
)
1576 return checkSatisfiability(
1577 expr
.isNull() ? std::vector
<Expr
>() : std::vector
<Expr
>{expr
},
1582 Result
SmtEngine::checkSatisfiability(const vector
<Expr
>& assumptions
,
1584 bool isEntailmentCheck
)
1588 SmtScope
smts(this);
1589 finalOptionsAreSet();
1592 Trace("smt") << "SmtEngine::"
1593 << (isEntailmentCheck
? "checkEntailed" : "checkSat") << "("
1594 << assumptions
<< ")" << endl
;
1596 if(d_queryMade
&& !options::incrementalSolving()) {
1597 throw ModalException("Cannot make multiple queries unless "
1598 "incremental solving is enabled "
1599 "(try --incremental)");
1602 // Note that a query has been made
1604 // reset global negation
1605 d_globalNegation
= false;
1607 bool didInternalPush
= false;
1609 setProblemExtended();
1611 if (isEntailmentCheck
)
1613 size_t size
= assumptions
.size();
1616 /* Assume: not (BIGAND assumptions) */
1617 d_assumptions
.push_back(
1618 d_exprManager
->mkExpr(kind::AND
, assumptions
).notExpr());
1622 /* Assume: not expr */
1623 d_assumptions
.push_back(assumptions
[0].notExpr());
1628 /* Assume: BIGAND assumptions */
1629 d_assumptions
= assumptions
;
1632 if (!d_assumptions
.empty())
1635 didInternalPush
= true;
1638 Result
r(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
1639 for (Expr e
: d_assumptions
)
1641 // Substitute out any abstract values in ex.
1642 e
= d_private
->substituteAbstractValues(Node::fromExpr(e
)).toExpr();
1643 Assert(e
.getExprManager() == d_exprManager
);
1644 // Ensure expr is type-checked at this point.
1647 /* Add assumption */
1648 if (d_assertionList
!= NULL
)
1650 d_assertionList
->push_back(e
);
1652 d_private
->addFormula(e
.getNode(), inUnsatCore
, true, true);
1657 if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
1658 && r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
1660 r
= Result(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
1662 // flipped if we did a global negation
1663 if (d_globalNegation
)
1665 Trace("smt") << "SmtEngine::process global negate " << r
<< std::endl
;
1666 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
1668 r
= Result(Result::SAT
);
1670 else if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
1672 // only if satisfaction complete
1673 if (d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
))
1675 r
= Result(Result::UNSAT
);
1679 r
= Result(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
1682 Trace("smt") << "SmtEngine::global negate returned " << r
<< std::endl
;
1685 d_needPostsolve
= true;
1688 if (didInternalPush
)
1693 // Remember the status
1695 // Check against expected status
1696 if (!d_expectedStatus
.isUnknown() && !d_status
.isUnknown()
1697 && d_status
!= d_expectedStatus
)
1699 CVC4_FATAL() << "Expected result " << d_expectedStatus
<< " but got "
1702 d_expectedStatus
= Result();
1703 // Update the SMT mode
1704 if (d_status
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
1706 d_smtMode
= SMT_MODE_UNSAT
;
1708 else if (d_status
.asSatisfiabilityResult().isSat() == Result::SAT
)
1710 d_smtMode
= SMT_MODE_SAT
;
1714 d_smtMode
= SMT_MODE_SAT_UNKNOWN
;
1717 Trace("smt") << "SmtEngine::" << (isEntailmentCheck
? "query" : "checkSat")
1718 << "(" << assumptions
<< ") => " << r
<< endl
;
1720 // Check that SAT results generate a model correctly.
1721 if(options::checkModels()) {
1722 if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
1727 // Check that UNSAT results generate a proof correctly.
1728 if(options::checkProofs()) {
1729 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
1733 // Check that UNSAT results generate an unsat core correctly.
1734 if(options::checkUnsatCores()) {
1735 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
1736 TimerStat::CodeTimer
checkUnsatCoreTimer(d_stats
->d_checkUnsatCoreTime
);
1742 } catch (UnsafeInterruptException
& e
) {
1743 AlwaysAssert(d_private
->getResourceManager()->out());
1744 Result::UnknownExplanation why
= d_private
->getResourceManager()->outOfResources() ?
1745 Result::RESOURCEOUT
: Result::TIMEOUT
;
1746 return Result(Result::SAT_UNKNOWN
, why
, d_filename
);
1750 vector
<Expr
> SmtEngine::getUnsatAssumptions(void)
1752 Trace("smt") << "SMT getUnsatAssumptions()" << endl
;
1753 SmtScope
smts(this);
1754 if (!options::unsatAssumptions())
1756 throw ModalException(
1757 "Cannot get unsat assumptions when produce-unsat-assumptions option "
1760 if (d_smtMode
!= SMT_MODE_UNSAT
)
1762 throw RecoverableModalException(
1763 "Cannot get unsat assumptions unless immediately preceded by "
1766 finalOptionsAreSet();
1767 if (Dump
.isOn("benchmark"))
1769 Dump("benchmark") << GetUnsatAssumptionsCommand();
1771 UnsatCore core
= getUnsatCoreInternal();
1773 for (const Expr
& e
: d_assumptions
)
1775 if (find(core
.begin(), core
.end(), e
) != core
.end()) { res
.push_back(e
); }
1780 Result
SmtEngine::assertFormula(const Expr
& ex
, bool inUnsatCore
)
1782 Assert(ex
.getExprManager() == d_exprManager
);
1783 SmtScope
smts(this);
1784 finalOptionsAreSet();
1787 Trace("smt") << "SmtEngine::assertFormula(" << ex
<< ")" << endl
;
1789 if (Dump
.isOn("raw-benchmark")) {
1790 Dump("raw-benchmark") << AssertCommand(ex
);
1793 // Substitute out any abstract values in ex
1794 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
1797 if(d_assertionList
!= NULL
) {
1798 d_assertionList
->push_back(e
);
1800 bool maybeHasFv
= language::isInputLangSygus(options::inputLanguage());
1801 d_private
->addFormula(e
.getNode(), inUnsatCore
, true, false, maybeHasFv
);
1802 return quickCheck().asEntailmentResult();
1803 }/* SmtEngine::assertFormula() */
1806 --------------------------------------------------------------------------
1807 Handling SyGuS commands
1808 --------------------------------------------------------------------------
1811 void SmtEngine::declareSygusVar(const std::string
& id
, Expr var
, Type type
)
1813 SmtScope
smts(this);
1814 finalOptionsAreSet();
1815 d_private
->d_sygusVars
.push_back(Node::fromExpr(var
));
1816 Trace("smt") << "SmtEngine::declareSygusVar: " << var
<< "\n";
1817 Dump("raw-benchmark") << DeclareSygusVarCommand(id
, var
, type
);
1818 // don't need to set that the conjecture is stale
1821 void SmtEngine::declareSygusPrimedVar(const std::string
& id
, Type type
)
1823 SmtScope
smts(this);
1824 finalOptionsAreSet();
1825 // do nothing (the command is spurious)
1826 Trace("smt") << "SmtEngine::declareSygusPrimedVar: " << id
<< "\n";
1827 // don't need to set that the conjecture is stale
1830 void SmtEngine::declareSygusFunctionVar(const std::string
& id
,
1834 SmtScope
smts(this);
1835 finalOptionsAreSet();
1836 d_private
->d_sygusVars
.push_back(Node::fromExpr(var
));
1837 Trace("smt") << "SmtEngine::declareSygusFunctionVar: " << var
<< "\n";
1838 Dump("raw-benchmark") << DeclareSygusVarCommand(id
, var
, type
);
1840 // don't need to set that the conjecture is stale
1843 void SmtEngine::declareSynthFun(const std::string
& id
,
1847 const std::vector
<Expr
>& vars
)
1849 SmtScope
smts(this);
1850 finalOptionsAreSet();
1852 Node fn
= Node::fromExpr(func
);
1853 d_private
->d_sygusFunSymbols
.push_back(fn
);
1856 Expr bvl
= d_exprManager
->mkExpr(kind::BOUND_VAR_LIST
, vars
);
1857 std::vector
<Expr
> attr_val_bvl
;
1858 attr_val_bvl
.push_back(bvl
);
1859 setUserAttribute("sygus-synth-fun-var-list", func
, attr_val_bvl
, "");
1861 // whether sygus type encodes syntax restrictions
1862 if (sygusType
.isDatatype()
1863 && static_cast<DatatypeType
>(sygusType
).getDatatype().isSygus())
1865 TypeNode stn
= TypeNode::fromType(sygusType
);
1866 Node sym
= d_nodeManager
->mkBoundVar("sfproxy", stn
);
1867 std::vector
<Expr
> attr_value
;
1868 attr_value
.push_back(sym
.toExpr());
1869 setUserAttribute("sygus-synth-grammar", func
, attr_value
, "");
1871 Trace("smt") << "SmtEngine::declareSynthFun: " << func
<< "\n";
1872 Dump("raw-benchmark") << SynthFunCommand(id
, func
, sygusType
, isInv
, vars
);
1873 // sygus conjecture is now stale
1874 setSygusConjectureStale();
1877 void SmtEngine::assertSygusConstraint(Expr constraint
)
1879 SmtScope
smts(this);
1880 finalOptionsAreSet();
1881 d_private
->d_sygusConstraints
.push_back(constraint
);
1883 Trace("smt") << "SmtEngine::assertSygusConstrant: " << constraint
<< "\n";
1884 Dump("raw-benchmark") << SygusConstraintCommand(constraint
);
1885 // sygus conjecture is now stale
1886 setSygusConjectureStale();
1889 void SmtEngine::assertSygusInvConstraint(const Expr
& inv
,
1894 SmtScope
smts(this);
1895 finalOptionsAreSet();
1896 // build invariant constraint
1898 // get variables (regular and their respective primed versions)
1899 std::vector
<Node
> terms
, vars
, primed_vars
;
1900 terms
.push_back(Node::fromExpr(inv
));
1901 terms
.push_back(Node::fromExpr(pre
));
1902 terms
.push_back(Node::fromExpr(trans
));
1903 terms
.push_back(Node::fromExpr(post
));
1904 // variables are built based on the invariant type
1905 FunctionType t
= static_cast<FunctionType
>(inv
.getType());
1906 std::vector
<Type
> argTypes
= t
.getArgTypes();
1907 for (const Type
& ti
: argTypes
)
1909 TypeNode tn
= TypeNode::fromType(ti
);
1910 vars
.push_back(d_nodeManager
->mkBoundVar(tn
));
1911 d_private
->d_sygusVars
.push_back(vars
.back());
1912 std::stringstream ss
;
1913 ss
<< vars
.back() << "'";
1914 primed_vars
.push_back(d_nodeManager
->mkBoundVar(ss
.str(), tn
));
1915 d_private
->d_sygusVars
.push_back(primed_vars
.back());
1918 // make relevant terms; 0 -> Inv, 1 -> Pre, 2 -> Trans, 3 -> Post
1919 for (unsigned i
= 0; i
< 4; ++i
)
1922 Trace("smt-debug") << "Make inv-constraint term #" << i
<< " : " << op
1923 << " with type " << op
.getType() << "...\n";
1924 std::vector
<Node
> children
;
1925 children
.push_back(op
);
1926 // transition relation applied over both variable lists
1929 children
.insert(children
.end(), vars
.begin(), vars
.end());
1930 children
.insert(children
.end(), primed_vars
.begin(), primed_vars
.end());
1934 children
.insert(children
.end(), vars
.begin(), vars
.end());
1936 terms
[i
] = d_nodeManager
->mkNode(kind::APPLY_UF
, children
);
1937 // make application of Inv on primed variables
1941 children
.push_back(op
);
1942 children
.insert(children
.end(), primed_vars
.begin(), primed_vars
.end());
1943 terms
.push_back(d_nodeManager
->mkNode(kind::APPLY_UF
, children
));
1947 std::vector
<Node
> conj
;
1948 conj
.push_back(d_nodeManager
->mkNode(kind::IMPLIES
, terms
[1], terms
[0]));
1949 Node term0_and_2
= d_nodeManager
->mkNode(kind::AND
, terms
[0], terms
[2]);
1950 conj
.push_back(d_nodeManager
->mkNode(kind::IMPLIES
, term0_and_2
, terms
[4]));
1951 conj
.push_back(d_nodeManager
->mkNode(kind::IMPLIES
, terms
[0], terms
[3]));
1952 Node constraint
= d_nodeManager
->mkNode(kind::AND
, conj
);
1954 d_private
->d_sygusConstraints
.push_back(constraint
);
1956 Trace("smt") << "SmtEngine::assertSygusInvConstrant: " << constraint
<< "\n";
1957 Dump("raw-benchmark") << SygusInvConstraintCommand(inv
, pre
, trans
, post
);
1958 // sygus conjecture is now stale
1959 setSygusConjectureStale();
1962 Result
SmtEngine::checkSynth()
1964 SmtScope
smts(this);
1966 if (options::incrementalSolving())
1968 // TODO (project #7)
1969 throw ModalException(
1970 "Cannot make check-synth commands when incremental solving is enabled");
1973 if (d_private
->d_sygusConjectureStale
)
1975 // build synthesis conjecture from asserted constraints and declared
1976 // variables/functions
1978 d_nodeManager
->mkSkolem("sygus", d_nodeManager
->booleanType());
1979 Node inst_attr
= d_nodeManager
->mkNode(kind::INST_ATTRIBUTE
, sygusVar
);
1980 Node sygusAttr
= d_nodeManager
->mkNode(kind::INST_PATTERN_LIST
, inst_attr
);
1981 std::vector
<Node
> bodyv
;
1982 Trace("smt") << "Sygus : Constructing sygus constraint...\n";
1983 unsigned n_constraints
= d_private
->d_sygusConstraints
.size();
1984 Node body
= n_constraints
== 0
1985 ? d_nodeManager
->mkConst(true)
1986 : (n_constraints
== 1
1987 ? d_private
->d_sygusConstraints
[0]
1988 : d_nodeManager
->mkNode(
1989 kind::AND
, d_private
->d_sygusConstraints
));
1990 body
= body
.notNode();
1991 Trace("smt") << "...constructed sygus constraint " << body
<< std::endl
;
1992 if (!d_private
->d_sygusVars
.empty())
1995 d_nodeManager
->mkNode(kind::BOUND_VAR_LIST
, d_private
->d_sygusVars
);
1996 body
= d_nodeManager
->mkNode(kind::EXISTS
, boundVars
, body
);
1997 Trace("smt") << "...constructed exists " << body
<< std::endl
;
1999 if (!d_private
->d_sygusFunSymbols
.empty())
2001 Node boundVars
= d_nodeManager
->mkNode(kind::BOUND_VAR_LIST
,
2002 d_private
->d_sygusFunSymbols
);
2003 body
= d_nodeManager
->mkNode(kind::FORALL
, boundVars
, body
, sygusAttr
);
2005 Trace("smt") << "...constructed forall " << body
<< std::endl
;
2007 // set attribute for synthesis conjecture
2008 setUserAttribute("sygus", sygusVar
.toExpr(), {}, "");
2010 Trace("smt") << "Check synthesis conjecture: " << body
<< std::endl
;
2011 Dump("raw-benchmark") << CheckSynthCommand();
2013 d_private
->d_sygusConjectureStale
= false;
2015 if (options::incrementalSolving())
2017 // we push a context so that this conjecture is removed if we modify it
2020 assertFormula(body
.toExpr(), true);
2024 query
= body
.toExpr();
2028 Result r
= checkSatisfiability(query
, true, false);
2030 // Check that synthesis solutions satisfy the conjecture
2031 if (options::checkSynthSol()
2032 && r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
2034 checkSynthSolution();
2040 --------------------------------------------------------------------------
2041 End of Handling SyGuS commands
2042 --------------------------------------------------------------------------
2045 Node
SmtEngine::postprocess(TNode node
, TypeNode expectedType
) const {
2049 Expr
SmtEngine::simplify(const Expr
& ex
)
2051 Assert(ex
.getExprManager() == d_exprManager
);
2052 SmtScope
smts(this);
2053 finalOptionsAreSet();
2055 Trace("smt") << "SMT simplify(" << ex
<< ")" << endl
;
2057 if(Dump
.isOn("benchmark")) {
2058 Dump("benchmark") << SimplifyCommand(ex
);
2061 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
2062 if( options::typeChecking() ) {
2063 e
.getType(true); // ensure expr is type-checked at this point
2066 // Make sure all preprocessing is done
2067 d_private
->processAssertions();
2068 Node n
= d_private
->simplify(Node::fromExpr(e
));
2069 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
2073 Expr
SmtEngine::expandDefinitions(const Expr
& ex
)
2075 d_private
->spendResource(ResourceManager::Resource::PreprocessStep
);
2077 Assert(ex
.getExprManager() == d_exprManager
);
2078 SmtScope
smts(this);
2079 finalOptionsAreSet();
2081 Trace("smt") << "SMT expandDefinitions(" << ex
<< ")" << endl
;
2083 // Substitute out any abstract values in ex.
2084 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
2085 if(options::typeChecking()) {
2086 // Ensure expr is type-checked at this point.
2090 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
2091 Node n
= d_private
->getProcessAssertions()->expandDefinitions(
2092 Node::fromExpr(e
), cache
, /* expandOnly = */ true);
2093 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
2098 // TODO(#1108): Simplify the error reporting of this method.
2099 Expr
SmtEngine::getValue(const Expr
& ex
) const
2101 Assert(ex
.getExprManager() == d_exprManager
);
2102 SmtScope
smts(this);
2104 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
2105 if(Dump
.isOn("benchmark")) {
2106 Dump("benchmark") << GetValueCommand(ex
);
2109 // Substitute out any abstract values in ex.
2110 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
2112 // Ensure expr is type-checked at this point.
2113 e
.getType(options::typeChecking());
2115 // do not need to apply preprocessing substitutions (should be recorded
2116 // in model already)
2118 Node n
= Node::fromExpr(e
);
2119 Trace("smt") << "--- getting value of " << n
<< endl
;
2120 TypeNode expectedType
= n
.getType();
2122 // Expand, then normalize
2123 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
2124 n
= d_private
->getProcessAssertions()->expandDefinitions(n
, cache
);
2125 // There are two ways model values for terms are computed (for historical
2126 // reasons). One way is that used in check-model; the other is that
2127 // used by the Model classes. It's not clear to me exactly how these
2128 // two are different, but they need to be unified. This ugly hack here
2129 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
2132 if(!n
.getType().isFunction()) {
2133 n
= Rewriter::rewrite(n
);
2136 Trace("smt") << "--- getting value of " << n
<< endl
;
2137 TheoryModel
* m
= getAvailableModel("get-value");
2140 resultNode
= m
->getValue(n
);
2142 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
2143 resultNode
= postprocess(resultNode
, expectedType
);
2144 Trace("smt") << "--- model-post returned " << resultNode
<< endl
;
2145 Trace("smt") << "--- model-post returned " << resultNode
.getType() << endl
;
2146 Trace("smt") << "--- model-post expected " << expectedType
<< endl
;
2148 // type-check the result we got
2149 // Notice that lambdas have function type, which does not respect the subtype
2150 // relation, so we ignore them here.
2151 Assert(resultNode
.isNull() || resultNode
.getKind() == kind::LAMBDA
2152 || resultNode
.getType().isSubtypeOf(expectedType
))
2153 << "Run with -t smt for details.";
2155 // Ensure it's a constant, or a lambda (for uninterpreted functions). This
2156 // assertion only holds for models that do not have approximate values.
2157 Assert(m
->hasApproximations() || resultNode
.getKind() == kind::LAMBDA
2158 || resultNode
.isConst());
2160 if(options::abstractValues() && resultNode
.getType().isArray()) {
2161 resultNode
= d_private
->mkAbstractValue(resultNode
);
2162 Trace("smt") << "--- abstract value >> " << resultNode
<< endl
;
2165 return resultNode
.toExpr();
2168 vector
<Expr
> SmtEngine::getValues(const vector
<Expr
>& exprs
)
2170 vector
<Expr
> result
;
2171 for (const Expr
& e
: exprs
)
2173 result
.push_back(getValue(e
));
2178 bool SmtEngine::addToAssignment(const Expr
& ex
) {
2179 SmtScope
smts(this);
2180 finalOptionsAreSet();
2182 // Substitute out any abstract values in ex
2183 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
2184 Type type
= e
.getType(options::typeChecking());
2186 PrettyCheckArgument(
2187 type
.isBoolean(), e
,
2188 "expected Boolean-typed variable or function application "
2189 "in addToAssignment()" );
2190 Node n
= e
.getNode();
2191 // must be a defined constant, or a variable
2192 PrettyCheckArgument(
2193 (((d_definedFunctions
->find(n
) != d_definedFunctions
->end())
2194 && n
.getNumChildren() == 0)
2197 "expected variable or defined-function application "
2198 "in addToAssignment(),\ngot %s",
2199 e
.toString().c_str());
2200 if(!options::produceAssignments()) {
2203 if(d_assignments
== NULL
) {
2204 d_assignments
= new (true) AssignmentSet(getContext());
2206 d_assignments
->insert(n
);
2211 // TODO(#1108): Simplify the error reporting of this method.
2212 vector
<pair
<Expr
, Expr
>> SmtEngine::getAssignment()
2214 Trace("smt") << "SMT getAssignment()" << endl
;
2215 SmtScope
smts(this);
2216 finalOptionsAreSet();
2217 if(Dump
.isOn("benchmark")) {
2218 Dump("benchmark") << GetAssignmentCommand();
2220 if(!options::produceAssignments()) {
2222 "Cannot get the current assignment when "
2223 "produce-assignments option is off.";
2224 throw ModalException(msg
);
2227 // Get the model here, regardless of whether d_assignments is null, since
2228 // we should throw errors related to model availability whether or not
2229 // assignments is null.
2230 TheoryModel
* m
= getAvailableModel("get assignment");
2232 vector
<pair
<Expr
,Expr
>> res
;
2233 if (d_assignments
!= nullptr)
2235 TypeNode boolType
= d_nodeManager
->booleanType();
2236 for (AssignmentSet::key_iterator i
= d_assignments
->key_begin(),
2237 iend
= d_assignments
->key_end();
2242 Assert(as
.getType() == boolType
);
2244 Trace("smt") << "--- getting value of " << as
<< endl
;
2246 // Expand, then normalize
2247 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
2248 Node n
= d_private
->getProcessAssertions()->expandDefinitions(as
, cache
);
2249 n
= Rewriter::rewrite(n
);
2251 Trace("smt") << "--- getting value of " << n
<< endl
;
2255 resultNode
= m
->getValue(n
);
2258 // type-check the result we got
2259 Assert(resultNode
.isNull() || resultNode
.getType() == boolType
);
2261 // ensure it's a constant
2262 Assert(resultNode
.isConst());
2265 res
.emplace_back(as
.toExpr(), resultNode
.toExpr());
2271 void SmtEngine::addToModelCommandAndDump(const Command
& c
, uint32_t flags
, bool userVisible
, const char* dumpTag
) {
2272 Trace("smt") << "SMT addToModelCommandAndDump(" << c
<< ")" << endl
;
2273 SmtScope
smts(this);
2274 // If we aren't yet fully inited, the user might still turn on
2275 // produce-models. So let's keep any commands around just in
2276 // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
2277 // sort "U" in QF_UF before setLogic() is run and we still want to
2278 // support finding card(U) with --finite-model-find, and (2) to
2279 // decouple SmtEngine and ExprManager if the user does a few
2280 // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
2281 // and expects to find their cardinalities in the model.
2282 if(/* userVisible && */
2283 (!d_fullyInited
|| options::produceModels()) &&
2284 (flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
2285 if(flags
& ExprManager::VAR_FLAG_GLOBAL
) {
2286 d_modelGlobalCommands
.push_back(c
.clone());
2288 d_modelCommands
->push_back(c
.clone());
2291 if(Dump
.isOn(dumpTag
)) {
2295 d_dumpCommands
.push_back(c
.clone());
2300 // TODO(#1108): Simplify the error reporting of this method.
2301 Model
* SmtEngine::getModel() {
2302 Trace("smt") << "SMT getModel()" << endl
;
2303 SmtScope
smts(this);
2305 finalOptionsAreSet();
2307 if(Dump
.isOn("benchmark")) {
2308 Dump("benchmark") << GetModelCommand();
2311 TheoryModel
* m
= getAvailableModel("get model");
2313 // Since model m is being returned to the user, we must ensure that this
2314 // model object remains valid with future check-sat calls. Hence, we set
2315 // the theory engine into "eager model building" mode. TODO #2648: revisit.
2316 d_theoryEngine
->setEagerModelBuilding();
2318 if (options::modelCoresMode() != options::ModelCoresMode::NONE
)
2320 // If we enabled model cores, we compute a model core for m based on our
2321 // (expanded) assertions using the model core builder utility
2322 std::vector
<Expr
> eassertsProc
= getExpandedAssertions();
2323 ModelCoreBuilder::setModelCore(eassertsProc
, m
, options::modelCoresMode());
2325 m
->d_inputName
= d_filename
;
2326 m
->d_isKnownSat
= (d_smtMode
== SMT_MODE_SAT
);
2330 Result
SmtEngine::blockModel()
2332 Trace("smt") << "SMT blockModel()" << endl
;
2333 SmtScope
smts(this);
2335 finalOptionsAreSet();
2337 if (Dump
.isOn("benchmark"))
2339 Dump("benchmark") << BlockModelCommand();
2342 TheoryModel
* m
= getAvailableModel("block model");
2344 if (options::blockModelsMode() == options::BlockModelsMode::NONE
)
2346 std::stringstream ss
;
2347 ss
<< "Cannot block model when block-models is set to none.";
2348 throw ModalException(ss
.str().c_str());
2351 // get expanded assertions
2352 std::vector
<Expr
> eassertsProc
= getExpandedAssertions();
2353 Expr eblocker
= ModelBlocker::getModelBlocker(
2354 eassertsProc
, m
, options::blockModelsMode());
2355 return assertFormula(eblocker
);
2358 Result
SmtEngine::blockModelValues(const std::vector
<Expr
>& exprs
)
2360 Trace("smt") << "SMT blockModelValues()" << endl
;
2361 SmtScope
smts(this);
2363 finalOptionsAreSet();
2365 PrettyCheckArgument(
2367 "block model values must be called on non-empty set of terms");
2368 if (Dump
.isOn("benchmark"))
2370 Dump("benchmark") << BlockModelValuesCommand(exprs
);
2373 TheoryModel
* m
= getAvailableModel("block model values");
2375 // get expanded assertions
2376 std::vector
<Expr
> eassertsProc
= getExpandedAssertions();
2377 // we always do block model values mode here
2378 Expr eblocker
= ModelBlocker::getModelBlocker(
2379 eassertsProc
, m
, options::BlockModelsMode::VALUES
, exprs
);
2380 return assertFormula(eblocker
);
2383 std::pair
<Expr
, Expr
> SmtEngine::getSepHeapAndNilExpr(void)
2385 if (!d_logic
.isTheoryEnabled(THEORY_SEP
))
2388 "Cannot obtain separation logic expressions if not using the "
2389 "separation logic theory.";
2390 throw RecoverableModalException(msg
);
2392 NodeManagerScope
nms(d_nodeManager
);
2395 Model
* m
= getAvailableModel("get separation logic heap and nil");
2396 if (!m
->getHeapModel(heap
, nil
))
2399 << "SmtEngine::getSepHeapAndNilExpr(): failed to obtain heap/nil "
2400 "expressions from theory model.";
2402 return std::make_pair(heap
, nil
);
2405 std::vector
<Expr
> SmtEngine::getExpandedAssertions()
2407 std::vector
<Expr
> easserts
= getAssertions();
2408 // must expand definitions
2409 std::vector
<Expr
> eassertsProc
;
2410 std::unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
2411 for (const Expr
& e
: easserts
)
2413 Node ea
= Node::fromExpr(e
);
2414 Node eae
= d_private
->getProcessAssertions()->expandDefinitions(ea
, cache
);
2415 eassertsProc
.push_back(eae
.toExpr());
2417 return eassertsProc
;
2420 Expr
SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first
; }
2422 Expr
SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second
; }
2424 void SmtEngine::checkProof()
2426 #if (IS_LFSC_BUILD && IS_PROOFS_BUILD)
2428 Chat() << "generating proof..." << endl
;
2430 const Proof
& pf
= getProof();
2432 Chat() << "checking proof..." << endl
;
2434 std::string logicString
= d_logic
.getLogicString();
2436 std::stringstream pfStream
;
2438 pfStream
<< proof::plf_signatures
<< endl
;
2439 int64_t sizeBeforeProof
= static_cast<int64_t>(pfStream
.tellp());
2441 pf
.toStream(pfStream
);
2442 d_stats
->d_proofsSize
+=
2443 static_cast<int64_t>(pfStream
.tellp()) - sizeBeforeProof
;
2446 TimerStat::CodeTimer
checkProofTimer(d_stats
->d_lfscCheckProofTime
);
2448 lfscc_check_file(pfStream
, false, false, false, false, false, false, false);
2450 // FIXME: we should actually call lfscc_cleanup here, but lfscc_cleanup
2451 // segfaults on regress0/bv/core/bitvec7.smt
2454 #else /* (IS_LFSC_BUILD && IS_PROOFS_BUILD) */
2456 << "This version of CVC4 was built without proof support; cannot check "
2458 #endif /* (IS_LFSC_BUILD && IS_PROOFS_BUILD) */
2461 UnsatCore
SmtEngine::getUnsatCoreInternal()
2464 if (!options::unsatCores())
2466 throw ModalException(
2467 "Cannot get an unsat core when produce-unsat-cores option is off.");
2469 if (d_smtMode
!= SMT_MODE_UNSAT
)
2471 throw RecoverableModalException(
2472 "Cannot get an unsat core unless immediately preceded by "
2473 "UNSAT/ENTAILED response.");
2476 d_proofManager
->traceUnsatCore(); // just to trigger core creation
2477 return UnsatCore(this, d_proofManager
->extractUnsatCore());
2478 #else /* IS_PROOFS_BUILD */
2479 throw ModalException(
2480 "This build of CVC4 doesn't have proof support (required for unsat "
2482 #endif /* IS_PROOFS_BUILD */
2485 void SmtEngine::checkUnsatCore() {
2486 Assert(options::unsatCores())
2487 << "cannot check unsat core if unsat cores are turned off";
2489 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl
;
2490 UnsatCore core
= getUnsatCore();
2492 SmtEngine
coreChecker(d_exprManager
);
2493 coreChecker
.setLogic(getLogicInfo());
2496 std::vector
<Command
*>::const_iterator itg
= d_defineCommands
.begin();
2497 for (; itg
!= d_defineCommands
.end(); ++itg
) {
2498 (*itg
)->invoke(&coreChecker
);
2502 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions (size == " << core
.size() << ")" << endl
;
2503 for(UnsatCore::iterator i
= core
.begin(); i
!= core
.end(); ++i
) {
2504 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
<< endl
;
2505 coreChecker
.assertFormula(*i
);
2507 const bool checkUnsatCores
= options::checkUnsatCores();
2510 options::checkUnsatCores
.set(false);
2511 options::checkProofs
.set(false);
2512 r
= coreChecker
.checkSat();
2514 options::checkUnsatCores
.set(checkUnsatCores
);
2517 Notice() << "SmtEngine::checkUnsatCore(): result is " << r
<< endl
;
2518 if(r
.asSatisfiabilityResult().isUnknown()) {
2520 << "SmtEngine::checkUnsatCore(): could not check core result unknown."
2523 else if (r
.asSatisfiabilityResult().isSat())
2526 << "SmtEngine::checkUnsatCore(): produced core was satisfiable.";
2530 void SmtEngine::checkModel(bool hardFailure
) {
2531 // --check-model implies --produce-assertions, which enables the
2532 // assertion list, so we should be ok.
2533 Assert(d_assertionList
!= NULL
)
2534 << "don't have an assertion list to check in SmtEngine::checkModel()";
2536 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
2538 // Throughout, we use Notice() to give diagnostic output.
2540 // If this function is running, the user gave --check-model (or equivalent),
2541 // and if Notice() is on, the user gave --verbose (or equivalent).
2543 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
2544 TheoryModel
* m
= getAvailableModel("check model");
2546 // check-model is not guaranteed to succeed if approximate values were used.
2547 // Thus, we intentionally abort here.
2548 if (m
->hasApproximations())
2550 throw RecoverableModalException(
2551 "Cannot run check-model on a model with approximate values.");
2554 // Check individual theory assertions
2555 if (options::debugCheckModels())
2557 d_theoryEngine
->checkTheoryAssertionsWithModel(hardFailure
);
2563 // We have a "fake context" for the substitution map (we don't need it
2564 // to be context-dependent)
2565 context::Context fakeContext
;
2566 SubstitutionMap
substitutions(&fakeContext
, /* substituteUnderQuantifiers = */ false);
2568 for(size_t k
= 0; k
< m
->getNumCommands(); ++k
) {
2569 const DeclareFunctionCommand
* c
= dynamic_cast<const DeclareFunctionCommand
*>(m
->getCommand(k
));
2570 Notice() << "SmtEngine::checkModel(): model command " << k
<< " : " << m
->getCommand(k
) << endl
;
2572 // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
2573 Notice() << "SmtEngine::checkModel(): skipping..." << endl
;
2575 // We have a DECLARE-FUN:
2577 // We'll first do some checks, then add to our substitution map
2578 // the mapping: function symbol |-> value
2580 Expr func
= c
->getFunction();
2581 Node val
= m
->getValue(func
);
2583 Notice() << "SmtEngine::checkModel(): adding substitution: " << func
<< " |-> " << val
<< endl
;
2585 // (1) if the value is a lambda, ensure the lambda doesn't contain the
2586 // function symbol (since then the definition is recursive)
2587 if (val
.getKind() == kind::LAMBDA
) {
2588 // first apply the model substitutions we have so far
2589 Debug("boolean-terms") << "applying subses to " << val
[1] << endl
;
2590 Node n
= substitutions
.apply(val
[1]);
2591 Debug("boolean-terms") << "++ got " << n
<< endl
;
2592 // now check if n contains func by doing a substitution
2593 // [func->func2] and checking equality of the Nodes.
2594 // (this just a way to check if func is in n.)
2595 SubstitutionMap
subs(&fakeContext
);
2596 Node func2
= NodeManager::currentNM()->mkSkolem("", TypeNode::fromType(func
.getType()), "", NodeManager::SKOLEM_NO_NOTIFY
);
2597 subs
.addSubstitution(func
, func2
);
2598 if(subs
.apply(n
) != n
) {
2599 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED IN TERMS OF ITSELF ***" << endl
;
2601 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
2602 << "considering model value for " << func
<< endl
2603 << "body of lambda is: " << val
<< endl
;
2605 ss
<< "body substitutes to: " << n
<< endl
;
2607 ss
<< "so " << func
<< " is defined in terms of itself." << endl
2608 << "Run with `--check-models -v' for additional diagnostics.";
2609 InternalError() << ss
.str();
2613 // (2) check that the value is actually a value
2614 else if (!val
.isConst())
2616 // This is only a warning since it could have been assigned an
2617 // unevaluable term (e.g. an application of a transcendental function).
2618 // This parallels the behavior (warnings for non-constant expressions)
2619 // when checking whether assertions are satisfied below.
2620 Warning() << "Warning : SmtEngine::checkModel(): "
2621 << "model value for " << func
<< endl
2622 << " is " << val
<< endl
2623 << "and that is not a constant (.isConst() == false)."
2625 << "Run with `--check-models -v' for additional diagnostics."
2629 // (3) check that it's the correct (sub)type
2630 // This was intended to be a more general check, but for now we can't do that because
2631 // e.g. "1" is an INT, which isn't a subrange type [1..10] (etc.).
2632 else if(func
.getType().isInteger() && !val
.getType().isInteger()) {
2633 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT CORRECT TYPE ***" << endl
;
2635 << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH "
2638 << "model value for " << func
<< endl
2639 << " is " << val
<< endl
2640 << "value type is " << val
.getType() << endl
2641 << "should be of type " << func
.getType() << endl
2642 << "Run with `--check-models -v' for additional diagnostics.";
2645 // (4) checks complete, add the substitution
2646 Debug("boolean-terms") << "cm: adding subs " << func
<< " :=> " << val
<< endl
;
2647 substitutions
.addSubstitution(func
, val
);
2651 // Now go through all our user assertions checking if they're satisfied.
2652 for(AssertionList::const_iterator i
= d_assertionList
->begin(); i
!= d_assertionList
->end(); ++i
) {
2653 Notice() << "SmtEngine::checkModel(): checking assertion " << *i
<< endl
;
2654 Node n
= Node::fromExpr(*i
);
2656 // Apply any define-funs from the problem.
2658 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
2659 n
= d_private
->getProcessAssertions()->expandDefinitions(n
, cache
);
2661 Notice() << "SmtEngine::checkModel(): -- expands to " << n
<< endl
;
2663 // Apply our model value substitutions.
2664 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
2665 n
= substitutions
.apply(n
);
2666 Debug("boolean-terms") << "++ got " << n
<< endl
;
2667 Notice() << "SmtEngine::checkModel(): -- substitutes to " << n
<< endl
;
2669 // We look up the value before simplifying. If n contains quantifiers,
2670 // this may increases the chance of finding its value before the node is
2671 // altered by simplification below.
2673 Notice() << "SmtEngine::checkModel(): -- get value : " << n
<< std::endl
;
2675 // Simplify the result.
2676 n
= d_private
->simplify(n
);
2677 Notice() << "SmtEngine::checkModel(): -- simplifies to " << n
<< endl
;
2679 // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
2680 n
= d_private
->d_iteRemover
.replace(n
);
2681 Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n
<< endl
;
2683 // Apply our model value substitutions (again), as things may have been simplified.
2684 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
2685 n
= substitutions
.apply(n
);
2686 Debug("boolean-terms") << "++ got " << n
<< endl
;
2687 Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n
<< endl
;
2689 // As a last-ditch effort, ask model to simplify it.
2690 // Presently, this is only an issue for quantifiers, which can have a value
2691 // but don't show up in our substitution map above.
2693 Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n
<< endl
;
2697 if (n
.getConst
<bool>())
2699 // assertion is true, everything is fine
2704 // Otherwise, we did not succeed in showing the current assertion to be
2705 // true. This may either indicate that our model is wrong, or that we cannot
2706 // check it. The latter may be the case for several reasons.
2707 // For example, quantified formulas are not checkable, although we assign
2708 // them to true/false based on the satisfying assignment. However,
2709 // quantified formulas can be modified during preprocess, so they may not
2710 // correspond to those in the satisfying assignment. Hence we throw
2711 // warnings for assertions that do not simplify to either true or false.
2712 // Other theories such as non-linear arithmetic (in particular,
2713 // transcendental functions) also have the property of not being able to
2714 // be checked precisely here.
2715 // Note that warnings like these can be avoided for quantified formulas
2716 // by making preprocessing passes explicitly record how they
2717 // rewrite quantified formulas (see cvc4-wishues#43).
2720 // Not constant, print a less severe warning message here.
2721 Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified "
2726 // Assertions that simplify to false result in an InternalError or
2727 // Warning being thrown below (when hardFailure is false).
2728 Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
2731 ss
<< "SmtEngine::checkModel(): "
2732 << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
2733 << "assertion: " << *i
<< endl
2734 << "simplifies to: " << n
<< endl
2735 << "expected `true'." << endl
2736 << "Run with `--check-models -v' for additional diagnostics.";
2739 // internal error if hardFailure is true
2740 InternalError() << ss
.str();
2744 Warning() << ss
.str() << endl
;
2747 Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl
;
2750 void SmtEngine::checkSynthSolution()
2752 NodeManager
* nm
= NodeManager::currentNM();
2753 Notice() << "SmtEngine::checkSynthSolution(): checking synthesis solution" << endl
;
2754 std::map
<Node
, std::map
<Node
, Node
>> sol_map
;
2755 /* Get solutions and build auxiliary vectors for substituting */
2756 if (!d_theoryEngine
->getSynthSolutions(sol_map
))
2758 InternalError() << "SmtEngine::checkSynthSolution(): No solution to check!";
2761 if (sol_map
.empty())
2763 InternalError() << "SmtEngine::checkSynthSolution(): Got empty solution!";
2766 Trace("check-synth-sol") << "Got solution map:\n";
2767 // the set of synthesis conjectures in our assertions
2768 std::unordered_set
<Node
, NodeHashFunction
> conjs
;
2769 // For each of the above conjectures, the functions-to-synthesis and their
2770 // solutions. This is used as a substitution below.
2771 std::map
<Node
, std::vector
<Node
>> fvarMap
;
2772 std::map
<Node
, std::vector
<Node
>> fsolMap
;
2773 for (const std::pair
<const Node
, std::map
<Node
, Node
>>& cmap
: sol_map
)
2775 Trace("check-synth-sol") << "For conjecture " << cmap
.first
<< ":\n";
2776 conjs
.insert(cmap
.first
);
2777 std::vector
<Node
>& fvars
= fvarMap
[cmap
.first
];
2778 std::vector
<Node
>& fsols
= fsolMap
[cmap
.first
];
2779 for (const std::pair
<const Node
, Node
>& pair
: cmap
.second
)
2781 Trace("check-synth-sol")
2782 << " " << pair
.first
<< " --> " << pair
.second
<< "\n";
2783 fvars
.push_back(pair
.first
);
2784 fsols
.push_back(pair
.second
);
2787 Trace("check-synth-sol") << "Starting new SMT Engine\n";
2788 /* Start new SMT engine to check solutions */
2789 SmtEngine
solChecker(d_exprManager
);
2790 solChecker
.setLogic(getLogicInfo());
2791 setOption("check-synth-sol", SExpr("false"));
2792 setOption("sygus-rec-fun", SExpr("false"));
2794 Trace("check-synth-sol") << "Retrieving assertions\n";
2795 // Build conjecture from original assertions
2796 if (d_assertionList
== NULL
)
2798 Trace("check-synth-sol") << "No assertions to check\n";
2801 // auxiliary assertions
2802 std::vector
<Node
> auxAssertions
;
2803 // expand definitions cache
2804 std::unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
2805 for (AssertionList::const_iterator i
= d_assertionList
->begin();
2806 i
!= d_assertionList
->end();
2809 Notice() << "SmtEngine::checkSynthSolution(): checking assertion " << *i
<< endl
;
2810 Trace("check-synth-sol") << "Retrieving assertion " << *i
<< "\n";
2811 Node assertion
= Node::fromExpr(*i
);
2812 // Apply any define-funs from the problem.
2814 d_private
->getProcessAssertions()->expandDefinitions(assertion
, cache
);
2815 Notice() << "SmtEngine::checkSynthSolution(): -- expands to " << assertion
2817 Trace("check-synth-sol") << "Expanded assertion " << assertion
<< "\n";
2818 if (conjs
.find(assertion
) == conjs
.end())
2820 Trace("check-synth-sol") << "It is an auxiliary assertion\n";
2821 auxAssertions
.push_back(assertion
);
2825 Trace("check-synth-sol") << "It is a synthesis conjecture\n";
2828 // check all conjectures
2829 for (const Node
& conj
: conjs
)
2831 // get the solution for this conjecture
2832 std::vector
<Node
>& fvars
= fvarMap
[conj
];
2833 std::vector
<Node
>& fsols
= fsolMap
[conj
];
2834 // Apply solution map to conjecture body
2836 /* Whether property is quantifier free */
2837 if (conj
[1].getKind() != kind::EXISTS
)
2839 conjBody
= conj
[1].substitute(
2840 fvars
.begin(), fvars
.end(), fsols
.begin(), fsols
.end());
2844 conjBody
= conj
[1][1].substitute(
2845 fvars
.begin(), fvars
.end(), fsols
.begin(), fsols
.end());
2847 /* Skolemize property */
2848 std::vector
<Node
> vars
, skos
;
2849 for (unsigned j
= 0, size
= conj
[1][0].getNumChildren(); j
< size
; ++j
)
2851 vars
.push_back(conj
[1][0][j
]);
2852 std::stringstream ss
;
2854 skos
.push_back(nm
->mkSkolem(ss
.str(), conj
[1][0][j
].getType()));
2855 Trace("check-synth-sol") << "\tSkolemizing " << conj
[1][0][j
] << " to "
2856 << skos
.back() << "\n";
2858 conjBody
= conjBody
.substitute(
2859 vars
.begin(), vars
.end(), skos
.begin(), skos
.end());
2861 Notice() << "SmtEngine::checkSynthSolution(): -- body substitutes to "
2862 << conjBody
<< endl
;
2863 Trace("check-synth-sol") << "Substituted body of assertion to " << conjBody
2865 solChecker
.assertFormula(conjBody
.toExpr());
2866 // Assert all auxiliary assertions. This may include recursive function
2867 // definitions that were added as assertions to the sygus problem.
2868 for (const Node
& a
: auxAssertions
)
2870 solChecker
.assertFormula(a
.toExpr());
2872 Result r
= solChecker
.checkSat();
2873 Notice() << "SmtEngine::checkSynthSolution(): result is " << r
<< endl
;
2874 Trace("check-synth-sol") << "Satsifiability check: " << r
<< "\n";
2875 if (r
.asSatisfiabilityResult().isUnknown())
2877 InternalError() << "SmtEngine::checkSynthSolution(): could not check "
2881 else if (r
.asSatisfiabilityResult().isSat())
2884 << "SmtEngine::checkSynthSolution(): produced solution leads to "
2885 "satisfiable negated conjecture.";
2887 solChecker
.resetAssertions();
2891 void SmtEngine::checkAbduct(Expr a
)
2893 Assert(a
.getType().isBoolean());
2894 Trace("check-abduct") << "SmtEngine::checkAbduct: get expanded assertions"
2897 std::vector
<Expr
> asserts
= getExpandedAssertions();
2898 asserts
.push_back(a
);
2900 // two checks: first, consistent with assertions, second, implies negated goal
2901 // is unsatisfiable.
2902 for (unsigned j
= 0; j
< 2; j
++)
2904 Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
2905 << ": make new SMT engine" << std::endl
;
2906 // Start new SMT engine to check solution
2907 SmtEngine
abdChecker(d_exprManager
);
2908 abdChecker
.setLogic(getLogicInfo());
2909 Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
2910 << ": asserting formulas" << std::endl
;
2911 for (const Expr
& e
: asserts
)
2913 abdChecker
.assertFormula(e
);
2915 Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
2916 << ": check the assertions" << std::endl
;
2917 Result r
= abdChecker
.checkSat();
2918 Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
2919 << ": result is " << r
<< endl
;
2920 std::stringstream serr
;
2921 bool isError
= false;
2924 if (r
.asSatisfiabilityResult().isSat() != Result::SAT
)
2927 serr
<< "SmtEngine::checkAbduct(): produced solution cannot be shown "
2928 "to be consisconsistenttent with assertions, result was "
2931 Trace("check-abduct")
2932 << "SmtEngine::checkAbduct: goal is " << d_abdConj
<< std::endl
;
2933 // add the goal to the set of assertions
2934 Assert(!d_abdConj
.isNull());
2935 asserts
.push_back(d_abdConj
);
2939 if (r
.asSatisfiabilityResult().isSat() != Result::UNSAT
)
2942 serr
<< "SmtEngine::checkAbduct(): negated goal cannot be shown "
2943 "unsatisfiable with produced solution, result was "
2947 // did we get an unexpected result?
2950 InternalError() << serr
.str();
2955 // TODO(#1108): Simplify the error reporting of this method.
2956 UnsatCore
SmtEngine::getUnsatCore() {
2957 Trace("smt") << "SMT getUnsatCore()" << endl
;
2958 SmtScope
smts(this);
2959 finalOptionsAreSet();
2960 if(Dump
.isOn("benchmark")) {
2961 Dump("benchmark") << GetUnsatCoreCommand();
2963 return getUnsatCoreInternal();
2966 // TODO(#1108): Simplify the error reporting of this method.
2967 const Proof
& SmtEngine::getProof()
2969 Trace("smt") << "SMT getProof()" << endl
;
2970 SmtScope
smts(this);
2971 finalOptionsAreSet();
2972 if(Dump
.isOn("benchmark")) {
2973 Dump("benchmark") << GetProofCommand();
2976 if(!options::proof()) {
2977 throw ModalException("Cannot get a proof when produce-proofs option is off.");
2979 if (d_smtMode
!= SMT_MODE_UNSAT
)
2981 throw RecoverableModalException(
2982 "Cannot get a proof unless immediately preceded by UNSAT/ENTAILED "
2986 return ProofManager::getProof(this);
2987 #else /* IS_PROOFS_BUILD */
2988 throw ModalException("This build of CVC4 doesn't have proof support.");
2989 #endif /* IS_PROOFS_BUILD */
2992 void SmtEngine::printInstantiations( std::ostream
& out
) {
2993 SmtScope
smts(this);
2994 finalOptionsAreSet();
2995 if (options::instFormatMode() == options::InstFormatMode::SZS
)
2997 out
<< "% SZS output start Proof for " << d_filename
.c_str() << std::endl
;
2999 if( d_theoryEngine
){
3000 d_theoryEngine
->printInstantiations( out
);
3004 if (options::instFormatMode() == options::InstFormatMode::SZS
)
3006 out
<< "% SZS output end Proof for " << d_filename
.c_str() << std::endl
;
3010 void SmtEngine::printSynthSolution( std::ostream
& out
) {
3011 SmtScope
smts(this);
3012 finalOptionsAreSet();
3013 if( d_theoryEngine
){
3014 d_theoryEngine
->printSynthSolution( out
);
3020 bool SmtEngine::getSynthSolutions(std::map
<Expr
, Expr
>& sol_map
)
3022 SmtScope
smts(this);
3023 finalOptionsAreSet();
3024 std::map
<Node
, std::map
<Node
, Node
>> sol_mapn
;
3025 Assert(d_theoryEngine
!= nullptr);
3026 // fail if the theory engine does not have synthesis solutions
3027 if (!d_theoryEngine
->getSynthSolutions(sol_mapn
))
3031 for (std::pair
<const Node
, std::map
<Node
, Node
>>& cs
: sol_mapn
)
3033 for (std::pair
<const Node
, Node
>& s
: cs
.second
)
3035 sol_map
[s
.first
.toExpr()] = s
.second
.toExpr();
3041 Expr
SmtEngine::doQuantifierElimination(const Expr
& e
, bool doFull
, bool strict
)
3043 SmtScope
smts(this);
3044 finalOptionsAreSet();
3045 if(!d_logic
.isPure(THEORY_ARITH
) && strict
){
3046 Warning() << "Unexpected logic for quantifier elimination " << d_logic
<< endl
;
3048 Trace("smt-qe") << "Do quantifier elimination " << e
<< std::endl
;
3049 Node n_e
= Node::fromExpr( e
);
3050 if (n_e
.getKind() != kind::EXISTS
&& n_e
.getKind() != kind::FORALL
)
3052 throw ModalException(
3053 "Expecting a quantified formula as argument to get-qe.");
3055 //tag the quantified formula with the quant-elim attribute
3056 TypeNode t
= NodeManager::currentNM()->booleanType();
3057 Node n_attr
= NodeManager::currentNM()->mkSkolem("qe", t
, "Auxiliary variable for qe attr.");
3058 std::vector
< Node
> node_values
;
3059 d_theoryEngine
->setUserAttribute( doFull
? "quant-elim" : "quant-elim-partial", n_attr
, node_values
, "");
3060 n_attr
= NodeManager::currentNM()->mkNode(kind::INST_ATTRIBUTE
, n_attr
);
3061 n_attr
= NodeManager::currentNM()->mkNode(kind::INST_PATTERN_LIST
, n_attr
);
3062 std::vector
< Node
> e_children
;
3063 e_children
.push_back( n_e
[0] );
3064 e_children
.push_back(n_e
.getKind() == kind::EXISTS
? n_e
[1]
3066 e_children
.push_back( n_attr
);
3067 Node nn_e
= NodeManager::currentNM()->mkNode( kind::EXISTS
, e_children
);
3068 Trace("smt-qe-debug") << "Query for quantifier elimination : " << nn_e
<< std::endl
;
3069 Assert(nn_e
.getNumChildren() == 3);
3070 Result r
= checkSatisfiability(nn_e
.toExpr(), true, true);
3071 Trace("smt-qe") << "Query returned " << r
<< std::endl
;
3072 if(r
.asSatisfiabilityResult().isSat() != Result::UNSAT
) {
3073 if( r
.asSatisfiabilityResult().isSat() != Result::SAT
&& doFull
){
3075 << "While performing quantifier elimination, unexpected result : "
3076 << r
<< " for query.";
3077 // failed, return original
3080 std::vector
< Node
> inst_qs
;
3081 d_theoryEngine
->getInstantiatedQuantifiedFormulas( inst_qs
);
3082 Assert(inst_qs
.size() <= 1);
3084 if( inst_qs
.size()==1 ){
3085 Node top_q
= inst_qs
[0];
3086 //Node top_q = Rewriter::rewrite( nn_e ).negate();
3087 Assert(top_q
.getKind() == kind::FORALL
);
3088 Trace("smt-qe") << "Get qe for " << top_q
<< std::endl
;
3089 ret_n
= d_theoryEngine
->getInstantiatedConjunction( top_q
);
3090 Trace("smt-qe") << "Returned : " << ret_n
<< std::endl
;
3091 if (n_e
.getKind() == kind::EXISTS
)
3093 ret_n
= Rewriter::rewrite(ret_n
.negate());
3096 ret_n
= NodeManager::currentNM()->mkConst(n_e
.getKind() != kind::EXISTS
);
3098 // do extended rewrite to minimize the size of the formula aggressively
3099 theory::quantifiers::ExtendedRewriter
extr(true);
3100 ret_n
= extr
.extendedRewrite(ret_n
);
3101 return ret_n
.toExpr();
3103 return NodeManager::currentNM()
3104 ->mkConst(n_e
.getKind() == kind::EXISTS
)
3109 bool SmtEngine::getAbduct(const Expr
& conj
, const Type
& grammarType
, Expr
& abd
)
3111 SmtScope
smts(this);
3113 if (!options::produceAbducts())
3115 const char* msg
= "Cannot get abduct when produce-abducts options is off.";
3116 throw ModalException(msg
);
3118 Trace("sygus-abduct") << "SmtEngine::getAbduct: conjecture " << conj
3120 std::vector
<Expr
> easserts
= getExpandedAssertions();
3121 std::vector
<Node
> axioms
;
3122 for (unsigned i
= 0, size
= easserts
.size(); i
< size
; i
++)
3124 axioms
.push_back(Node::fromExpr(easserts
[i
]));
3126 std::vector
<Node
> asserts(axioms
.begin(), axioms
.end());
3127 // negate the conjecture
3128 Node conjn
= Node::fromExpr(conj
);
3129 // must expand definitions
3130 std::unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
3131 conjn
= d_private
->getProcessAssertions()->expandDefinitions(conjn
, cache
);
3133 conjn
= conjn
.negate();
3134 d_abdConj
= conjn
.toExpr();
3135 asserts
.push_back(conjn
);
3136 std::string
name("A");
3137 Node aconj
= theory::quantifiers::SygusAbduct::mkAbductionConjecture(
3138 name
, asserts
, axioms
, TypeNode::fromType(grammarType
));
3139 // should be a quantified conjecture with one function-to-synthesize
3140 Assert(aconj
.getKind() == kind::FORALL
&& aconj
[0].getNumChildren() == 1);
3141 // remember the abduct-to-synthesize
3142 d_sssf
= aconj
[0][0].toExpr();
3143 Trace("sygus-abduct") << "SmtEngine::getAbduct: made conjecture : " << aconj
3144 << ", solving for " << d_sssf
<< std::endl
;
3145 // we generate a new smt engine to do the abduction query
3146 d_subsolver
.reset(new SmtEngine(NodeManager::currentNM()->toExprManager()));
3147 d_subsolver
->setIsInternalSubsolver();
3149 LogicInfo l
= d_logic
.getUnlockedCopy();
3150 // enable everything needed for sygus
3152 d_subsolver
->setLogic(l
);
3153 // assert the abduction query
3154 d_subsolver
->assertFormula(aconj
.toExpr());
3155 if (getAbductInternal(abd
))
3157 // successfully generated an abduct, update to abduct state
3158 d_smtMode
= SMT_MODE_ABDUCT
;
3161 // failed, we revert to the assert state
3162 d_smtMode
= SMT_MODE_ASSERT
;
3166 bool SmtEngine::getAbductInternal(Expr
& abd
)
3168 // should have initialized the subsolver by now
3169 Assert(d_subsolver
!= nullptr);
3170 Trace("sygus-abduct") << " SmtEngine::getAbduct check sat..." << std::endl
;
3171 Result r
= d_subsolver
->checkSat();
3172 Trace("sygus-abduct") << " SmtEngine::getAbduct result: " << r
<< std::endl
;
3173 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
3175 // get the synthesis solution
3176 std::map
<Expr
, Expr
> sols
;
3177 d_subsolver
->getSynthSolutions(sols
);
3178 Assert(sols
.size() == 1);
3179 std::map
<Expr
, Expr
>::iterator its
= sols
.find(d_sssf
);
3180 if (its
!= sols
.end())
3182 Trace("sygus-abduct")
3183 << "SmtEngine::getAbduct: solution is " << its
->second
<< std::endl
;
3184 Node abdn
= Node::fromExpr(its
->second
);
3185 if (abdn
.getKind() == kind::LAMBDA
)
3189 // get the grammar type for the abduct
3190 Node af
= Node::fromExpr(d_sssf
);
3191 Node agdtbv
= af
.getAttribute(theory::SygusSynthFunVarListAttribute());
3192 Assert(!agdtbv
.isNull());
3193 Assert(agdtbv
.getKind() == kind::BOUND_VAR_LIST
);
3194 // convert back to original
3195 // must replace formal arguments of abd with the free variables in the
3196 // input problem that they correspond to.
3197 std::vector
<Node
> vars
;
3198 std::vector
<Node
> syms
;
3199 SygusVarToTermAttribute sta
;
3200 for (const Node
& bv
: agdtbv
)
3203 syms
.push_back(bv
.hasAttribute(sta
) ? bv
.getAttribute(sta
) : bv
);
3206 abdn
.substitute(vars
.begin(), vars
.end(), syms
.begin(), syms
.end());
3208 // convert to expression
3209 abd
= abdn
.toExpr();
3211 // if check abducts option is set, we check the correctness
3212 if (options::checkAbducts())
3218 Trace("sygus-abduct") << "SmtEngine::getAbduct: could not find solution!"
3220 throw RecoverableModalException("Could not find solution for get-abduct.");
3225 bool SmtEngine::getAbduct(const Expr
& conj
, Expr
& abd
)
3228 return getAbduct(conj
, grammarType
, abd
);
3231 void SmtEngine::getInstantiatedQuantifiedFormulas( std::vector
< Expr
>& qs
) {
3232 SmtScope
smts(this);
3233 if( d_theoryEngine
){
3234 std::vector
< Node
> qs_n
;
3235 d_theoryEngine
->getInstantiatedQuantifiedFormulas( qs_n
);
3236 for( unsigned i
=0; i
<qs_n
.size(); i
++ ){
3237 qs
.push_back( qs_n
[i
].toExpr() );
3244 void SmtEngine::getInstantiations( Expr q
, std::vector
< Expr
>& insts
) {
3245 SmtScope
smts(this);
3246 if( d_theoryEngine
){
3247 std::vector
< Node
> insts_n
;
3248 d_theoryEngine
->getInstantiations( Node::fromExpr( q
), insts_n
);
3249 for( unsigned i
=0; i
<insts_n
.size(); i
++ ){
3250 insts
.push_back( insts_n
[i
].toExpr() );
3257 void SmtEngine::getInstantiationTermVectors( Expr q
, std::vector
< std::vector
< Expr
> >& tvecs
) {
3258 SmtScope
smts(this);
3259 Assert(options::trackInstLemmas());
3260 if( d_theoryEngine
){
3261 std::vector
< std::vector
< Node
> > tvecs_n
;
3262 d_theoryEngine
->getInstantiationTermVectors( Node::fromExpr( q
), tvecs_n
);
3263 for( unsigned i
=0; i
<tvecs_n
.size(); i
++ ){
3264 std::vector
< Expr
> tvec
;
3265 for( unsigned j
=0; j
<tvecs_n
[i
].size(); j
++ ){
3266 tvec
.push_back( tvecs_n
[i
][j
].toExpr() );
3268 tvecs
.push_back( tvec
);
3275 vector
<Expr
> SmtEngine::getAssertions() {
3276 SmtScope
smts(this);
3277 finalOptionsAreSet();
3279 if(Dump
.isOn("benchmark")) {
3280 Dump("benchmark") << GetAssertionsCommand();
3282 Trace("smt") << "SMT getAssertions()" << endl
;
3283 if(!options::produceAssertions()) {
3285 "Cannot query the current assertion list when not in produce-assertions mode.";
3286 throw ModalException(msg
);
3288 Assert(d_assertionList
!= NULL
);
3289 // copy the result out
3290 return vector
<Expr
>(d_assertionList
->begin(), d_assertionList
->end());
3293 void SmtEngine::push()
3295 SmtScope
smts(this);
3296 finalOptionsAreSet();
3298 Trace("smt") << "SMT push()" << endl
;
3299 d_private
->notifyPush();
3300 d_private
->processAssertions();
3301 if(Dump
.isOn("benchmark")) {
3302 Dump("benchmark") << PushCommand();
3304 if(!options::incrementalSolving()) {
3305 throw ModalException("Cannot push when not solving incrementally (use --incremental)");
3309 // The problem isn't really "extended" yet, but this disallows
3310 // get-model after a push, simplifying our lives somewhat and
3311 // staying symmetric with pop.
3312 setProblemExtended();
3314 d_userLevels
.push_back(d_userContext
->getLevel());
3316 Trace("userpushpop") << "SmtEngine: pushed to level "
3317 << d_userContext
->getLevel() << endl
;
3320 void SmtEngine::pop() {
3321 SmtScope
smts(this);
3322 finalOptionsAreSet();
3323 Trace("smt") << "SMT pop()" << endl
;
3324 if(Dump
.isOn("benchmark")) {
3325 Dump("benchmark") << PopCommand();
3327 if(!options::incrementalSolving()) {
3328 throw ModalException("Cannot pop when not solving incrementally (use --incremental)");
3330 if(d_userLevels
.size() == 0) {
3331 throw ModalException("Cannot pop beyond the first user frame");
3334 // The problem isn't really "extended" yet, but this disallows
3335 // get-model after a pop, simplifying our lives somewhat. It might
3336 // not be strictly necessary to do so, since the pops occur lazily,
3337 // but also it would be weird to have a legally-executed (get-model)
3338 // that only returns a subset of the assignment (because the rest
3339 // is no longer in scope!).
3340 setProblemExtended();
3342 AlwaysAssert(d_userContext
->getLevel() > 0);
3343 AlwaysAssert(d_userLevels
.back() < d_userContext
->getLevel());
3344 while (d_userLevels
.back() < d_userContext
->getLevel()) {
3347 d_userLevels
.pop_back();
3349 // Clear out assertion queues etc., in case anything is still in there
3350 d_private
->notifyPop();
3352 Trace("userpushpop") << "SmtEngine: popped to level "
3353 << d_userContext
->getLevel() << endl
;
3354 // FIXME: should we reset d_status here?
3355 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
3358 void SmtEngine::internalPush() {
3359 Assert(d_fullyInited
);
3360 Trace("smt") << "SmtEngine::internalPush()" << endl
;
3362 if(options::incrementalSolving()) {
3363 d_private
->processAssertions();
3364 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
3365 d_userContext
->push();
3366 // the d_context push is done inside of the SAT solver
3367 d_propEngine
->push();
3371 void SmtEngine::internalPop(bool immediate
) {
3372 Assert(d_fullyInited
);
3373 Trace("smt") << "SmtEngine::internalPop()" << endl
;
3374 if(options::incrementalSolving()) {
3382 void SmtEngine::doPendingPops() {
3383 Trace("smt") << "SmtEngine::doPendingPops()" << endl
;
3384 Assert(d_pendingPops
== 0 || options::incrementalSolving());
3385 // check to see if a postsolve() is pending
3386 if (d_needPostsolve
)
3388 d_propEngine
->resetTrail();
3390 while(d_pendingPops
> 0) {
3391 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
3392 d_propEngine
->pop();
3393 // the d_context pop is done inside of the SAT solver
3394 d_userContext
->pop();
3397 if (d_needPostsolve
)
3399 d_theoryEngine
->postsolve();
3400 d_needPostsolve
= false;
3404 void SmtEngine::reset()
3406 SmtScope
smts(this);
3407 ExprManager
*em
= d_exprManager
;
3408 Trace("smt") << "SMT reset()" << endl
;
3409 if(Dump
.isOn("benchmark")) {
3410 Dump("benchmark") << ResetCommand();
3413 opts
.copyValues(d_originalOptions
);
3415 NodeManager::fromExprManager(em
)->getOptions().copyValues(opts
);
3416 new(this) SmtEngine(em
);
3419 void SmtEngine::resetAssertions()
3421 SmtScope
smts(this);
3425 // We're still in Start Mode, nothing asserted yet, do nothing.
3426 // (see solver execution modes in the SMT-LIB standard)
3427 Assert(d_context
->getLevel() == 0);
3428 Assert(d_userContext
->getLevel() == 0);
3429 DeleteAndClearCommandVector(d_modelGlobalCommands
);
3435 Trace("smt") << "SMT resetAssertions()" << endl
;
3436 if (Dump
.isOn("benchmark"))
3438 Dump("benchmark") << ResetAssertionsCommand();
3441 while (!d_userLevels
.empty())
3446 // Remember the global push/pop around everything when beyond Start mode
3447 // (see solver execution modes in the SMT-LIB standard)
3448 Assert(d_userLevels
.size() == 0 && d_userContext
->getLevel() == 1);
3449 d_context
->popto(0);
3450 d_userContext
->popto(0);
3451 DeleteAndClearCommandVector(d_modelGlobalCommands
);
3452 d_userContext
->push();
3455 /* Create new PropEngine.
3456 * First force destruction of referenced PropEngine to enforce that
3457 * statistics are unregistered by the obsolete PropEngine object before
3458 * registered again by the new PropEngine object */
3459 d_propEngine
.reset(nullptr);
3460 d_propEngine
.reset(new PropEngine(getTheoryEngine(),
3463 d_private
->getResourceManager()));
3464 d_theoryEngine
->setPropEngine(getPropEngine());
3467 void SmtEngine::interrupt()
3469 if(!d_fullyInited
) {
3472 d_propEngine
->interrupt();
3473 d_theoryEngine
->interrupt();
3476 void SmtEngine::setResourceLimit(unsigned long units
, bool cumulative
) {
3477 d_private
->getResourceManager()->setResourceLimit(units
, cumulative
);
3479 void SmtEngine::setTimeLimit(unsigned long milis
, bool cumulative
) {
3480 d_private
->getResourceManager()->setTimeLimit(milis
, cumulative
);
3483 unsigned long SmtEngine::getResourceUsage() const {
3484 return d_private
->getResourceManager()->getResourceUsage();
3487 unsigned long SmtEngine::getTimeUsage() const {
3488 return d_private
->getResourceManager()->getTimeUsage();
3491 unsigned long SmtEngine::getResourceRemaining() const
3493 return d_private
->getResourceManager()->getResourceRemaining();
3496 unsigned long SmtEngine::getTimeRemaining() const
3498 return d_private
->getResourceManager()->getTimeRemaining();
3501 Statistics
SmtEngine::getStatistics() const
3503 return Statistics(*d_statisticsRegistry
);
3506 SExpr
SmtEngine::getStatistic(std::string name
) const
3508 return d_statisticsRegistry
->getStatistic(name
);
3511 void SmtEngine::safeFlushStatistics(int fd
) const {
3512 d_statisticsRegistry
->safeFlushInformation(fd
);
3515 void SmtEngine::setUserAttribute(const std::string
& attr
,
3517 const std::vector
<Expr
>& expr_values
,
3518 const std::string
& str_value
)
3520 SmtScope
smts(this);
3521 finalOptionsAreSet();
3522 std::vector
<Node
> node_values
;
3523 for( unsigned i
=0; i
<expr_values
.size(); i
++ ){
3524 node_values
.push_back( expr_values
[i
].getNode() );
3526 d_theoryEngine
->setUserAttribute(attr
, expr
.getNode(), node_values
, str_value
);
3529 void SmtEngine::setPrintFuncInModel(Expr f
, bool p
) {
3530 Trace("setp-model") << "Set printInModel " << f
<< " to " << p
<< std::endl
;
3531 for( unsigned i
=0; i
<d_modelGlobalCommands
.size(); i
++ ){
3532 Command
* c
= d_modelGlobalCommands
[i
];
3533 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
3535 if( dfc
->getFunction()==f
){
3536 dfc
->setPrintInModel( p
);
3540 for( unsigned i
=0; i
<d_modelCommands
->size(); i
++ ){
3541 Command
* c
= (*d_modelCommands
)[i
];
3542 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
3544 if( dfc
->getFunction()==f
){
3545 dfc
->setPrintInModel( p
);
3551 void SmtEngine::beforeSearch()
3554 throw ModalException(
3555 "SmtEngine::beforeSearch called after initialization.");
3560 void SmtEngine::setOption(const std::string
& key
, const CVC4::SExpr
& value
)
3562 NodeManagerScope
nms(d_nodeManager
);
3563 Trace("smt") << "SMT setOption(" << key
<< ", " << value
<< ")" << endl
;
3565 if(Dump
.isOn("benchmark")) {
3566 Dump("benchmark") << SetOptionCommand(key
, value
);
3569 if(key
== "command-verbosity") {
3570 if(!value
.isAtom()) {
3571 const vector
<SExpr
>& cs
= value
.getChildren();
3572 if(cs
.size() == 2 &&
3573 (cs
[0].isKeyword() || cs
[0].isString()) &&
3574 cs
[1].isInteger()) {
3575 string c
= cs
[0].getValue();
3576 const Integer
& v
= cs
[1].getIntegerValue();
3577 if(v
< 0 || v
> 2) {
3578 throw OptionException("command-verbosity must be 0, 1, or 2");
3580 d_commandVerbosity
[c
] = v
;
3584 throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
3587 if(!value
.isAtom()) {
3588 throw OptionException("bad value for :" + key
);
3591 string optionarg
= value
.getValue();
3592 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
3593 nodeManagerOptions
.setOption(key
, optionarg
);
3596 void SmtEngine::setIsInternalSubsolver() { d_isInternalSubsolver
= true; }
3598 bool SmtEngine::isInternalSubsolver() const { return d_isInternalSubsolver
; }
3600 CVC4::SExpr
SmtEngine::getOption(const std::string
& key
) const
3602 NodeManagerScope
nms(d_nodeManager
);
3604 Trace("smt") << "SMT getOption(" << key
<< ")" << endl
;
3606 if(key
.length() >= 18 &&
3607 key
.compare(0, 18, "command-verbosity:") == 0) {
3608 map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.find(key
.c_str() + 18);
3609 if(i
!= d_commandVerbosity
.end()) {
3610 return SExpr((*i
).second
);
3612 i
= d_commandVerbosity
.find("*");
3613 if(i
!= d_commandVerbosity
.end()) {
3614 return SExpr((*i
).second
);
3616 return SExpr(Integer(2));
3619 if(Dump
.isOn("benchmark")) {
3620 Dump("benchmark") << GetOptionCommand(key
);
3623 if(key
== "command-verbosity") {
3624 vector
<SExpr
> result
;
3625 SExpr defaultVerbosity
;
3626 for(map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.begin();
3627 i
!= d_commandVerbosity
.end();
3630 v
.push_back(SExpr((*i
).first
));
3631 v
.push_back(SExpr((*i
).second
));
3632 if((*i
).first
== "*") {
3633 // put the default at the end of the SExpr
3634 defaultVerbosity
= SExpr(v
);
3636 result
.push_back(SExpr(v
));
3639 // put the default at the end of the SExpr
3640 if(!defaultVerbosity
.isAtom()) {
3641 result
.push_back(defaultVerbosity
);
3643 // ensure the default is always listed
3645 v
.push_back(SExpr("*"));
3646 v
.push_back(SExpr(Integer(2)));
3647 result
.push_back(SExpr(v
));
3649 return SExpr(result
);
3652 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
3653 return SExpr::parseAtom(nodeManagerOptions
.getOption(key
));
3656 bool SmtEngine::getExpressionName(Expr e
, std::string
& name
) const {
3657 return d_private
->getExpressionName(e
, name
);
3660 void SmtEngine::setExpressionName(Expr e
, const std::string
& name
) {
3661 Trace("smt-debug") << "Set expression name " << e
<< " to " << name
<< std::endl
;
3662 d_private
->setExpressionName(e
,name
);
3665 void SmtEngine::setSygusConjectureStale()
3667 if (d_private
->d_sygusConjectureStale
)
3672 d_private
->d_sygusConjectureStale
= true;
3673 if (options::incrementalSolving())
3679 }/* CVC4 namespace */