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-2018 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"
26 #include <unordered_map>
27 #include <unordered_set>
31 #include "base/configuration.h"
32 #include "base/configuration_private.h"
33 #include "base/exception.h"
34 #include "base/listener.h"
35 #include "base/modal_exception.h"
36 #include "base/output.h"
37 #include "context/cdhashmap.h"
38 #include "context/cdhashset.h"
39 #include "context/cdlist.h"
40 #include "context/context.h"
41 #include "decision/decision_engine.h"
42 #include "expr/attribute.h"
43 #include "expr/expr.h"
44 #include "expr/kind.h"
45 #include "expr/metakind.h"
46 #include "expr/node.h"
47 #include "expr/node_builder.h"
48 #include "expr/node_self_iterator.h"
49 #include "options/arith_options.h"
50 #include "options/arrays_options.h"
51 #include "options/base_options.h"
52 #include "options/booleans_options.h"
53 #include "options/bv_options.h"
54 #include "options/datatypes_options.h"
55 #include "options/decision_mode.h"
56 #include "options/decision_options.h"
57 #include "options/language.h"
58 #include "options/main_options.h"
59 #include "options/open_ostream.h"
60 #include "options/option_exception.h"
61 #include "options/printer_options.h"
62 #include "options/proof_options.h"
63 #include "options/prop_options.h"
64 #include "options/quantifiers_options.h"
65 #include "options/sep_options.h"
66 #include "options/set_language.h"
67 #include "options/smt_options.h"
68 #include "options/strings_options.h"
69 #include "options/theory_options.h"
70 #include "options/uf_options.h"
71 #include "preprocessing/passes/bv_gauss.h"
72 #include "preprocessing/passes/int_to_bv.h"
73 #include "preprocessing/passes/pseudo_boolean_processor.h"
74 #include "preprocessing/passes/symmetry_detect.h"
75 #include "preprocessing/preprocessing_pass.h"
76 #include "preprocessing/preprocessing_pass_context.h"
77 #include "preprocessing/preprocessing_pass_registry.h"
78 #include "printer/printer.h"
79 #include "proof/proof.h"
80 #include "proof/proof_manager.h"
81 #include "proof/theory_proof.h"
82 #include "proof/unsat_core.h"
83 #include "prop/prop_engine.h"
84 #include "smt/command.h"
85 #include "smt/command_list.h"
86 #include "smt/logic_request.h"
87 #include "smt/managed_ostreams.h"
88 #include "smt/smt_engine_scope.h"
89 #include "smt/term_formula_removal.h"
90 #include "smt/update_ostream.h"
91 #include "smt_util/boolean_simplification.h"
92 #include "smt_util/nary_builder.h"
93 #include "smt_util/node_visitor.h"
94 #include "theory/arith/arith_msum.h"
95 #include "theory/booleans/circuit_propagator.h"
96 #include "theory/bv/bvintropow2.h"
97 #include "theory/bv/theory_bv_rewriter.h"
98 #include "theory/logic_info.h"
99 #include "theory/quantifiers/fun_def_process.h"
100 #include "theory/quantifiers/global_negate.h"
101 #include "theory/quantifiers/macros.h"
102 #include "theory/quantifiers/quantifiers_rewriter.h"
103 #include "theory/quantifiers/single_inv_partition.h"
104 #include "theory/quantifiers/sygus/ce_guided_instantiation.h"
105 #include "theory/quantifiers/sygus_inference.h"
106 #include "theory/quantifiers/term_util.h"
107 #include "theory/sort_inference.h"
108 #include "theory/strings/theory_strings.h"
109 #include "theory/substitutions.h"
110 #include "theory/theory_engine.h"
111 #include "theory/theory_model.h"
112 #include "theory/theory_traits.h"
113 #include "util/hash.h"
114 #include "util/proof.h"
115 #include "util/random.h"
116 #include "util/resource_manager.h"
119 using namespace CVC4
;
120 using namespace CVC4::smt
;
121 using namespace CVC4::preprocessing
;
122 using namespace CVC4::preprocessing::passes
;
123 using namespace CVC4::prop
;
124 using namespace CVC4::context
;
125 using namespace CVC4::theory
;
130 struct DeleteCommandFunction
: public std::unary_function
<const Command
*, void>
132 void operator()(const Command
* command
) { delete command
; }
135 void DeleteAndClearCommandVector(std::vector
<Command
*>& commands
) {
136 std::for_each(commands
.begin(), commands
.end(), DeleteCommandFunction());
140 /** Useful for counting the number of recursive calls. */
145 ScopeCounter(unsigned& d
) : d_depth(d
) {
154 * Representation of a defined function. We keep these around in
155 * SmtEngine to permit expanding definitions late (and lazily), to
156 * support getValue() over defined functions, to support user output
157 * in terms of defined functions, etc.
159 class DefinedFunction
{
161 vector
<Node
> d_formals
;
165 DefinedFunction(Node func
, vector
<Node
> formals
, Node formula
) :
170 Node
getFunction() const { return d_func
; }
171 vector
<Node
> getFormals() const { return d_formals
; }
172 Node
getFormula() const { return d_formula
; }
173 };/* class DefinedFunction */
175 struct SmtEngineStatistics
{
176 /** time spent in gaussian elimination */
177 TimerStat d_gaussElimTime
;
178 /** time spent in definition-expansion */
179 TimerStat d_definitionExpansionTime
;
180 /** time spent in non-clausal simplification */
181 TimerStat d_nonclausalSimplificationTime
;
182 /** time spent in miplib pass */
183 TimerStat d_miplibPassTime
;
184 /** number of assertions removed by miplib pass */
185 IntStat d_numMiplibAssertionsRemoved
;
186 /** number of constant propagations found during nonclausal simp */
187 IntStat d_numConstantProps
;
188 /** time spent in static learning */
189 TimerStat d_staticLearningTime
;
190 /** time spent in simplifying ITEs */
191 TimerStat d_simpITETime
;
192 /** time spent in simplifying ITEs */
193 TimerStat d_unconstrainedSimpTime
;
194 /** time spent removing ITEs */
195 TimerStat d_iteRemovalTime
;
196 /** time spent in theory preprocessing */
197 TimerStat d_theoryPreprocessTime
;
198 /** time spent in theory preprocessing */
199 TimerStat d_rewriteApplyToConstTime
;
200 /** time spent converting to CNF */
201 TimerStat d_cnfConversionTime
;
202 /** Num of assertions before ite removal */
203 IntStat d_numAssertionsPre
;
204 /** Num of assertions after ite removal */
205 IntStat d_numAssertionsPost
;
206 /** time spent in checkModel() */
207 TimerStat d_checkModelTime
;
208 /** time spent in checkProof() */
209 TimerStat d_checkProofTime
;
210 /** time spent in checkUnsatCore() */
211 TimerStat d_checkUnsatCoreTime
;
212 /** time spent in PropEngine::checkSat() */
213 TimerStat d_solveTime
;
214 /** time spent in pushing/popping */
215 TimerStat d_pushPopTime
;
216 /** time spent in processAssertions() */
217 TimerStat d_processAssertionsTime
;
219 /** Has something simplified to false? */
220 IntStat d_simplifiedToFalse
;
221 /** Number of resource units spent. */
222 ReferenceStat
<uint64_t> d_resourceUnitsUsed
;
224 SmtEngineStatistics() :
225 d_gaussElimTime("smt::SmtEngine::gaussElimTime"),
226 d_definitionExpansionTime("smt::SmtEngine::definitionExpansionTime"),
227 d_nonclausalSimplificationTime("smt::SmtEngine::nonclausalSimplificationTime"),
228 d_miplibPassTime("smt::SmtEngine::miplibPassTime"),
229 d_numMiplibAssertionsRemoved("smt::SmtEngine::numMiplibAssertionsRemoved", 0),
230 d_numConstantProps("smt::SmtEngine::numConstantProps", 0),
231 d_staticLearningTime("smt::SmtEngine::staticLearningTime"),
232 d_simpITETime("smt::SmtEngine::simpITETime"),
233 d_unconstrainedSimpTime("smt::SmtEngine::unconstrainedSimpTime"),
234 d_iteRemovalTime("smt::SmtEngine::iteRemovalTime"),
235 d_theoryPreprocessTime("smt::SmtEngine::theoryPreprocessTime"),
236 d_rewriteApplyToConstTime("smt::SmtEngine::rewriteApplyToConstTime"),
237 d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
238 d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
239 d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
240 d_checkModelTime("smt::SmtEngine::checkModelTime"),
241 d_checkProofTime("smt::SmtEngine::checkProofTime"),
242 d_checkUnsatCoreTime("smt::SmtEngine::checkUnsatCoreTime"),
243 d_solveTime("smt::SmtEngine::solveTime"),
244 d_pushPopTime("smt::SmtEngine::pushPopTime"),
245 d_processAssertionsTime("smt::SmtEngine::processAssertionsTime"),
246 d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0),
247 d_resourceUnitsUsed("smt::SmtEngine::resourceUnitsUsed")
250 smtStatisticsRegistry()->registerStat(&d_gaussElimTime
);
251 smtStatisticsRegistry()->registerStat(&d_definitionExpansionTime
);
252 smtStatisticsRegistry()->registerStat(&d_nonclausalSimplificationTime
);
253 smtStatisticsRegistry()->registerStat(&d_miplibPassTime
);
254 smtStatisticsRegistry()->registerStat(&d_numMiplibAssertionsRemoved
);
255 smtStatisticsRegistry()->registerStat(&d_numConstantProps
);
256 smtStatisticsRegistry()->registerStat(&d_staticLearningTime
);
257 smtStatisticsRegistry()->registerStat(&d_simpITETime
);
258 smtStatisticsRegistry()->registerStat(&d_unconstrainedSimpTime
);
259 smtStatisticsRegistry()->registerStat(&d_iteRemovalTime
);
260 smtStatisticsRegistry()->registerStat(&d_theoryPreprocessTime
);
261 smtStatisticsRegistry()->registerStat(&d_rewriteApplyToConstTime
);
262 smtStatisticsRegistry()->registerStat(&d_cnfConversionTime
);
263 smtStatisticsRegistry()->registerStat(&d_numAssertionsPre
);
264 smtStatisticsRegistry()->registerStat(&d_numAssertionsPost
);
265 smtStatisticsRegistry()->registerStat(&d_checkModelTime
);
266 smtStatisticsRegistry()->registerStat(&d_checkProofTime
);
267 smtStatisticsRegistry()->registerStat(&d_checkUnsatCoreTime
);
268 smtStatisticsRegistry()->registerStat(&d_solveTime
);
269 smtStatisticsRegistry()->registerStat(&d_pushPopTime
);
270 smtStatisticsRegistry()->registerStat(&d_processAssertionsTime
);
271 smtStatisticsRegistry()->registerStat(&d_simplifiedToFalse
);
272 smtStatisticsRegistry()->registerStat(&d_resourceUnitsUsed
);
275 ~SmtEngineStatistics() {
276 smtStatisticsRegistry()->unregisterStat(&d_gaussElimTime
);
277 smtStatisticsRegistry()->unregisterStat(&d_definitionExpansionTime
);
278 smtStatisticsRegistry()->unregisterStat(&d_nonclausalSimplificationTime
);
279 smtStatisticsRegistry()->unregisterStat(&d_miplibPassTime
);
280 smtStatisticsRegistry()->unregisterStat(&d_numMiplibAssertionsRemoved
);
281 smtStatisticsRegistry()->unregisterStat(&d_numConstantProps
);
282 smtStatisticsRegistry()->unregisterStat(&d_staticLearningTime
);
283 smtStatisticsRegistry()->unregisterStat(&d_simpITETime
);
284 smtStatisticsRegistry()->unregisterStat(&d_unconstrainedSimpTime
);
285 smtStatisticsRegistry()->unregisterStat(&d_iteRemovalTime
);
286 smtStatisticsRegistry()->unregisterStat(&d_theoryPreprocessTime
);
287 smtStatisticsRegistry()->unregisterStat(&d_rewriteApplyToConstTime
);
288 smtStatisticsRegistry()->unregisterStat(&d_cnfConversionTime
);
289 smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPre
);
290 smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPost
);
291 smtStatisticsRegistry()->unregisterStat(&d_checkModelTime
);
292 smtStatisticsRegistry()->unregisterStat(&d_checkProofTime
);
293 smtStatisticsRegistry()->unregisterStat(&d_checkUnsatCoreTime
);
294 smtStatisticsRegistry()->unregisterStat(&d_solveTime
);
295 smtStatisticsRegistry()->unregisterStat(&d_pushPopTime
);
296 smtStatisticsRegistry()->unregisterStat(&d_processAssertionsTime
);
297 smtStatisticsRegistry()->unregisterStat(&d_simplifiedToFalse
);
298 smtStatisticsRegistry()->unregisterStat(&d_resourceUnitsUsed
);
300 };/* struct SmtEngineStatistics */
303 class SoftResourceOutListener
: public Listener
{
305 SoftResourceOutListener(SmtEngine
& smt
) : d_smt(&smt
) {}
306 void notify() override
308 SmtScope
scope(d_smt
);
309 Assert(smt::smtEngineInScope());
314 }; /* class SoftResourceOutListener */
317 class HardResourceOutListener
: public Listener
{
319 HardResourceOutListener(SmtEngine
& smt
) : d_smt(&smt
) {}
320 void notify() override
322 SmtScope
scope(d_smt
);
323 theory::Rewriter::clearCaches();
327 }; /* class HardResourceOutListener */
329 class SetLogicListener
: public Listener
{
331 SetLogicListener(SmtEngine
& smt
) : d_smt(&smt
) {}
332 void notify() override
334 LogicInfo
inOptions(options::forceLogicString());
335 d_smt
->setLogic(inOptions
);
339 }; /* class SetLogicListener */
341 class BeforeSearchListener
: public Listener
{
343 BeforeSearchListener(SmtEngine
& smt
) : d_smt(&smt
) {}
344 void notify() override
{ d_smt
->beforeSearch(); }
348 }; /* class BeforeSearchListener */
350 class UseTheoryListListener
: public Listener
{
352 UseTheoryListListener(TheoryEngine
* theoryEngine
)
353 : d_theoryEngine(theoryEngine
)
356 void notify() override
358 std::stringstream
commaList(options::useTheoryList());
361 Debug("UseTheoryListListener") << "UseTheoryListListener::notify() "
362 << options::useTheoryList() << std::endl
;
364 while(std::getline(commaList
, token
, ',')){
365 if(token
== "help") {
366 puts(theory::useTheoryHelp
);
369 if(theory::useTheoryValidate(token
)) {
370 d_theoryEngine
->enableTheoryAlternative(token
);
372 throw OptionException(
373 std::string("unknown option for --use-theory : `") + token
+
374 "'. Try --use-theory=help.");
380 TheoryEngine
* d_theoryEngine
;
381 }; /* class UseTheoryListListener */
384 class SetDefaultExprDepthListener
: public Listener
{
386 void notify() override
388 int depth
= options::defaultExprDepth();
389 Debug
.getStream() << expr::ExprSetDepth(depth
);
390 Trace
.getStream() << expr::ExprSetDepth(depth
);
391 Notice
.getStream() << expr::ExprSetDepth(depth
);
392 Chat
.getStream() << expr::ExprSetDepth(depth
);
393 Message
.getStream() << expr::ExprSetDepth(depth
);
394 Warning
.getStream() << expr::ExprSetDepth(depth
);
395 // intentionally exclude Dump stream from this list
399 class SetDefaultExprDagListener
: public Listener
{
401 void notify() override
403 int dag
= options::defaultDagThresh();
404 Debug
.getStream() << expr::ExprDag(dag
);
405 Trace
.getStream() << expr::ExprDag(dag
);
406 Notice
.getStream() << expr::ExprDag(dag
);
407 Chat
.getStream() << expr::ExprDag(dag
);
408 Message
.getStream() << expr::ExprDag(dag
);
409 Warning
.getStream() << expr::ExprDag(dag
);
410 Dump
.getStream() << expr::ExprDag(dag
);
414 class SetPrintExprTypesListener
: public Listener
{
416 void notify() override
418 bool value
= options::printExprTypes();
419 Debug
.getStream() << expr::ExprPrintTypes(value
);
420 Trace
.getStream() << expr::ExprPrintTypes(value
);
421 Notice
.getStream() << expr::ExprPrintTypes(value
);
422 Chat
.getStream() << expr::ExprPrintTypes(value
);
423 Message
.getStream() << expr::ExprPrintTypes(value
);
424 Warning
.getStream() << expr::ExprPrintTypes(value
);
425 // intentionally exclude Dump stream from this list
429 class DumpModeListener
: public Listener
{
431 void notify() override
433 const std::string
& value
= options::dumpModeString();
434 Dump
.setDumpFromString(value
);
438 class PrintSuccessListener
: public Listener
{
440 void notify() override
442 bool value
= options::printSuccess();
443 Debug
.getStream() << Command::printsuccess(value
);
444 Trace
.getStream() << Command::printsuccess(value
);
445 Notice
.getStream() << Command::printsuccess(value
);
446 Chat
.getStream() << Command::printsuccess(value
);
447 Message
.getStream() << Command::printsuccess(value
);
448 Warning
.getStream() << Command::printsuccess(value
);
449 *options::out() << Command::printsuccess(value
);
456 * This is an inelegant solution, but for the present, it will work.
457 * The point of this is to separate the public and private portions of
458 * the SmtEngine class, so that smt_engine.h doesn't
459 * include "expr/node.h", which is a private CVC4 header (and can lead
460 * to linking errors due to the improper inlining of non-visible symbols
463 * The "real" solution (that which is usually implemented) is to move
464 * ALL the implementation to SmtEnginePrivate and maintain a
465 * heap-allocated instance of it in SmtEngine. SmtEngine (the public
466 * one) becomes an "interface shell" which simply acts as a forwarder
469 class SmtEnginePrivate
: public NodeManagerListener
{
472 typedef unordered_map
<Node
, Node
, NodeHashFunction
> NodeToNodeHashMap
;
473 typedef unordered_map
<Node
, bool, NodeHashFunction
> NodeToBoolHashMap
;
476 * Manager for limiting time and abstract resource usage.
478 ResourceManager
* d_resourceManager
;
480 /** Manager for the memory of regular-output-channel. */
481 ManagedRegularOutputChannel d_managedRegularChannel
;
483 /** Manager for the memory of diagnostic-output-channel. */
484 ManagedDiagnosticOutputChannel d_managedDiagnosticChannel
;
486 /** Manager for the memory of --dump-to. */
487 ManagedDumpOStream d_managedDumpChannel
;
489 /** Manager for --replay-log. */
490 ManagedReplayLogOstream d_managedReplayLog
;
493 * This list contains:
497 * beforeSearchListener
498 * UseTheoryListListener
500 * This needs to be deleted before both NodeManager's Options,
501 * SmtEngine, d_resourceManager, and TheoryEngine.
503 ListenerRegistrationList
* d_listenerRegistrations
;
505 /** Learned literals */
506 vector
<Node
> d_nonClausalLearnedLiterals
;
508 /** Size of assertions array when preprocessing starts */
509 unsigned d_realAssertionsEnd
;
511 /** A circuit propagator for non-clausal propositional deduction */
512 booleans::CircuitPropagator d_propagator
;
513 bool d_propagatorNeedsFinish
;
514 std::vector
<Node
> d_boolVars
;
516 /** Assertions in the preprocessing pipeline */
517 AssertionPipeline d_assertions
;
519 /** Whether any assertions have been processed */
520 CDO
<bool> d_assertionsProcessed
;
522 /** Index for where to store substitutions */
523 CDO
<unsigned> d_substitutionsIndex
;
529 * A context that never pushes/pops, for use by CD structures (like
530 * SubstitutionMaps) that should be "global".
532 context::Context d_fakeContext
;
535 * A map of AbsractValues to their actual constants. Only used if
536 * options::abstractValues() is on.
538 SubstitutionMap d_abstractValueMap
;
541 * A mapping of all abstract values (actual value |-> abstract) that
542 * we've handed out. This is necessary to ensure that we give the
543 * same AbstractValues for the same real constants. Only used if
544 * options::abstractValues() is on.
546 NodeToNodeHashMap d_abstractValues
;
548 /** Number of calls of simplify assertions active.
550 unsigned d_simplifyAssertionsDepth
;
552 /** TODO: whether certain preprocess steps are necessary */
553 //bool d_needsExpandDefs;
555 //------------------------------- expression names
556 /** mapping from expressions to name */
557 context::CDHashMap
< Node
, std::string
, NodeHashFunction
> d_exprNames
;
558 //------------------------------- end expression names
561 * Map from skolem variables to index in d_assertions containing
562 * corresponding introduced Boolean ite
564 IteSkolemMap d_iteSkolemMap
;
566 /** Instance of the ITE remover */
567 RemoveTermFormulas d_iteRemover
;
569 /* Finishes the initialization of the private portion of SMTEngine. */
573 std::unique_ptr
<PreprocessingPassContext
> d_preprocessingPassContext
;
574 PreprocessingPassRegistry d_preprocessingPassRegistry
;
576 /** The top level substitutions */
577 SubstitutionMap d_topLevelSubstitutions
;
579 static const bool d_doConstantProp
= true;
582 * Runs the nonclausal solver and tries to solve all the assigned
585 * Returns false if the formula simplifies to "false"
587 bool nonClausalSimplify();
590 * Performs static learning on the assertions.
592 void staticLearning();
595 * Remove ITEs from the assertions.
599 Node
realToInt(TNode n
, NodeToNodeHashMap
& cache
, std::vector
< Node
>& var_eq
);
600 Node
purifyNlTerms(TNode n
, NodeToNodeHashMap
& cache
, NodeToNodeHashMap
& bcache
, std::vector
< Node
>& var_eq
, bool beneathMult
= false);
603 * Helper function to fix up assertion list to restore invariants needed after
606 void collectSkolems(TNode n
, set
<TNode
>& skolemSet
, NodeToBoolHashMap
& cache
);
609 * Helper function to fix up assertion list to restore invariants needed after
612 bool checkForBadSkolems(TNode n
, TNode skolem
, NodeToBoolHashMap
& cache
);
614 // Lift bit-vectors of size 1 to booleans
617 // Convert booleans to bit-vectors of size 1
620 // Abstract common structure over small domains to UF
621 // return true if changes were made.
622 void bvAbstraction();
624 // Simplify ITE structure
627 // Simplify based on unconstrained values
628 void unconstrainedSimp();
631 * Ensures the assertions asserted after before now effectively come before
632 * d_realAssertionsEnd.
634 void compressBeforeRealAssertions(size_t before
);
637 * Trace nodes back to their assertions using CircuitPropagator's
640 void traceBackToAssertions(const std::vector
<Node
>& nodes
,
641 std::vector
<TNode
>& assertions
);
644 * Remove conjuncts in toRemove from conjunction n. Return # of removed
647 size_t removeFromConjunction(Node
& n
,
648 const std::unordered_set
<unsigned long>& toRemove
);
650 /** Scrub miplib encodings. */
651 void doMiplibTrick();
654 * Perform non-clausal simplification of a Node. This involves
655 * Theory implementations, but does NOT involve the SAT solver in
658 * Returns false if the formula simplifies to "false"
660 bool simplifyAssertions();
664 SmtEnginePrivate(SmtEngine
& smt
) :
666 d_managedRegularChannel(),
667 d_managedDiagnosticChannel(),
668 d_managedDumpChannel(),
669 d_managedReplayLog(),
670 d_listenerRegistrations(new ListenerRegistrationList()),
671 d_nonClausalLearnedLiterals(),
672 d_realAssertionsEnd(0),
673 d_propagator(d_nonClausalLearnedLiterals
, true, true),
674 d_propagatorNeedsFinish(false),
676 d_assertionsProcessed(smt
.d_userContext
, false),
677 d_substitutionsIndex(smt
.d_userContext
, 0),
679 d_abstractValueMap(&d_fakeContext
),
681 d_simplifyAssertionsDepth(0),
682 //d_needsExpandDefs(true), //TODO?
683 d_exprNames(smt
.d_userContext
),
685 d_iteRemover(smt
.d_userContext
),
686 d_topLevelSubstitutions(smt
.d_userContext
)
688 d_smt
.d_nodeManager
->subscribeEvents(this);
689 d_true
= NodeManager::currentNM()->mkConst(true);
690 d_resourceManager
= NodeManager::currentResourceManager();
692 d_listenerRegistrations
->add(d_resourceManager
->registerSoftListener(
693 new SoftResourceOutListener(d_smt
)));
695 d_listenerRegistrations
->add(d_resourceManager
->registerHardListener(
696 new HardResourceOutListener(d_smt
)));
698 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
699 d_listenerRegistrations
->add(
700 nodeManagerOptions
.registerForceLogicListener(
701 new SetLogicListener(d_smt
), true));
703 // Multiple options reuse BeforeSearchListener so registration requires an
704 // extra bit of care.
705 // We can safely not call notify on this before search listener at
706 // registration time. This d_smt cannot be beforeSearch at construction
707 // time. Therefore the BeforeSearchListener is a no-op. Therefore it does
708 // not have to be called.
709 d_listenerRegistrations
->add(
710 nodeManagerOptions
.registerBeforeSearchListener(
711 new BeforeSearchListener(d_smt
)));
713 // These do need registration calls.
714 d_listenerRegistrations
->add(
715 nodeManagerOptions
.registerSetDefaultExprDepthListener(
716 new SetDefaultExprDepthListener(), true));
717 d_listenerRegistrations
->add(
718 nodeManagerOptions
.registerSetDefaultExprDagListener(
719 new SetDefaultExprDagListener(), true));
720 d_listenerRegistrations
->add(
721 nodeManagerOptions
.registerSetPrintExprTypesListener(
722 new SetPrintExprTypesListener(), true));
723 d_listenerRegistrations
->add(
724 nodeManagerOptions
.registerSetDumpModeListener(
725 new DumpModeListener(), true));
726 d_listenerRegistrations
->add(
727 nodeManagerOptions
.registerSetPrintSuccessListener(
728 new PrintSuccessListener(), true));
729 d_listenerRegistrations
->add(
730 nodeManagerOptions
.registerSetRegularOutputChannelListener(
731 new SetToDefaultSourceListener(&d_managedRegularChannel
), true));
732 d_listenerRegistrations
->add(
733 nodeManagerOptions
.registerSetDiagnosticOutputChannelListener(
734 new SetToDefaultSourceListener(&d_managedDiagnosticChannel
), true));
735 d_listenerRegistrations
->add(
736 nodeManagerOptions
.registerDumpToFileNameListener(
737 new SetToDefaultSourceListener(&d_managedDumpChannel
), true));
738 d_listenerRegistrations
->add(
739 nodeManagerOptions
.registerSetReplayLogFilename(
740 new SetToDefaultSourceListener(&d_managedReplayLog
), true));
745 delete d_listenerRegistrations
;
747 if(d_propagatorNeedsFinish
) {
748 d_propagator
.finish();
749 d_propagatorNeedsFinish
= false;
751 d_smt
.d_nodeManager
->unsubscribeEvents(this);
754 ResourceManager
* getResourceManager() { return d_resourceManager
; }
755 void spendResource(unsigned amount
)
757 d_resourceManager
->spendResource(amount
);
760 void nmNotifyNewSort(TypeNode tn
, uint32_t flags
) override
762 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
765 if((flags
& ExprManager::SORT_FLAG_PLACEHOLDER
) == 0) {
766 d_smt
.addToModelCommandAndDump(c
, flags
);
770 void nmNotifyNewSortConstructor(TypeNode tn
) override
772 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
773 tn
.getAttribute(expr::SortArityAttr()),
775 d_smt
.addToModelCommandAndDump(c
);
778 void nmNotifyNewDatatypes(const std::vector
<DatatypeType
>& dtts
) override
780 DatatypeDeclarationCommand
c(dtts
);
781 d_smt
.addToModelCommandAndDump(c
);
784 void nmNotifyNewVar(TNode n
, uint32_t flags
) override
786 DeclareFunctionCommand
c(n
.getAttribute(expr::VarNameAttr()),
788 n
.getType().toType());
789 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
790 d_smt
.addToModelCommandAndDump(c
, flags
);
792 if(n
.getType().isBoolean() && !options::incrementalSolving()) {
793 d_boolVars
.push_back(n
);
797 void nmNotifyNewSkolem(TNode n
,
798 const std::string
& comment
,
799 uint32_t flags
) override
801 string id
= n
.getAttribute(expr::VarNameAttr());
802 DeclareFunctionCommand
c(id
, n
.toExpr(), n
.getType().toType());
803 if(Dump
.isOn("skolems") && comment
!= "") {
804 Dump("skolems") << CommentCommand(id
+ " is " + comment
);
806 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
807 d_smt
.addToModelCommandAndDump(c
, flags
, false, "skolems");
809 if(n
.getType().isBoolean() && !options::incrementalSolving()) {
810 d_boolVars
.push_back(n
);
814 void nmNotifyDeleteNode(TNode n
) override
{}
816 Node
applySubstitutions(TNode node
) const {
817 return Rewriter::rewrite(d_topLevelSubstitutions
.apply(node
));
821 * Apply the substitutions in d_topLevelAssertions and the rewriter to each of
822 * the assertions in d_assertions, and store the result back in d_assertions.
824 void applySubstitutionsToAssertions();
827 * Process the assertions that have been asserted.
829 void processAssertions();
831 /** Process a user push.
838 * Process a user pop. Clears out the non-context-dependent stuff in this
839 * SmtEnginePrivate. Necessary to clear out our assertion vectors in case
840 * someone does a push-assert-pop without a check-sat. It also pops the
841 * last map of expression names from notifyPush.
844 d_assertions
.clear();
845 d_nonClausalLearnedLiterals
.clear();
846 d_realAssertionsEnd
= 0;
847 d_iteSkolemMap
.clear();
851 * Adds a formula to the current context. Action here depends on
852 * the SimplificationMode (in the current Options scope); the
853 * formula might be pushed out to the propositional layer
854 * immediately, or it might be simplified and kept, or it might not
855 * even be simplified.
856 * the 2nd and 3rd arguments added for bookkeeping for proofs
858 void addFormula(TNode n
, bool inUnsatCore
, bool inInput
= true);
860 /** Expand definitions in n. */
861 Node
expandDefinitions(TNode n
,
862 NodeToNodeHashMap
& cache
,
863 bool expandOnly
= false);
866 * Simplify node "in" by expanding definitions and applying any
867 * substitutions learned from preprocessing.
869 Node
simplify(TNode in
) {
870 // Substitute out any abstract values in ex.
871 // Expand definitions.
872 NodeToNodeHashMap cache
;
873 Node n
= expandDefinitions(in
, cache
).toExpr();
874 // Make sure we've done all preprocessing, etc.
875 Assert(d_assertions
.size() == 0);
876 return applySubstitutions(n
).toExpr();
880 * Substitute away all AbstractValues in a node.
882 Node
substituteAbstractValues(TNode n
) {
883 // We need to do this even if options::abstractValues() is off,
884 // since the setting might have changed after we already gave out
885 // some abstract values.
886 return d_abstractValueMap
.apply(n
);
890 * Make a new (or return an existing) abstract value for a node.
891 * Can only use this if options::abstractValues() is on.
893 Node
mkAbstractValue(TNode n
) {
894 Assert(options::abstractValues());
895 Node
& val
= d_abstractValues
[n
];
897 val
= d_smt
.d_nodeManager
->mkAbstractValue(n
.getType());
898 d_abstractValueMap
.addSubstitution(val
, n
);
900 // We are supposed to ascribe types to all abstract values that go out.
901 NodeManager
* current
= d_smt
.d_nodeManager
;
902 Node ascription
= current
->mkConst(AscriptionType(n
.getType().toType()));
903 Node retval
= current
->mkNode(kind::APPLY_TYPE_ASCRIPTION
, ascription
, val
);
907 NodeToNodeHashMap d_rewriteApplyToConstCache
;
908 Node
rewriteApplyToConst(TNode n
) {
909 Trace("rewriteApplyToConst") << "rewriteApplyToConst :: " << n
<< std::endl
;
911 if(n
.getMetaKind() == kind::metakind::CONSTANT
||
912 n
.getMetaKind() == kind::metakind::VARIABLE
||
913 n
.getMetaKind() == kind::metakind::NULLARY_OPERATOR
)
918 if(d_rewriteApplyToConstCache
.find(n
) != d_rewriteApplyToConstCache
.end()) {
919 Trace("rewriteApplyToConst") << "in cache :: "
920 << d_rewriteApplyToConstCache
[n
]
922 return d_rewriteApplyToConstCache
[n
];
925 if(n
.getKind() == kind::APPLY_UF
) {
926 if(n
.getNumChildren() == 1 && n
[0].isConst() &&
927 n
[0].getType().isInteger())
930 ss
<< n
.getOperator() << "_";
931 if(n
[0].getConst
<Rational
>() < 0) {
932 ss
<< "m" << -n
[0].getConst
<Rational
>();
936 Node newvar
= NodeManager::currentNM()->mkSkolem(
937 ss
.str(), n
.getType(), "rewriteApplyToConst skolem",
938 NodeManager::SKOLEM_EXACT_NAME
);
939 d_rewriteApplyToConstCache
[n
] = newvar
;
940 Trace("rewriteApplyToConst") << "made :: " << newvar
<< std::endl
;
944 ss
<< "The rewrite-apply-to-const preprocessor is currently limited;"
946 << "it only works if all function symbols are unary and with Integer"
948 << "domain, and all applications are to integer values." << std::endl
949 << "Found application: " << n
;
954 NodeBuilder
<> builder(n
.getKind());
955 if(n
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
956 builder
<< n
.getOperator();
958 for(unsigned i
= 0; i
< n
.getNumChildren(); ++i
) {
959 builder
<< rewriteApplyToConst(n
[i
]);
962 d_rewriteApplyToConstCache
[n
] = rewr
;
963 Trace("rewriteApplyToConst") << "built :: " << rewr
<< std::endl
;
967 void addUseTheoryListListener(TheoryEngine
* theoryEngine
){
968 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
969 d_listenerRegistrations
->add(
970 nodeManagerOptions
.registerUseTheoryListListener(
971 new UseTheoryListListener(theoryEngine
), true));
974 std::ostream
* getReplayLog() const {
975 return d_managedReplayLog
.getReplayLog();
978 //------------------------------- expression names
979 // implements setExpressionName, as described in smt_engine.h
980 void setExpressionName(Expr e
, std::string name
) {
981 d_exprNames
[Node::fromExpr(e
)] = name
;
984 // implements getExpressionName, as described in smt_engine.h
985 bool getExpressionName(Expr e
, std::string
& name
) const {
986 context::CDHashMap
< Node
, std::string
, NodeHashFunction
>::const_iterator it
= d_exprNames
.find(e
);
987 if(it
!=d_exprNames
.end()) {
994 //------------------------------- end expression names
996 };/* class SmtEnginePrivate */
998 }/* namespace CVC4::smt */
1000 SmtEngine::SmtEngine(ExprManager
* em
)
1001 : d_context(new Context()),
1003 d_userContext(new UserContext()),
1005 d_nodeManager(d_exprManager
->getNodeManager()),
1006 d_decisionEngine(NULL
),
1007 d_theoryEngine(NULL
),
1009 d_proofManager(NULL
),
1010 d_definedFunctions(NULL
),
1011 d_fmfRecFunctionsDefined(NULL
),
1012 d_assertionList(NULL
),
1013 d_assignments(NULL
),
1014 d_modelGlobalCommands(),
1015 d_modelCommands(NULL
),
1019 d_originalOptions(),
1021 d_fullyInited(false),
1022 d_problemExtended(false),
1024 d_needPostsolve(false),
1025 d_earlyTheoryPP(true),
1026 d_globalNegation(false),
1028 d_replayStream(NULL
),
1030 d_statisticsRegistry(NULL
),
1032 d_channels(new LemmaChannels())
1034 SmtScope
smts(this);
1035 d_originalOptions
.copyValues(em
->getOptions());
1036 d_private
= new smt::SmtEnginePrivate(*this);
1037 d_statisticsRegistry
= new StatisticsRegistry();
1038 d_stats
= new SmtEngineStatistics();
1039 d_stats
->d_resourceUnitsUsed
.setData(
1040 d_private
->getResourceManager()->getResourceUsage());
1042 // The ProofManager is constructed before any other proof objects such as
1043 // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
1044 // initialized in TheoryEngine and PropEngine respectively.
1045 Assert(d_proofManager
== NULL
);
1047 // d_proofManager must be created before Options has been finished
1048 // being parsed from the input file. Because of this, we cannot trust
1049 // that options::proof() is set correctly yet.
1051 d_proofManager
= new ProofManager(d_userContext
);
1054 // We have mutual dependency here, so we add the prop engine to the theory
1055 // engine later (it is non-essential there)
1056 d_theoryEngine
= new TheoryEngine(d_context
, d_userContext
,
1057 d_private
->d_iteRemover
,
1058 const_cast<const LogicInfo
&>(d_logic
),
1062 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
1063 TheoryConstructor::addTheory(d_theoryEngine
, id
);
1064 //register with proof engine if applicable
1066 ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine
->theoryOf(id
));
1070 d_private
->addUseTheoryListListener(d_theoryEngine
);
1072 // global push/pop around everything, to ensure proper destruction
1073 // of context-dependent data structures
1074 d_userContext
->push();
1077 d_definedFunctions
= new(true) DefinedFunctionMap(d_userContext
);
1078 d_fmfRecFunctionsDefined
= new(true) NodeList(d_userContext
);
1079 d_modelCommands
= new(true) smt::CommandList(d_userContext
);
1082 void SmtEngine::finishInit() {
1083 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl
;
1084 // ensure that our heuristics are properly set up
1087 Trace("smt-debug") << "Making decision engine..." << std::endl
;
1089 d_decisionEngine
= new DecisionEngine(d_context
, d_userContext
);
1090 d_decisionEngine
->init(); // enable appropriate strategies
1092 Trace("smt-debug") << "Making prop engine..." << std::endl
;
1093 d_propEngine
= new PropEngine(d_theoryEngine
, d_decisionEngine
, d_context
,
1094 d_userContext
, d_private
->getReplayLog(),
1095 d_replayStream
, d_channels
);
1097 Trace("smt-debug") << "Setting up theory engine..." << std::endl
;
1098 d_theoryEngine
->setPropEngine(d_propEngine
);
1099 d_theoryEngine
->setDecisionEngine(d_decisionEngine
);
1100 Trace("smt-debug") << "Finishing init for theory engine..." << std::endl
;
1101 d_theoryEngine
->finishInit();
1103 Trace("smt-debug") << "Set up assertion list..." << std::endl
;
1104 // [MGD 10/20/2011] keep around in incremental mode, due to a
1105 // cleanup ordering issue and Nodes/TNodes. If SAT is popped
1106 // first, some user-context-dependent TNodes might still exist
1108 if(options::produceAssertions() ||
1109 options::incrementalSolving()) {
1110 // In the case of incremental solving, we appear to need these to
1111 // ensure the relevant Nodes remain live.
1112 d_assertionList
= new(true) AssertionList(d_userContext
);
1115 // dump out a set-logic command
1116 if(Dump
.isOn("benchmark")) {
1117 if (Dump
.isOn("raw-benchmark")) {
1118 Dump("raw-benchmark") << SetBenchmarkLogicCommand(d_logic
.getLogicString());
1120 LogicInfo everything
;
1122 Dump("benchmark") << CommentCommand("CVC4 always dumps the most general, all-supported logic (below), as some internals might require the use of a logic more general than the input.")
1123 << SetBenchmarkLogicCommand(everything
.getLogicString());
1127 Trace("smt-debug") << "Dump declaration commands..." << std::endl
;
1128 // dump out any pending declaration commands
1129 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
1130 Dump("declarations") << *d_dumpCommands
[i
];
1131 delete d_dumpCommands
[i
];
1133 d_dumpCommands
.clear();
1135 PROOF( ProofManager::currentPM()->setLogic(d_logic
); );
1137 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
1138 ProofManager::currentPM()->getTheoryProofEngine()->
1139 finishRegisterTheory(d_theoryEngine
->theoryOf(id
));
1142 d_private
->finishInit();
1143 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl
;
1146 void SmtEngine::finalOptionsAreSet() {
1151 if(! d_logic
.isLocked()) {
1155 // finish initialization, create the prop engine, etc.
1158 AlwaysAssert( d_propEngine
->getAssertionLevel() == 0,
1159 "The PropEngine has pushed but the SmtEngine "
1160 "hasn't finished initializing!" );
1162 d_fullyInited
= true;
1163 Assert(d_logic
.isLocked());
1165 d_propEngine
->assertFormula(NodeManager::currentNM()->mkConst
<bool>(true));
1166 d_propEngine
->assertFormula(NodeManager::currentNM()->mkConst
<bool>(false).notNode());
1169 void SmtEngine::shutdown() {
1172 while(options::incrementalSolving() && d_userContext
->getLevel() > 1) {
1176 // check to see if a postsolve() is pending
1177 if(d_needPostsolve
) {
1178 d_theoryEngine
->postsolve();
1179 d_needPostsolve
= false;
1182 if(d_propEngine
!= NULL
) {
1183 d_propEngine
->shutdown();
1185 if(d_theoryEngine
!= NULL
) {
1186 d_theoryEngine
->shutdown();
1188 if(d_decisionEngine
!= NULL
) {
1189 d_decisionEngine
->shutdown();
1193 SmtEngine::~SmtEngine()
1195 SmtScope
smts(this);
1200 // global push/pop around everything, to ensure proper destruction
1201 // of context-dependent data structures
1202 d_context
->popto(0);
1203 d_userContext
->popto(0);
1205 if(d_assignments
!= NULL
) {
1206 d_assignments
->deleteSelf();
1209 if(d_assertionList
!= NULL
) {
1210 d_assertionList
->deleteSelf();
1213 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
1214 delete d_dumpCommands
[i
];
1215 d_dumpCommands
[i
] = NULL
;
1217 d_dumpCommands
.clear();
1219 DeleteAndClearCommandVector(d_modelGlobalCommands
);
1221 if(d_modelCommands
!= NULL
) {
1222 d_modelCommands
->deleteSelf();
1225 d_definedFunctions
->deleteSelf();
1226 d_fmfRecFunctionsDefined
->deleteSelf();
1228 delete d_theoryEngine
;
1229 d_theoryEngine
= NULL
;
1230 delete d_propEngine
;
1231 d_propEngine
= NULL
;
1232 delete d_decisionEngine
;
1233 d_decisionEngine
= NULL
;
1236 // d_proofManager is always created when proofs are enabled at configure time.
1237 // Becuase of this, this code should not be wrapped in PROOF() which
1238 // additionally checks flags such as options::proof().
1240 delete d_proofManager
;
1241 d_proofManager
= NULL
;
1246 delete d_statisticsRegistry
;
1247 d_statisticsRegistry
= NULL
;
1252 delete d_userContext
;
1253 d_userContext
= NULL
;
1260 } catch(Exception
& e
) {
1261 Warning() << "CVC4 threw an exception during cleanup." << endl
1266 void SmtEngine::setLogic(const LogicInfo
& logic
)
1268 SmtScope
smts(this);
1270 throw ModalException("Cannot set logic in SmtEngine after the engine has "
1271 "finished initializing.");
1277 void SmtEngine::setLogic(const std::string
& s
)
1279 SmtScope
smts(this);
1281 setLogic(LogicInfo(s
));
1282 } catch(IllegalArgumentException
& e
) {
1283 throw LogicException(e
.what());
1287 void SmtEngine::setLogic(const char* logic
) { setLogic(string(logic
)); }
1288 LogicInfo
SmtEngine::getLogicInfo() const {
1291 void SmtEngine::setLogicInternal()
1293 Assert(!d_fullyInited
, "setting logic in SmtEngine but the engine has already"
1294 " finished initializing for this run");
1298 void SmtEngine::setDefaults() {
1299 Random::getRandom().setSeed(options::seed());
1300 // Language-based defaults
1301 if (!options::bitvectorDivByZeroConst
.wasSetByUser())
1303 options::bitvectorDivByZeroConst
.set(options::inputLanguage()
1304 == language::input::LANG_SMTLIB_V2_6
);
1306 if (options::inputLanguage() == language::input::LANG_SYGUS
)
1308 if (!options::ceGuidedInst
.wasSetByUser())
1310 options::ceGuidedInst
.set(true);
1312 // must use Ferrante/Rackoff for real arithmetic
1313 if (!options::cbqiMidpoint
.wasSetByUser())
1315 options::cbqiMidpoint
.set(true);
1319 if(options::forceLogicString
.wasSetByUser()) {
1320 d_logic
= LogicInfo(options::forceLogicString());
1321 }else if (options::solveIntAsBV() > 0) {
1322 d_logic
= LogicInfo("QF_BV");
1323 }else if (d_logic
.getLogicString() == "QF_NRA" && options::solveRealAsInt()) {
1324 d_logic
= LogicInfo("QF_NIA");
1325 } else if ((d_logic
.getLogicString() == "QF_UFBV" ||
1326 d_logic
.getLogicString() == "QF_ABV") &&
1327 options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
) {
1328 d_logic
= LogicInfo("QF_BV");
1332 /* - disabled for 1.4 release [MGD 2014.06.25]
1333 if(!d_logic.hasEverything() && d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
1334 if(! options::stringExp.wasSetByUser()) {
1335 options::stringExp.set( true );
1336 Trace("smt") << "turning on strings-exp, for the theory of strings" << std::endl;
1341 if(options::stringExp()) {
1342 if( !d_logic
.isQuantified() ) {
1343 d_logic
= d_logic
.getUnlockedCopy();
1344 d_logic
.enableQuantifiers();
1346 Trace("smt") << "turning on quantifier logic, for strings-exp"
1349 if(! options::fmfBound
.wasSetByUser()) {
1350 options::fmfBound
.set( true );
1351 Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl
;
1353 if(! options::fmfInstEngine
.wasSetByUser()) {
1354 options::fmfInstEngine
.set( true );
1355 Trace("smt") << "turning on fmf-inst-engine, for strings-exp" << std::endl
;
1358 if(! options::rewriteDivk.wasSetByUser()) {
1359 options::rewriteDivk.set( true );
1360 Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
1363 if(! options::stringFMF.wasSetByUser()) {
1364 options::stringFMF.set( true );
1365 Trace("smt") << "turning on strings-fmf, for strings-exp" << std::endl;
1370 // sygus inference may require datatypes
1371 if (options::sygusInference())
1373 d_logic
= d_logic
.getUnlockedCopy();
1374 d_logic
.enableTheory(THEORY_DATATYPES
);
1378 if ((options::checkModels() || options::checkSynthSol())
1379 && !options::produceAssertions())
1381 Notice() << "SmtEngine: turning on produce-assertions to support "
1382 << "check-models or check-synth-sol." << endl
;
1383 setOption("produce-assertions", SExpr("true"));
1386 if(options::unsatCores()) {
1387 if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
1388 if(options::simplificationMode
.wasSetByUser()) {
1389 throw OptionException("simplification not supported with unsat cores");
1391 Notice() << "SmtEngine: turning off simplification to support unsat-cores"
1393 options::simplificationMode
.set(SIMPLIFICATION_MODE_NONE
);
1396 if(options::unconstrainedSimp()) {
1397 if(options::unconstrainedSimp
.wasSetByUser()) {
1398 throw OptionException("unconstrained simplification not supported with unsat cores");
1400 Notice() << "SmtEngine: turning off unconstrained simplification to support unsat-cores" << endl
;
1401 options::unconstrainedSimp
.set(false);
1404 if(options::pbRewrites()) {
1405 if(options::pbRewrites
.wasSetByUser()) {
1406 throw OptionException("pseudoboolean rewrites not supported with unsat cores");
1408 Notice() << "SmtEngine: turning off pseudoboolean rewrites to support unsat-cores" << endl
;
1409 setOption("pb-rewrites", false);
1412 if(options::sortInference()) {
1413 if(options::sortInference
.wasSetByUser()) {
1414 throw OptionException("sort inference not supported with unsat cores");
1416 Notice() << "SmtEngine: turning off sort inference to support unsat-cores" << endl
;
1417 options::sortInference
.set(false);
1420 if(options::preSkolemQuant()) {
1421 if(options::preSkolemQuant
.wasSetByUser()) {
1422 throw OptionException("pre-skolemization not supported with unsat cores");
1424 Notice() << "SmtEngine: turning off pre-skolemization to support unsat-cores" << endl
;
1425 options::preSkolemQuant
.set(false);
1428 if(options::bitvectorToBool()) {
1429 if(options::bitvectorToBool
.wasSetByUser()) {
1430 throw OptionException("bv-to-bool not supported with unsat cores");
1432 Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat-cores" << endl
;
1433 options::bitvectorToBool
.set(false);
1436 if(options::boolToBitvector()) {
1437 if(options::boolToBitvector
.wasSetByUser()) {
1438 throw OptionException("bool-to-bv not supported with unsat cores");
1440 Notice() << "SmtEngine: turning off bool-to-bitvector to support unsat-cores" << endl
;
1441 options::boolToBitvector
.set(false);
1444 if(options::bvIntroducePow2()) {
1445 if(options::bvIntroducePow2
.wasSetByUser()) {
1446 throw OptionException("bv-intro-pow2 not supported with unsat cores");
1448 Notice() << "SmtEngine: turning off bv-intro-pow2 to support unsat-cores" << endl
;
1449 setOption("bv-intro-pow2", false);
1452 if(options::repeatSimp()) {
1453 if(options::repeatSimp
.wasSetByUser()) {
1454 throw OptionException("repeat-simp not supported with unsat cores");
1456 Notice() << "SmtEngine: turning off repeat-simp to support unsat-cores" << endl
;
1457 setOption("repeat-simp", false);
1460 if (options::globalNegate())
1462 if (options::globalNegate
.wasSetByUser())
1464 throw OptionException("global-negate not supported with unsat cores");
1466 Notice() << "SmtEngine: turning off global-negate to support unsat-cores"
1468 setOption("global-negate", false);
1472 if (options::cbqiBv() && d_logic
.isQuantified())
1474 if(options::boolToBitvector
.wasSetByUser()) {
1475 throw OptionException(
1476 "bool-to-bv not supported with CBQI BV for quantified logics");
1478 Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
1480 options::boolToBitvector
.set(false);
1483 // cases where we need produce models
1484 if (!options::produceModels()
1485 && (options::produceAssignments() || options::sygusRewSynthCheck()))
1487 Notice() << "SmtEngine: turning on produce-models" << endl
;
1488 setOption("produce-models", SExpr("true"));
1491 // Set the options for the theoryOf
1492 if(!options::theoryOfMode
.wasSetByUser()) {
1493 if(d_logic
.isSharingEnabled() &&
1494 !d_logic
.isTheoryEnabled(THEORY_BV
) &&
1495 !d_logic
.isTheoryEnabled(THEORY_STRINGS
) &&
1496 !d_logic
.isTheoryEnabled(THEORY_SETS
) ) {
1497 Trace("smt") << "setting theoryof-mode to term-based" << endl
;
1498 options::theoryOfMode
.set(THEORY_OF_TERM_BASED
);
1502 // strings require LIA, UF; widen the logic
1503 if(d_logic
.isTheoryEnabled(THEORY_STRINGS
)) {
1504 LogicInfo
log(d_logic
.getUnlockedCopy());
1505 // Strings requires arith for length constraints, and also UF
1506 if(!d_logic
.isTheoryEnabled(THEORY_UF
)) {
1507 Trace("smt") << "because strings are enabled, also enabling UF" << endl
;
1508 log
.enableTheory(THEORY_UF
);
1510 if(!d_logic
.isTheoryEnabled(THEORY_ARITH
) || d_logic
.isDifferenceLogic() || !d_logic
.areIntegersUsed()) {
1511 Trace("smt") << "because strings are enabled, also enabling linear integer arithmetic" << endl
;
1512 log
.enableTheory(THEORY_ARITH
);
1513 log
.enableIntegers();
1514 log
.arithOnlyLinear();
1519 if(d_logic
.isTheoryEnabled(THEORY_ARRAYS
) || d_logic
.isTheoryEnabled(THEORY_DATATYPES
) || d_logic
.isTheoryEnabled(THEORY_SETS
)) {
1520 if(!d_logic
.isTheoryEnabled(THEORY_UF
)) {
1521 LogicInfo
log(d_logic
.getUnlockedCopy());
1522 Trace("smt") << "because a theory that permits Boolean terms is enabled, also enabling UF" << endl
;
1523 log
.enableTheory(THEORY_UF
);
1529 // by default, symmetry breaker is on only for QF_UF
1530 if(! options::ufSymmetryBreaker
.wasSetByUser()) {
1531 bool qf_uf
= d_logic
.isPure(THEORY_UF
) && !d_logic
.isQuantified() && !options::proof();
1532 Trace("smt") << "setting uf symmetry breaker to " << qf_uf
<< endl
;
1533 options::ufSymmetryBreaker
.set(qf_uf
);
1535 // by default, nonclausal simplification is off for QF_SAT
1536 if(! options::simplificationMode
.wasSetByUser()) {
1537 bool qf_sat
= d_logic
.isPure(THEORY_BOOL
) && !d_logic
.isQuantified();
1538 Trace("smt") << "setting simplification mode to <" << d_logic
.getLogicString() << "> " << (!qf_sat
) << endl
;
1539 //simplification=none works better for SMT LIB benchmarks with quantifiers, not others
1540 //options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
1541 options::simplificationMode
.set(qf_sat
? SIMPLIFICATION_MODE_NONE
: SIMPLIFICATION_MODE_BATCH
);
1544 // If in arrays, set the UF handler to arrays
1545 if(d_logic
.isTheoryEnabled(THEORY_ARRAYS
) && ( !d_logic
.isQuantified() ||
1546 (d_logic
.isQuantified() && !d_logic
.isTheoryEnabled(THEORY_UF
)))) {
1547 Theory::setUninterpretedSortOwner(THEORY_ARRAYS
);
1549 Theory::setUninterpretedSortOwner(THEORY_UF
);
1552 // Turn on ite simplification for QF_LIA and QF_AUFBV
1553 // WARNING: These checks match much more than just QF_AUFBV and
1554 // QF_LIA logics. --K [2014/10/15]
1555 if(! options::doITESimp
.wasSetByUser()) {
1556 bool qf_aufbv
= !d_logic
.isQuantified() &&
1557 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1558 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1559 d_logic
.isTheoryEnabled(THEORY_BV
);
1560 bool qf_lia
= !d_logic
.isQuantified() &&
1561 d_logic
.isPure(THEORY_ARITH
) &&
1562 d_logic
.isLinear() &&
1563 !d_logic
.isDifferenceLogic() &&
1564 !d_logic
.areRealsUsed();
1566 bool iteSimp
= (qf_aufbv
|| qf_lia
);
1567 Trace("smt") << "setting ite simplification to " << iteSimp
<< endl
;
1568 options::doITESimp
.set(iteSimp
);
1570 if(! options::compressItes
.wasSetByUser() ){
1571 bool qf_lia
= !d_logic
.isQuantified() &&
1572 d_logic
.isPure(THEORY_ARITH
) &&
1573 d_logic
.isLinear() &&
1574 !d_logic
.isDifferenceLogic() &&
1575 !d_logic
.areRealsUsed();
1577 bool compressIte
= qf_lia
;
1578 Trace("smt") << "setting ite compression to " << compressIte
<< endl
;
1579 options::compressItes
.set(compressIte
);
1581 if(! options::simplifyWithCareEnabled
.wasSetByUser() ){
1582 bool qf_aufbv
= !d_logic
.isQuantified() &&
1583 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1584 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1585 d_logic
.isTheoryEnabled(THEORY_BV
);
1587 bool withCare
= qf_aufbv
;
1588 Trace("smt") << "setting ite simplify with care to " << withCare
<< endl
;
1589 options::simplifyWithCareEnabled
.set(withCare
);
1591 // Turn off array eager index splitting for QF_AUFLIA
1592 if(! options::arraysEagerIndexSplitting
.wasSetByUser()) {
1593 if (not d_logic
.isQuantified() &&
1594 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1595 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1596 d_logic
.isTheoryEnabled(THEORY_ARITH
)) {
1597 Trace("smt") << "setting array eager index splitting to false" << endl
;
1598 options::arraysEagerIndexSplitting
.set(false);
1601 // Turn on model-based arrays for QF_AX (unless models are enabled)
1602 // if(! options::arraysModelBased.wasSetByUser()) {
1603 // if (not d_logic.isQuantified() &&
1604 // d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1605 // d_logic.isPure(THEORY_ARRAYS) &&
1606 // !options::produceModels() &&
1607 // !options::checkModels()) {
1608 // Trace("smt") << "turning on model-based array solver" << endl;
1609 // options::arraysModelBased.set(true);
1612 // Turn on multiple-pass non-clausal simplification for QF_AUFBV
1613 if(! options::repeatSimp
.wasSetByUser()) {
1614 bool repeatSimp
= !d_logic
.isQuantified() &&
1615 (d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1616 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1617 d_logic
.isTheoryEnabled(THEORY_BV
)) &&
1618 !options::unsatCores();
1619 Trace("smt") << "setting repeat simplification to " << repeatSimp
<< endl
;
1620 options::repeatSimp
.set(repeatSimp
);
1622 // Turn on unconstrained simplification for QF_AUFBV
1623 if(!options::unconstrainedSimp
.wasSetByUser() ||
1624 options::incrementalSolving()) {
1625 // bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
1626 // bool uncSimp = false && !qf_sat && !options::incrementalSolving();
1627 bool uncSimp
= !options::incrementalSolving() &&
1628 !d_logic
.isQuantified() &&
1629 !options::produceModels() &&
1630 !options::produceAssignments() &&
1631 !options::checkModels() &&
1632 !options::unsatCores() &&
1633 (d_logic
.isTheoryEnabled(THEORY_ARRAYS
) && d_logic
.isTheoryEnabled(THEORY_BV
));
1634 Trace("smt") << "setting unconstrained simplification to " << uncSimp
<< endl
;
1635 options::unconstrainedSimp
.set(uncSimp
);
1637 // Unconstrained simp currently does *not* support model generation
1638 if (options::unconstrainedSimp
.wasSetByUser() && options::unconstrainedSimp()) {
1639 if (options::produceModels()) {
1640 if (options::produceModels
.wasSetByUser()) {
1641 throw OptionException("Cannot use unconstrained-simp with model generation.");
1643 Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl
;
1644 setOption("produce-models", SExpr("false"));
1646 if (options::produceAssignments()) {
1647 if (options::produceAssignments
.wasSetByUser()) {
1648 throw OptionException("Cannot use unconstrained-simp with model generation (produce-assignments).");
1650 Notice() << "SmtEngine: turning off produce-assignments to support unconstrainedSimp" << endl
;
1651 setOption("produce-assignments", SExpr("false"));
1653 if (options::checkModels()) {
1654 if (options::checkModels
.wasSetByUser()) {
1655 throw OptionException("Cannot use unconstrained-simp with model generation (check-models).");
1657 Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl
;
1658 setOption("check-models", SExpr("false"));
1663 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
&&
1664 options::incrementalSolving()) {
1665 if (options::incrementalSolving
.wasSetByUser()) {
1666 throw OptionException(std::string("Eager bit-blasting does not currently support incremental mode. \n\
1667 Try --bitblast=lazy"));
1669 Notice() << "SmtEngine: turning off incremental to support eager bit-blasting" << endl
;
1670 setOption("incremental", SExpr("false"));
1673 if (! options::bvEagerExplanations
.wasSetByUser() &&
1674 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1675 d_logic
.isTheoryEnabled(THEORY_BV
)) {
1676 Trace("smt") << "enabling eager bit-vector explanations " << endl
;
1677 options::bvEagerExplanations
.set(true);
1680 if( !options::bitvectorEqualitySolver() ){
1681 Trace("smt") << "disabling bvLazyRewriteExtf since equality solver is disabled" << endl
;
1682 options::bvLazyRewriteExtf
.set(false);
1685 // Turn on arith rewrite equalities only for pure arithmetic
1686 if(! options::arithRewriteEq
.wasSetByUser()) {
1687 bool arithRewriteEq
= d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isQuantified();
1688 Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq
<< endl
;
1689 options::arithRewriteEq
.set(arithRewriteEq
);
1691 if(! options::arithHeuristicPivots
.wasSetByUser()) {
1692 int16_t heuristicPivots
= 5;
1693 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()) {
1694 if(d_logic
.isDifferenceLogic()) {
1695 heuristicPivots
= -1;
1696 } else if(!d_logic
.areIntegersUsed()) {
1697 heuristicPivots
= 0;
1700 Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots
<< endl
;
1701 options::arithHeuristicPivots
.set(heuristicPivots
);
1703 if(! options::arithPivotThreshold
.wasSetByUser()){
1704 uint16_t pivotThreshold
= 2;
1705 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()){
1706 if(d_logic
.isDifferenceLogic()){
1707 pivotThreshold
= 16;
1710 Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold
<< endl
;
1711 options::arithPivotThreshold
.set(pivotThreshold
);
1713 if(! options::arithStandardCheckVarOrderPivots
.wasSetByUser()){
1714 int16_t varOrderPivots
= -1;
1715 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()){
1716 varOrderPivots
= 200;
1718 Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots
<< endl
;
1719 options::arithStandardCheckVarOrderPivots
.set(varOrderPivots
);
1721 // Turn off early theory preprocessing if arithRewriteEq is on
1722 if (options::arithRewriteEq()) {
1723 d_earlyTheoryPP
= false;
1726 // Set decision mode based on logic (if not set by user)
1727 if(!options::decisionMode
.wasSetByUser()) {
1728 decision::DecisionMode decMode
=
1730 d_logic
.hasEverything() ? decision::DECISION_STRATEGY_JUSTIFICATION
:
1732 (not d_logic
.isQuantified() &&
1733 d_logic
.isPure(THEORY_BV
)
1735 // QF_AUFBV or QF_ABV or QF_UFBV
1736 (not d_logic
.isQuantified() &&
1737 (d_logic
.isTheoryEnabled(THEORY_ARRAYS
) ||
1738 d_logic
.isTheoryEnabled(THEORY_UF
)) &&
1739 d_logic
.isTheoryEnabled(THEORY_BV
)
1741 // QF_AUFLIA (and may be ends up enabling QF_AUFLRA?)
1742 (not d_logic
.isQuantified() &&
1743 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1744 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1745 d_logic
.isTheoryEnabled(THEORY_ARITH
)
1748 (not d_logic
.isQuantified() &&
1749 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
1752 d_logic
.isQuantified() ||
1754 d_logic
.isTheoryEnabled(THEORY_STRINGS
)
1755 ? decision::DECISION_STRATEGY_JUSTIFICATION
1756 : decision::DECISION_STRATEGY_INTERNAL
1761 d_logic
.hasEverything() || d_logic
.isTheoryEnabled(THEORY_STRINGS
) ? false :
1763 (not d_logic
.isQuantified() &&
1764 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1765 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1766 d_logic
.isTheoryEnabled(THEORY_ARITH
)
1769 (not d_logic
.isQuantified() &&
1770 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
1775 Trace("smt") << "setting decision mode to " << decMode
<< endl
;
1776 options::decisionMode
.set(decMode
);
1777 options::decisionStopOnly
.set(stoponly
);
1779 if( options::incrementalSolving() ){
1780 //disable modes not supported by incremental
1781 options::sortInference
.set( false );
1782 options::ufssFairnessMonotone
.set( false );
1783 options::quantEpr
.set( false );
1784 options::globalNegate
.set(false);
1786 if( d_logic
.hasCardinalityConstraints() ){
1787 //must have finite model finding on
1788 options::finiteModelFind
.set( true );
1791 //if it contains a theory with non-termination, do not strictly enforce that quantifiers and theory combination must be interleaved
1792 if( d_logic
.isTheoryEnabled(THEORY_STRINGS
) || (d_logic
.isTheoryEnabled(THEORY_ARITH
) && !d_logic
.isLinear()) ){
1793 if( !options::instWhenStrictInterleave
.wasSetByUser() ){
1794 options::instWhenStrictInterleave
.set( false );
1798 //local theory extensions
1799 if( options::localTheoryExt() ){
1800 if( !options::instMaxLevel
.wasSetByUser() ){
1801 options::instMaxLevel
.set( 0 );
1804 if( options::instMaxLevel()!=-1 ){
1805 Notice() << "SmtEngine: turning off cbqi to support instMaxLevel" << endl
;
1806 options::cbqi
.set(false);
1808 //track instantiations?
1809 if( options::cbqiNestedQE() || ( options::proof() && !options::trackInstLemmas
.wasSetByUser() ) ){
1810 options::trackInstLemmas
.set( true );
1813 if( ( options::fmfBoundLazy
.wasSetByUser() && options::fmfBoundLazy() ) ||
1814 ( options::fmfBoundInt
.wasSetByUser() && options::fmfBoundInt() ) ) {
1815 options::fmfBound
.set( true );
1817 //now have determined whether fmfBoundInt is on/off
1818 //apply fmfBoundInt options
1819 if( options::fmfBound() ){
1820 //must have finite model finding on
1821 options::finiteModelFind
.set( true );
1822 if( ! options::mbqiMode
.wasSetByUser() ||
1823 ( options::mbqiMode()!=quantifiers::MBQI_NONE
&&
1824 options::mbqiMode()!=quantifiers::MBQI_FMC
&&
1825 options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL
) ){
1826 //if bounded integers are set, use no MBQI by default
1827 options::mbqiMode
.set( quantifiers::MBQI_NONE
);
1829 if( ! options::prenexQuant
.wasSetByUser() ){
1830 options::prenexQuant
.set( quantifiers::PRENEX_QUANT_NONE
);
1833 if( options::ufHo() ){
1834 //if higher-order, then current variants of model-based instantiation cannot be used
1835 if( options::mbqiMode()!=quantifiers::MBQI_NONE
){
1836 options::mbqiMode
.set( quantifiers::MBQI_NONE
);
1839 if( options::mbqiMode()==quantifiers::MBQI_ABS
){
1840 if( !d_logic
.isPure(THEORY_UF
) ){
1841 //MBQI_ABS is only supported in pure quantified UF
1842 options::mbqiMode
.set( quantifiers::MBQI_FMC
);
1845 if( options::ufssSymBreak() ){
1846 options::sortInference
.set( true );
1848 if( options::fmfFunWellDefinedRelevant() ){
1849 if( !options::fmfFunWellDefined
.wasSetByUser() ){
1850 options::fmfFunWellDefined
.set( true );
1853 if( options::fmfFunWellDefined() ){
1854 if( !options::finiteModelFind
.wasSetByUser() ){
1855 options::finiteModelFind
.set( true );
1859 if( options::quantEpr() ){
1860 if( !options::preSkolemQuant
.wasSetByUser() ){
1861 options::preSkolemQuant
.set( true );
1865 //now, have determined whether finite model find is on/off
1866 //apply finite model finding options
1867 if( options::finiteModelFind() ){
1868 //apply conservative quantifiers splitting
1869 if( !options::quantDynamicSplit
.wasSetByUser() ){
1870 options::quantDynamicSplit
.set( quantifiers::QUANT_DSPLIT_MODE_DEFAULT
);
1872 //do not eliminate extended arithmetic symbols from quantified formulas
1873 if( !options::elimExtArithQuant
.wasSetByUser() ){
1874 options::elimExtArithQuant
.set( false );
1876 if( !options::eMatching
.wasSetByUser() ){
1877 options::eMatching
.set( options::fmfInstEngine() );
1879 if( !options::instWhenMode
.wasSetByUser() ){
1880 //instantiate only on last call
1881 if( options::eMatching() ){
1882 options::instWhenMode
.set( quantifiers::INST_WHEN_LAST_CALL
);
1885 if( options::mbqiMode()==quantifiers::MBQI_ABS
){
1886 if( !options::preSkolemQuant
.wasSetByUser() ){
1887 options::preSkolemQuant
.set( true );
1889 if( !options::preSkolemQuantNested
.wasSetByUser() ){
1890 options::preSkolemQuantNested
.set( true );
1892 if( !options::fmfOneInstPerRound
.wasSetByUser() ){
1893 options::fmfOneInstPerRound
.set( true );
1898 //apply counterexample guided instantiation options
1899 // if we are attempting to rewrite everything to SyGuS, use ceGuidedInst
1900 if (options::sygusInference())
1902 if (!options::ceGuidedInst
.wasSetByUser())
1904 options::ceGuidedInst
.set(true);
1906 // optimization: apply preskolemization, makes it succeed more often
1907 if (!options::preSkolemQuant
.wasSetByUser())
1909 options::preSkolemQuant
.set(true);
1911 if (!options::preSkolemQuantNested
.wasSetByUser())
1913 options::preSkolemQuantNested
.set(true);
1916 if( options::cegqiSingleInvMode()!=quantifiers::CEGQI_SI_MODE_NONE
){
1917 if( !options::ceGuidedInst
.wasSetByUser() ){
1918 options::ceGuidedInst
.set( true );
1921 if( options::ceGuidedInst() ){
1922 //counterexample-guided instantiation for sygus
1923 if( !options::cegqiSingleInvMode
.wasSetByUser() ){
1924 options::cegqiSingleInvMode
.set( quantifiers::CEGQI_SI_MODE_USE
);
1926 if( !options::quantConflictFind
.wasSetByUser() ){
1927 options::quantConflictFind
.set( false );
1929 if( !options::instNoEntail
.wasSetByUser() ){
1930 options::instNoEntail
.set( false );
1932 if (options::sygusRew())
1934 options::sygusRewSynth
.set(true);
1935 options::sygusRewVerify
.set(true);
1937 if (options::sygusRewSynth() || options::sygusRewVerify())
1939 // rewrite rule synthesis implies that sygus stream must be true
1940 options::sygusStream
.set(true);
1942 if (options::sygusStream())
1944 // PBE and streaming modes are incompatible
1945 if (!options::sygusPbe
.wasSetByUser())
1947 options::sygusPbe
.set(false);
1950 //do not allow partial functions
1951 if( !options::bitvectorDivByZeroConst
.wasSetByUser() ){
1952 options::bitvectorDivByZeroConst
.set( true );
1954 if( !options::dtRewriteErrorSel
.wasSetByUser() ){
1955 options::dtRewriteErrorSel
.set( true );
1958 if( !options::miniscopeQuant
.wasSetByUser() ){
1959 options::miniscopeQuant
.set( false );
1961 if( !options::miniscopeQuantFreeVar
.wasSetByUser() ){
1962 options::miniscopeQuantFreeVar
.set( false );
1965 if( !options::rewriteDivk
.wasSetByUser()) {
1966 options::rewriteDivk
.set( true );
1969 if( !options::macrosQuant
.wasSetByUser()) {
1970 options::macrosQuant
.set( false );
1972 if( !options::cbqiPreRegInst
.wasSetByUser()) {
1973 options::cbqiPreRegInst
.set( true );
1976 //counterexample-guided instantiation for non-sygus
1977 // enable if any possible quantifiers with arithmetic, datatypes or bitvectors
1978 if( d_logic
.isQuantified() &&
1979 ( ( options::decisionMode()!=decision::DECISION_STRATEGY_INTERNAL
&&
1980 ( d_logic
.isTheoryEnabled(THEORY_ARITH
) || d_logic
.isTheoryEnabled(THEORY_DATATYPES
) || d_logic
.isTheoryEnabled(THEORY_BV
) ) ) ||
1981 d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
) ||
1982 options::cbqiAll() ) ){
1983 if( !options::cbqi
.wasSetByUser() ){
1984 options::cbqi
.set( true );
1986 // check whether we should apply full cbqi
1987 if (d_logic
.isPure(THEORY_BV
))
1989 if (!options::cbqiFullEffort
.wasSetByUser())
1991 options::cbqiFullEffort
.set(true);
1995 if( options::cbqi() ){
1997 if( !options::rewriteDivk
.wasSetByUser()) {
1998 options::rewriteDivk
.set( true );
2000 if (d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
))
2002 options::cbqiAll
.set( false );
2003 if( !options::quantConflictFind
.wasSetByUser() ){
2004 options::quantConflictFind
.set( false );
2006 if( !options::instNoEntail
.wasSetByUser() ){
2007 options::instNoEntail
.set( false );
2009 if( !options::instWhenMode
.wasSetByUser() && options::cbqiModel() ){
2010 //only instantiation should happen at last call when model is avaiable
2011 options::instWhenMode
.set( quantifiers::INST_WHEN_LAST_CALL
);
2014 // only supported in pure arithmetic or pure BV
2015 options::cbqiNestedQE
.set(false);
2018 if (options::cbqiNestedQE()
2019 || options::decisionMode() == decision::DECISION_STRATEGY_INTERNAL
)
2021 // only complete with prenex = disj_normal or normal
2022 if (options::prenexQuant() <= quantifiers::PRENEX_QUANT_DISJ_NORMAL
)
2024 options::prenexQuant
.set(quantifiers::PRENEX_QUANT_DISJ_NORMAL
);
2027 else if (options::globalNegate())
2029 if (!options::prenexQuant
.wasSetByUser())
2031 options::prenexQuant
.set(quantifiers::PRENEX_QUANT_NONE
);
2035 //implied options...
2036 if( options::strictTriggers() ){
2037 if( !options::userPatternsQuant
.wasSetByUser() ){
2038 options::userPatternsQuant
.set( quantifiers::USER_PAT_MODE_TRUST
);
2041 if( options::qcfMode
.wasSetByUser() || options::qcfTConstraint() ){
2042 options::quantConflictFind
.set( true );
2044 if( options::cbqiNestedQE() ){
2045 options::prenexQuantUser
.set( true );
2046 if( !options::preSkolemQuant
.wasSetByUser() ){
2047 options::preSkolemQuant
.set( true );
2050 //for induction techniques
2051 if( options::quantInduction() ){
2052 if( !options::dtStcInduction
.wasSetByUser() ){
2053 options::dtStcInduction
.set( true );
2055 if( !options::intWfInduction
.wasSetByUser() ){
2056 options::intWfInduction
.set( true );
2059 if( options::dtStcInduction() ){
2060 //leads to unfairness FIXME
2061 if( !options::dtForceAssignment
.wasSetByUser() ){
2062 options::dtForceAssignment
.set( true );
2064 //try to remove ITEs from quantified formulas
2065 if( !options::iteDtTesterSplitQuant
.wasSetByUser() ){
2066 options::iteDtTesterSplitQuant
.set( true );
2068 if( !options::iteLiftQuant
.wasSetByUser() ){
2069 options::iteLiftQuant
.set( quantifiers::ITE_LIFT_QUANT_MODE_ALL
);
2072 if( options::intWfInduction() ){
2073 if( !options::purifyTriggers
.wasSetByUser() ){
2074 options::purifyTriggers
.set( true );
2077 if( options::conjectureNoFilter() ){
2078 if( !options::conjectureFilterActiveTerms
.wasSetByUser() ){
2079 options::conjectureFilterActiveTerms
.set( false );
2081 if( !options::conjectureFilterCanonical
.wasSetByUser() ){
2082 options::conjectureFilterCanonical
.set( false );
2084 if( !options::conjectureFilterModel
.wasSetByUser() ){
2085 options::conjectureFilterModel
.set( false );
2088 if( options::conjectureGenPerRound
.wasSetByUser() ){
2089 if( options::conjectureGenPerRound()>0 ){
2090 options::conjectureGen
.set( true );
2092 options::conjectureGen
.set( false );
2095 //can't pre-skolemize nested quantifiers without UF theory
2096 if( !d_logic
.isTheoryEnabled(THEORY_UF
) && options::preSkolemQuant() ){
2097 if( !options::preSkolemQuantNested
.wasSetByUser() ){
2098 options::preSkolemQuantNested
.set( false );
2101 if( !d_logic
.isTheoryEnabled(THEORY_DATATYPES
) ){
2102 options::quantDynamicSplit
.set( quantifiers::QUANT_DSPLIT_MODE_NONE
);
2105 //until bugs 371,431 are fixed
2106 if( ! options::minisatUseElim
.wasSetByUser()){
2107 //AJR: cannot use minisat elim for new implementation of sets TODO: why?
2108 if( d_logic
.isTheoryEnabled(THEORY_SETS
) || d_logic
.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
2109 options::minisatUseElim
.set( false );
2112 else if (options::minisatUseElim()) {
2113 if (options::produceModels()) {
2114 Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl
;
2115 setOption("produce-models", SExpr("false"));
2117 if (options::produceAssignments()) {
2118 Notice() << "SmtEngine: turning off produce-assignments to support minisatUseElim" << endl
;
2119 setOption("produce-assignments", SExpr("false"));
2121 if (options::checkModels()) {
2122 Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl
;
2123 setOption("check-models", SExpr("false"));
2127 // For now, these array theory optimizations do not support model-building
2128 if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
2129 options::arraysOptimizeLinear
.set(false);
2130 options::arraysLazyRIntro1
.set(false);
2133 // Non-linear arithmetic does not support models unless nlExt is enabled
2134 if ((d_logic
.isTheoryEnabled(THEORY_ARITH
) && !d_logic
.isLinear()
2135 && !options::nlExt())
2136 || options::globalNegate())
2138 std::string reason
=
2139 options::globalNegate() ? "--global-negate" : "nonlinear arithmetic";
2140 if (options::produceModels()) {
2141 if(options::produceModels
.wasSetByUser()) {
2142 throw OptionException(
2143 std::string("produce-model not supported with " + reason
));
2146 << "SmtEngine: turning off produce-models because unsupported for "
2148 setOption("produce-models", SExpr("false"));
2150 if (options::produceAssignments()) {
2151 if(options::produceAssignments
.wasSetByUser()) {
2152 throw OptionException(
2153 std::string("produce-assignments not supported with " + reason
));
2155 Warning() << "SmtEngine: turning off produce-assignments because "
2158 setOption("produce-assignments", SExpr("false"));
2160 if (options::checkModels()) {
2161 if(options::checkModels
.wasSetByUser()) {
2162 throw OptionException(
2163 std::string("check-models not supported with " + reason
));
2166 << "SmtEngine: turning off check-models because unsupported for "
2168 setOption("check-models", SExpr("false"));
2172 if(options::incrementalSolving() && options::proof()) {
2173 Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof, try --tear-down-incremental instead)" << endl
;
2174 setOption("incremental", SExpr("false"));
2177 if (options::proof())
2179 if (options::bitvectorAlgebraicSolver())
2181 if (options::bitvectorAlgebraicSolver
.wasSetByUser())
2183 throw OptionException(
2184 "--bv-algebraic-solver is not supported with proofs");
2186 Notice() << "SmtEngine: turning off bv algebraic solver to support proofs"
2188 options::bitvectorAlgebraicSolver
.set(false);
2190 if (options::bitvectorEqualitySolver())
2192 if (options::bitvectorEqualitySolver
.wasSetByUser())
2194 throw OptionException("--bv-eq-solver is not supported with proofs");
2196 Notice() << "SmtEngine: turning off bv eq solver to support proofs"
2198 options::bitvectorEqualitySolver
.set(false);
2200 if (options::bitvectorInequalitySolver())
2202 if (options::bitvectorInequalitySolver
.wasSetByUser())
2204 throw OptionException(
2205 "--bv-inequality-solver is not supported with proofs");
2207 Notice() << "SmtEngine: turning off bv ineq solver to support proofs"
2209 options::bitvectorInequalitySolver
.set(false);
2214 void SmtEngine::setProblemExtended(bool value
)
2216 d_problemExtended
= value
;
2217 if (value
) { d_assumptions
.clear(); }
2220 void SmtEngine::setInfo(const std::string
& key
, const CVC4::SExpr
& value
)
2222 SmtScope
smts(this);
2224 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
2226 if(Dump
.isOn("benchmark")) {
2227 if(key
== "status") {
2228 string s
= value
.getValue();
2229 BenchmarkStatus status
=
2230 (s
== "sat") ? SMT_SATISFIABLE
:
2231 ((s
== "unsat") ? SMT_UNSATISFIABLE
: SMT_UNKNOWN
);
2232 Dump("benchmark") << SetBenchmarkStatusCommand(status
);
2234 Dump("benchmark") << SetInfoCommand(key
, value
);
2238 // Check for CVC4-specific info keys (prefixed with "cvc4-" or "cvc4_")
2239 if(key
.length() > 5) {
2240 string prefix
= key
.substr(0, 5);
2241 if(prefix
== "cvc4-" || prefix
== "cvc4_") {
2242 string cvc4key
= key
.substr(5);
2243 if(cvc4key
== "logic") {
2244 if(! value
.isAtom()) {
2245 throw OptionException("argument to (set-info :cvc4-logic ..) must be a string");
2247 SmtScope
smts(this);
2248 d_logic
= value
.getValue();
2252 throw UnrecognizedOptionException();
2257 // Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
2258 if(key
== "source" ||
2259 key
== "category" ||
2260 key
== "difficulty" ||
2264 } else if(key
== "name") {
2265 d_filename
= value
.getValue();
2267 } else if(key
== "smt-lib-version") {
2268 if( (value
.isInteger() && value
.getIntegerValue() == Integer(2)) ||
2269 (value
.isRational() && value
.getRationalValue() == Rational(2)) ||
2270 value
.getValue() == "2" ||
2271 value
.getValue() == "2.0" ) {
2272 options::inputLanguage
.set(language::input::LANG_SMTLIB_V2_0
);
2274 // supported SMT-LIB version
2275 if(!options::outputLanguage
.wasSetByUser() &&
2276 ( options::outputLanguage() == language::output::LANG_SMTLIB_V2_5
|| options::outputLanguage() == language::output::LANG_SMTLIB_V2_6
)) {
2277 options::outputLanguage
.set(language::output::LANG_SMTLIB_V2_0
);
2278 *options::out() << language::SetLanguage(language::output::LANG_SMTLIB_V2_0
);
2281 } else if( (value
.isRational() && value
.getRationalValue() == Rational(5, 2)) ||
2282 value
.getValue() == "2.5" ) {
2283 options::inputLanguage
.set(language::input::LANG_SMTLIB_V2_5
);
2285 // supported SMT-LIB version
2286 if(!options::outputLanguage
.wasSetByUser() &&
2287 options::outputLanguage() == language::output::LANG_SMTLIB_V2_0
) {
2288 options::outputLanguage
.set(language::output::LANG_SMTLIB_V2_5
);
2289 *options::out() << language::SetLanguage(language::output::LANG_SMTLIB_V2_5
);
2292 } else if( (value
.isRational() && value
.getRationalValue() == Rational(13, 5)) ||
2293 value
.getValue() == "2.6" ) {
2294 options::inputLanguage
.set(language::input::LANG_SMTLIB_V2_6
);
2296 // supported SMT-LIB version
2297 if(!options::outputLanguage
.wasSetByUser() &&
2298 options::outputLanguage() == language::output::LANG_SMTLIB_V2_0
) {
2299 options::outputLanguage
.set(language::output::LANG_SMTLIB_V2_6
);
2300 *options::out() << language::SetLanguage(language::output::LANG_SMTLIB_V2_6
);
2304 Warning() << "Warning: unsupported smt-lib-version: " << value
<< endl
;
2305 throw UnrecognizedOptionException();
2306 } else if(key
== "status") {
2308 if(value
.isAtom()) {
2309 s
= value
.getValue();
2311 if(s
!= "sat" && s
!= "unsat" && s
!= "unknown") {
2312 throw OptionException("argument to (set-info :status ..) must be "
2313 "`sat' or `unsat' or `unknown'");
2315 d_status
= Result(s
, d_filename
);
2318 throw UnrecognizedOptionException();
2321 CVC4::SExpr
SmtEngine::getInfo(const std::string
& key
) const {
2323 SmtScope
smts(this);
2325 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
2326 if(key
== "all-statistics") {
2327 vector
<SExpr
> stats
;
2328 for(StatisticsRegistry::const_iterator i
= NodeManager::fromExprManager(d_exprManager
)->getStatisticsRegistry()->begin();
2329 i
!= NodeManager::fromExprManager(d_exprManager
)->getStatisticsRegistry()->end();
2332 v
.push_back((*i
).first
);
2333 v
.push_back((*i
).second
);
2336 for(StatisticsRegistry::const_iterator i
= d_statisticsRegistry
->begin();
2337 i
!= d_statisticsRegistry
->end();
2340 v
.push_back((*i
).first
);
2341 v
.push_back((*i
).second
);
2344 return SExpr(stats
);
2345 } else if(key
== "error-behavior") {
2346 // immediate-exit | continued-execution
2347 if( options::continuedExecution() || options::interactive() ) {
2348 return SExpr(SExpr::Keyword("continued-execution"));
2350 return SExpr(SExpr::Keyword("immediate-exit"));
2352 } else if(key
== "name") {
2353 return SExpr(Configuration::getName());
2354 } else if(key
== "version") {
2355 return SExpr(Configuration::getVersionString());
2356 } else if(key
== "authors") {
2357 return SExpr(Configuration::about());
2358 } else if(key
== "status") {
2359 // sat | unsat | unknown
2360 switch(d_status
.asSatisfiabilityResult().isSat()) {
2362 return SExpr(SExpr::Keyword("sat"));
2364 return SExpr(SExpr::Keyword("unsat"));
2366 return SExpr(SExpr::Keyword("unknown"));
2368 } else if(key
== "reason-unknown") {
2369 if(!d_status
.isNull() && d_status
.isUnknown()) {
2371 ss
<< d_status
.whyUnknown();
2372 string s
= ss
.str();
2373 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
2374 return SExpr(SExpr::Keyword(s
));
2376 throw ModalException("Can't get-info :reason-unknown when the "
2377 "last result wasn't unknown!");
2379 } else if(key
== "assertion-stack-levels") {
2380 AlwaysAssert(d_userLevels
.size() <=
2381 std::numeric_limits
<unsigned long int>::max());
2382 return SExpr(static_cast<unsigned long int>(d_userLevels
.size()));
2383 } else if(key
== "all-options") {
2384 // get the options, like all-statistics
2385 std::vector
< std::vector
<std::string
> > current_options
=
2386 Options::current()->getOptions();
2387 return SExpr::parseListOfListOfAtoms(current_options
);
2389 throw UnrecognizedOptionException();
2393 void SmtEngine::debugCheckFormals(const std::vector
<Expr
>& formals
, Expr func
)
2395 for(std::vector
<Expr
>::const_iterator i
= formals
.begin(); i
!= formals
.end(); ++i
) {
2396 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
2398 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
2399 << "definition of function " << func
<< ", formal\n"
2400 << " " << *i
<< "\n"
2401 << "has kind " << (*i
).getKind();
2402 throw TypeCheckingException(func
, ss
.str());
2407 void SmtEngine::debugCheckFunctionBody(Expr formula
,
2408 const std::vector
<Expr
>& formals
,
2411 Type formulaType
= formula
.getType(options::typeChecking());
2412 Type funcType
= func
.getType();
2413 // We distinguish here between definitions of constants and functions,
2414 // because the type checking for them is subtly different. Perhaps we
2415 // should instead have SmtEngine::defineFunction() and
2416 // SmtEngine::defineConstant() for better clarity, although then that
2417 // doesn't match the SMT-LIBv2 standard...
2418 if(formals
.size() > 0) {
2419 Type rangeType
= FunctionType(funcType
).getRangeType();
2420 if(! formulaType
.isComparableTo(rangeType
)) {
2422 ss
<< "Type of defined function does not match its declaration\n"
2423 << "The function : " << func
<< "\n"
2424 << "Declared type : " << rangeType
<< "\n"
2425 << "The body : " << formula
<< "\n"
2426 << "Body type : " << formulaType
;
2427 throw TypeCheckingException(func
, ss
.str());
2430 if(! formulaType
.isComparableTo(funcType
)) {
2432 ss
<< "Declared type of defined constant does not match its definition\n"
2433 << "The constant : " << func
<< "\n"
2434 << "Declared type : " << funcType
<< " " << Type::getTypeNode(funcType
)->getId() << "\n"
2435 << "The definition : " << formula
<< "\n"
2436 << "Definition type: " << formulaType
<< " " << Type::getTypeNode(formulaType
)->getId();
2437 throw TypeCheckingException(func
, ss
.str());
2442 void SmtEngine::defineFunction(Expr func
,
2443 const std::vector
<Expr
>& formals
,
2446 SmtScope
smts(this);
2448 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
2449 debugCheckFormals(formals
, func
);
2452 ss
<< language::SetLanguage(
2453 language::SetLanguage::getLanguage(Dump
.getStream()))
2455 DefineFunctionCommand
c(ss
.str(), func
, formals
, formula
);
2456 addToModelCommandAndDump(
2457 c
, ExprManager::VAR_FLAG_DEFINED
, true, "declarations");
2459 PROOF(if (options::checkUnsatCores()) {
2460 d_defineCommands
.push_back(c
.clone());
2464 debugCheckFunctionBody(formula
, formals
, func
);
2466 // Substitute out any abstract values in formula
2468 d_private
->substituteAbstractValues(Node::fromExpr(formula
)).toExpr();
2470 TNode funcNode
= func
.getTNode();
2471 vector
<Node
> formalsNodes
;
2472 for(vector
<Expr
>::const_iterator i
= formals
.begin(),
2473 iend
= formals
.end();
2476 formalsNodes
.push_back((*i
).getNode());
2478 TNode formNode
= form
.getTNode();
2479 DefinedFunction
def(funcNode
, formalsNodes
, formNode
);
2480 // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
2481 // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
2482 // d_haveAdditions = true;
2483 Debug("smt") << "definedFunctions insert " << funcNode
<< " " << formNode
<< endl
;
2484 d_definedFunctions
->insert(funcNode
, def
);
2487 void SmtEngine::defineFunctionsRec(
2488 const std::vector
<Expr
>& funcs
,
2489 const std::vector
<std::vector
<Expr
> >& formals
,
2490 const std::vector
<Expr
>& formulas
)
2492 SmtScope
smts(this);
2493 finalOptionsAreSet();
2495 Trace("smt") << "SMT defineFunctionsRec(...)" << endl
;
2497 if (funcs
.size() != formals
.size() && funcs
.size() != formulas
.size())
2500 ss
<< "Number of functions, formals, and function bodies passed to "
2501 "defineFunctionsRec do not match:"
2503 << " #functions : " << funcs
.size() << "\n"
2504 << " #arg lists : " << formals
.size() << "\n"
2505 << " #function bodies : " << formulas
.size() << "\n";
2506 throw ModalException(ss
.str());
2508 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
2510 // check formal argument list
2511 debugCheckFormals(formals
[i
], funcs
[i
]);
2513 debugCheckFunctionBody(formulas
[i
], formals
[i
], funcs
[i
]);
2516 if (Dump
.isOn("raw-benchmark"))
2518 Dump("raw-benchmark") << DefineFunctionRecCommand(funcs
, formals
, formulas
);
2521 ExprManager
* em
= getExprManager();
2522 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
2524 // we assert a quantified formula
2526 // make the function application
2527 if (formals
[i
].empty())
2529 // it has no arguments
2530 func_app
= funcs
[i
];
2534 std::vector
<Expr
> children
;
2535 children
.push_back(funcs
[i
]);
2536 children
.insert(children
.end(), formals
[i
].begin(), formals
[i
].end());
2537 func_app
= em
->mkExpr(kind::APPLY_UF
, children
);
2539 Expr lem
= em
->mkExpr(kind::EQUAL
, func_app
, formulas
[i
]);
2540 if (!formals
[i
].empty())
2542 // set the attribute to denote this is a function definition
2543 std::string
attr_name("fun-def");
2544 Expr aexpr
= em
->mkExpr(kind::INST_ATTRIBUTE
, func_app
);
2545 aexpr
= em
->mkExpr(kind::INST_PATTERN_LIST
, aexpr
);
2546 std::vector
<Expr
> expr_values
;
2547 std::string str_value
;
2548 setUserAttribute(attr_name
, func_app
, expr_values
, str_value
);
2549 // make the quantified formula
2550 Expr boundVars
= em
->mkExpr(kind::BOUND_VAR_LIST
, formals
[i
]);
2551 lem
= em
->mkExpr(kind::FORALL
, boundVars
, lem
, aexpr
);
2553 // assert the quantified formula
2554 // notice we don't call assertFormula directly, since this would
2555 // duplicate the output on raw-benchmark.
2556 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(lem
)).toExpr();
2557 if (d_assertionList
!= NULL
)
2559 d_assertionList
->push_back(e
);
2561 d_private
->addFormula(e
.getNode(), false);
2565 void SmtEngine::defineFunctionRec(Expr func
,
2566 const std::vector
<Expr
>& formals
,
2569 std::vector
<Expr
> funcs
;
2570 funcs
.push_back(func
);
2571 std::vector
<std::vector
<Expr
> > formals_multi
;
2572 formals_multi
.push_back(formals
);
2573 std::vector
<Expr
> formulas
;
2574 formulas
.push_back(formula
);
2575 defineFunctionsRec(funcs
, formals_multi
, formulas
);
2578 bool SmtEngine::isDefinedFunction( Expr func
){
2579 Node nf
= Node::fromExpr( func
);
2580 Debug("smt") << "isDefined function " << nf
<< "?" << std::endl
;
2581 return d_definedFunctions
->find(nf
) != d_definedFunctions
->end();
2584 void SmtEnginePrivate::finishInit() {
2585 d_preprocessingPassContext
.reset(new PreprocessingPassContext(&d_smt
));
2586 // TODO: register passes here (this will likely change when we add support for
2587 // actually assembling preprocessing pipelines).
2588 std::unique_ptr
<BVGauss
> bvGauss(new BVGauss(d_preprocessingPassContext
.get()));
2589 std::unique_ptr
<IntToBV
> intToBV(new IntToBV(d_preprocessingPassContext
.get()));
2590 std::unique_ptr
<PseudoBooleanProcessor
> pbProc(
2591 new PseudoBooleanProcessor(d_preprocessingPassContext
.get()));
2593 d_preprocessingPassRegistry
.registerPass("bv-gauss", std::move(bvGauss
));
2594 d_preprocessingPassRegistry
.registerPass("int-to-bv", std::move(intToBV
));
2595 d_preprocessingPassRegistry
.registerPass("pseudo-boolean-processor",
2599 Node
SmtEnginePrivate::expandDefinitions(TNode n
, unordered_map
<Node
, Node
, NodeHashFunction
>& cache
, bool expandOnly
)
2601 stack
< triple
<Node
, Node
, bool> > worklist
;
2603 worklist
.push(make_triple(Node(n
), Node(n
), false));
2604 // The worklist is made of triples, each is input / original node then the output / rewritten node
2605 // and finally a flag tracking whether the children have been explored (i.e. if this is a downward
2609 spendResource(options::preprocessStep());
2610 n
= worklist
.top().first
; // n is the input / original
2611 Node node
= worklist
.top().second
; // node is the output / result
2612 bool childrenPushed
= worklist
.top().third
;
2615 // Working downwards
2616 if(!childrenPushed
) {
2617 Kind k
= n
.getKind();
2619 // we can short circuit (variable) leaves
2621 SmtEngine::DefinedFunctionMap::const_iterator i
= d_smt
.d_definedFunctions
->find(n
);
2622 if(i
!= d_smt
.d_definedFunctions
->end()) {
2623 // replacement must be closed
2624 if((*i
).second
.getFormals().size() > 0) {
2625 result
.push(d_smt
.d_nodeManager
->mkNode(kind::LAMBDA
, d_smt
.d_nodeManager
->mkNode(kind::BOUND_VAR_LIST
, (*i
).second
.getFormals()), (*i
).second
.getFormula()));
2628 // don't bother putting in the cache
2629 result
.push((*i
).second
.getFormula());
2632 // don't bother putting in the cache
2637 // maybe it's in the cache
2638 unordered_map
<Node
, Node
, NodeHashFunction
>::iterator cacheHit
= cache
.find(n
);
2639 if(cacheHit
!= cache
.end()) {
2640 TNode ret
= (*cacheHit
).second
;
2641 result
.push(ret
.isNull() ? n
: ret
);
2645 // otherwise expand it
2646 bool doExpand
= k
== kind::APPLY
;
2648 if( options::macrosQuant() ){
2649 //expand if we have inferred an operator corresponds to a defined function
2650 doExpand
= k
==kind::APPLY_UF
&& d_smt
.isDefinedFunction( n
.getOperator().toExpr() );
2654 vector
<Node
> formals
;
2656 if( n
.getOperator().getKind() == kind::LAMBDA
){
2657 TNode op
= n
.getOperator();
2659 for( unsigned i
=0; i
<op
[0].getNumChildren(); i
++ ){
2660 formals
.push_back( op
[0][i
] );
2664 // application of a user-defined symbol
2665 TNode func
= n
.getOperator();
2666 SmtEngine::DefinedFunctionMap::const_iterator i
= d_smt
.d_definedFunctions
->find(func
);
2667 if(i
== d_smt
.d_definedFunctions
->end()) {
2668 throw TypeCheckingException(n
.toExpr(), string("Undefined function: `") + func
.toString() + "'");
2670 DefinedFunction def
= (*i
).second
;
2671 formals
= def
.getFormals();
2673 if(Debug
.isOn("expand")) {
2674 Debug("expand") << "found: " << n
<< endl
;
2675 Debug("expand") << " func: " << func
<< endl
;
2676 string name
= func
.getAttribute(expr::VarNameAttr());
2677 Debug("expand") << " : \"" << name
<< "\"" << endl
;
2679 if(Debug
.isOn("expand")) {
2680 Debug("expand") << " defn: " << def
.getFunction() << endl
2682 if(formals
.size() > 0) {
2683 copy( formals
.begin(), formals
.end() - 1,
2684 ostream_iterator
<Node
>(Debug("expand"), ", ") );
2685 Debug("expand") << formals
.back();
2687 Debug("expand") << "]" << endl
2688 << " " << def
.getFunction().getType() << endl
2689 << " " << def
.getFormula() << endl
;
2692 fm
= def
.getFormula();
2695 Node instance
= fm
.substitute(formals
.begin(),
2698 n
.begin() + formals
.size());
2699 Debug("expand") << "made : " << instance
<< endl
;
2701 Node expanded
= expandDefinitions(instance
, cache
, expandOnly
);
2702 cache
[n
] = (n
== expanded
? Node::null() : expanded
);
2703 result
.push(expanded
);
2706 } else if(! expandOnly
) {
2707 // do not do any theory stuff if expandOnly is true
2709 theory::Theory
* t
= d_smt
.d_theoryEngine
->theoryOf(node
);
2712 LogicRequest
req(d_smt
);
2713 node
= t
->expandDefinition(req
, n
);
2716 // the partial functions can fall through, in which case we still
2717 // consider their children
2718 worklist
.push(make_triple(Node(n
), node
, true)); // Original and rewritten result
2720 for(size_t i
= 0; i
< node
.getNumChildren(); ++i
) {
2721 worklist
.push(make_triple(node
[i
], node
[i
], false)); // Rewrite the children of the result only
2726 // Reconstruct the node from it's (now rewritten) children on the stack
2728 Debug("expand") << "cons : " << node
<< endl
;
2729 if(node
.getNumChildren()>0) {
2730 //cout << "cons : " << node << endl;
2731 NodeBuilder
<> nb(node
.getKind());
2732 if(node
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
2733 Debug("expand") << "op : " << node
.getOperator() << endl
;
2734 //cout << "op : " << node.getOperator() << endl;
2735 nb
<< node
.getOperator();
2737 for(size_t i
= 0; i
< node
.getNumChildren(); ++i
) {
2738 Assert(!result
.empty());
2739 Node expanded
= result
.top();
2741 //cout << "exchld : " << expanded << endl;
2742 Debug("expand") << "exchld : " << expanded
<< endl
;
2747 cache
[n
] = n
== node
? Node::null() : node
; // Only cache once all subterms are expanded
2750 } while(!worklist
.empty());
2752 AlwaysAssert(result
.size() == 1);
2754 return result
.top();
2757 typedef std::unordered_map
<Node
, Node
, NodeHashFunction
> NodeMap
;
2759 Node
SmtEnginePrivate::realToInt(TNode n
, NodeMap
& cache
, std::vector
< Node
>& var_eq
) {
2760 Trace("real-as-int-debug") << "Convert : " << n
<< std::endl
;
2761 NodeMap::iterator find
= cache
.find(n
);
2762 if (find
!= cache
.end()) {
2763 return (*find
).second
;
2766 if( n
.getNumChildren()>0 ){
2767 if( n
.getKind()==kind::EQUAL
|| n
.getKind()==kind::GEQ
|| n
.getKind()==kind::LT
|| n
.getKind()==kind::GT
|| n
.getKind()==kind::LEQ
){
2768 ret
= Rewriter::rewrite( n
);
2769 Trace("real-as-int-debug") << "Now looking at : " << ret
<< std::endl
;
2770 if( !ret
.isConst() ){
2771 Node ret_lit
= ret
.getKind()==kind::NOT
? ret
[0] : ret
;
2772 bool ret_pol
= ret
.getKind()!=kind::NOT
;
2773 std::map
< Node
, Node
> msum
;
2774 if (ArithMSum::getMonomialSumLit(ret_lit
, msum
))
2776 //get common coefficient
2777 std::vector
< Node
> coeffs
;
2778 for( std::map
< Node
, Node
>::iterator itm
= msum
.begin(); itm
!= msum
.end(); ++itm
){
2779 Node v
= itm
->first
;
2780 Node c
= itm
->second
;
2782 Assert( c
.isConst() );
2783 coeffs
.push_back( NodeManager::currentNM()->mkConst( Rational( c
.getConst
<Rational
>().getDenominator() ) ) );
2786 Node cc
= coeffs
.empty() ? Node::null() : ( coeffs
.size()==1 ? coeffs
[0] : Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::MULT
, coeffs
) ) );
2787 std::vector
< Node
> sum
;
2788 for( std::map
< Node
, Node
>::iterator itm
= msum
.begin(); itm
!= msum
.end(); ++itm
){
2789 Node v
= itm
->first
;
2790 Node c
= itm
->second
;
2793 c
= cc
.isNull() ? NodeManager::currentNM()->mkConst( Rational( 1 ) ) : cc
;
2796 c
= Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::MULT
, c
, cc
) );
2799 Assert( c
.getType().isInteger() );
2803 Node vv
= realToInt( v
, cache
, var_eq
);
2804 if( vv
.getType().isInteger() ){
2805 sum
.push_back( NodeManager::currentNM()->mkNode( kind::MULT
, c
, vv
) );
2807 throw TypeCheckingException(v
.toExpr(), string("Cannot translate to Int: ") + v
.toString());
2811 Node sumt
= sum
.empty() ? NodeManager::currentNM()->mkConst( Rational( 0 ) ) : ( sum
.size()==1 ? sum
[0] : NodeManager::currentNM()->mkNode( kind::PLUS
, sum
) );
2812 ret
= NodeManager::currentNM()->mkNode( ret_lit
.getKind(), sumt
, NodeManager::currentNM()->mkConst( Rational( 0 ) ) );
2816 Trace("real-as-int") << "Convert : " << std::endl
;
2817 Trace("real-as-int") << " " << n
<< std::endl
;
2818 Trace("real-as-int") << " " << ret
<< std::endl
;
2820 throw TypeCheckingException(n
.toExpr(), string("Cannot translate to Int: ") + n
.toString());
2824 bool childChanged
= false;
2825 std::vector
< Node
> children
;
2826 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
2827 Node nc
= realToInt( n
[i
], cache
, var_eq
);
2828 childChanged
= childChanged
|| nc
!=n
[i
];
2829 children
.push_back( nc
);
2832 ret
= NodeManager::currentNM()->mkNode( n
.getKind(), children
);
2837 if( !n
.getType().isInteger() ){
2838 ret
= NodeManager::currentNM()->mkSkolem("__realToInt_var", NodeManager::currentNM()->integerType(), "Variable introduced in realToInt pass");
2839 var_eq
.push_back( n
.eqNode( ret
) );
2840 TheoryModel
* m
= d_smt
.d_theoryEngine
->getModel();
2841 m
->addSubstitution(n
,ret
);
2850 Node
SmtEnginePrivate::purifyNlTerms(TNode n
, NodeMap
& cache
, NodeMap
& bcache
, std::vector
< Node
>& var_eq
, bool beneathMult
) {
2852 NodeMap::iterator find
= bcache
.find(n
);
2853 if (find
!= bcache
.end()) {
2854 return (*find
).second
;
2857 NodeMap::iterator find
= cache
.find(n
);
2858 if (find
!= cache
.end()) {
2859 return (*find
).second
;
2863 if( n
.getNumChildren()>0 ){
2864 if( beneathMult
&& n
.getKind()!=kind::MULT
){
2866 ret
= NodeManager::currentNM()->mkSkolem("__purifyNl_var", n
.getType(), "Variable introduced in purifyNl pass");
2867 Node np
= purifyNlTerms( n
, cache
, bcache
, var_eq
, false );
2868 var_eq
.push_back( np
.eqNode( ret
) );
2870 bool beneathMultNew
= beneathMult
|| n
.getKind()==kind::MULT
;
2871 bool childChanged
= false;
2872 std::vector
< Node
> children
;
2873 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
2874 Node nc
= purifyNlTerms( n
[i
], cache
, bcache
, var_eq
, beneathMultNew
);
2875 childChanged
= childChanged
|| nc
!=n
[i
];
2876 children
.push_back( nc
);
2879 ret
= NodeManager::currentNM()->mkNode( n
.getKind(), children
);
2891 void SmtEnginePrivate::removeITEs() {
2892 d_smt
.finalOptionsAreSet();
2893 spendResource(options::preprocessStep());
2894 Trace("simplify") << "SmtEnginePrivate::removeITEs()" << endl
;
2896 // Remove all of the ITE occurrences and normalize
2897 d_iteRemover
.run(d_assertions
.ref(), d_iteSkolemMap
, true);
2898 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
2899 d_assertions
.replace(i
, Rewriter::rewrite(d_assertions
[i
]));
2903 void SmtEnginePrivate::staticLearning() {
2904 d_smt
.finalOptionsAreSet();
2905 spendResource(options::preprocessStep());
2907 TimerStat::CodeTimer
staticLearningTimer(d_smt
.d_stats
->d_staticLearningTime
);
2909 Trace("simplify") << "SmtEnginePrivate::staticLearning()" << endl
;
2911 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
2913 NodeBuilder
<> learned(kind::AND
);
2914 learned
<< d_assertions
[i
];
2915 d_smt
.d_theoryEngine
->ppStaticLearn(d_assertions
[i
], learned
);
2916 if(learned
.getNumChildren() == 1) {
2919 d_assertions
.replace(i
, learned
);
2924 // do dumping (before/after any preprocessing pass)
2925 static void dumpAssertions(const char* key
,
2926 const AssertionPipeline
& assertionList
) {
2927 if( Dump
.isOn("assertions") &&
2928 Dump
.isOn(string("assertions:") + key
) ) {
2929 // Push the simplified assertions to the dump output stream
2930 for(unsigned i
= 0; i
< assertionList
.size(); ++ i
) {
2931 TNode n
= assertionList
[i
];
2932 Dump("assertions") << AssertCommand(Expr(n
.toExpr()));
2937 // returns false if it learns a conflict
2938 bool SmtEnginePrivate::nonClausalSimplify() {
2939 spendResource(options::preprocessStep());
2940 d_smt
.finalOptionsAreSet();
2942 if(options::unsatCores() || options::fewerPreprocessingHoles()) {
2946 TimerStat::CodeTimer
nonclausalTimer(d_smt
.d_stats
->d_nonclausalSimplificationTime
);
2948 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl
;
2949 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
2950 Trace("simplify") << "Assertion #" << i
<< " : " << d_assertions
[i
] << std::endl
;
2953 if(d_propagatorNeedsFinish
) {
2954 d_propagator
.finish();
2955 d_propagatorNeedsFinish
= false;
2957 d_propagator
.initialize();
2959 // Assert all the assertions to the propagator
2960 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2961 << "asserting to propagator" << endl
;
2962 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
2963 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
2964 // Don't reprocess substitutions
2965 if (d_substitutionsIndex
> 0 && i
== d_substitutionsIndex
) {
2968 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertions
[i
] << endl
;
2969 Debug("cores") << "d_propagator assertTrue: " << d_assertions
[i
] << std::endl
;
2970 d_propagator
.assertTrue(d_assertions
[i
]);
2973 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2974 << "propagating" << endl
;
2975 if (d_propagator
.propagate()) {
2976 // If in conflict, just return false
2977 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2978 << "conflict in non-clausal propagation" << endl
;
2979 Node falseNode
= NodeManager::currentNM()->mkConst
<bool>(false);
2980 Assert(!options::unsatCores() && !options::fewerPreprocessingHoles());
2981 d_assertions
.clear();
2982 addFormula(falseNode
, false, false);
2983 d_propagatorNeedsFinish
= true;
2988 Trace("simplify") << "Iterate through " << d_nonClausalLearnedLiterals
.size() << " learned literals." << std::endl
;
2989 // No conflict, go through the literals and solve them
2990 SubstitutionMap
constantPropagations(d_smt
.d_context
);
2991 SubstitutionMap
newSubstitutions(d_smt
.d_context
);
2992 SubstitutionMap::iterator pos
;
2994 for(unsigned i
= 0, i_end
= d_nonClausalLearnedLiterals
.size(); i
< i_end
; ++ i
) {
2995 // Simplify the literal we learned wrt previous substitutions
2996 Node learnedLiteral
= d_nonClausalLearnedLiterals
[i
];
2997 Assert(Rewriter::rewrite(learnedLiteral
) == learnedLiteral
);
2998 Assert(d_topLevelSubstitutions
.apply(learnedLiteral
) == learnedLiteral
);
2999 Trace("simplify") << "Process learnedLiteral : " << learnedLiteral
<< std::endl
;
3000 Node learnedLiteralNew
= newSubstitutions
.apply(learnedLiteral
);
3001 if (learnedLiteral
!= learnedLiteralNew
) {
3002 learnedLiteral
= Rewriter::rewrite(learnedLiteralNew
);
3004 Trace("simplify") << "Process learnedLiteral, after newSubs : " << learnedLiteral
<< std::endl
;
3006 learnedLiteralNew
= constantPropagations
.apply(learnedLiteral
);
3007 if (learnedLiteralNew
== learnedLiteral
) {
3010 ++d_smt
.d_stats
->d_numConstantProps
;
3011 learnedLiteral
= Rewriter::rewrite(learnedLiteralNew
);
3013 Trace("simplify") << "Process learnedLiteral, after constProp : " << learnedLiteral
<< std::endl
;
3014 // It might just simplify to a constant
3015 if (learnedLiteral
.isConst()) {
3016 if (learnedLiteral
.getConst
<bool>()) {
3017 // If the learned literal simplifies to true, it's redundant
3020 // If the learned literal simplifies to false, we're in conflict
3021 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3023 << d_nonClausalLearnedLiterals
[i
] << endl
;
3024 Assert(!options::unsatCores());
3025 d_assertions
.clear();
3026 addFormula(NodeManager::currentNM()->mkConst
<bool>(false), false, false);
3027 d_propagatorNeedsFinish
= true;
3032 // Solve it with the corresponding theory, possibly adding new
3033 // substitutions to newSubstitutions
3034 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3035 << "solving " << learnedLiteral
<< endl
;
3037 Theory::PPAssertStatus solveStatus
=
3038 d_smt
.d_theoryEngine
->solve(learnedLiteral
, newSubstitutions
);
3040 switch (solveStatus
) {
3041 case Theory::PP_ASSERT_STATUS_SOLVED
: {
3042 // The literal should rewrite to true
3043 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3044 << "solved " << learnedLiteral
<< endl
;
3045 Assert(Rewriter::rewrite(newSubstitutions
.apply(learnedLiteral
)).isConst());
3046 // vector<pair<Node, Node> > equations;
3047 // constantPropagations.simplifyLHS(d_topLevelSubstitutions, equations, true);
3048 // if (equations.empty()) {
3051 // Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
3052 // else fall through
3055 case Theory::PP_ASSERT_STATUS_CONFLICT
:
3056 // If in conflict, we return false
3057 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3058 << "conflict while solving "
3059 << learnedLiteral
<< endl
;
3060 Assert(!options::unsatCores());
3061 d_assertions
.clear();
3062 addFormula(NodeManager::currentNM()->mkConst
<bool>(false), false, false);
3063 d_propagatorNeedsFinish
= true;
3066 if (d_doConstantProp
&& learnedLiteral
.getKind() == kind::EQUAL
&& (learnedLiteral
[0].isConst() || learnedLiteral
[1].isConst())) {
3067 // constant propagation
3070 if (learnedLiteral
[0].isConst()) {
3071 t
= learnedLiteral
[1];
3072 c
= learnedLiteral
[0];
3075 t
= learnedLiteral
[0];
3076 c
= learnedLiteral
[1];
3078 Assert(!t
.isConst());
3079 Assert(constantPropagations
.apply(t
) == t
);
3080 Assert(d_topLevelSubstitutions
.apply(t
) == t
);
3081 Assert(newSubstitutions
.apply(t
) == t
);
3082 constantPropagations
.addSubstitution(t
, c
);
3083 // vector<pair<Node,Node> > equations;
3084 // constantPropagations.simplifyLHS(t, c, equations, true);
3085 // if (!equations.empty()) {
3086 // Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
3087 // d_assertions.clear();
3088 // addFormula(NodeManager::currentNM()->mkConst<bool>(false), false, false);
3091 // d_topLevelSubstitutions.simplifyRHS(constantPropagations);
3095 d_nonClausalLearnedLiterals
[j
++] = d_nonClausalLearnedLiterals
[i
];
3101 #ifdef CVC4_ASSERTIONS
3102 // NOTE: When debugging this code, consider moving this check inside of the
3103 // loop over d_nonClausalLearnedLiterals. This check has been moved outside
3104 // because it is costly for certain inputs (see bug 508).
3106 // Check data structure invariants:
3107 // 1. for each lhs of d_topLevelSubstitutions, does not appear anywhere in rhs of d_topLevelSubstitutions or anywhere in constantPropagations
3108 // 2. each lhs of constantPropagations rewrites to itself
3109 // 3. if l -> r is a constant propagation and l is a subterm of l' with l' -> r' another constant propagation, then l'[l/r] -> r' should be a
3110 // constant propagation too
3111 // 4. each lhs of constantPropagations is different from each rhs
3112 for (pos
= newSubstitutions
.begin(); pos
!= newSubstitutions
.end(); ++pos
) {
3113 Assert((*pos
).first
.isVar());
3114 Assert(d_topLevelSubstitutions
.apply((*pos
).first
) == (*pos
).first
);
3115 Assert(d_topLevelSubstitutions
.apply((*pos
).second
) == (*pos
).second
);
3116 Assert(newSubstitutions
.apply(newSubstitutions
.apply((*pos
).second
)) == newSubstitutions
.apply((*pos
).second
));
3118 for (pos
= constantPropagations
.begin(); pos
!= constantPropagations
.end(); ++pos
) {
3119 Assert((*pos
).second
.isConst());
3120 Assert(Rewriter::rewrite((*pos
).first
) == (*pos
).first
);
3121 // Node newLeft = d_topLevelSubstitutions.apply((*pos).first);
3122 // if (newLeft != (*pos).first) {
3123 // newLeft = Rewriter::rewrite(newLeft);
3124 // Assert(newLeft == (*pos).second ||
3125 // (constantPropagations.hasSubstitution(newLeft) && constantPropagations.apply(newLeft) == (*pos).second));
3127 // newLeft = constantPropagations.apply((*pos).first);
3128 // if (newLeft != (*pos).first) {
3129 // newLeft = Rewriter::rewrite(newLeft);
3130 // Assert(newLeft == (*pos).second ||
3131 // (constantPropagations.hasSubstitution(newLeft) && constantPropagations.apply(newLeft) == (*pos).second));
3133 Assert(constantPropagations
.apply((*pos
).second
) == (*pos
).second
);
3135 #endif /* CVC4_ASSERTIONS */
3137 // Resize the learnt
3138 Trace("simplify") << "Resize non-clausal learned literals to " << j
<< std::endl
;
3139 d_nonClausalLearnedLiterals
.resize(j
);
3141 unordered_set
<TNode
, TNodeHashFunction
> s
;
3142 Trace("debugging") << "NonClausal simplify pre-preprocess\n";
3143 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3144 Node assertion
= d_assertions
[i
];
3145 Node assertionNew
= newSubstitutions
.apply(assertion
);
3146 Trace("debugging") << "assertion = " << assertion
<< endl
;
3147 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
3148 if (assertion
!= assertionNew
) {
3149 assertion
= Rewriter::rewrite(assertionNew
);
3150 Trace("debugging") << "rewrite(assertion) = " << assertion
<< endl
;
3152 Assert(Rewriter::rewrite(assertion
) == assertion
);
3154 assertionNew
= constantPropagations
.apply(assertion
);
3155 if (assertionNew
== assertion
) {
3158 ++d_smt
.d_stats
->d_numConstantProps
;
3159 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
3160 assertion
= Rewriter::rewrite(assertionNew
);
3161 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
3163 Trace("debugging") << "\n";
3164 s
.insert(assertion
);
3165 d_assertions
.replace(i
, assertion
);
3166 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3167 << "non-clausal preprocessed: "
3168 << assertion
<< endl
;
3171 // If in incremental mode, add substitutions to the list of assertions
3172 if (d_substitutionsIndex
> 0) {
3173 NodeBuilder
<> substitutionsBuilder(kind::AND
);
3174 substitutionsBuilder
<< d_assertions
[d_substitutionsIndex
];
3175 pos
= newSubstitutions
.begin();
3176 for (; pos
!= newSubstitutions
.end(); ++pos
) {
3177 // Add back this substitution as an assertion
3178 TNode lhs
= (*pos
).first
, rhs
= newSubstitutions
.apply((*pos
).second
);
3179 Node n
= NodeManager::currentNM()->mkNode(kind::EQUAL
, lhs
, rhs
);
3180 substitutionsBuilder
<< n
;
3181 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n
<< endl
;
3183 if (substitutionsBuilder
.getNumChildren() > 1) {
3184 d_assertions
.replace(d_substitutionsIndex
,
3185 Rewriter::rewrite(Node(substitutionsBuilder
)));
3188 // If not in incremental mode, must add substitutions to model
3189 TheoryModel
* m
= d_smt
.d_theoryEngine
->getModel();
3191 for(pos
= newSubstitutions
.begin(); pos
!= newSubstitutions
.end(); ++pos
) {
3192 Node n
= (*pos
).first
;
3193 Node v
= newSubstitutions
.apply((*pos
).second
);
3194 Trace("model") << "Add substitution : " << n
<< " " << v
<< endl
;
3195 m
->addSubstitution( n
, v
);
3200 NodeBuilder
<> learnedBuilder(kind::AND
);
3201 Assert(d_realAssertionsEnd
<= d_assertions
.size());
3202 learnedBuilder
<< d_assertions
[d_realAssertionsEnd
- 1];
3204 for (unsigned i
= 0; i
< d_nonClausalLearnedLiterals
.size(); ++ i
) {
3205 Node learned
= d_nonClausalLearnedLiterals
[i
];
3206 Assert(d_topLevelSubstitutions
.apply(learned
) == learned
);
3207 Node learnedNew
= newSubstitutions
.apply(learned
);
3208 if (learned
!= learnedNew
) {
3209 learned
= Rewriter::rewrite(learnedNew
);
3211 Assert(Rewriter::rewrite(learned
) == learned
);
3213 learnedNew
= constantPropagations
.apply(learned
);
3214 if (learnedNew
== learned
) {
3217 ++d_smt
.d_stats
->d_numConstantProps
;
3218 learned
= Rewriter::rewrite(learnedNew
);
3220 if (s
.find(learned
) != s
.end()) {
3224 learnedBuilder
<< learned
;
3225 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3226 << "non-clausal learned : "
3229 d_nonClausalLearnedLiterals
.clear();
3231 for (pos
= constantPropagations
.begin(); pos
!= constantPropagations
.end(); ++pos
) {
3232 Node cProp
= (*pos
).first
.eqNode((*pos
).second
);
3233 Assert(d_topLevelSubstitutions
.apply(cProp
) == cProp
);
3234 Node cPropNew
= newSubstitutions
.apply(cProp
);
3235 if (cProp
!= cPropNew
) {
3236 cProp
= Rewriter::rewrite(cPropNew
);
3237 Assert(Rewriter::rewrite(cProp
) == cProp
);
3239 if (s
.find(cProp
) != s
.end()) {
3243 learnedBuilder
<< cProp
;
3244 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3245 << "non-clausal constant propagation : "
3249 // Add new substitutions to topLevelSubstitutions
3250 // Note that we don't have to keep rhs's in full solved form
3251 // because SubstitutionMap::apply does a fixed-point iteration when substituting
3252 d_topLevelSubstitutions
.addSubstitutions(newSubstitutions
);
3254 if(learnedBuilder
.getNumChildren() > 1) {
3255 d_assertions
.replace(d_realAssertionsEnd
- 1,
3256 Rewriter::rewrite(Node(learnedBuilder
)));
3259 d_propagatorNeedsFinish
= true;
3263 void SmtEnginePrivate::bvAbstraction() {
3264 Trace("bv-abstraction") << "SmtEnginePrivate::bvAbstraction()" << endl
;
3265 std::vector
<Node
> new_assertions
;
3266 bool changed
= d_smt
.d_theoryEngine
->ppBvAbstraction(d_assertions
.ref(), new_assertions
);
3267 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3268 d_assertions
.replace(i
, Rewriter::rewrite(new_assertions
[i
]));
3270 // if we are using the lazy solver and the abstraction
3271 // applies, then UF symbols were introduced
3272 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY
&&
3274 LogicRequest
req(d_smt
);
3275 req
.widenLogic(THEORY_UF
);
3280 void SmtEnginePrivate::bvToBool() {
3281 Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl
;
3282 spendResource(options::preprocessStep());
3283 std::vector
<Node
> new_assertions
;
3284 d_smt
.d_theoryEngine
->ppBvToBool(d_assertions
.ref(), new_assertions
);
3285 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3286 d_assertions
.replace(i
, Rewriter::rewrite(new_assertions
[i
]));
3290 void SmtEnginePrivate::boolToBv() {
3291 Trace("bool-to-bv") << "SmtEnginePrivate::boolToBv()" << endl
;
3292 spendResource(options::preprocessStep());
3293 std::vector
<Node
> new_assertions
;
3294 d_smt
.d_theoryEngine
->ppBoolToBv(d_assertions
.ref(), new_assertions
);
3295 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3296 d_assertions
.replace(i
, Rewriter::rewrite(new_assertions
[i
]));
3300 bool SmtEnginePrivate::simpITE() {
3301 TimerStat::CodeTimer
simpITETimer(d_smt
.d_stats
->d_simpITETime
);
3303 spendResource(options::preprocessStep());
3305 Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl
;
3307 unsigned numAssertionOnEntry
= d_assertions
.size();
3308 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
) {
3309 spendResource(options::preprocessStep());
3310 Node result
= d_smt
.d_theoryEngine
->ppSimpITE(d_assertions
[i
]);
3311 d_assertions
.replace(i
, result
);
3312 if(result
.isConst() && !result
.getConst
<bool>()){
3316 bool result
= d_smt
.d_theoryEngine
->donePPSimpITE(d_assertions
.ref());
3317 if(numAssertionOnEntry
< d_assertions
.size()){
3318 compressBeforeRealAssertions(numAssertionOnEntry
);
3323 void SmtEnginePrivate::compressBeforeRealAssertions(size_t before
){
3324 size_t curr
= d_assertions
.size();
3325 if(before
>= curr
||
3326 d_realAssertionsEnd
<= 0 ||
3327 d_realAssertionsEnd
>= curr
){
3332 // original: [0 ... d_realAssertionsEnd)
3334 // ites skolems [d_realAssertionsEnd, before)
3336 // added [before, curr)
3338 Assert(0 < d_realAssertionsEnd
);
3339 Assert(d_realAssertionsEnd
<= before
);
3340 Assert(before
< curr
);
3342 std::vector
<Node
> intoConjunction
;
3343 for(size_t i
= before
; i
<curr
; ++i
){
3344 intoConjunction
.push_back(d_assertions
[i
]);
3346 d_assertions
.resize(before
);
3347 size_t lastBeforeItes
= d_realAssertionsEnd
- 1;
3348 intoConjunction
.push_back(d_assertions
[lastBeforeItes
]);
3349 Node newLast
= util::NaryBuilder::mkAssoc(kind::AND
, intoConjunction
);
3350 d_assertions
.replace(lastBeforeItes
, newLast
);
3351 Assert(d_assertions
.size() == before
);
3354 void SmtEnginePrivate::unconstrainedSimp() {
3355 TimerStat::CodeTimer
unconstrainedSimpTimer(d_smt
.d_stats
->d_unconstrainedSimpTime
);
3356 spendResource(options::preprocessStep());
3357 Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl
;
3358 d_smt
.d_theoryEngine
->ppUnconstrainedSimp(d_assertions
.ref());
3361 void SmtEnginePrivate::traceBackToAssertions(const std::vector
<Node
>& nodes
, std::vector
<TNode
>& assertions
) {
3362 const booleans::CircuitPropagator::BackEdgesMap
& backEdges
= d_propagator
.getBackEdges();
3363 for(vector
<Node
>::const_iterator i
= nodes
.begin(); i
!= nodes
.end(); ++i
) {
3364 booleans::CircuitPropagator::BackEdgesMap::const_iterator j
= backEdges
.find(*i
);
3365 // term must appear in map, otherwise how did we get here?!
3366 Assert(j
!= backEdges
.end());
3367 // if term maps to empty, that means it's a top-level assertion
3368 if(!(*j
).second
.empty()) {
3369 traceBackToAssertions((*j
).second
, assertions
);
3371 assertions
.push_back(*i
);
3376 size_t SmtEnginePrivate::removeFromConjunction(Node
& n
, const std::unordered_set
<unsigned long>& toRemove
) {
3377 Assert(n
.getKind() == kind::AND
);
3378 size_t removals
= 0;
3379 for(Node::iterator j
= n
.begin(); j
!= n
.end(); ++j
) {
3380 size_t subremovals
= 0;
3382 if(toRemove
.find(sub
.getId()) != toRemove
.end() ||
3383 (sub
.getKind() == kind::AND
&& (subremovals
= removeFromConjunction(sub
, toRemove
)) > 0)) {
3384 NodeBuilder
<> b(kind::AND
);
3385 b
.append(n
.begin(), j
);
3386 if(subremovals
> 0) {
3387 removals
+= subremovals
;
3392 for(++j
; j
!= n
.end(); ++j
) {
3393 if(toRemove
.find((*j
).getId()) != toRemove
.end()) {
3395 } else if((*j
).getKind() == kind::AND
) {
3397 if((subremovals
= removeFromConjunction(sub
, toRemove
)) > 0) {
3398 removals
+= subremovals
;
3407 if(b
.getNumChildren() == 0) {
3410 } else if(b
.getNumChildren() == 1) {
3416 n
= Rewriter::rewrite(n
);
3421 Assert(removals
== 0);
3425 void SmtEnginePrivate::doMiplibTrick() {
3426 Assert(d_realAssertionsEnd
== d_assertions
.size());
3427 Assert(!options::incrementalSolving());
3429 const booleans::CircuitPropagator::BackEdgesMap
& backEdges
= d_propagator
.getBackEdges();
3430 unordered_set
<unsigned long> removeAssertions
;
3432 NodeManager
* nm
= NodeManager::currentNM();
3433 Node zero
= nm
->mkConst(Rational(0)), one
= nm
->mkConst(Rational(1));
3435 unordered_map
<TNode
, Node
, TNodeHashFunction
> intVars
;
3436 for(vector
<Node
>::const_iterator i
= d_boolVars
.begin(); i
!= d_boolVars
.end(); ++i
) {
3437 if(d_propagator
.isAssigned(*i
)) {
3438 Debug("miplib") << "ineligible: " << *i
<< " because assigned " << d_propagator
.getAssignment(*i
) << endl
;
3442 vector
<TNode
> assertions
;
3443 booleans::CircuitPropagator::BackEdgesMap::const_iterator j
= backEdges
.find(*i
);
3444 // if not in back edges map, the bool var is unconstrained, showing up in no assertions.
3445 // if maps to an empty vector, that means the bool var was asserted itself.
3446 if(j
!= backEdges
.end()) {
3447 if(!(*j
).second
.empty()) {
3448 traceBackToAssertions((*j
).second
, assertions
);
3450 assertions
.push_back(*i
);
3453 Debug("miplib") << "for " << *i
<< endl
;
3454 bool eligible
= true;
3455 map
<pair
<Node
, Node
>, uint64_t> marks
;
3456 map
<pair
<Node
, Node
>, vector
<Rational
> > coef
;
3457 map
<pair
<Node
, Node
>, vector
<Rational
> > checks
;
3458 map
<pair
<Node
, Node
>, vector
<TNode
> > asserts
;
3459 for(vector
<TNode
>::const_iterator j
= assertions
.begin(); j
!= assertions
.end(); ++j
) {
3460 Debug("miplib") << " found: " << *j
<< endl
;
3461 if((*j
).getKind() != kind::IMPLIES
) {
3463 Debug("miplib") << " -- INELIGIBLE -- (not =>)" << endl
;
3466 Node conj
= BooleanSimplification::simplify((*j
)[0]);
3467 if(conj
.getKind() == kind::AND
&& conj
.getNumChildren() > 6) {
3469 Debug("miplib") << " -- INELIGIBLE -- (N-ary /\\ too big)" << endl
;
3472 if(conj
.getKind() != kind::AND
&& !conj
.isVar() && !(conj
.getKind() == kind::NOT
&& conj
[0].isVar())) {
3474 Debug("miplib") << " -- INELIGIBLE -- (not /\\ or literal)" << endl
;
3477 if((*j
)[1].getKind() != kind::EQUAL
||
3478 !( ( (*j
)[1][0].isVar() &&
3479 (*j
)[1][1].getKind() == kind::CONST_RATIONAL
) ||
3480 ( (*j
)[1][0].getKind() == kind::CONST_RATIONAL
&&
3481 (*j
)[1][1].isVar() ) )) {
3483 Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl
;
3486 if(conj
.getKind() == kind::AND
) {
3488 bool found_x
= false;
3489 map
<TNode
, bool> neg
;
3490 for(Node::iterator ii
= conj
.begin(); ii
!= conj
.end(); ++ii
) {
3492 posv
.push_back(*ii
);
3494 found_x
= found_x
|| *i
== *ii
;
3495 } else if((*ii
).getKind() == kind::NOT
&& (*ii
)[0].isVar()) {
3496 posv
.push_back((*ii
)[0]);
3497 neg
[(*ii
)[0]] = true;
3498 found_x
= found_x
|| *i
== (*ii
)[0];
3501 Debug("miplib") << " -- INELIGIBLE -- (non-var: " << *ii
<< ")" << endl
;
3504 if(d_propagator
.isAssigned(posv
.back())) {
3506 Debug("miplib") << " -- INELIGIBLE -- (" << posv
.back() << " asserted)" << endl
;
3515 Debug("miplib") << " --INELIGIBLE -- (couldn't find " << *i
<< " in conjunction)" << endl
;
3518 sort(posv
.begin(), posv
.end());
3519 const Node pos
= NodeManager::currentNM()->mkNode(kind::AND
, posv
);
3520 const TNode var
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][1] : (*j
)[1][0];
3521 const pair
<Node
, Node
> pos_var(pos
, var
);
3522 const Rational
& constant
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][0].getConst
<Rational
>() : (*j
)[1][1].getConst
<Rational
>();
3524 unsigned countneg
= 0, thepos
= 0;
3525 for(unsigned ii
= 0; ii
< pos
.getNumChildren(); ++ii
) {
3530 mark
|= (0x1 << ii
);
3533 if((marks
[pos_var
] & (1lu << mark
)) != 0) {
3535 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl
;
3538 Debug("miplib") << "mark is " << mark
<< " -- " << (1lu << mark
) << endl
;
3539 marks
[pos_var
] |= (1lu << mark
);
3540 Debug("miplib") << "marks[" << pos
<< "," << var
<< "] now " << marks
[pos_var
] << endl
;
3541 if(countneg
== pos
.getNumChildren()) {
3544 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl
;
3547 } else if(countneg
== pos
.getNumChildren() - 1) {
3548 Assert(coef
[pos_var
].size() <= 6 && thepos
< 6);
3549 if(coef
[pos_var
].size() <= thepos
) {
3550 coef
[pos_var
].resize(thepos
+ 1);
3552 coef
[pos_var
][thepos
] = constant
;
3554 if(checks
[pos_var
].size() <= mark
) {
3555 checks
[pos_var
].resize(mark
+ 1);
3557 checks
[pos_var
][mark
] = constant
;
3559 asserts
[pos_var
].push_back(*j
);
3562 if(x
!= *i
&& x
!= (*i
).notNode()) {
3564 Debug("miplib") << " -- INELIGIBLE -- (x not present where I expect it)" << endl
;
3567 const bool xneg
= (x
.getKind() == kind::NOT
);
3568 x
= xneg
? x
[0] : x
;
3569 Debug("miplib") << " x:" << x
<< " " << xneg
<< endl
;
3570 const TNode var
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][1] : (*j
)[1][0];
3571 const pair
<Node
, Node
> x_var(x
, var
);
3572 const Rational
& constant
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][0].getConst
<Rational
>() : (*j
)[1][1].getConst
<Rational
>();
3573 unsigned mark
= (xneg
? 0 : 1);
3574 if((marks
[x_var
] & (1u << mark
)) != 0) {
3576 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl
;
3579 marks
[x_var
] |= (1u << mark
);
3583 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl
;
3587 Assert(coef
[x_var
].size() <= 6);
3588 coef
[x_var
].resize(6);
3589 coef
[x_var
][0] = constant
;
3591 asserts
[x_var
].push_back(*j
);
3595 for(map
<pair
<Node
, Node
>, uint64_t>::const_iterator j
= marks
.begin(); j
!= marks
.end(); ++j
) {
3596 const TNode pos
= (*j
).first
.first
;
3597 const TNode var
= (*j
).first
.second
;
3598 const pair
<Node
, Node
>& pos_var
= (*j
).first
;
3599 const uint64_t mark
= (*j
).second
;
3600 const unsigned numVars
= pos
.getKind() == kind::AND
? pos
.getNumChildren() : 1;
3601 uint64_t expected
= (uint64_t(1) << (1 << numVars
)) - 1;
3602 expected
= (expected
== 0) ? -1 : expected
; // fix for overflow
3603 Debug("miplib") << "[" << pos
<< "] => " << hex
<< mark
<< " expect " << expected
<< dec
<< endl
;
3604 Assert(pos
.getKind() == kind::AND
|| pos
.isVar());
3605 if(mark
!= expected
) {
3606 Debug("miplib") << " -- INELIGIBLE " << pos
<< " -- (insufficiently marked, got " << mark
<< " for " << numVars
<< " vars, expected " << expected
<< endl
;
3608 if(mark
!= 3) { // exclude single-var case; nothing to check there
3609 uint64_t sz
= (uint64_t(1) << checks
[pos_var
].size()) - 1;
3610 sz
= (sz
== 0) ? -1 : sz
; // fix for overflow
3611 Assert(sz
== mark
, "expected size %u == mark %u", sz
, mark
);
3612 for(size_t k
= 0; k
< checks
[pos_var
].size(); ++k
) {
3613 if((k
& (k
- 1)) != 0) {
3615 Debug("miplib") << k
<< " => " << checks
[pos_var
][k
] << endl
;
3616 for(size_t v
= 1, kk
= k
; kk
!= 0; ++v
, kk
>>= 1) {
3617 if((kk
& 0x1) == 1) {
3618 Assert(pos
.getKind() == kind::AND
);
3619 Debug("miplib") << "var " << v
<< " : " << pos
[v
- 1] << " coef:" << coef
[pos_var
][v
- 1] << endl
;
3620 sum
+= coef
[pos_var
][v
- 1];
3623 Debug("miplib") << "checkSum is " << sum
<< " input says " << checks
[pos_var
][k
] << endl
;
3624 if(sum
!= checks
[pos_var
][k
]) {
3626 Debug("miplib") << " -- INELIGIBLE " << pos
<< " -- (nonlinear combination)" << endl
;
3630 Assert(checks
[pos_var
][k
] == 0, "checks[(%s,%s)][%u] should be 0, but it's %s", pos
.toString().c_str(), var
.toString().c_str(), k
, checks
[pos_var
][k
].toString().c_str()); // we never set for single-positive-var
3635 eligible
= true; // next is still eligible
3639 Debug("miplib") << " -- ELIGIBLE " << *i
<< " , " << pos
<< " --" << endl
;
3640 vector
<Node
> newVars
;
3641 expr::NodeSelfIterator ii
, iiend
;
3642 if(pos
.getKind() == kind::AND
) {
3646 ii
= expr::NodeSelfIterator::self(pos
);
3647 iiend
= expr::NodeSelfIterator::selfEnd(pos
);
3649 for(; ii
!= iiend
; ++ii
) {
3650 Node
& varRef
= intVars
[*ii
];
3651 if(varRef
.isNull()) {
3653 ss
<< "mipvar_" << *ii
;
3654 Node newVar
= nm
->mkSkolem(ss
.str(), nm
->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME
);
3655 Node geq
= Rewriter::rewrite(nm
->mkNode(kind::GEQ
, newVar
, zero
));
3656 Node leq
= Rewriter::rewrite(nm
->mkNode(kind::LEQ
, newVar
, one
));
3657 addFormula(Rewriter::rewrite(geq
.andNode(leq
)), false, false);
3658 SubstitutionMap
nullMap(&d_fakeContext
);
3659 Theory::PPAssertStatus status CVC4_UNUSED
; // just for assertions
3660 status
= d_smt
.d_theoryEngine
->solve(geq
, nullMap
);
3661 Assert(status
== Theory::PP_ASSERT_STATUS_UNSOLVED
,
3662 "unexpected solution from arith's ppAssert()");
3663 Assert(nullMap
.empty(),
3664 "unexpected substitution from arith's ppAssert()");
3665 status
= d_smt
.d_theoryEngine
->solve(leq
, nullMap
);
3666 Assert(status
== Theory::PP_ASSERT_STATUS_UNSOLVED
,
3667 "unexpected solution from arith's ppAssert()");
3668 Assert(nullMap
.empty(),
3669 "unexpected substitution from arith's ppAssert()");
3670 d_smt
.d_theoryEngine
->getModel()->addSubstitution(*ii
, newVar
.eqNode(one
));
3671 newVars
.push_back(newVar
);
3674 newVars
.push_back(varRef
);
3676 if(!d_smt
.d_logic
.areIntegersUsed()) {
3677 d_smt
.d_logic
= d_smt
.d_logic
.getUnlockedCopy();
3678 d_smt
.d_logic
.enableIntegers();
3679 d_smt
.d_logic
.lock();
3683 if(pos
.getKind() == kind::AND
) {
3684 NodeBuilder
<> sumb(kind::PLUS
);
3685 for(size_t ii
= 0; ii
< pos
.getNumChildren(); ++ii
) {
3686 sumb
<< nm
->mkNode(kind::MULT
, nm
->mkConst(coef
[pos_var
][ii
]), newVars
[ii
]);
3690 sum
= nm
->mkNode(kind::MULT
, nm
->mkConst(coef
[pos_var
][0]), newVars
[0]);
3692 Debug("miplib") << "vars[] " << var
<< endl
3693 << " eq " << Rewriter::rewrite(sum
) << endl
;
3694 Node newAssertion
= var
.eqNode(Rewriter::rewrite(sum
));
3695 if(d_topLevelSubstitutions
.hasSubstitution(newAssertion
[0])) {
3696 //Warning() << "RE-SUBSTITUTION " << newAssertion[0] << endl;
3697 //Warning() << "REPLACE " << newAssertion[1] << endl;
3698 //Warning() << "ORIG " << d_topLevelSubstitutions.getSubstitution(newAssertion[0]) << endl;
3699 Assert(d_topLevelSubstitutions
.getSubstitution(newAssertion
[0]) == newAssertion
[1]);
3700 } else if(pos
.getNumChildren() <= options::arithMLTrickSubstitutions()) {
3701 d_topLevelSubstitutions
.addSubstitution(newAssertion
[0], newAssertion
[1]);
3702 Debug("miplib") << "addSubs: " << newAssertion
[0] << " to " << newAssertion
[1] << endl
;
3704 Debug("miplib") << "skipSubs: " << newAssertion
[0] << " to " << newAssertion
[1] << " (threshold is " << options::arithMLTrickSubstitutions() << ")" << endl
;
3706 newAssertion
= Rewriter::rewrite(newAssertion
);
3707 Debug("miplib") << " " << newAssertion
<< endl
;
3708 addFormula(newAssertion
, false, false);
3709 Debug("miplib") << " assertions to remove: " << endl
;
3710 for(vector
<TNode
>::const_iterator k
= asserts
[pos_var
].begin(), k_end
= asserts
[pos_var
].end(); k
!= k_end
; ++k
) {
3711 Debug("miplib") << " " << *k
<< endl
;
3712 removeAssertions
.insert((*k
).getId());
3718 if(!removeAssertions
.empty()) {
3719 Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl
;
3720 for(size_t i
= 0; i
< d_realAssertionsEnd
; ++i
) {
3721 if(removeAssertions
.find(d_assertions
[i
].getId()) != removeAssertions
.end()) {
3722 Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertions
[i
] << endl
;
3723 d_assertions
[i
] = d_true
;
3724 ++d_smt
.d_stats
->d_numMiplibAssertionsRemoved
;
3725 } else if(d_assertions
[i
].getKind() == kind::AND
) {
3726 size_t removals
= removeFromConjunction(d_assertions
[i
], removeAssertions
);
3728 Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertions
[i
] << endl
;
3729 Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals
<< " conjuncts" << endl
;
3730 d_smt
.d_stats
->d_numMiplibAssertionsRemoved
+= removals
;
3733 Debug("miplib") << "had: " << d_assertions
[i
] << endl
;
3734 d_assertions
[i
] = Rewriter::rewrite(d_topLevelSubstitutions
.apply(d_assertions
[i
]));
3735 Debug("miplib") << "now: " << d_assertions
[i
] << endl
;
3738 Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl
;
3740 d_realAssertionsEnd
= d_assertions
.size();
3744 // returns false if simplification led to "false"
3745 bool SmtEnginePrivate::simplifyAssertions()
3747 spendResource(options::preprocessStep());
3748 Assert(d_smt
.d_pendingPops
== 0);
3750 ScopeCounter
depth(d_simplifyAssertionsDepth
);
3752 Trace("simplify") << "SmtEnginePrivate::simplify()" << endl
;
3754 dumpAssertions("pre-nonclausal", d_assertions
);
3756 if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
3757 // Perform non-clausal simplification
3758 Chat() << "...performing nonclausal simplification..." << endl
;
3759 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3760 << "performing non-clausal simplification" << endl
;
3761 bool noConflict
= nonClausalSimplify();
3766 // We piggy-back off of the BackEdgesMap in the CircuitPropagator to
3767 // do the miplib trick.
3768 if( // check that option is on
3769 options::arithMLTrick() &&
3770 // miplib rewrites aren't safe in incremental mode
3771 ! options::incrementalSolving() &&
3772 // only useful in arith
3773 d_smt
.d_logic
.isTheoryEnabled(THEORY_ARITH
) &&
3774 // we add new assertions and need this (in practice, this
3775 // restriction only disables miplib processing during
3776 // re-simplification, which we don't expect to be useful anyway)
3777 d_realAssertionsEnd
== d_assertions
.size() ) {
3778 Chat() << "...fixing miplib encodings..." << endl
;
3779 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3780 << "looking for miplib pseudobooleans..." << endl
;
3782 TimerStat::CodeTimer
miplibTimer(d_smt
.d_stats
->d_miplibPassTime
);
3786 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3787 << "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl
;
3791 dumpAssertions("post-nonclausal", d_assertions
);
3792 Trace("smt") << "POST nonClausalSimplify" << endl
;
3793 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3795 // before ppRewrite check if only core theory for BV theory
3796 d_smt
.d_theoryEngine
->staticInitializeBVOptions(d_assertions
.ref());
3798 dumpAssertions("pre-theorypp", d_assertions
);
3800 // Theory preprocessing
3801 if (d_smt
.d_earlyTheoryPP
) {
3802 Chat() << "...doing early theory preprocessing..." << endl
;
3803 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
3804 // Call the theory preprocessors
3805 d_smt
.d_theoryEngine
->preprocessStart();
3806 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3807 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
3808 d_assertions
.replace(i
, d_smt
.d_theoryEngine
->preprocess(d_assertions
[i
]));
3809 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
3813 dumpAssertions("post-theorypp", d_assertions
);
3814 Trace("smt") << "POST theoryPP" << endl
;
3815 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3817 // ITE simplification
3818 if(options::doITESimp() &&
3819 (d_simplifyAssertionsDepth
<= 1 || options::doITESimpOnRepeat())) {
3820 Chat() << "...doing ITE simplification..." << endl
;
3821 bool noConflict
= simpITE();
3823 Chat() << "...ITE simplification found unsat..." << endl
;
3828 dumpAssertions("post-itesimp", d_assertions
);
3829 Trace("smt") << "POST iteSimp" << endl
;
3830 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3832 // Unconstrained simplification
3833 if(options::unconstrainedSimp()) {
3834 Chat() << "...doing unconstrained simplification..." << endl
;
3835 unconstrainedSimp();
3838 dumpAssertions("post-unconstrained", d_assertions
);
3839 Trace("smt") << "POST unconstrainedSimp" << endl
;
3840 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3842 if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
3843 Chat() << "...doing another round of nonclausal simplification..." << endl
;
3844 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3845 << " doing repeated simplification" << endl
;
3846 bool noConflict
= nonClausalSimplify();
3852 dumpAssertions("post-repeatsimp", d_assertions
);
3853 Trace("smt") << "POST repeatSimp" << endl
;
3854 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3856 } catch(TypeCheckingExceptionPrivate
& tcep
) {
3857 // Calls to this function should have already weeded out any
3858 // typechecking exceptions via (e.g.) ensureBoolean(). But a
3859 // theory could still create a new expression that isn't
3860 // well-typed, and we don't want the C++ runtime to abort our
3861 // process without any error notice.
3863 ss
<< "A bad expression was produced. Original exception follows:\n"
3865 InternalError(ss
.str().c_str());
3870 Result
SmtEngine::check() {
3871 Assert(d_fullyInited
);
3872 Assert(d_pendingPops
== 0);
3874 Trace("smt") << "SmtEngine::check()" << endl
;
3876 ResourceManager
* resourceManager
= d_private
->getResourceManager();
3878 resourceManager
->beginCall();
3880 // Only way we can be out of resource is if cumulative budget is on
3881 if (resourceManager
->cumulativeLimitOn() &&
3882 resourceManager
->out()) {
3883 Result::UnknownExplanation why
= resourceManager
->outOfResources() ?
3884 Result::RESOURCEOUT
: Result::TIMEOUT
;
3885 return Result(Result::VALIDITY_UNKNOWN
, why
, d_filename
);
3888 // Make sure the prop layer has all of the assertions
3889 Trace("smt") << "SmtEngine::check(): processing assertions" << endl
;
3890 d_private
->processAssertions();
3891 Trace("smt") << "SmtEngine::check(): done processing assertions" << endl
;
3893 // Turn off stop only for QF_LRA
3894 // TODO: Bring up in a meeting where to put this
3895 if(options::decisionStopOnly() && !options::decisionMode
.wasSetByUser() ){
3897 (not d_logic
.isQuantified() &&
3898 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
3900 if(d_private
->d_iteSkolemMap
.empty()){
3901 options::decisionStopOnly
.set(false);
3902 d_decisionEngine
->clearStrategies();
3903 Trace("smt") << "SmtEngine::check(): turning off stop only" << endl
;
3908 TimerStat::CodeTimer
solveTimer(d_stats
->d_solveTime
);
3910 Chat() << "solving..." << endl
;
3911 Trace("smt") << "SmtEngine::check(): running check" << endl
;
3912 Result result
= d_propEngine
->checkSat();
3914 resourceManager
->endCall();
3915 Trace("limit") << "SmtEngine::check(): cumulative millis " << resourceManager
->getTimeUsage()
3916 << ", resources " << resourceManager
->getResourceUsage() << endl
;
3919 return Result(result
, d_filename
);
3922 Result
SmtEngine::quickCheck() {
3923 Assert(d_fullyInited
);
3924 Trace("smt") << "SMT quickCheck()" << endl
;
3925 return Result(Result::VALIDITY_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, d_filename
);
3929 void SmtEnginePrivate::collectSkolems(TNode n
, set
<TNode
>& skolemSet
, unordered_map
<Node
, bool, NodeHashFunction
>& cache
)
3931 unordered_map
<Node
, bool, NodeHashFunction
>::iterator it
;
3933 if (it
!= cache
.end()) {
3937 size_t sz
= n
.getNumChildren();
3939 IteSkolemMap::iterator it
= d_iteSkolemMap
.find(n
);
3940 if (it
!= d_iteSkolemMap
.end()) {
3941 skolemSet
.insert(n
);
3948 for (; k
< sz
; ++k
) {
3949 collectSkolems(n
[k
], skolemSet
, cache
);
3955 bool SmtEnginePrivate::checkForBadSkolems(TNode n
, TNode skolem
, unordered_map
<Node
, bool, NodeHashFunction
>& cache
)
3957 unordered_map
<Node
, bool, NodeHashFunction
>::iterator it
;
3959 if (it
!= cache
.end()) {
3960 return (*it
).second
;
3963 size_t sz
= n
.getNumChildren();
3965 IteSkolemMap::iterator it
= d_iteSkolemMap
.find(n
);
3967 if (it
!= d_iteSkolemMap
.end()) {
3968 if (!((*it
).first
< n
)) {
3977 for (; k
< sz
; ++k
) {
3978 if (checkForBadSkolems(n
[k
], skolem
, cache
)) {
3988 void SmtEnginePrivate::applySubstitutionsToAssertions() {
3989 if(!options::unsatCores()) {
3990 Chat() << "applying substitutions..." << endl
;
3991 Trace("simplify") << "SmtEnginePrivate::processAssertions(): "
3992 << "applying substitutions" << endl
;
3993 // TODO(b/1255): Substitutions in incremental mode should be managed with a
3994 // proper data structure.
3996 // When solving incrementally, all substitutions are piled into the
3997 // assertion at d_substitutionsIndex: we don't want to apply substitutions
3998 // to this assertion or information will be lost.
3999 unsigned substitutionAssertion
= d_substitutionsIndex
> 0 ? d_substitutionsIndex
: d_assertions
.size();
4000 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4001 if (i
== substitutionAssertion
) {
4004 Trace("simplify") << "applying to " << d_assertions
[i
] << endl
;
4005 spendResource(options::preprocessStep());
4006 d_assertions
.replace(i
, Rewriter::rewrite(d_topLevelSubstitutions
.apply(d_assertions
[i
])));
4007 Trace("simplify") << " got " << d_assertions
[i
] << endl
;
4012 void SmtEnginePrivate::processAssertions() {
4013 TimerStat::CodeTimer
paTimer(d_smt
.d_stats
->d_processAssertionsTime
);
4014 spendResource(options::preprocessStep());
4015 Assert(d_smt
.d_fullyInited
);
4016 Assert(d_smt
.d_pendingPops
== 0);
4018 // Dump the assertions
4019 dumpAssertions("pre-everything", d_assertions
);
4021 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() begin" << endl
;
4022 Trace("smt") << "SmtEnginePrivate::processAssertions()" << endl
;
4024 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4026 if (d_assertions
.size() == 0) {
4031 if (options::bvGaussElim())
4033 TimerStat::CodeTimer
gaussElimTimer(d_smt
.d_stats
->d_gaussElimTime
);
4034 d_preprocessingPassRegistry
.getPass("bv-gauss")->apply(&d_assertions
);
4037 if (d_assertionsProcessed
&& options::incrementalSolving()) {
4038 // TODO(b/1255): Substitutions in incremental mode should be managed with a
4039 // proper data structure.
4041 // Placeholder for storing substitutions
4042 d_substitutionsIndex
= d_assertions
.size();
4043 d_assertions
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
4046 // Add dummy assertion in last position - to be used as a
4047 // placeholder for any new assertions to get added
4048 d_assertions
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
4049 // any assertions added beyond realAssertionsEnd must NOT affect the
4050 // equisatisfiability
4051 d_realAssertionsEnd
= d_assertions
.size();
4053 // Assertions are NOT guaranteed to be rewritten by this point
4055 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-definition-expansion" << endl
;
4056 dumpAssertions("pre-definition-expansion", d_assertions
);
4058 Chat() << "expanding definitions..." << endl
;
4059 Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl
;
4060 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_definitionExpansionTime
);
4061 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4062 for(unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4063 d_assertions
.replace(i
, expandDefinitions(d_assertions
[i
], cache
));
4066 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-definition-expansion" << endl
;
4067 dumpAssertions("post-definition-expansion", d_assertions
);
4069 // save the assertions now
4072 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
) {
4073 ProofManager::currentPM()->addAssertion(d_assertions
[i
].toExpr());
4077 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4079 if (options::sygusInference())
4081 // try recast as sygus
4082 quantifiers::SygusInference si
;
4083 if (si
.simplify(d_assertions
.ref()))
4085 Trace("smt-proc") << "...converted to sygus conjecture." << std::endl
;
4086 d_smt
.d_globalNegation
= !d_smt
.d_globalNegation
;
4089 else if (options::globalNegate())
4091 // global negation of the formula
4092 quantifiers::GlobalNegate gn
;
4093 gn
.simplify(d_assertions
.ref());
4094 d_smt
.d_globalNegation
= !d_smt
.d_globalNegation
;
4097 if( options::nlExtPurify() ){
4098 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4099 unordered_map
<Node
, Node
, NodeHashFunction
> bcache
;
4100 std::vector
< Node
> var_eq
;
4101 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4102 d_assertions
.replace(i
, purifyNlTerms(d_assertions
[i
], cache
, bcache
, var_eq
));
4104 if( !var_eq
.empty() ){
4105 unsigned lastIndex
= d_assertions
.size()-1;
4106 var_eq
.insert( var_eq
.begin(), d_assertions
[lastIndex
] );
4107 d_assertions
.replace(lastIndex
, NodeManager::currentNM()->mkNode( kind::AND
, var_eq
) );
4111 if( options::ceGuidedInst() ){
4112 //register sygus conjecture pre-rewrite (motivated by solution reconstruction)
4113 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4114 d_smt
.d_theoryEngine
->getQuantifiersEngine()->getCegInstantiation()->preregisterAssertion( d_assertions
[i
] );
4118 if (options::solveRealAsInt()) {
4119 Chat() << "converting reals to ints..." << endl
;
4120 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4121 std::vector
< Node
> var_eq
;
4122 for(unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4123 d_assertions
.replace(i
, realToInt(d_assertions
[i
], cache
, var_eq
));
4126 if( !var_eq.empty() ){
4127 unsigned lastIndex = d_assertions.size()-1;
4128 var_eq.insert( var_eq.begin(), d_assertions[lastIndex] );
4129 d_assertions.replace(last_index, NodeManager::currentNM()->mkNode( kind::AND, var_eq ) );
4134 if (options::solveIntAsBV() > 0)
4136 d_preprocessingPassRegistry
.getPass("int-to-bv")->apply(&d_assertions
);
4139 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
&&
4140 !d_smt
.d_logic
.isPure(THEORY_BV
) &&
4141 d_smt
.d_logic
.getLogicString() != "QF_UFBV" &&
4142 d_smt
.d_logic
.getLogicString() != "QF_ABV") {
4143 throw ModalException("Eager bit-blasting does not currently support theory combination. "
4144 "Note that in a QF_BV problem UF symbols can be introduced for division. "
4145 "Try --bv-div-zero-const to interpret division by zero as a constant.");
4148 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
) {
4149 d_smt
.d_theoryEngine
->mkAckermanizationAssertions(d_assertions
.ref());
4152 if ( options::bvAbstraction() &&
4153 !options::incrementalSolving()) {
4154 dumpAssertions("pre-bv-abstraction", d_assertions
);
4156 dumpAssertions("post-bv-abstraction", d_assertions
);
4159 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4161 bool noConflict
= true;
4163 if (options::extRewPrep())
4165 theory::quantifiers::ExtendedRewriter
extr(options::extRewPrepAgg());
4166 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
)
4168 Node a
= d_assertions
[i
];
4169 d_assertions
.replace(i
, extr
.extendedRewrite(a
));
4173 // Unconstrained simplification
4174 if(options::unconstrainedSimp()) {
4175 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-unconstrained-simp" << endl
;
4176 dumpAssertions("pre-unconstrained-simp", d_assertions
);
4177 Chat() << "...doing unconstrained simplification..." << endl
;
4178 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4179 d_assertions
.replace(i
, Rewriter::rewrite(d_assertions
[i
]));
4181 unconstrainedSimp();
4182 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-unconstrained-simp" << endl
;
4183 dumpAssertions("post-unconstrained-simp", d_assertions
);
4186 if(options::bvIntroducePow2()){
4187 theory::bv::BVIntroducePow2::pow2Rewrite(d_assertions
.ref());
4190 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-substitution" << endl
;
4191 dumpAssertions("pre-substitution", d_assertions
);
4193 if(options::unsatCores()) {
4194 // special rewriting pass for unsat cores, since many of the passes below are skipped
4195 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4196 d_assertions
.replace(i
, Rewriter::rewrite(d_assertions
[i
]));
4199 applySubstitutionsToAssertions();
4201 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-substitution" << endl
;
4202 dumpAssertions("post-substitution", d_assertions
);
4204 // Assertions ARE guaranteed to be rewritten by this point
4205 #ifdef CVC4_ASSERTIONS
4206 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
)
4208 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
4212 // Lift bit-vectors of size 1 to bool
4213 if(options::bitvectorToBool()) {
4214 dumpAssertions("pre-bv-to-bool", d_assertions
);
4215 Chat() << "...doing bvToBool..." << endl
;
4217 dumpAssertions("post-bv-to-bool", d_assertions
);
4218 Trace("smt") << "POST bvToBool" << endl
;
4220 // Convert non-top-level Booleans to bit-vectors of size 1
4221 if(options::boolToBitvector()) {
4222 dumpAssertions("pre-bool-to-bv", d_assertions
);
4223 Chat() << "...doing boolToBv..." << endl
;
4225 dumpAssertions("post-bool-to-bv", d_assertions
);
4226 Trace("smt") << "POST boolToBv" << endl
;
4228 if(options::sepPreSkolemEmp()) {
4229 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4230 Node prev
= d_assertions
[i
];
4231 Node next
= sep::TheorySepRewriter::preprocess( prev
);
4233 d_assertions
.replace( i
, Rewriter::rewrite( next
) );
4234 Trace("sep-preprocess") << "*** Preprocess sep " << prev
<< endl
;
4235 Trace("sep-preprocess") << " ...got " << d_assertions
[i
] << endl
;
4240 if( d_smt
.d_logic
.isQuantified() ){
4241 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-quant-preprocess" << endl
;
4243 dumpAssertions("pre-skolem-quant", d_assertions
);
4244 //remove rewrite rules, apply pre-skolemization to existential quantifiers
4245 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4246 Node prev
= d_assertions
[i
];
4247 Node next
= quantifiers::QuantifiersRewriter::preprocess( prev
);
4249 d_assertions
.replace( i
, Rewriter::rewrite( next
) );
4250 Trace("quantifiers-preprocess") << "*** Pre-skolemize " << prev
<< endl
;
4251 Trace("quantifiers-preprocess") << " ...got " << d_assertions
[i
] << endl
;
4254 dumpAssertions("post-skolem-quant", d_assertions
);
4255 if( options::macrosQuant() ){
4256 //quantifiers macro expansion
4257 quantifiers::QuantifierMacros
qm( d_smt
.d_theoryEngine
->getQuantifiersEngine() );
4260 success
= qm
.simplify( d_assertions
.ref(), true );
4262 //finalize the definitions
4263 qm
.finalizeDefinitions();
4266 //fmf-fun : assume admissible functions, applying preprocessing reduction to FMF
4267 if( options::fmfFunWellDefined() ){
4268 quantifiers::FunDefFmf fdf
;
4269 Assert( d_smt
.d_fmfRecFunctionsDefined
!=NULL
);
4270 //must carry over current definitions (for incremental)
4271 for( context::CDList
<Node
>::const_iterator fit
= d_smt
.d_fmfRecFunctionsDefined
->begin();
4272 fit
!= d_smt
.d_fmfRecFunctionsDefined
->end(); ++fit
) {
4274 Assert( d_smt
.d_fmfRecFunctionsAbs
.find( f
)!=d_smt
.d_fmfRecFunctionsAbs
.end() );
4275 TypeNode ft
= d_smt
.d_fmfRecFunctionsAbs
[f
];
4276 fdf
.d_sorts
[f
] = ft
;
4277 std::map
< Node
, std::vector
< Node
> >::iterator fcit
= d_smt
.d_fmfRecFunctionsConcrete
.find( f
);
4278 Assert( fcit
!=d_smt
.d_fmfRecFunctionsConcrete
.end() );
4279 for( unsigned j
=0; j
<fcit
->second
.size(); j
++ ){
4280 fdf
.d_input_arg_inj
[f
].push_back( fcit
->second
[j
] );
4283 fdf
.simplify( d_assertions
.ref() );
4284 //must store new definitions (for incremental)
4285 for( unsigned i
=0; i
<fdf
.d_funcs
.size(); i
++ ){
4286 Node f
= fdf
.d_funcs
[i
];
4287 d_smt
.d_fmfRecFunctionsAbs
[f
] = fdf
.d_sorts
[f
];
4288 d_smt
.d_fmfRecFunctionsConcrete
[f
].clear();
4289 for( unsigned j
=0; j
<fdf
.d_input_arg_inj
[f
].size(); j
++ ){
4290 d_smt
.d_fmfRecFunctionsConcrete
[f
].push_back( fdf
.d_input_arg_inj
[f
][j
] );
4292 d_smt
.d_fmfRecFunctionsDefined
->push_back( f
);
4295 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-quant-preprocess" << endl
;
4298 if( options::sortInference() || options::ufssFairnessMonotone() ){
4299 //sort inference technique
4300 SortInference
* si
= d_smt
.d_theoryEngine
->getSortInference();
4301 si
->simplify( d_assertions
.ref(), options::sortInference(), options::ufssFairnessMonotone() );
4302 for( std::map
< Node
, Node
>::iterator it
= si
->d_model_replace_f
.begin(); it
!= si
->d_model_replace_f
.end(); ++it
){
4303 d_smt
.setPrintFuncInModel( it
->first
.toExpr(), false );
4304 d_smt
.setPrintFuncInModel( it
->second
.toExpr(), true );
4308 if( options::pbRewrites() ){
4309 d_preprocessingPassRegistry
.getPass("pseudo-boolean-processor")
4310 ->apply(&d_assertions
);
4313 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-simplify" << endl
;
4314 dumpAssertions("pre-simplify", d_assertions
);
4315 Chat() << "simplifying assertions..." << endl
;
4316 noConflict
= simplifyAssertions();
4318 ++(d_smt
.d_stats
->d_simplifiedToFalse
);
4320 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-simplify" << endl
;
4321 dumpAssertions("post-simplify", d_assertions
);
4323 if (options::symmetryDetect())
4325 SymmetryDetect symd
;
4326 vector
<vector
<Node
>> part
;
4327 symd
.getPartition(part
, d_assertions
.ref());
4330 dumpAssertions("pre-static-learning", d_assertions
);
4331 if(options::doStaticLearning()) {
4332 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-static-learning" << endl
;
4333 // Perform static learning
4334 Chat() << "doing static learning..." << endl
;
4335 Trace("simplify") << "SmtEnginePrivate::simplify(): "
4336 << "performing static learning" << endl
;
4338 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-static-learning" << endl
;
4340 dumpAssertions("post-static-learning", d_assertions
);
4342 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4345 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-ite-removal" << endl
;
4346 dumpAssertions("pre-ite-removal", d_assertions
);
4348 Chat() << "removing term ITEs..." << endl
;
4349 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_iteRemovalTime
);
4350 // Remove ITEs, updating d_iteSkolemMap
4351 d_smt
.d_stats
->d_numAssertionsPre
+= d_assertions
.size();
4353 // This is needed because when solving incrementally, removeITEs may introduce
4354 // skolems that were solved for earlier and thus appear in the substitution
4356 applySubstitutionsToAssertions();
4357 d_smt
.d_stats
->d_numAssertionsPost
+= d_assertions
.size();
4359 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-ite-removal" << endl
;
4360 dumpAssertions("post-ite-removal", d_assertions
);
4362 dumpAssertions("pre-repeat-simplify", d_assertions
);
4363 if(options::repeatSimp()) {
4364 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-repeat-simplify" << endl
;
4365 Chat() << "re-simplifying assertions..." << endl
;
4366 ScopeCounter
depth(d_simplifyAssertionsDepth
);
4367 noConflict
&= simplifyAssertions();
4369 // Need to fix up assertion list to maintain invariants:
4370 // Let Sk be the set of Skolem variables introduced by ITE's. Let <_sk be the order in which these variables were introduced
4371 // during ite removal.
4372 // For each skolem variable sk, let iteExpr = iteMap(sk) be the ite expr mapped to by sk.
4374 // cache for expression traversal
4375 unordered_map
<Node
, bool, NodeHashFunction
> cache
;
4377 // First, find all skolems that appear in the substitution map - their associated iteExpr will need
4378 // to be moved to the main assertion set
4379 set
<TNode
> skolemSet
;
4380 SubstitutionMap::iterator pos
= d_topLevelSubstitutions
.begin();
4381 for (; pos
!= d_topLevelSubstitutions
.end(); ++pos
) {
4382 collectSkolems((*pos
).first
, skolemSet
, cache
);
4383 collectSkolems((*pos
).second
, skolemSet
, cache
);
4386 // We need to ensure:
4387 // 1. iteExpr has the form (ite cond (sk = t) (sk = e))
4388 // 2. if some sk' in Sk appears in cond, t, or e, then sk' <_sk sk
4389 // If either of these is violated, we must add iteExpr as a proper assertion
4390 IteSkolemMap::iterator it
= d_iteSkolemMap
.begin();
4391 IteSkolemMap::iterator iend
= d_iteSkolemMap
.end();
4392 NodeBuilder
<> builder(kind::AND
);
4393 builder
<< d_assertions
[d_realAssertionsEnd
- 1];
4394 vector
<TNode
> toErase
;
4395 for (; it
!= iend
; ++it
) {
4396 if (skolemSet
.find((*it
).first
) == skolemSet
.end()) {
4397 TNode iteExpr
= d_assertions
[(*it
).second
];
4398 if (iteExpr
.getKind() == kind::ITE
&&
4399 iteExpr
[1].getKind() == kind::EQUAL
&&
4400 iteExpr
[1][0] == (*it
).first
&&
4401 iteExpr
[2].getKind() == kind::EQUAL
&&
4402 iteExpr
[2][0] == (*it
).first
) {
4404 bool bad
= checkForBadSkolems(iteExpr
[0], (*it
).first
, cache
);
4405 bad
= bad
|| checkForBadSkolems(iteExpr
[1][1], (*it
).first
, cache
);
4406 bad
= bad
|| checkForBadSkolems(iteExpr
[2][1], (*it
).first
, cache
);
4412 // Move this iteExpr into the main assertions
4413 builder
<< d_assertions
[(*it
).second
];
4414 d_assertions
[(*it
).second
] = NodeManager::currentNM()->mkConst
<bool>(true);
4415 toErase
.push_back((*it
).first
);
4417 if(builder
.getNumChildren() > 1) {
4418 while (!toErase
.empty()) {
4419 d_iteSkolemMap
.erase(toErase
.back());
4422 d_assertions
[d_realAssertionsEnd
- 1] = Rewriter::rewrite(Node(builder
));
4424 // TODO(b/1256): For some reason this is needed for some benchmarks, such as
4425 // QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
4427 applySubstitutionsToAssertions();
4428 // Assert(iteRewriteAssertionsEnd == d_assertions.size());
4430 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-repeat-simplify" << endl
;
4432 dumpAssertions("post-repeat-simplify", d_assertions
);
4434 dumpAssertions("pre-rewrite-apply-to-const", d_assertions
);
4435 if(options::rewriteApplyToConst()) {
4436 Chat() << "Rewriting applies to constants..." << endl
;
4437 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_rewriteApplyToConstTime
);
4438 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4439 d_assertions
[i
] = Rewriter::rewrite(rewriteApplyToConst(d_assertions
[i
]));
4442 dumpAssertions("post-rewrite-apply-to-const", d_assertions
);
4444 // begin: INVARIANT to maintain: no reordering of assertions or
4445 // introducing new ones
4446 #ifdef CVC4_ASSERTIONS
4447 unsigned iteRewriteAssertionsEnd
= d_assertions
.size();
4450 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4452 Debug("smt") << "SmtEnginePrivate::processAssertions() POST SIMPLIFICATION" << endl
;
4453 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4455 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-theory-preprocessing" << endl
;
4456 dumpAssertions("pre-theory-preprocessing", d_assertions
);
4458 Chat() << "theory preprocessing..." << endl
;
4459 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
4460 // Call the theory preprocessors
4461 d_smt
.d_theoryEngine
->preprocessStart();
4462 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4463 d_assertions
.replace(i
, d_smt
.d_theoryEngine
->preprocess(d_assertions
[i
]));
4466 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-theory-preprocessing" << endl
;
4467 dumpAssertions("post-theory-preprocessing", d_assertions
);
4469 // If we are using eager bit-blasting wrap assertions in fake atom so that
4470 // everything gets bit-blasted to internal SAT solver
4471 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
) {
4472 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
) {
4473 TNode atom
= d_assertions
[i
];
4474 Node eager_atom
= NodeManager::currentNM()->mkNode(kind::BITVECTOR_EAGER_ATOM
, atom
);
4475 d_assertions
.replace(i
, eager_atom
);
4476 TheoryModel
* m
= d_smt
.d_theoryEngine
->getModel();
4477 m
->addSubstitution(eager_atom
, atom
);
4481 //notify theory engine new preprocessed assertions
4482 d_smt
.d_theoryEngine
->notifyPreprocessedAssertions( d_assertions
.ref() );
4484 // Push the formula to decision engine
4486 Chat() << "pushing to decision engine..." << endl
;
4487 Assert(iteRewriteAssertionsEnd
== d_assertions
.size());
4488 d_smt
.d_decisionEngine
->addAssertions
4489 (d_assertions
.ref(), d_realAssertionsEnd
, d_iteSkolemMap
);
4492 // end: INVARIANT to maintain: no reordering of assertions or
4493 // introducing new ones
4495 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() end" << endl
;
4496 dumpAssertions("post-everything", d_assertions
);
4498 // Push the formula to SAT
4500 Chat() << "converting to CNF..." << endl
;
4501 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_cnfConversionTime
);
4502 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4503 Chat() << "+ " << d_assertions
[i
] << std::endl
;
4504 d_smt
.d_propEngine
->assertFormula(d_assertions
[i
]);
4508 d_assertionsProcessed
= true;
4510 d_assertions
.clear();
4511 d_iteSkolemMap
.clear();
4514 void SmtEnginePrivate::addFormula(TNode n
, bool inUnsatCore
, bool inInput
)
4521 Trace("smt") << "SmtEnginePrivate::addFormula(" << n
<< "), inUnsatCore = " << inUnsatCore
<< ", inInput = " << inInput
<< endl
;
4523 // Give it to proof manager
4526 // n is an input assertion
4527 if (inUnsatCore
|| options::unsatCores() || options::dumpUnsatCores() || options::checkUnsatCores() || options::fewerPreprocessingHoles()) {
4529 ProofManager::currentPM()->addCoreAssertion(n
.toExpr());
4532 // n is the result of an unknown preprocessing step, add it to dependency map to null
4533 ProofManager::currentPM()->addDependence(n
, Node::null());
4535 // rewrite rules are by default in the unsat core because
4536 // they need to be applied until saturation
4537 if(options::unsatCores() &&
4538 n
.getKind() == kind::REWRITE_RULE
){
4539 ProofManager::currentPM()->addUnsatCore(n
.toExpr());
4543 // Add the normalized formula to the queue
4544 d_assertions
.push_back(n
);
4545 //d_assertions.push_back(Rewriter::rewrite(n));
4548 void SmtEngine::ensureBoolean(const Expr
& e
)
4550 Type type
= e
.getType(options::typeChecking());
4551 Type boolType
= d_exprManager
->booleanType();
4552 if(type
!= boolType
) {
4554 ss
<< "Expected " << boolType
<< "\n"
4555 << "The assertion : " << e
<< "\n"
4556 << "Its type : " << type
;
4557 throw TypeCheckingException(e
, ss
.str());
4561 Result
SmtEngine::checkSat(const Expr
& assumption
, bool inUnsatCore
)
4563 return checkSatisfiability(assumption
, inUnsatCore
, false);
4566 Result
SmtEngine::checkSat(const vector
<Expr
>& assumptions
, bool inUnsatCore
)
4568 return checkSatisfiability(assumptions
, inUnsatCore
, false);
4571 Result
SmtEngine::query(const Expr
& assumption
, bool inUnsatCore
)
4573 Assert(!assumption
.isNull());
4574 return checkSatisfiability(assumption
, inUnsatCore
, true);
4577 Result
SmtEngine::query(const vector
<Expr
>& assumptions
, bool inUnsatCore
)
4579 return checkSatisfiability(assumptions
, inUnsatCore
, true);
4582 Result
SmtEngine::checkSatisfiability(const Expr
& expr
,
4586 return checkSatisfiability(
4587 expr
.isNull() ? vector
<Expr
>() : vector
<Expr
>{expr
},
4592 Result
SmtEngine::checkSatisfiability(const vector
<Expr
>& assumptions
,
4598 SmtScope
smts(this);
4599 finalOptionsAreSet();
4602 Trace("smt") << "SmtEngine::" << (isQuery
? "query" : "checkSat") << "("
4603 << assumptions
<< ")" << endl
;
4605 if(d_queryMade
&& !options::incrementalSolving()) {
4606 throw ModalException("Cannot make multiple queries unless "
4607 "incremental solving is enabled "
4608 "(try --incremental)");
4611 // check to see if a postsolve() is pending
4612 if(d_needPostsolve
) {
4613 d_theoryEngine
->postsolve();
4614 d_needPostsolve
= false;
4616 // Note that a query has been made
4618 // reset global negation
4619 d_globalNegation
= false;
4621 bool didInternalPush
= false;
4623 setProblemExtended(true);
4627 size_t size
= assumptions
.size();
4630 /* Assume: not (BIGAND assumptions) */
4631 d_assumptions
.push_back(
4632 d_exprManager
->mkExpr(kind::AND
, assumptions
).notExpr());
4636 /* Assume: not expr */
4637 d_assumptions
.push_back(assumptions
[0].notExpr());
4642 /* Assume: BIGAND assumptions */
4643 d_assumptions
= assumptions
;
4646 Result
r(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
4647 for (Expr e
: d_assumptions
)
4649 // Substitute out any abstract values in ex.
4650 e
= d_private
->substituteAbstractValues(Node::fromExpr(e
)).toExpr();
4651 Assert(e
.getExprManager() == d_exprManager
);
4652 // Ensure expr is type-checked at this point.
4655 /* Add assumption */
4657 didInternalPush
= true;
4658 if (d_assertionList
!= NULL
)
4660 d_assertionList
->push_back(e
);
4662 d_private
->addFormula(e
.getNode(), inUnsatCore
);
4665 r
= isQuery
? check().asValidityResult() : check().asSatisfiabilityResult();
4667 if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
4668 && r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
4670 r
= Result(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
4672 // flipped if we did a global negation
4673 if (d_globalNegation
)
4675 Trace("smt") << "SmtEngine::process global negate " << r
<< std::endl
;
4676 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
4678 r
= Result(Result::SAT
);
4680 else if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
4682 // only if satisfaction complete
4683 if (d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
))
4685 r
= Result(Result::UNSAT
);
4689 r
= Result(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
4692 Trace("smt") << "SmtEngine::global negate returned " << r
<< std::endl
;
4695 d_needPostsolve
= true;
4697 // Dump the query if requested
4698 if (Dump
.isOn("benchmark"))
4700 size_t size
= assumptions
.size();
4701 // the expr already got dumped out if assertion-dumping is on
4702 if (isQuery
&& size
== 1)
4704 Dump("benchmark") << QueryCommand(assumptions
[0]);
4708 Dump("benchmark") << CheckSatCommand();
4712 Dump("benchmark") << CheckSatAssumingCommand(d_assumptions
,
4718 if (didInternalPush
)
4723 // Remember the status
4726 setProblemExtended(false);
4728 Trace("smt") << "SmtEngine::" << (isQuery
? "query" : "checkSat") << "("
4729 << assumptions
<< ") => " << r
<< endl
;
4731 // Check that SAT results generate a model correctly.
4732 if(options::checkModels()) {
4733 // TODO (#1693) check model when unknown result?
4734 if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
4739 // Check that UNSAT results generate a proof correctly.
4740 if(options::checkProofs()) {
4741 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
4742 TimerStat::CodeTimer
checkProofTimer(d_stats
->d_checkProofTime
);
4746 // Check that UNSAT results generate an unsat core correctly.
4747 if(options::checkUnsatCores()) {
4748 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
4749 TimerStat::CodeTimer
checkUnsatCoreTimer(d_stats
->d_checkUnsatCoreTime
);
4753 // Check that synthesis solutions satisfy the conjecture
4754 if (options::checkSynthSol()
4755 && r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
4757 checkSynthSolution();
4761 } catch (UnsafeInterruptException
& e
) {
4762 AlwaysAssert(d_private
->getResourceManager()->out());
4763 Result::UnknownExplanation why
= d_private
->getResourceManager()->outOfResources() ?
4764 Result::RESOURCEOUT
: Result::TIMEOUT
;
4765 return Result(Result::SAT_UNKNOWN
, why
, d_filename
);
4769 vector
<Expr
> SmtEngine::getUnsatAssumptions(void)
4771 Trace("smt") << "SMT getUnsatAssumptions()" << endl
;
4772 SmtScope
smts(this);
4773 if (!options::unsatAssumptions())
4775 throw ModalException(
4776 "Cannot get unsat assumptions when produce-unsat-assumptions option "
4779 if (d_status
.isNull()
4780 || d_status
.asSatisfiabilityResult() != Result::UNSAT
4781 || d_problemExtended
)
4783 throw RecoverableModalException(
4784 "Cannot get unsat assumptions unless immediately preceded by "
4785 "UNSAT/VALID response.");
4787 finalOptionsAreSet();
4788 if (Dump
.isOn("benchmark"))
4790 Dump("benchmark") << GetUnsatCoreCommand();
4792 UnsatCore core
= getUnsatCore();
4794 for (const Expr
& e
: d_assumptions
)
4796 if (find(core
.begin(), core
.end(), e
) != core
.end()) { res
.push_back(e
); }
4801 Result
SmtEngine::checkSynth(const Expr
& e
)
4803 SmtScope
smts(this);
4804 Trace("smt") << "Check synth: " << e
<< std::endl
;
4805 Trace("smt-synth") << "Check synthesis conjecture: " << e
<< std::endl
;
4807 if (options::sygusQePreproc())
4809 // the following does quantifier elimination as a preprocess step
4810 // for "non-ground single invocation synthesis conjectures":
4811 // exists f. forall xy. P[ f(x), x, y ]
4812 // We run quantifier elimination:
4813 // exists y. P[ z, x, y ] ----> Q[ z, x ]
4814 // Where we replace the original conjecture with:
4815 // exists f. forall x. Q[ f(x), x ]
4816 // For more details, see Example 6 of Reynolds et al. SYNT 2017.
4817 Node conj
= Node::fromExpr(e
);
4818 if (conj
.getKind() == kind::FORALL
&& conj
[1].getKind() == kind::EXISTS
)
4820 Node conj_se
= Node::fromExpr(expandDefinitions(conj
[1][1].toExpr()));
4822 Trace("smt-synth") << "Compute single invocation for " << conj_se
<< "..."
4824 quantifiers::SingleInvocationPartition sip
;
4825 std::vector
<Node
> funcs
;
4826 funcs
.insert(funcs
.end(), conj
[0].begin(), conj
[0].end());
4827 sip
.init(funcs
, conj_se
.negate());
4828 Trace("smt-synth") << "...finished, got:" << std::endl
;
4829 sip
.debugPrint("smt-synth");
4831 if (!sip
.isPurelySingleInvocation() && sip
.isNonGroundSingleInvocation())
4833 // create new smt engine to do quantifier elimination
4834 SmtEngine
smt_qe(d_exprManager
);
4835 smt_qe
.setLogic(getLogicInfo());
4836 Trace("smt-synth") << "Property is non-ground single invocation, run "
4837 "QE to obtain single invocation."
4839 NodeManager
* nm
= NodeManager::currentNM();
4840 // partition variables
4841 std::vector
<Node
> all_vars
;
4842 sip
.getAllVariables(all_vars
);
4843 std::vector
<Node
> si_vars
;
4844 sip
.getSingleInvocationVariables(si_vars
);
4845 std::vector
<Node
> qe_vars
;
4846 std::vector
<Node
> nqe_vars
;
4847 for (unsigned i
= 0, size
= all_vars
.size(); i
< size
; i
++)
4849 Node v
= all_vars
[i
];
4850 if (std::find(si_vars
.begin(), si_vars
.end(), v
) == si_vars
.end())
4852 qe_vars
.push_back(v
);
4856 nqe_vars
.push_back(v
);
4859 std::vector
<Node
> orig
;
4860 std::vector
<Node
> subs
;
4861 // skolemize non-qe variables
4862 for (unsigned i
= 0; i
< nqe_vars
.size(); i
++)
4864 Node k
= nm
->mkSkolem("k",
4865 nqe_vars
[i
].getType(),
4866 "qe for non-ground single invocation");
4867 orig
.push_back(nqe_vars
[i
]);
4869 Trace("smt-synth") << " subs : " << nqe_vars
[i
] << " -> " << k
4872 std::vector
<Node
> funcs
;
4873 sip
.getFunctions(funcs
);
4874 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
4877 Node fi
= sip
.getFunctionInvocationFor(f
);
4878 Node fv
= sip
.getFirstOrderVariableForFunction(f
);
4879 Assert(!fi
.isNull());
4884 "qe for function in non-ground single invocation");
4886 Trace("smt-synth") << " subs : " << fi
<< " -> " << k
<< std::endl
;
4888 Node conj_se_ngsi
= sip
.getFullSpecification();
4889 Trace("smt-synth") << "Full specification is " << conj_se_ngsi
4891 Node conj_se_ngsi_subs
= conj_se_ngsi
.substitute(
4892 orig
.begin(), orig
.end(), subs
.begin(), subs
.end());
4893 Assert(!qe_vars
.empty());
4895 nm
->mkNode(kind::EXISTS
,
4896 nm
->mkNode(kind::BOUND_VAR_LIST
, qe_vars
),
4897 conj_se_ngsi_subs
.negate());
4899 Trace("smt-synth") << "Run quantifier elimination on "
4900 << conj_se_ngsi_subs
<< std::endl
;
4901 Expr qe_res
= smt_qe
.doQuantifierElimination(
4902 conj_se_ngsi_subs
.toExpr(), true, false);
4903 Trace("smt-synth") << "Result : " << qe_res
<< std::endl
;
4905 // create single invocation conjecture
4906 Node qe_res_n
= Node::fromExpr(qe_res
);
4907 qe_res_n
= qe_res_n
.substitute(
4908 subs
.begin(), subs
.end(), orig
.begin(), orig
.end());
4909 if (!nqe_vars
.empty())
4911 qe_res_n
= nm
->mkNode(kind::EXISTS
,
4912 nm
->mkNode(kind::BOUND_VAR_LIST
, nqe_vars
),
4915 Assert(conj
.getNumChildren() == 3);
4916 qe_res_n
= nm
->mkNode(kind::FORALL
, conj
[0], qe_res_n
, conj
[2]);
4917 Trace("smt-synth") << "Converted conjecture after QE : " << qe_res_n
4919 e_check
= qe_res_n
.toExpr();
4924 return checkSatisfiability( e_check
, true, false );
4927 Result
SmtEngine::assertFormula(const Expr
& ex
, bool inUnsatCore
)
4929 Assert(ex
.getExprManager() == d_exprManager
);
4930 SmtScope
smts(this);
4931 finalOptionsAreSet();
4934 Trace("smt") << "SmtEngine::assertFormula(" << ex
<< ")" << endl
;
4936 if (Dump
.isOn("raw-benchmark")) {
4937 Dump("raw-benchmark") << AssertCommand(ex
);
4940 // Substitute out any abstract values in ex
4941 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4944 if(d_assertionList
!= NULL
) {
4945 d_assertionList
->push_back(e
);
4947 d_private
->addFormula(e
.getNode(), inUnsatCore
);
4948 return quickCheck().asValidityResult();
4949 }/* SmtEngine::assertFormula() */
4951 Node
SmtEngine::postprocess(TNode node
, TypeNode expectedType
) const {
4955 Expr
SmtEngine::simplify(const Expr
& ex
)
4957 Assert(ex
.getExprManager() == d_exprManager
);
4958 SmtScope
smts(this);
4959 finalOptionsAreSet();
4961 Trace("smt") << "SMT simplify(" << ex
<< ")" << endl
;
4963 if(Dump
.isOn("benchmark")) {
4964 Dump("benchmark") << SimplifyCommand(ex
);
4967 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4968 if( options::typeChecking() ) {
4969 e
.getType(true); // ensure expr is type-checked at this point
4972 // Make sure all preprocessing is done
4973 d_private
->processAssertions();
4974 Node n
= d_private
->simplify(Node::fromExpr(e
));
4975 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
4979 Expr
SmtEngine::expandDefinitions(const Expr
& ex
)
4981 d_private
->spendResource(options::preprocessStep());
4983 Assert(ex
.getExprManager() == d_exprManager
);
4984 SmtScope
smts(this);
4985 finalOptionsAreSet();
4987 Trace("smt") << "SMT expandDefinitions(" << ex
<< ")" << endl
;
4989 // Substitute out any abstract values in ex.
4990 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4991 if(options::typeChecking()) {
4992 // Ensure expr is type-checked at this point.
4995 if(Dump
.isOn("benchmark")) {
4996 Dump("benchmark") << ExpandDefinitionsCommand(e
);
4998 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4999 Node n
= d_private
->expandDefinitions(Node::fromExpr(e
), cache
, /* expandOnly = */ true);
5000 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
5005 // TODO(#1108): Simplify the error reporting of this method.
5006 Expr
SmtEngine::getValue(const Expr
& ex
) const
5008 Assert(ex
.getExprManager() == d_exprManager
);
5009 SmtScope
smts(this);
5011 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
5012 if(Dump
.isOn("benchmark")) {
5013 Dump("benchmark") << GetValueCommand(ex
);
5016 if(!options::produceModels()) {
5018 "Cannot get value when produce-models options is off.";
5019 throw ModalException(msg
);
5021 if(d_status
.isNull() ||
5022 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
5023 d_problemExtended
) {
5025 "Cannot get value unless immediately preceded by SAT/INVALID or UNKNOWN response.";
5026 throw RecoverableModalException(msg
);
5029 // Substitute out any abstract values in ex.
5030 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
5032 // Ensure expr is type-checked at this point.
5033 e
.getType(options::typeChecking());
5035 // do not need to apply preprocessing substitutions (should be recorded
5036 // in model already)
5038 Node n
= Node::fromExpr(e
);
5039 Trace("smt") << "--- getting value of " << n
<< endl
;
5040 TypeNode expectedType
= n
.getType();
5042 // Expand, then normalize
5043 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
5044 n
= d_private
->expandDefinitions(n
, cache
);
5045 // There are two ways model values for terms are computed (for historical
5046 // reasons). One way is that used in check-model; the other is that
5047 // used by the Model classes. It's not clear to me exactly how these
5048 // two are different, but they need to be unified. This ugly hack here
5049 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
5052 if(!n
.getType().isFunction()) {
5053 n
= Rewriter::rewrite(n
);
5056 Trace("smt") << "--- getting value of " << n
<< endl
;
5057 TheoryModel
* m
= d_theoryEngine
->getModel();
5060 resultNode
= m
->getValue(n
);
5062 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
5063 resultNode
= postprocess(resultNode
, expectedType
);
5064 Trace("smt") << "--- model-post returned " << resultNode
<< endl
;
5065 Trace("smt") << "--- model-post returned " << resultNode
.getType() << endl
;
5066 Trace("smt") << "--- model-post expected " << expectedType
<< endl
;
5068 // type-check the result we got
5069 Assert(resultNode
.isNull() || resultNode
.getType().isSubtypeOf(expectedType
),
5070 "Run with -t smt for details.");
5072 // ensure it's a constant
5073 Assert(resultNode
.getKind() == kind::LAMBDA
|| resultNode
.isConst());
5075 if(options::abstractValues() && resultNode
.getType().isArray()) {
5076 resultNode
= d_private
->mkAbstractValue(resultNode
);
5077 Trace("smt") << "--- abstract value >> " << resultNode
<< endl
;
5080 return resultNode
.toExpr();
5083 bool SmtEngine::addToAssignment(const Expr
& ex
) {
5084 SmtScope
smts(this);
5085 finalOptionsAreSet();
5087 // Substitute out any abstract values in ex
5088 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
5089 Type type
= e
.getType(options::typeChecking());
5091 PrettyCheckArgument(
5092 type
.isBoolean(), e
,
5093 "expected Boolean-typed variable or function application "
5094 "in addToAssignment()" );
5095 Node n
= e
.getNode();
5096 // must be an APPLY of a zero-ary defined function, or a variable
5097 PrettyCheckArgument(
5098 ( ( n
.getKind() == kind::APPLY
&&
5099 ( d_definedFunctions
->find(n
.getOperator()) !=
5100 d_definedFunctions
->end() ) &&
5101 n
.getNumChildren() == 0 ) ||
5103 "expected variable or defined-function application "
5104 "in addToAssignment(),\ngot %s", e
.toString().c_str() );
5105 if(!options::produceAssignments()) {
5108 if(d_assignments
== NULL
) {
5109 d_assignments
= new(true) AssignmentSet(d_context
);
5111 d_assignments
->insert(n
);
5116 // TODO(#1108): Simplify the error reporting of this method.
5117 vector
<pair
<Expr
, Expr
>> SmtEngine::getAssignment()
5119 Trace("smt") << "SMT getAssignment()" << endl
;
5120 SmtScope
smts(this);
5121 finalOptionsAreSet();
5122 if(Dump
.isOn("benchmark")) {
5123 Dump("benchmark") << GetAssignmentCommand();
5125 if(!options::produceAssignments()) {
5127 "Cannot get the current assignment when "
5128 "produce-assignments option is off.";
5129 throw ModalException(msg
);
5131 if(d_status
.isNull() ||
5132 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
5133 d_problemExtended
) {
5135 "Cannot get the current assignment unless immediately "
5136 "preceded by SAT/INVALID or UNKNOWN response.";
5137 throw RecoverableModalException(msg
);
5140 vector
<pair
<Expr
,Expr
>> res
;
5141 if (d_assignments
!= nullptr)
5143 TypeNode boolType
= d_nodeManager
->booleanType();
5144 TheoryModel
* m
= d_theoryEngine
->getModel();
5145 for (AssignmentSet::key_iterator i
= d_assignments
->key_begin(),
5146 iend
= d_assignments
->key_end();
5151 Assert(as
.getType() == boolType
);
5153 Trace("smt") << "--- getting value of " << as
<< endl
;
5155 // Expand, then normalize
5156 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
5157 Node n
= d_private
->expandDefinitions(as
, cache
);
5158 n
= Rewriter::rewrite(n
);
5160 Trace("smt") << "--- getting value of " << n
<< endl
;
5164 resultNode
= m
->getValue(n
);
5167 // type-check the result we got
5168 Assert(resultNode
.isNull() || resultNode
.getType() == boolType
);
5170 // ensure it's a constant
5171 Assert(resultNode
.isConst());
5173 Assert(as
.getKind() == kind::APPLY
|| as
.isVar());
5174 Assert(as
.getKind() != kind::APPLY
|| as
.getNumChildren() == 0);
5175 res
.emplace_back(as
.toExpr(), resultNode
.toExpr());
5181 void SmtEngine::addToModelCommandAndDump(const Command
& c
, uint32_t flags
, bool userVisible
, const char* dumpTag
) {
5182 Trace("smt") << "SMT addToModelCommandAndDump(" << c
<< ")" << endl
;
5183 SmtScope
smts(this);
5184 // If we aren't yet fully inited, the user might still turn on
5185 // produce-models. So let's keep any commands around just in
5186 // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
5187 // sort "U" in QF_UF before setLogic() is run and we still want to
5188 // support finding card(U) with --finite-model-find, and (2) to
5189 // decouple SmtEngine and ExprManager if the user does a few
5190 // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
5191 // and expects to find their cardinalities in the model.
5192 if(/* userVisible && */
5193 (!d_fullyInited
|| options::produceModels()) &&
5194 (flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
5196 if(flags
& ExprManager::VAR_FLAG_GLOBAL
) {
5197 d_modelGlobalCommands
.push_back(c
.clone());
5199 d_modelCommands
->push_back(c
.clone());
5202 if(Dump
.isOn(dumpTag
)) {
5206 d_dumpCommands
.push_back(c
.clone());
5211 // TODO(#1108): Simplify the error reporting of this method.
5212 Model
* SmtEngine::getModel() {
5213 Trace("smt") << "SMT getModel()" << endl
;
5214 SmtScope
smts(this);
5216 finalOptionsAreSet();
5218 if(Dump
.isOn("benchmark")) {
5219 Dump("benchmark") << GetModelCommand();
5222 if(d_status
.isNull() ||
5223 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
5224 d_problemExtended
) {
5226 "Cannot get the current model unless immediately "
5227 "preceded by SAT/INVALID or UNKNOWN response.";
5228 throw RecoverableModalException(msg
);
5230 if(!options::produceModels()) {
5232 "Cannot get model when produce-models options is off.";
5233 throw ModalException(msg
);
5235 TheoryModel
* m
= d_theoryEngine
->getModel();
5236 m
->d_inputName
= d_filename
;
5240 void SmtEngine::checkUnsatCore() {
5241 Assert(options::unsatCores(), "cannot check unsat core if unsat cores are turned off");
5243 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl
;
5244 UnsatCore core
= getUnsatCore();
5246 SmtEngine
coreChecker(d_exprManager
);
5247 coreChecker
.setLogic(getLogicInfo());
5250 std::vector
<Command
*>::const_iterator itg
= d_defineCommands
.begin();
5251 for (; itg
!= d_defineCommands
.end(); ++itg
) {
5252 (*itg
)->invoke(&coreChecker
);
5256 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions (size == " << core
.size() << ")" << endl
;
5257 for(UnsatCore::iterator i
= core
.begin(); i
!= core
.end(); ++i
) {
5258 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
<< endl
;
5259 coreChecker
.assertFormula(*i
);
5261 const bool checkUnsatCores
= options::checkUnsatCores();
5264 options::checkUnsatCores
.set(false);
5265 options::checkProofs
.set(false);
5266 r
= coreChecker
.checkSat();
5268 options::checkUnsatCores
.set(checkUnsatCores
);
5271 Notice() << "SmtEngine::checkUnsatCore(): result is " << r
<< endl
;
5272 if(r
.asSatisfiabilityResult().isUnknown()) {
5273 InternalError("SmtEngine::checkUnsatCore(): could not check core result unknown.");
5276 if(r
.asSatisfiabilityResult().isSat()) {
5277 InternalError("SmtEngine::checkUnsatCore(): produced core was satisfiable.");
5281 void SmtEngine::checkModel(bool hardFailure
) {
5282 // --check-model implies --produce-assertions, which enables the
5283 // assertion list, so we should be ok.
5284 Assert(d_assertionList
!= NULL
, "don't have an assertion list to check in SmtEngine::checkModel()");
5286 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
5288 // Throughout, we use Notice() to give diagnostic output.
5290 // If this function is running, the user gave --check-model (or equivalent),
5291 // and if Notice() is on, the user gave --verbose (or equivalent).
5293 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
5294 TheoryModel
* m
= d_theoryEngine
->getModel();
5296 // Check individual theory assertions
5297 d_theoryEngine
->checkTheoryAssertionsWithModel(hardFailure
);
5302 // We have a "fake context" for the substitution map (we don't need it
5303 // to be context-dependent)
5304 context::Context fakeContext
;
5305 SubstitutionMap
substitutions(&fakeContext
, /* substituteUnderQuantifiers = */ false);
5307 for(size_t k
= 0; k
< m
->getNumCommands(); ++k
) {
5308 const DeclareFunctionCommand
* c
= dynamic_cast<const DeclareFunctionCommand
*>(m
->getCommand(k
));
5309 Notice() << "SmtEngine::checkModel(): model command " << k
<< " : " << m
->getCommand(k
) << endl
;
5311 // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
5312 Notice() << "SmtEngine::checkModel(): skipping..." << endl
;
5314 // We have a DECLARE-FUN:
5316 // We'll first do some checks, then add to our substitution map
5317 // the mapping: function symbol |-> value
5319 Expr func
= c
->getFunction();
5320 Node val
= m
->getValue(func
);
5322 Notice() << "SmtEngine::checkModel(): adding substitution: " << func
<< " |-> " << val
<< endl
;
5324 // (1) if the value is a lambda, ensure the lambda doesn't contain the
5325 // function symbol (since then the definition is recursive)
5326 if (val
.getKind() == kind::LAMBDA
) {
5327 // first apply the model substitutions we have so far
5328 Debug("boolean-terms") << "applying subses to " << val
[1] << endl
;
5329 Node n
= substitutions
.apply(val
[1]);
5330 Debug("boolean-terms") << "++ got " << n
<< endl
;
5331 // now check if n contains func by doing a substitution
5332 // [func->func2] and checking equality of the Nodes.
5333 // (this just a way to check if func is in n.)
5334 SubstitutionMap
subs(&fakeContext
);
5335 Node func2
= NodeManager::currentNM()->mkSkolem("", TypeNode::fromType(func
.getType()), "", NodeManager::SKOLEM_NO_NOTIFY
);
5336 subs
.addSubstitution(func
, func2
);
5337 if(subs
.apply(n
) != n
) {
5338 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED IN TERMS OF ITSELF ***" << endl
;
5340 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5341 << "considering model value for " << func
<< endl
5342 << "body of lambda is: " << val
<< endl
;
5344 ss
<< "body substitutes to: " << n
<< endl
;
5346 ss
<< "so " << func
<< " is defined in terms of itself." << endl
5347 << "Run with `--check-models -v' for additional diagnostics.";
5348 InternalError(ss
.str());
5352 // (2) check that the value is actually a value
5353 else if (!val
.isConst()) {
5354 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT A CONSTANT ***" << endl
;
5356 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5357 << "model value for " << func
<< endl
5358 << " is " << val
<< endl
5359 << "and that is not a constant (.isConst() == false)." << endl
5360 << "Run with `--check-models -v' for additional diagnostics.";
5361 InternalError(ss
.str());
5364 // (3) check that it's the correct (sub)type
5365 // This was intended to be a more general check, but for now we can't do that because
5366 // e.g. "1" is an INT, which isn't a subrange type [1..10] (etc.).
5367 else if(func
.getType().isInteger() && !val
.getType().isInteger()) {
5368 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT CORRECT TYPE ***" << endl
;
5370 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5371 << "model value for " << func
<< endl
5372 << " is " << val
<< endl
5373 << "value type is " << val
.getType() << endl
5374 << "should be of type " << func
.getType() << endl
5375 << "Run with `--check-models -v' for additional diagnostics.";
5376 InternalError(ss
.str());
5379 // (4) checks complete, add the substitution
5380 Debug("boolean-terms") << "cm: adding subs " << func
<< " :=> " << val
<< endl
;
5381 substitutions
.addSubstitution(func
, val
);
5385 // Now go through all our user assertions checking if they're satisfied.
5386 for(AssertionList::const_iterator i
= d_assertionList
->begin(); i
!= d_assertionList
->end(); ++i
) {
5387 Notice() << "SmtEngine::checkModel(): checking assertion " << *i
<< endl
;
5388 Node n
= Node::fromExpr(*i
);
5390 // Apply any define-funs from the problem.
5392 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
5393 n
= d_private
->expandDefinitions(n
, cache
);
5395 Notice() << "SmtEngine::checkModel(): -- expands to " << n
<< endl
;
5397 // Apply our model value substitutions.
5398 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
5399 n
= substitutions
.apply(n
);
5400 Debug("boolean-terms") << "++ got " << n
<< endl
;
5401 Notice() << "SmtEngine::checkModel(): -- substitutes to " << n
<< endl
;
5403 if( n
.getKind() != kind::REWRITE_RULE
){
5404 // In case it's a quantifier (or contains one), look up its value before
5405 // simplifying, or the quantifier might be irreparably altered.
5407 Notice() << "SmtEngine::checkModel(): -- get value : " << n
<< std::endl
;
5409 // Note this "skip" is done here, rather than above. This is
5410 // because (1) the quantifier could in principle simplify to false,
5411 // which should be reported, and (2) checking for the quantifier
5412 // above, before simplification, doesn't catch buried quantifiers
5413 // anyway (those not at the top-level).
5414 Notice() << "SmtEngine::checkModel(): -- skipping rewrite-rules assertion"
5419 // Simplify the result.
5420 n
= d_private
->simplify(n
);
5421 Notice() << "SmtEngine::checkModel(): -- simplifies to " << n
<< endl
;
5423 // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
5424 n
= d_private
->d_iteRemover
.replace(n
);
5425 Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n
<< endl
;
5427 // Apply our model value substitutions (again), as things may have been simplified.
5428 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
5429 n
= substitutions
.apply(n
);
5430 Debug("boolean-terms") << "++ got " << n
<< endl
;
5431 Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n
<< endl
;
5433 // As a last-ditch effort, ask model to simplify it.
5434 // Presently, this is only an issue for quantifiers, which can have a value
5435 // but don't show up in our substitution map above.
5437 Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n
<< endl
;
5439 if( d_logic
.isQuantified() ){
5440 // AJR: since quantified formulas are not checkable, we assign them to true/false based on the satisfying assignment.
5441 // however, quantified formulas can be modified during preprocess, so they may not correspond to those in the satisfying assignment.
5442 // hence we use a relaxed version of check model here.
5443 // this is necessary until preprocessing passes explicitly record how they rewrite quantified formulas
5444 if( hardFailure
&& !n
.isConst() && n
.getKind() != kind::LAMBDA
){
5445 Notice() << "SmtEngine::checkModel(): -- relax check model wrt quantified formulas..." << endl
;
5446 AlwaysAssert( quantifiers::QuantifiersRewriter::containsQuantifiers( n
) );
5447 Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified assertion : " << n
<< endl
;
5451 AlwaysAssert(!hardFailure
|| n
.isConst() || n
.getKind() == kind::LAMBDA
);
5453 // The result should be == true.
5454 if(n
!= NodeManager::currentNM()->mkConst(true)) {
5455 Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
5458 ss
<< "SmtEngine::checkModel(): "
5459 << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5460 << "assertion: " << *i
<< endl
5461 << "simplifies to: " << n
<< endl
5462 << "expected `true'." << endl
5463 << "Run with `--check-models -v' for additional diagnostics.";
5465 InternalError(ss
.str());
5467 Warning() << ss
.str() << endl
;
5471 Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl
;
5474 void SmtEngine::checkSynthSolution()
5476 NodeManager
* nm
= NodeManager::currentNM();
5477 Notice() << "SmtEngine::checkSynthSolution(): checking synthesis solution" << endl
;
5478 map
<Node
, Node
> sol_map
;
5479 /* Get solutions and build auxiliary vectors for substituting */
5480 d_theoryEngine
->getSynthSolutions(sol_map
);
5481 Trace("check-synth-sol") << "Got solution map:\n";
5482 std::vector
<Node
> function_vars
, function_sols
;
5483 for (const auto& pair
: sol_map
)
5485 Trace("check-synth-sol") << pair
.first
<< " --> " << pair
.second
<< "\n";
5486 function_vars
.push_back(pair
.first
);
5487 function_sols
.push_back(pair
.second
);
5489 Trace("check-synth-sol") << "Starting new SMT Engine\n";
5490 /* Start new SMT engine to check solutions */
5491 SmtEngine
solChecker(d_exprManager
);
5492 solChecker
.setLogic(getLogicInfo());
5493 setOption("check-synth-sol", SExpr("false"));
5495 Trace("check-synth-sol") << "Retrieving assertions\n";
5496 // Build conjecture from original assertions
5497 if (d_assertionList
== NULL
)
5499 Trace("check-synth-sol") << "No assertions to check\n";
5502 for (AssertionList::const_iterator i
= d_assertionList
->begin();
5503 i
!= d_assertionList
->end();
5506 Notice() << "SmtEngine::checkSynthSolution(): checking assertion " << *i
<< endl
;
5507 Trace("check-synth-sol") << "Retrieving assertion " << *i
<< "\n";
5508 Node conj
= Node::fromExpr(*i
);
5509 // Apply any define-funs from the problem.
5511 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
5512 conj
= d_private
->expandDefinitions(conj
, cache
);
5514 Notice() << "SmtEngine::checkSynthSolution(): -- expands to " << conj
<< endl
;
5515 Trace("check-synth-sol") << "Expanded assertion " << conj
<< "\n";
5517 // Apply solution map to conjecture body
5519 /* Whether property is quantifier free */
5520 if (conj
[1].getKind() != kind::EXISTS
)
5522 conjBody
= conj
[1].substitute(function_vars
.begin(),
5523 function_vars
.end(),
5524 function_sols
.begin(),
5525 function_sols
.end());
5529 conjBody
= conj
[1][1].substitute(function_vars
.begin(),
5530 function_vars
.end(),
5531 function_sols
.begin(),
5532 function_sols
.end());
5534 /* Skolemize property */
5535 std::vector
<Node
> vars
, skos
;
5536 for (unsigned j
= 0, size
= conj
[1][0].getNumChildren(); j
< size
; ++j
)
5538 vars
.push_back(conj
[1][0][j
]);
5539 std::stringstream ss
;
5541 skos
.push_back(nm
->mkSkolem(ss
.str(), conj
[1][0][j
].getType()));
5542 Trace("check-synth-sol") << "\tSkolemizing " << conj
[1][0][j
] << " to "
5543 << skos
.back() << "\n";
5545 conjBody
= conjBody
.substitute(
5546 vars
.begin(), vars
.end(), skos
.begin(), skos
.end());
5548 Notice() << "SmtEngine::checkSynthSolution(): -- body substitutes to "
5549 << conjBody
<< endl
;
5550 Trace("check-synth-sol") << "Substituted body of assertion to " << conjBody
5552 solChecker
.assertFormula(conjBody
.toExpr());
5553 Result r
= solChecker
.checkSat();
5554 Notice() << "SmtEngine::checkSynthSolution(): result is " << r
<< endl
;
5555 Trace("check-synth-sol") << "Satsifiability check: " << r
<< "\n";
5556 if (r
.asSatisfiabilityResult().isUnknown())
5559 "SmtEngine::checkSynthSolution(): could not check solution, result "
5562 else if (r
.asSatisfiabilityResult().isSat())
5565 "SmtEngine::checkSynhtSol(): produced solution allows satisfiable "
5566 "negated conjecture.");
5568 solChecker
.resetAssertions();
5572 // TODO(#1108): Simplify the error reporting of this method.
5573 UnsatCore
SmtEngine::getUnsatCore() {
5574 Trace("smt") << "SMT getUnsatCore()" << endl
;
5575 SmtScope
smts(this);
5576 finalOptionsAreSet();
5577 if(Dump
.isOn("benchmark")) {
5578 Dump("benchmark") << GetUnsatCoreCommand();
5581 if(!options::unsatCores()) {
5582 throw ModalException("Cannot get an unsat core when produce-unsat-cores option is off.");
5584 if(d_status
.isNull() ||
5585 d_status
.asSatisfiabilityResult() != Result::UNSAT
||
5586 d_problemExtended
) {
5587 throw RecoverableModalException(
5588 "Cannot get an unsat core unless immediately preceded by UNSAT/VALID "
5592 d_proofManager
->traceUnsatCore();// just to trigger core creation
5593 return UnsatCore(this, d_proofManager
->extractUnsatCore());
5594 #else /* IS_PROOFS_BUILD */
5595 throw ModalException("This build of CVC4 doesn't have proof support (required for unsat cores).");
5596 #endif /* IS_PROOFS_BUILD */
5599 // TODO(#1108): Simplify the error reporting of this method.
5600 const Proof
& SmtEngine::getProof()
5602 Trace("smt") << "SMT getProof()" << endl
;
5603 SmtScope
smts(this);
5604 finalOptionsAreSet();
5605 if(Dump
.isOn("benchmark")) {
5606 Dump("benchmark") << GetProofCommand();
5609 if(!options::proof()) {
5610 throw ModalException("Cannot get a proof when produce-proofs option is off.");
5612 if(d_status
.isNull() ||
5613 d_status
.asSatisfiabilityResult() != Result::UNSAT
||
5614 d_problemExtended
) {
5615 throw RecoverableModalException(
5616 "Cannot get a proof unless immediately preceded by UNSAT/VALID "
5620 return ProofManager::getProof(this);
5621 #else /* IS_PROOFS_BUILD */
5622 throw ModalException("This build of CVC4 doesn't have proof support.");
5623 #endif /* IS_PROOFS_BUILD */
5626 void SmtEngine::printInstantiations( std::ostream
& out
) {
5627 SmtScope
smts(this);
5628 if( options::instFormatMode()==INST_FORMAT_MODE_SZS
){
5629 out
<< "% SZS output start Proof for " << d_filename
.c_str() << std::endl
;
5631 if( d_theoryEngine
){
5632 d_theoryEngine
->printInstantiations( out
);
5636 if( options::instFormatMode()==INST_FORMAT_MODE_SZS
){
5637 out
<< "% SZS output end Proof for " << d_filename
.c_str() << std::endl
;
5641 void SmtEngine::printSynthSolution( std::ostream
& out
) {
5642 SmtScope
smts(this);
5643 if( d_theoryEngine
){
5644 d_theoryEngine
->printSynthSolution( out
);
5650 Expr
SmtEngine::doQuantifierElimination(const Expr
& e
, bool doFull
, bool strict
)
5652 SmtScope
smts(this);
5653 if(!d_logic
.isPure(THEORY_ARITH
) && strict
){
5654 Warning() << "Unexpected logic for quantifier elimination " << d_logic
<< endl
;
5656 Trace("smt-qe") << "Do quantifier elimination " << e
<< std::endl
;
5657 Node n_e
= Node::fromExpr( e
);
5658 if (n_e
.getKind() != kind::EXISTS
&& n_e
.getKind() != kind::FORALL
)
5660 throw ModalException(
5661 "Expecting a quantified formula as argument to get-qe.");
5663 //tag the quantified formula with the quant-elim attribute
5664 TypeNode t
= NodeManager::currentNM()->booleanType();
5665 Node n_attr
= NodeManager::currentNM()->mkSkolem("qe", t
, "Auxiliary variable for qe attr.");
5666 std::vector
< Node
> node_values
;
5667 d_theoryEngine
->setUserAttribute( doFull
? "quant-elim" : "quant-elim-partial", n_attr
, node_values
, "");
5668 n_attr
= NodeManager::currentNM()->mkNode(kind::INST_ATTRIBUTE
, n_attr
);
5669 n_attr
= NodeManager::currentNM()->mkNode(kind::INST_PATTERN_LIST
, n_attr
);
5670 std::vector
< Node
> e_children
;
5671 e_children
.push_back( n_e
[0] );
5672 e_children
.push_back(n_e
.getKind() == kind::EXISTS
? n_e
[1]
5674 e_children
.push_back( n_attr
);
5675 Node nn_e
= NodeManager::currentNM()->mkNode( kind::EXISTS
, e_children
);
5676 Trace("smt-qe-debug") << "Query for quantifier elimination : " << nn_e
<< std::endl
;
5677 Assert( nn_e
.getNumChildren()==3 );
5678 Result r
= checkSatisfiability(nn_e
.toExpr(), true, true);
5679 Trace("smt-qe") << "Query returned " << r
<< std::endl
;
5680 if(r
.asSatisfiabilityResult().isSat() != Result::UNSAT
) {
5681 if( r
.asSatisfiabilityResult().isSat() != Result::SAT
&& doFull
){
5683 ss
<< "While performing quantifier elimination, unexpected result : " << r
<< " for query.";
5684 InternalError(ss
.str().c_str());
5686 std::vector
< Node
> inst_qs
;
5687 d_theoryEngine
->getInstantiatedQuantifiedFormulas( inst_qs
);
5688 Assert( inst_qs
.size()<=1 );
5690 if( inst_qs
.size()==1 ){
5691 Node top_q
= inst_qs
[0];
5692 //Node top_q = Rewriter::rewrite( nn_e ).negate();
5693 Assert( top_q
.getKind()==kind::FORALL
);
5694 Trace("smt-qe") << "Get qe for " << top_q
<< std::endl
;
5695 ret_n
= d_theoryEngine
->getInstantiatedConjunction( top_q
);
5696 Trace("smt-qe") << "Returned : " << ret_n
<< std::endl
;
5697 if (n_e
.getKind() == kind::EXISTS
)
5699 ret_n
= Rewriter::rewrite(ret_n
.negate());
5702 ret_n
= NodeManager::currentNM()->mkConst(n_e
.getKind() != kind::EXISTS
);
5704 return ret_n
.toExpr();
5706 return NodeManager::currentNM()
5707 ->mkConst(n_e
.getKind() == kind::EXISTS
)
5712 void SmtEngine::getInstantiatedQuantifiedFormulas( std::vector
< Expr
>& qs
) {
5713 SmtScope
smts(this);
5714 if( d_theoryEngine
){
5715 std::vector
< Node
> qs_n
;
5716 d_theoryEngine
->getInstantiatedQuantifiedFormulas( qs_n
);
5717 for( unsigned i
=0; i
<qs_n
.size(); i
++ ){
5718 qs
.push_back( qs_n
[i
].toExpr() );
5725 void SmtEngine::getInstantiations( Expr q
, std::vector
< Expr
>& insts
) {
5726 SmtScope
smts(this);
5727 if( d_theoryEngine
){
5728 std::vector
< Node
> insts_n
;
5729 d_theoryEngine
->getInstantiations( Node::fromExpr( q
), insts_n
);
5730 for( unsigned i
=0; i
<insts_n
.size(); i
++ ){
5731 insts
.push_back( insts_n
[i
].toExpr() );
5738 void SmtEngine::getInstantiationTermVectors( Expr q
, std::vector
< std::vector
< Expr
> >& tvecs
) {
5739 SmtScope
smts(this);
5740 Assert(options::trackInstLemmas());
5741 if( d_theoryEngine
){
5742 std::vector
< std::vector
< Node
> > tvecs_n
;
5743 d_theoryEngine
->getInstantiationTermVectors( Node::fromExpr( q
), tvecs_n
);
5744 for( unsigned i
=0; i
<tvecs_n
.size(); i
++ ){
5745 std::vector
< Expr
> tvec
;
5746 for( unsigned j
=0; j
<tvecs_n
[i
].size(); j
++ ){
5747 tvec
.push_back( tvecs_n
[i
][j
].toExpr() );
5749 tvecs
.push_back( tvec
);
5756 vector
<Expr
> SmtEngine::getAssertions() {
5757 SmtScope
smts(this);
5758 finalOptionsAreSet();
5760 if(Dump
.isOn("benchmark")) {
5761 Dump("benchmark") << GetAssertionsCommand();
5763 Trace("smt") << "SMT getAssertions()" << endl
;
5764 if(!options::produceAssertions()) {
5766 "Cannot query the current assertion list when not in produce-assertions mode.";
5767 throw ModalException(msg
);
5769 Assert(d_assertionList
!= NULL
);
5770 // copy the result out
5771 return vector
<Expr
>(d_assertionList
->begin(), d_assertionList
->end());
5774 void SmtEngine::push()
5776 SmtScope
smts(this);
5777 finalOptionsAreSet();
5779 Trace("smt") << "SMT push()" << endl
;
5780 d_private
->notifyPush();
5781 d_private
->processAssertions();
5782 if(Dump
.isOn("benchmark")) {
5783 Dump("benchmark") << PushCommand();
5785 if(!options::incrementalSolving()) {
5786 throw ModalException("Cannot push when not solving incrementally (use --incremental)");
5789 // check to see if a postsolve() is pending
5790 if(d_needPostsolve
) {
5791 d_theoryEngine
->postsolve();
5792 d_needPostsolve
= false;
5795 // The problem isn't really "extended" yet, but this disallows
5796 // get-model after a push, simplifying our lives somewhat and
5797 // staying symmtric with pop.
5798 setProblemExtended(true);
5800 d_userLevels
.push_back(d_userContext
->getLevel());
5802 Trace("userpushpop") << "SmtEngine: pushed to level "
5803 << d_userContext
->getLevel() << endl
;
5806 void SmtEngine::pop() {
5807 SmtScope
smts(this);
5808 finalOptionsAreSet();
5809 Trace("smt") << "SMT pop()" << endl
;
5810 if(Dump
.isOn("benchmark")) {
5811 Dump("benchmark") << PopCommand();
5813 if(!options::incrementalSolving()) {
5814 throw ModalException("Cannot pop when not solving incrementally (use --incremental)");
5816 if(d_userLevels
.size() == 0) {
5817 throw ModalException("Cannot pop beyond the first user frame");
5820 // check to see if a postsolve() is pending
5821 if(d_needPostsolve
) {
5822 d_theoryEngine
->postsolve();
5823 d_needPostsolve
= false;
5826 // The problem isn't really "extended" yet, but this disallows
5827 // get-model after a pop, simplifying our lives somewhat. It might
5828 // not be strictly necessary to do so, since the pops occur lazily,
5829 // but also it would be weird to have a legally-executed (get-model)
5830 // that only returns a subset of the assignment (because the rest
5831 // is no longer in scope!).
5832 setProblemExtended(true);
5834 AlwaysAssert(d_userContext
->getLevel() > 0);
5835 AlwaysAssert(d_userLevels
.back() < d_userContext
->getLevel());
5836 while (d_userLevels
.back() < d_userContext
->getLevel()) {
5839 d_userLevels
.pop_back();
5841 // Clear out assertion queues etc., in case anything is still in there
5842 d_private
->notifyPop();
5844 Trace("userpushpop") << "SmtEngine: popped to level "
5845 << d_userContext
->getLevel() << endl
;
5846 // FIXME: should we reset d_status here?
5847 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
5850 void SmtEngine::internalPush() {
5851 Assert(d_fullyInited
);
5852 Trace("smt") << "SmtEngine::internalPush()" << endl
;
5854 if(options::incrementalSolving()) {
5855 d_private
->processAssertions();
5856 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
5857 d_userContext
->push();
5858 // the d_context push is done inside of the SAT solver
5859 d_propEngine
->push();
5863 void SmtEngine::internalPop(bool immediate
) {
5864 Assert(d_fullyInited
);
5865 Trace("smt") << "SmtEngine::internalPop()" << endl
;
5866 if(options::incrementalSolving()) {
5874 void SmtEngine::doPendingPops() {
5875 Assert(d_pendingPops
== 0 || options::incrementalSolving());
5876 while(d_pendingPops
> 0) {
5877 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
5878 d_propEngine
->pop();
5879 // the d_context pop is done inside of the SAT solver
5880 d_userContext
->pop();
5885 void SmtEngine::reset()
5887 SmtScope
smts(this);
5888 ExprManager
*em
= d_exprManager
;
5889 Trace("smt") << "SMT reset()" << endl
;
5890 if(Dump
.isOn("benchmark")) {
5891 Dump("benchmark") << ResetCommand();
5894 opts
.copyValues(d_originalOptions
);
5896 NodeManager::fromExprManager(em
)->getOptions().copyValues(opts
);
5897 new(this) SmtEngine(em
);
5900 void SmtEngine::resetAssertions()
5902 SmtScope
smts(this);
5905 Trace("smt") << "SMT resetAssertions()" << endl
;
5906 if(Dump
.isOn("benchmark")) {
5907 Dump("benchmark") << ResetAssertionsCommand();
5910 while(!d_userLevels
.empty()) {
5914 // Also remember the global push/pop around everything.
5915 Assert(d_userLevels
.size() == 0 && d_userContext
->getLevel() == 1);
5916 d_context
->popto(0);
5917 d_userContext
->popto(0);
5918 DeleteAndClearCommandVector(d_modelGlobalCommands
);
5919 d_userContext
->push();
5923 void SmtEngine::interrupt()
5925 if(!d_fullyInited
) {
5928 d_propEngine
->interrupt();
5929 d_theoryEngine
->interrupt();
5932 void SmtEngine::setResourceLimit(unsigned long units
, bool cumulative
) {
5933 d_private
->getResourceManager()->setResourceLimit(units
, cumulative
);
5935 void SmtEngine::setTimeLimit(unsigned long milis
, bool cumulative
) {
5936 d_private
->getResourceManager()->setTimeLimit(milis
, cumulative
);
5939 unsigned long SmtEngine::getResourceUsage() const {
5940 return d_private
->getResourceManager()->getResourceUsage();
5943 unsigned long SmtEngine::getTimeUsage() const {
5944 return d_private
->getResourceManager()->getTimeUsage();
5947 unsigned long SmtEngine::getResourceRemaining() const
5949 return d_private
->getResourceManager()->getResourceRemaining();
5952 unsigned long SmtEngine::getTimeRemaining() const
5954 return d_private
->getResourceManager()->getTimeRemaining();
5957 Statistics
SmtEngine::getStatistics() const
5959 return Statistics(*d_statisticsRegistry
);
5962 SExpr
SmtEngine::getStatistic(std::string name
) const
5964 return d_statisticsRegistry
->getStatistic(name
);
5967 void SmtEngine::safeFlushStatistics(int fd
) const {
5968 d_statisticsRegistry
->safeFlushInformation(fd
);
5971 void SmtEngine::setUserAttribute(const std::string
& attr
,
5973 const std::vector
<Expr
>& expr_values
,
5974 const std::string
& str_value
)
5976 SmtScope
smts(this);
5977 std::vector
<Node
> node_values
;
5978 for( unsigned i
=0; i
<expr_values
.size(); i
++ ){
5979 node_values
.push_back( expr_values
[i
].getNode() );
5981 d_theoryEngine
->setUserAttribute(attr
, expr
.getNode(), node_values
, str_value
);
5984 void SmtEngine::setPrintFuncInModel(Expr f
, bool p
) {
5985 Trace("setp-model") << "Set printInModel " << f
<< " to " << p
<< std::endl
;
5986 for( unsigned i
=0; i
<d_modelGlobalCommands
.size(); i
++ ){
5987 Command
* c
= d_modelGlobalCommands
[i
];
5988 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
5990 if( dfc
->getFunction()==f
){
5991 dfc
->setPrintInModel( p
);
5995 for( unsigned i
=0; i
<d_modelCommands
->size(); i
++ ){
5996 Command
* c
= (*d_modelCommands
)[i
];
5997 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
5999 if( dfc
->getFunction()==f
){
6000 dfc
->setPrintInModel( p
);
6006 void SmtEngine::beforeSearch()
6009 throw ModalException(
6010 "SmtEngine::beforeSearch called after initialization.");
6015 void SmtEngine::setOption(const std::string
& key
, const CVC4::SExpr
& value
)
6017 NodeManagerScope
nms(d_nodeManager
);
6018 Trace("smt") << "SMT setOption(" << key
<< ", " << value
<< ")" << endl
;
6020 if(Dump
.isOn("benchmark")) {
6021 Dump("benchmark") << SetOptionCommand(key
, value
);
6024 if(key
== "command-verbosity") {
6025 if(!value
.isAtom()) {
6026 const vector
<SExpr
>& cs
= value
.getChildren();
6027 if(cs
.size() == 2 &&
6028 (cs
[0].isKeyword() || cs
[0].isString()) &&
6029 cs
[1].isInteger()) {
6030 string c
= cs
[0].getValue();
6031 const Integer
& v
= cs
[1].getIntegerValue();
6032 if(v
< 0 || v
> 2) {
6033 throw OptionException("command-verbosity must be 0, 1, or 2");
6035 d_commandVerbosity
[c
] = v
;
6039 throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
6042 if(!value
.isAtom()) {
6043 throw OptionException("bad value for :" + key
);
6046 string optionarg
= value
.getValue();
6047 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
6048 nodeManagerOptions
.setOption(key
, optionarg
);
6051 CVC4::SExpr
SmtEngine::getOption(const std::string
& key
) const
6053 NodeManagerScope
nms(d_nodeManager
);
6055 Trace("smt") << "SMT getOption(" << key
<< ")" << endl
;
6057 if(key
.length() >= 18 &&
6058 key
.compare(0, 18, "command-verbosity:") == 0) {
6059 map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.find(key
.c_str() + 18);
6060 if(i
!= d_commandVerbosity
.end()) {
6061 return SExpr((*i
).second
);
6063 i
= d_commandVerbosity
.find("*");
6064 if(i
!= d_commandVerbosity
.end()) {
6065 return SExpr((*i
).second
);
6067 return SExpr(Integer(2));
6070 if(Dump
.isOn("benchmark")) {
6071 Dump("benchmark") << GetOptionCommand(key
);
6074 if(key
== "command-verbosity") {
6075 vector
<SExpr
> result
;
6076 SExpr defaultVerbosity
;
6077 for(map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.begin();
6078 i
!= d_commandVerbosity
.end();
6081 v
.push_back(SExpr((*i
).first
));
6082 v
.push_back(SExpr((*i
).second
));
6083 if((*i
).first
== "*") {
6084 // put the default at the end of the SExpr
6085 defaultVerbosity
= SExpr(v
);
6087 result
.push_back(SExpr(v
));
6090 // put the default at the end of the SExpr
6091 if(!defaultVerbosity
.isAtom()) {
6092 result
.push_back(defaultVerbosity
);
6094 // ensure the default is always listed
6096 v
.push_back(SExpr("*"));
6097 v
.push_back(SExpr(Integer(2)));
6098 result
.push_back(SExpr(v
));
6100 return SExpr(result
);
6103 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
6104 return SExpr::parseAtom(nodeManagerOptions
.getOption(key
));
6107 void SmtEngine::setReplayStream(ExprStream
* replayStream
) {
6108 AlwaysAssert(!d_fullyInited
,
6109 "Cannot set replay stream once fully initialized");
6110 d_replayStream
= replayStream
;
6113 bool SmtEngine::getExpressionName(Expr e
, std::string
& name
) const {
6114 return d_private
->getExpressionName(e
, name
);
6117 void SmtEngine::setExpressionName(Expr e
, const std::string
& name
) {
6118 Trace("smt-debug") << "Set expression name " << e
<< " to " << name
<< std::endl
;
6119 d_private
->setExpressionName(e
,name
);
6122 }/* CVC4 namespace */