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"
27 #include <unordered_map>
28 #include <unordered_set>
32 #include "base/configuration.h"
33 #include "base/configuration_private.h"
34 #include "base/exception.h"
35 #include "base/listener.h"
36 #include "base/modal_exception.h"
37 #include "base/output.h"
38 #include "context/cdhashmap.h"
39 #include "context/cdhashset.h"
40 #include "context/cdlist.h"
41 #include "context/context.h"
42 #include "decision/decision_engine.h"
43 #include "expr/attribute.h"
44 #include "expr/expr.h"
45 #include "expr/kind.h"
46 #include "expr/metakind.h"
47 #include "expr/node.h"
48 #include "expr/node_builder.h"
49 #include "expr/node_self_iterator.h"
50 #include "options/arith_options.h"
51 #include "options/arrays_options.h"
52 #include "options/base_options.h"
53 #include "options/booleans_options.h"
54 #include "options/bv_options.h"
55 #include "options/datatypes_options.h"
56 #include "options/decision_mode.h"
57 #include "options/decision_options.h"
58 #include "options/language.h"
59 #include "options/main_options.h"
60 #include "options/open_ostream.h"
61 #include "options/option_exception.h"
62 #include "options/printer_options.h"
63 #include "options/proof_options.h"
64 #include "options/prop_options.h"
65 #include "options/quantifiers_options.h"
66 #include "options/sep_options.h"
67 #include "options/set_language.h"
68 #include "options/smt_options.h"
69 #include "options/strings_options.h"
70 #include "options/theory_options.h"
71 #include "options/uf_options.h"
72 #include "preprocessing/passes/apply_substs.h"
73 #include "preprocessing/passes/apply_to_const.h"
74 #include "preprocessing/passes/bool_to_bv.h"
75 #include "preprocessing/passes/bv_abstraction.h"
76 #include "preprocessing/passes/bv_ackermann.h"
77 #include "preprocessing/passes/bv_eager_atoms.h"
78 #include "preprocessing/passes/bv_gauss.h"
79 #include "preprocessing/passes/bv_intro_pow2.h"
80 #include "preprocessing/passes/bv_to_bool.h"
81 #include "preprocessing/passes/extended_rewriter_pass.h"
82 #include "preprocessing/passes/int_to_bv.h"
83 #include "preprocessing/passes/ite_removal.h"
84 #include "preprocessing/passes/pseudo_boolean_processor.h"
85 #include "preprocessing/passes/quantifiers_preprocess.h"
86 #include "preprocessing/passes/real_to_int.h"
87 #include "preprocessing/passes/rewrite.h"
88 #include "preprocessing/passes/sep_skolem_emp.h"
89 #include "preprocessing/passes/sort_infer.h"
90 #include "preprocessing/passes/static_learning.h"
91 #include "preprocessing/passes/symmetry_breaker.h"
92 #include "preprocessing/passes/symmetry_detect.h"
93 #include "preprocessing/passes/synth_rew_rules.h"
94 #include "preprocessing/preprocessing_pass.h"
95 #include "preprocessing/preprocessing_pass_context.h"
96 #include "preprocessing/preprocessing_pass_registry.h"
97 #include "printer/printer.h"
98 #include "proof/proof.h"
99 #include "proof/proof_manager.h"
100 #include "proof/theory_proof.h"
101 #include "proof/unsat_core.h"
102 #include "prop/prop_engine.h"
103 #include "smt/command.h"
104 #include "smt/command_list.h"
105 #include "smt/logic_request.h"
106 #include "smt/managed_ostreams.h"
107 #include "smt/smt_engine_scope.h"
108 #include "smt/term_formula_removal.h"
109 #include "smt/update_ostream.h"
110 #include "smt_util/boolean_simplification.h"
111 #include "smt_util/nary_builder.h"
112 #include "smt_util/node_visitor.h"
113 #include "theory/booleans/circuit_propagator.h"
114 #include "theory/bv/theory_bv_rewriter.h"
115 #include "theory/logic_info.h"
116 #include "theory/quantifiers/fun_def_process.h"
117 #include "theory/quantifiers/global_negate.h"
118 #include "theory/quantifiers/macros.h"
119 #include "theory/quantifiers/quantifiers_rewriter.h"
120 #include "theory/quantifiers/single_inv_partition.h"
121 #include "theory/quantifiers/sygus/ce_guided_instantiation.h"
122 #include "theory/quantifiers/sygus_inference.h"
123 #include "theory/quantifiers/term_util.h"
124 #include "theory/rewriter.h"
125 #include "theory/sort_inference.h"
126 #include "theory/strings/theory_strings.h"
127 #include "theory/substitutions.h"
128 #include "theory/theory_engine.h"
129 #include "theory/theory_model.h"
130 #include "theory/theory_traits.h"
131 #include "util/hash.h"
132 #include "util/proof.h"
133 #include "util/random.h"
134 #include "util/resource_manager.h"
137 using namespace CVC4
;
138 using namespace CVC4::smt
;
139 using namespace CVC4::preprocessing
;
140 using namespace CVC4::preprocessing::passes
;
141 using namespace CVC4::prop
;
142 using namespace CVC4::context
;
143 using namespace CVC4::theory
;
148 struct DeleteCommandFunction
: public std::unary_function
<const Command
*, void>
150 void operator()(const Command
* command
) { delete command
; }
153 void DeleteAndClearCommandVector(std::vector
<Command
*>& commands
) {
154 std::for_each(commands
.begin(), commands
.end(), DeleteCommandFunction());
158 /** Useful for counting the number of recursive calls. */
163 ScopeCounter(unsigned& d
) : d_depth(d
) {
172 * Representation of a defined function. We keep these around in
173 * SmtEngine to permit expanding definitions late (and lazily), to
174 * support getValue() over defined functions, to support user output
175 * in terms of defined functions, etc.
177 class DefinedFunction
{
179 vector
<Node
> d_formals
;
183 DefinedFunction(Node func
, vector
<Node
> formals
, Node formula
) :
188 Node
getFunction() const { return d_func
; }
189 vector
<Node
> getFormals() const { return d_formals
; }
190 Node
getFormula() const { return d_formula
; }
191 };/* class DefinedFunction */
193 struct SmtEngineStatistics
{
194 /** time spent in definition-expansion */
195 TimerStat d_definitionExpansionTime
;
196 /** time spent in non-clausal simplification */
197 TimerStat d_nonclausalSimplificationTime
;
198 /** time spent in miplib pass */
199 TimerStat d_miplibPassTime
;
200 /** number of assertions removed by miplib pass */
201 IntStat d_numMiplibAssertionsRemoved
;
202 /** number of constant propagations found during nonclausal simp */
203 IntStat d_numConstantProps
;
204 /** time spent in simplifying ITEs */
205 TimerStat d_simpITETime
;
206 /** time spent in simplifying ITEs */
207 TimerStat d_unconstrainedSimpTime
;
208 /** time spent in theory preprocessing */
209 TimerStat d_theoryPreprocessTime
;
210 /** time spent converting to CNF */
211 TimerStat d_cnfConversionTime
;
212 /** Num of assertions before ite removal */
213 IntStat d_numAssertionsPre
;
214 /** Num of assertions after ite removal */
215 IntStat d_numAssertionsPost
;
216 /** time spent in checkModel() */
217 TimerStat d_checkModelTime
;
218 /** time spent in checkProof() */
219 TimerStat d_checkProofTime
;
220 /** time spent in checkUnsatCore() */
221 TimerStat d_checkUnsatCoreTime
;
222 /** time spent in PropEngine::checkSat() */
223 TimerStat d_solveTime
;
224 /** time spent in pushing/popping */
225 TimerStat d_pushPopTime
;
226 /** time spent in processAssertions() */
227 TimerStat d_processAssertionsTime
;
229 /** Has something simplified to false? */
230 IntStat d_simplifiedToFalse
;
231 /** Number of resource units spent. */
232 ReferenceStat
<uint64_t> d_resourceUnitsUsed
;
234 SmtEngineStatistics() :
235 d_definitionExpansionTime("smt::SmtEngine::definitionExpansionTime"),
236 d_nonclausalSimplificationTime("smt::SmtEngine::nonclausalSimplificationTime"),
237 d_miplibPassTime("smt::SmtEngine::miplibPassTime"),
238 d_numMiplibAssertionsRemoved("smt::SmtEngine::numMiplibAssertionsRemoved", 0),
239 d_numConstantProps("smt::SmtEngine::numConstantProps", 0),
240 d_simpITETime("smt::SmtEngine::simpITETime"),
241 d_unconstrainedSimpTime("smt::SmtEngine::unconstrainedSimpTime"),
242 d_theoryPreprocessTime("smt::SmtEngine::theoryPreprocessTime"),
243 d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
244 d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
245 d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
246 d_checkModelTime("smt::SmtEngine::checkModelTime"),
247 d_checkProofTime("smt::SmtEngine::checkProofTime"),
248 d_checkUnsatCoreTime("smt::SmtEngine::checkUnsatCoreTime"),
249 d_solveTime("smt::SmtEngine::solveTime"),
250 d_pushPopTime("smt::SmtEngine::pushPopTime"),
251 d_processAssertionsTime("smt::SmtEngine::processAssertionsTime"),
252 d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0),
253 d_resourceUnitsUsed("smt::SmtEngine::resourceUnitsUsed")
255 smtStatisticsRegistry()->registerStat(&d_definitionExpansionTime
);
256 smtStatisticsRegistry()->registerStat(&d_nonclausalSimplificationTime
);
257 smtStatisticsRegistry()->registerStat(&d_miplibPassTime
);
258 smtStatisticsRegistry()->registerStat(&d_numMiplibAssertionsRemoved
);
259 smtStatisticsRegistry()->registerStat(&d_numConstantProps
);
260 smtStatisticsRegistry()->registerStat(&d_simpITETime
);
261 smtStatisticsRegistry()->registerStat(&d_unconstrainedSimpTime
);
262 smtStatisticsRegistry()->registerStat(&d_theoryPreprocessTime
);
263 smtStatisticsRegistry()->registerStat(&d_cnfConversionTime
);
264 smtStatisticsRegistry()->registerStat(&d_numAssertionsPre
);
265 smtStatisticsRegistry()->registerStat(&d_numAssertionsPost
);
266 smtStatisticsRegistry()->registerStat(&d_checkModelTime
);
267 smtStatisticsRegistry()->registerStat(&d_checkProofTime
);
268 smtStatisticsRegistry()->registerStat(&d_checkUnsatCoreTime
);
269 smtStatisticsRegistry()->registerStat(&d_solveTime
);
270 smtStatisticsRegistry()->registerStat(&d_pushPopTime
);
271 smtStatisticsRegistry()->registerStat(&d_processAssertionsTime
);
272 smtStatisticsRegistry()->registerStat(&d_simplifiedToFalse
);
273 smtStatisticsRegistry()->registerStat(&d_resourceUnitsUsed
);
276 ~SmtEngineStatistics() {
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_simpITETime
);
283 smtStatisticsRegistry()->unregisterStat(&d_unconstrainedSimpTime
);
284 smtStatisticsRegistry()->unregisterStat(&d_theoryPreprocessTime
);
285 smtStatisticsRegistry()->unregisterStat(&d_cnfConversionTime
);
286 smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPre
);
287 smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPost
);
288 smtStatisticsRegistry()->unregisterStat(&d_checkModelTime
);
289 smtStatisticsRegistry()->unregisterStat(&d_checkProofTime
);
290 smtStatisticsRegistry()->unregisterStat(&d_checkUnsatCoreTime
);
291 smtStatisticsRegistry()->unregisterStat(&d_solveTime
);
292 smtStatisticsRegistry()->unregisterStat(&d_pushPopTime
);
293 smtStatisticsRegistry()->unregisterStat(&d_processAssertionsTime
);
294 smtStatisticsRegistry()->unregisterStat(&d_simplifiedToFalse
);
295 smtStatisticsRegistry()->unregisterStat(&d_resourceUnitsUsed
);
297 };/* struct SmtEngineStatistics */
300 class SoftResourceOutListener
: public Listener
{
302 SoftResourceOutListener(SmtEngine
& smt
) : d_smt(&smt
) {}
303 void notify() override
305 SmtScope
scope(d_smt
);
306 Assert(smt::smtEngineInScope());
311 }; /* class SoftResourceOutListener */
314 class HardResourceOutListener
: public Listener
{
316 HardResourceOutListener(SmtEngine
& smt
) : d_smt(&smt
) {}
317 void notify() override
319 SmtScope
scope(d_smt
);
320 theory::Rewriter::clearCaches();
324 }; /* class HardResourceOutListener */
326 class SetLogicListener
: public Listener
{
328 SetLogicListener(SmtEngine
& smt
) : d_smt(&smt
) {}
329 void notify() override
331 LogicInfo
inOptions(options::forceLogicString());
332 d_smt
->setLogic(inOptions
);
336 }; /* class SetLogicListener */
338 class BeforeSearchListener
: public Listener
{
340 BeforeSearchListener(SmtEngine
& smt
) : d_smt(&smt
) {}
341 void notify() override
{ d_smt
->beforeSearch(); }
345 }; /* class BeforeSearchListener */
347 class UseTheoryListListener
: public Listener
{
349 UseTheoryListListener(TheoryEngine
* theoryEngine
)
350 : d_theoryEngine(theoryEngine
)
353 void notify() override
355 std::stringstream
commaList(options::useTheoryList());
358 Debug("UseTheoryListListener") << "UseTheoryListListener::notify() "
359 << options::useTheoryList() << std::endl
;
361 while(std::getline(commaList
, token
, ',')){
362 if(token
== "help") {
363 puts(theory::useTheoryHelp
);
366 if(theory::useTheoryValidate(token
)) {
367 d_theoryEngine
->enableTheoryAlternative(token
);
369 throw OptionException(
370 std::string("unknown option for --use-theory : `") + token
+
371 "'. Try --use-theory=help.");
377 TheoryEngine
* d_theoryEngine
;
378 }; /* class UseTheoryListListener */
381 class SetDefaultExprDepthListener
: public Listener
{
383 void notify() override
385 int depth
= options::defaultExprDepth();
386 Debug
.getStream() << expr::ExprSetDepth(depth
);
387 Trace
.getStream() << expr::ExprSetDepth(depth
);
388 Notice
.getStream() << expr::ExprSetDepth(depth
);
389 Chat
.getStream() << expr::ExprSetDepth(depth
);
390 Message
.getStream() << expr::ExprSetDepth(depth
);
391 Warning
.getStream() << expr::ExprSetDepth(depth
);
392 // intentionally exclude Dump stream from this list
396 class SetDefaultExprDagListener
: public Listener
{
398 void notify() override
400 int dag
= options::defaultDagThresh();
401 Debug
.getStream() << expr::ExprDag(dag
);
402 Trace
.getStream() << expr::ExprDag(dag
);
403 Notice
.getStream() << expr::ExprDag(dag
);
404 Chat
.getStream() << expr::ExprDag(dag
);
405 Message
.getStream() << expr::ExprDag(dag
);
406 Warning
.getStream() << expr::ExprDag(dag
);
407 Dump
.getStream() << expr::ExprDag(dag
);
411 class SetPrintExprTypesListener
: public Listener
{
413 void notify() override
415 bool value
= options::printExprTypes();
416 Debug
.getStream() << expr::ExprPrintTypes(value
);
417 Trace
.getStream() << expr::ExprPrintTypes(value
);
418 Notice
.getStream() << expr::ExprPrintTypes(value
);
419 Chat
.getStream() << expr::ExprPrintTypes(value
);
420 Message
.getStream() << expr::ExprPrintTypes(value
);
421 Warning
.getStream() << expr::ExprPrintTypes(value
);
422 // intentionally exclude Dump stream from this list
426 class DumpModeListener
: public Listener
{
428 void notify() override
430 const std::string
& value
= options::dumpModeString();
431 Dump
.setDumpFromString(value
);
435 class PrintSuccessListener
: public Listener
{
437 void notify() override
439 bool value
= options::printSuccess();
440 Debug
.getStream() << Command::printsuccess(value
);
441 Trace
.getStream() << Command::printsuccess(value
);
442 Notice
.getStream() << Command::printsuccess(value
);
443 Chat
.getStream() << Command::printsuccess(value
);
444 Message
.getStream() << Command::printsuccess(value
);
445 Warning
.getStream() << Command::printsuccess(value
);
446 *options::out() << Command::printsuccess(value
);
453 * This is an inelegant solution, but for the present, it will work.
454 * The point of this is to separate the public and private portions of
455 * the SmtEngine class, so that smt_engine.h doesn't
456 * include "expr/node.h", which is a private CVC4 header (and can lead
457 * to linking errors due to the improper inlining of non-visible symbols
460 * The "real" solution (that which is usually implemented) is to move
461 * ALL the implementation to SmtEnginePrivate and maintain a
462 * heap-allocated instance of it in SmtEngine. SmtEngine (the public
463 * one) becomes an "interface shell" which simply acts as a forwarder
466 class SmtEnginePrivate
: public NodeManagerListener
{
469 typedef unordered_map
<Node
, Node
, NodeHashFunction
> NodeToNodeHashMap
;
470 typedef unordered_map
<Node
, bool, NodeHashFunction
> NodeToBoolHashMap
;
473 * Manager for limiting time and abstract resource usage.
475 ResourceManager
* d_resourceManager
;
477 /** Manager for the memory of regular-output-channel. */
478 ManagedRegularOutputChannel d_managedRegularChannel
;
480 /** Manager for the memory of diagnostic-output-channel. */
481 ManagedDiagnosticOutputChannel d_managedDiagnosticChannel
;
483 /** Manager for the memory of --dump-to. */
484 ManagedDumpOStream d_managedDumpChannel
;
486 /** Manager for --replay-log. */
487 ManagedReplayLogOstream d_managedReplayLog
;
490 * This list contains:
494 * beforeSearchListener
495 * UseTheoryListListener
497 * This needs to be deleted before both NodeManager's Options,
498 * SmtEngine, d_resourceManager, and TheoryEngine.
500 ListenerRegistrationList
* d_listenerRegistrations
;
502 /** Learned literals */
503 vector
<Node
> d_nonClausalLearnedLiterals
;
505 /** Size of assertions array when preprocessing starts */
506 unsigned d_realAssertionsEnd
;
508 /** A circuit propagator for non-clausal propositional deduction */
509 booleans::CircuitPropagator d_propagator
;
510 bool d_propagatorNeedsFinish
;
511 std::vector
<Node
> d_boolVars
;
513 /** Assertions in the preprocessing pipeline */
514 AssertionPipeline d_assertions
;
516 /** Whether any assertions have been processed */
517 CDO
<bool> d_assertionsProcessed
;
523 * A context that never pushes/pops, for use by CD structures (like
524 * SubstitutionMaps) that should be "global".
526 context::Context d_fakeContext
;
529 * A map of AbsractValues to their actual constants. Only used if
530 * options::abstractValues() is on.
532 SubstitutionMap d_abstractValueMap
;
535 * A mapping of all abstract values (actual value |-> abstract) that
536 * we've handed out. This is necessary to ensure that we give the
537 * same AbstractValues for the same real constants. Only used if
538 * options::abstractValues() is on.
540 NodeToNodeHashMap d_abstractValues
;
542 /** Number of calls of simplify assertions active.
544 unsigned d_simplifyAssertionsDepth
;
546 /** TODO: whether certain preprocess steps are necessary */
547 //bool d_needsExpandDefs;
549 //------------------------------- expression names
550 /** mapping from expressions to name */
551 context::CDHashMap
< Node
, std::string
, NodeHashFunction
> d_exprNames
;
552 //------------------------------- end expression names
554 IteSkolemMap
& getIteSkolemMap() { return d_assertions
.getIteSkolemMap(); }
556 /** Instance of the ITE remover */
557 RemoveTermFormulas d_iteRemover
;
559 /* Finishes the initialization of the private portion of SMTEngine. */
563 std::unique_ptr
<PreprocessingPassContext
> d_preprocessingPassContext
;
564 PreprocessingPassRegistry d_preprocessingPassRegistry
;
566 static const bool d_doConstantProp
= true;
569 * Runs the nonclausal solver and tries to solve all the assigned
572 * Returns false if the formula simplifies to "false"
574 bool nonClausalSimplify();
577 * Performs static learning on the assertions.
579 void staticLearning();
581 Node
realToInt(TNode n
, NodeToNodeHashMap
& cache
, std::vector
< Node
>& var_eq
);
582 Node
purifyNlTerms(TNode n
, NodeToNodeHashMap
& cache
, NodeToNodeHashMap
& bcache
, std::vector
< Node
>& var_eq
, bool beneathMult
= false);
585 * Helper function to fix up assertion list to restore invariants needed after
588 void collectSkolems(TNode n
, set
<TNode
>& skolemSet
, NodeToBoolHashMap
& cache
);
591 * Helper function to fix up assertion list to restore invariants needed after
594 bool checkForBadSkolems(TNode n
, TNode skolem
, NodeToBoolHashMap
& cache
);
596 // Simplify ITE structure
599 // Simplify based on unconstrained values
600 void unconstrainedSimp();
603 * Ensures the assertions asserted after before now effectively come before
604 * d_realAssertionsEnd.
606 void compressBeforeRealAssertions(size_t before
);
609 * Trace nodes back to their assertions using CircuitPropagator's
612 void traceBackToAssertions(const std::vector
<Node
>& nodes
,
613 std::vector
<TNode
>& assertions
);
616 * Remove conjuncts in toRemove from conjunction n. Return # of removed
619 size_t removeFromConjunction(
620 Node
& n
, const std::unordered_set
<unsigned long>& toRemove
);
622 /** Scrub miplib encodings. */
623 void doMiplibTrick();
626 * Perform non-clausal simplification of a Node. This involves
627 * Theory implementations, but does NOT involve the SAT solver in
630 * Returns false if the formula simplifies to "false"
632 bool simplifyAssertions();
635 SmtEnginePrivate(SmtEngine
& smt
)
637 d_managedRegularChannel(),
638 d_managedDiagnosticChannel(),
639 d_managedDumpChannel(),
640 d_managedReplayLog(),
641 d_listenerRegistrations(new ListenerRegistrationList()),
642 d_nonClausalLearnedLiterals(),
643 d_realAssertionsEnd(0),
644 d_propagator(d_nonClausalLearnedLiterals
, true, true),
645 d_propagatorNeedsFinish(false),
646 d_assertions(d_smt
.d_userContext
),
647 d_assertionsProcessed(smt
.d_userContext
, false),
649 d_abstractValueMap(&d_fakeContext
),
651 d_simplifyAssertionsDepth(0),
652 // d_needsExpandDefs(true), //TODO?
653 d_exprNames(smt
.d_userContext
),
654 d_iteRemover(smt
.d_userContext
)
656 d_smt
.d_nodeManager
->subscribeEvents(this);
657 d_true
= NodeManager::currentNM()->mkConst(true);
658 d_resourceManager
= NodeManager::currentResourceManager();
660 d_listenerRegistrations
->add(d_resourceManager
->registerSoftListener(
661 new SoftResourceOutListener(d_smt
)));
663 d_listenerRegistrations
->add(d_resourceManager
->registerHardListener(
664 new HardResourceOutListener(d_smt
)));
666 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
667 d_listenerRegistrations
->add(
668 nodeManagerOptions
.registerForceLogicListener(
669 new SetLogicListener(d_smt
), true));
671 // Multiple options reuse BeforeSearchListener so registration requires an
672 // extra bit of care.
673 // We can safely not call notify on this before search listener at
674 // registration time. This d_smt cannot be beforeSearch at construction
675 // time. Therefore the BeforeSearchListener is a no-op. Therefore it does
676 // not have to be called.
677 d_listenerRegistrations
->add(
678 nodeManagerOptions
.registerBeforeSearchListener(
679 new BeforeSearchListener(d_smt
)));
681 // These do need registration calls.
682 d_listenerRegistrations
->add(
683 nodeManagerOptions
.registerSetDefaultExprDepthListener(
684 new SetDefaultExprDepthListener(), true));
685 d_listenerRegistrations
->add(
686 nodeManagerOptions
.registerSetDefaultExprDagListener(
687 new SetDefaultExprDagListener(), true));
688 d_listenerRegistrations
->add(
689 nodeManagerOptions
.registerSetPrintExprTypesListener(
690 new SetPrintExprTypesListener(), true));
691 d_listenerRegistrations
->add(
692 nodeManagerOptions
.registerSetDumpModeListener(
693 new DumpModeListener(), true));
694 d_listenerRegistrations
->add(
695 nodeManagerOptions
.registerSetPrintSuccessListener(
696 new PrintSuccessListener(), true));
697 d_listenerRegistrations
->add(
698 nodeManagerOptions
.registerSetRegularOutputChannelListener(
699 new SetToDefaultSourceListener(&d_managedRegularChannel
), true));
700 d_listenerRegistrations
->add(
701 nodeManagerOptions
.registerSetDiagnosticOutputChannelListener(
702 new SetToDefaultSourceListener(&d_managedDiagnosticChannel
), true));
703 d_listenerRegistrations
->add(
704 nodeManagerOptions
.registerDumpToFileNameListener(
705 new SetToDefaultSourceListener(&d_managedDumpChannel
), true));
706 d_listenerRegistrations
->add(
707 nodeManagerOptions
.registerSetReplayLogFilename(
708 new SetToDefaultSourceListener(&d_managedReplayLog
), true));
713 delete d_listenerRegistrations
;
715 if(d_propagatorNeedsFinish
) {
716 d_propagator
.finish();
717 d_propagatorNeedsFinish
= false;
719 d_smt
.d_nodeManager
->unsubscribeEvents(this);
722 void unregisterPreprocessingPasses()
724 d_preprocessingPassRegistry
.unregisterPasses();
727 ResourceManager
* getResourceManager() { return d_resourceManager
; }
728 void spendResource(unsigned amount
)
730 d_resourceManager
->spendResource(amount
);
733 void nmNotifyNewSort(TypeNode tn
, uint32_t flags
) override
735 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
738 if((flags
& ExprManager::SORT_FLAG_PLACEHOLDER
) == 0) {
739 d_smt
.addToModelCommandAndDump(c
, flags
);
743 void nmNotifyNewSortConstructor(TypeNode tn
, uint32_t flags
) override
745 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
746 tn
.getAttribute(expr::SortArityAttr()),
748 if ((flags
& ExprManager::SORT_FLAG_PLACEHOLDER
) == 0)
750 d_smt
.addToModelCommandAndDump(c
);
754 void nmNotifyNewDatatypes(const std::vector
<DatatypeType
>& dtts
) override
756 DatatypeDeclarationCommand
c(dtts
);
757 d_smt
.addToModelCommandAndDump(c
);
760 void nmNotifyNewVar(TNode n
, uint32_t flags
) override
762 DeclareFunctionCommand
c(n
.getAttribute(expr::VarNameAttr()),
764 n
.getType().toType());
765 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
766 d_smt
.addToModelCommandAndDump(c
, flags
);
768 if(n
.getType().isBoolean() && !options::incrementalSolving()) {
769 d_boolVars
.push_back(n
);
773 void nmNotifyNewSkolem(TNode n
,
774 const std::string
& comment
,
775 uint32_t flags
) override
777 string id
= n
.getAttribute(expr::VarNameAttr());
778 DeclareFunctionCommand
c(id
, n
.toExpr(), n
.getType().toType());
779 if(Dump
.isOn("skolems") && comment
!= "") {
780 Dump("skolems") << CommentCommand(id
+ " is " + comment
);
782 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
783 d_smt
.addToModelCommandAndDump(c
, flags
, false, "skolems");
785 if(n
.getType().isBoolean() && !options::incrementalSolving()) {
786 d_boolVars
.push_back(n
);
790 void nmNotifyDeleteNode(TNode n
) override
{}
792 Node
applySubstitutions(TNode node
)
794 return Rewriter::rewrite(
795 d_assertions
.getTopLevelSubstitutions().apply(node
));
799 * Process the assertions that have been asserted.
801 void processAssertions();
803 /** Process a user push.
810 * Process a user pop. Clears out the non-context-dependent stuff in this
811 * SmtEnginePrivate. Necessary to clear out our assertion vectors in case
812 * someone does a push-assert-pop without a check-sat. It also pops the
813 * last map of expression names from notifyPush.
816 d_assertions
.clear();
817 d_nonClausalLearnedLiterals
.clear();
818 d_realAssertionsEnd
= 0;
819 getIteSkolemMap().clear();
823 * Adds a formula to the current context. Action here depends on
824 * the SimplificationMode (in the current Options scope); the
825 * formula might be pushed out to the propositional layer
826 * immediately, or it might be simplified and kept, or it might not
827 * even be simplified.
828 * the 2nd and 3rd arguments added for bookkeeping for proofs
830 void addFormula(TNode n
, bool inUnsatCore
, bool inInput
= true);
832 /** Expand definitions in n. */
833 Node
expandDefinitions(TNode n
,
834 NodeToNodeHashMap
& cache
,
835 bool expandOnly
= false);
838 * Simplify node "in" by expanding definitions and applying any
839 * substitutions learned from preprocessing.
841 Node
simplify(TNode in
) {
842 // Substitute out any abstract values in ex.
843 // Expand definitions.
844 NodeToNodeHashMap cache
;
845 Node n
= expandDefinitions(in
, cache
).toExpr();
846 // Make sure we've done all preprocessing, etc.
847 Assert(d_assertions
.size() == 0);
848 return applySubstitutions(n
).toExpr();
852 * Substitute away all AbstractValues in a node.
854 Node
substituteAbstractValues(TNode n
) {
855 // We need to do this even if options::abstractValues() is off,
856 // since the setting might have changed after we already gave out
857 // some abstract values.
858 return d_abstractValueMap
.apply(n
);
862 * Make a new (or return an existing) abstract value for a node.
863 * Can only use this if options::abstractValues() is on.
865 Node
mkAbstractValue(TNode n
) {
866 Assert(options::abstractValues());
867 Node
& val
= d_abstractValues
[n
];
869 val
= d_smt
.d_nodeManager
->mkAbstractValue(n
.getType());
870 d_abstractValueMap
.addSubstitution(val
, n
);
872 // We are supposed to ascribe types to all abstract values that go out.
873 NodeManager
* current
= d_smt
.d_nodeManager
;
874 Node ascription
= current
->mkConst(AscriptionType(n
.getType().toType()));
875 Node retval
= current
->mkNode(kind::APPLY_TYPE_ASCRIPTION
, ascription
, val
);
879 void addUseTheoryListListener(TheoryEngine
* theoryEngine
){
880 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
881 d_listenerRegistrations
->add(
882 nodeManagerOptions
.registerUseTheoryListListener(
883 new UseTheoryListListener(theoryEngine
), true));
886 std::ostream
* getReplayLog() const {
887 return d_managedReplayLog
.getReplayLog();
890 //------------------------------- expression names
891 // implements setExpressionName, as described in smt_engine.h
892 void setExpressionName(Expr e
, std::string name
) {
893 d_exprNames
[Node::fromExpr(e
)] = name
;
896 // implements getExpressionName, as described in smt_engine.h
897 bool getExpressionName(Expr e
, std::string
& name
) const {
898 context::CDHashMap
< Node
, std::string
, NodeHashFunction
>::const_iterator it
= d_exprNames
.find(e
);
899 if(it
!=d_exprNames
.end()) {
906 //------------------------------- end expression names
908 };/* class SmtEnginePrivate */
910 }/* namespace CVC4::smt */
912 SmtEngine::SmtEngine(ExprManager
* em
)
913 : d_context(new Context()),
915 d_userContext(new UserContext()),
917 d_nodeManager(d_exprManager
->getNodeManager()),
918 d_decisionEngine(NULL
),
919 d_theoryEngine(NULL
),
921 d_proofManager(NULL
),
922 d_definedFunctions(NULL
),
923 d_fmfRecFunctionsDefined(NULL
),
924 d_assertionList(NULL
),
926 d_modelGlobalCommands(),
927 d_modelCommands(NULL
),
933 d_fullyInited(false),
934 d_problemExtended(false),
936 d_needPostsolve(false),
937 d_earlyTheoryPP(true),
938 d_globalNegation(false),
940 d_replayStream(NULL
),
942 d_statisticsRegistry(NULL
),
944 d_channels(new LemmaChannels())
947 d_originalOptions
.copyValues(em
->getOptions());
948 d_private
= new smt::SmtEnginePrivate(*this);
949 d_statisticsRegistry
= new StatisticsRegistry();
950 d_stats
= new SmtEngineStatistics();
951 d_stats
->d_resourceUnitsUsed
.setData(
952 d_private
->getResourceManager()->getResourceUsage());
954 // The ProofManager is constructed before any other proof objects such as
955 // SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
956 // initialized in TheoryEngine and PropEngine respectively.
957 Assert(d_proofManager
== NULL
);
959 // d_proofManager must be created before Options has been finished
960 // being parsed from the input file. Because of this, we cannot trust
961 // that options::proof() is set correctly yet.
963 d_proofManager
= new ProofManager(d_userContext
);
966 // We have mutual dependency here, so we add the prop engine to the theory
967 // engine later (it is non-essential there)
968 d_theoryEngine
= new TheoryEngine(d_context
,
970 d_private
->d_iteRemover
,
971 const_cast<const LogicInfo
&>(d_logic
),
975 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
976 TheoryConstructor::addTheory(d_theoryEngine
, id
);
977 //register with proof engine if applicable
979 ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine
->theoryOf(id
));
983 d_private
->addUseTheoryListListener(d_theoryEngine
);
985 // global push/pop around everything, to ensure proper destruction
986 // of context-dependent data structures
987 d_userContext
->push();
990 d_definedFunctions
= new(true) DefinedFunctionMap(d_userContext
);
991 d_fmfRecFunctionsDefined
= new(true) NodeList(d_userContext
);
992 d_modelCommands
= new(true) smt::CommandList(d_userContext
);
995 void SmtEngine::finishInit() {
996 Trace("smt-debug") << "SmtEngine::finishInit" << std::endl
;
997 // ensure that our heuristics are properly set up
1000 Trace("smt-debug") << "Making decision engine..." << std::endl
;
1002 d_decisionEngine
= new DecisionEngine(d_context
, d_userContext
);
1003 d_decisionEngine
->init(); // enable appropriate strategies
1005 Trace("smt-debug") << "Making prop engine..." << std::endl
;
1006 d_propEngine
= new PropEngine(d_theoryEngine
, d_decisionEngine
, d_context
,
1007 d_userContext
, d_private
->getReplayLog(),
1008 d_replayStream
, d_channels
);
1010 Trace("smt-debug") << "Setting up theory engine..." << std::endl
;
1011 d_theoryEngine
->setPropEngine(d_propEngine
);
1012 d_theoryEngine
->setDecisionEngine(d_decisionEngine
);
1013 Trace("smt-debug") << "Finishing init for theory engine..." << std::endl
;
1014 d_theoryEngine
->finishInit();
1016 Trace("smt-debug") << "Set up assertion list..." << std::endl
;
1017 // [MGD 10/20/2011] keep around in incremental mode, due to a
1018 // cleanup ordering issue and Nodes/TNodes. If SAT is popped
1019 // first, some user-context-dependent TNodes might still exist
1021 if(options::produceAssertions() ||
1022 options::incrementalSolving()) {
1023 // In the case of incremental solving, we appear to need these to
1024 // ensure the relevant Nodes remain live.
1025 d_assertionList
= new(true) AssertionList(d_userContext
);
1028 // dump out a set-logic command
1029 if(Dump
.isOn("benchmark")) {
1030 if (Dump
.isOn("raw-benchmark")) {
1031 Dump("raw-benchmark") << SetBenchmarkLogicCommand(d_logic
.getLogicString());
1033 LogicInfo everything
;
1035 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.")
1036 << SetBenchmarkLogicCommand(everything
.getLogicString());
1040 Trace("smt-debug") << "Dump declaration commands..." << std::endl
;
1041 // dump out any pending declaration commands
1042 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
1043 Dump("declarations") << *d_dumpCommands
[i
];
1044 delete d_dumpCommands
[i
];
1046 d_dumpCommands
.clear();
1048 PROOF( ProofManager::currentPM()->setLogic(d_logic
); );
1050 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
1051 ProofManager::currentPM()->getTheoryProofEngine()->
1052 finishRegisterTheory(d_theoryEngine
->theoryOf(id
));
1055 d_private
->finishInit();
1056 Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl
;
1059 void SmtEngine::finalOptionsAreSet() {
1064 if(! d_logic
.isLocked()) {
1068 // finish initialization, create the prop engine, etc.
1071 AlwaysAssert( d_propEngine
->getAssertionLevel() == 0,
1072 "The PropEngine has pushed but the SmtEngine "
1073 "hasn't finished initializing!" );
1075 d_fullyInited
= true;
1076 Assert(d_logic
.isLocked());
1078 d_propEngine
->assertFormula(NodeManager::currentNM()->mkConst
<bool>(true));
1079 d_propEngine
->assertFormula(NodeManager::currentNM()->mkConst
<bool>(false).notNode());
1082 void SmtEngine::shutdown() {
1085 while(options::incrementalSolving() && d_userContext
->getLevel() > 1) {
1089 // check to see if a postsolve() is pending
1090 if(d_needPostsolve
) {
1091 d_theoryEngine
->postsolve();
1092 d_needPostsolve
= false;
1095 if(d_propEngine
!= NULL
) {
1096 d_propEngine
->shutdown();
1098 if(d_theoryEngine
!= NULL
) {
1099 d_theoryEngine
->shutdown();
1101 if(d_decisionEngine
!= NULL
) {
1102 d_decisionEngine
->shutdown();
1106 SmtEngine::~SmtEngine()
1108 SmtScope
smts(this);
1113 // global push/pop around everything, to ensure proper destruction
1114 // of context-dependent data structures
1115 d_context
->popto(0);
1116 d_userContext
->popto(0);
1118 if(d_assignments
!= NULL
) {
1119 d_assignments
->deleteSelf();
1122 if(d_assertionList
!= NULL
) {
1123 d_assertionList
->deleteSelf();
1126 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
1127 delete d_dumpCommands
[i
];
1128 d_dumpCommands
[i
] = NULL
;
1130 d_dumpCommands
.clear();
1132 DeleteAndClearCommandVector(d_modelGlobalCommands
);
1134 if(d_modelCommands
!= NULL
) {
1135 d_modelCommands
->deleteSelf();
1138 d_definedFunctions
->deleteSelf();
1139 d_fmfRecFunctionsDefined
->deleteSelf();
1141 //destroy all passes before destroying things that they refer to
1142 d_private
->unregisterPreprocessingPasses();
1144 delete d_theoryEngine
;
1145 d_theoryEngine
= NULL
;
1146 delete d_propEngine
;
1147 d_propEngine
= NULL
;
1148 delete d_decisionEngine
;
1149 d_decisionEngine
= NULL
;
1152 // d_proofManager is always created when proofs are enabled at configure time.
1153 // Becuase of this, this code should not be wrapped in PROOF() which
1154 // additionally checks flags such as options::proof().
1156 delete d_proofManager
;
1157 d_proofManager
= NULL
;
1162 delete d_statisticsRegistry
;
1163 d_statisticsRegistry
= NULL
;
1168 delete d_userContext
;
1169 d_userContext
= NULL
;
1176 } catch(Exception
& e
) {
1177 Warning() << "CVC4 threw an exception during cleanup." << endl
1182 void SmtEngine::setLogic(const LogicInfo
& logic
)
1184 SmtScope
smts(this);
1186 throw ModalException("Cannot set logic in SmtEngine after the engine has "
1187 "finished initializing.");
1193 void SmtEngine::setLogic(const std::string
& s
)
1195 SmtScope
smts(this);
1197 setLogic(LogicInfo(s
));
1198 } catch(IllegalArgumentException
& e
) {
1199 throw LogicException(e
.what());
1203 void SmtEngine::setLogic(const char* logic
) { setLogic(string(logic
)); }
1204 LogicInfo
SmtEngine::getLogicInfo() const {
1207 void SmtEngine::setLogicInternal()
1209 Assert(!d_fullyInited
, "setting logic in SmtEngine but the engine has already"
1210 " finished initializing for this run");
1214 void SmtEngine::setDefaults() {
1215 Random::getRandom().setSeed(options::seed());
1216 // Language-based defaults
1217 if (!options::bitvectorDivByZeroConst
.wasSetByUser())
1219 // Bitvector-divide-by-zero changed semantics in SMT LIB 2.6, thus we
1220 // set this option if the input format is SMT LIB 2.6. We also set this
1221 // option if we are sygus, since we assume SMT LIB 2.6 semantics for sygus.
1222 options::bitvectorDivByZeroConst
.set(
1223 language::isInputLang_smt2_6(options::inputLanguage())
1224 || options::inputLanguage() == language::input::LANG_SYGUS
);
1226 bool is_sygus
= false;
1227 if (options::inputLanguage() == language::input::LANG_SYGUS
)
1230 if (!options::ceGuidedInst
.wasSetByUser())
1232 options::ceGuidedInst
.set(true);
1234 // must use Ferrante/Rackoff for real arithmetic
1235 if (!options::cbqiMidpoint
.wasSetByUser())
1237 options::cbqiMidpoint
.set(true);
1239 if (options::sygusRepairConst())
1241 if (!options::cbqi
.wasSetByUser())
1243 options::cbqi
.set(true);
1248 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
)
1250 if (options::produceModels()
1251 && (d_logic
.isTheoryEnabled(THEORY_ARRAYS
)
1252 || d_logic
.isTheoryEnabled(THEORY_UF
)))
1254 if (options::bitblastMode
.wasSetByUser()
1255 || options::produceModels
.wasSetByUser())
1257 throw OptionException(std::string(
1258 "Eager bit-blasting currently does not support model generation "
1259 "for the combination of bit-vectors with arrays or uinterpreted "
1260 "functions. Try --bitblast=lazy"));
1262 Notice() << "SmtEngine: setting bit-blast mode to lazy to support model"
1263 << "generation" << endl
;
1264 setOption("bitblastMode", SExpr("lazy"));
1267 if (options::incrementalSolving() && !d_logic
.isPure(THEORY_BV
))
1269 throw OptionException(
1270 "Incremental eager bit-blasting is currently "
1271 "only supported for QF_BV. Try --bitblast=lazy.");
1275 if(options::forceLogicString
.wasSetByUser()) {
1276 d_logic
= LogicInfo(options::forceLogicString());
1277 }else if (options::solveIntAsBV() > 0) {
1278 d_logic
= LogicInfo("QF_BV");
1279 }else if (d_logic
.getLogicString() == "QF_NRA" && options::solveRealAsInt()) {
1280 d_logic
= LogicInfo("QF_NIA");
1281 } else if ((d_logic
.getLogicString() == "QF_UFBV" ||
1282 d_logic
.getLogicString() == "QF_ABV") &&
1283 options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
) {
1284 d_logic
= LogicInfo("QF_BV");
1288 /* - disabled for 1.4 release [MGD 2014.06.25]
1289 if(!d_logic.hasEverything() && d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
1290 if(! options::stringExp.wasSetByUser()) {
1291 options::stringExp.set( true );
1292 Trace("smt") << "turning on strings-exp, for the theory of strings" << std::endl;
1297 if(options::stringExp()) {
1298 if( !d_logic
.isQuantified() ) {
1299 d_logic
= d_logic
.getUnlockedCopy();
1300 d_logic
.enableQuantifiers();
1302 Trace("smt") << "turning on quantifier logic, for strings-exp"
1305 if(! options::fmfBound
.wasSetByUser()) {
1306 options::fmfBound
.set( true );
1307 Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl
;
1309 if(! options::fmfInstEngine
.wasSetByUser()) {
1310 options::fmfInstEngine
.set( true );
1311 Trace("smt") << "turning on fmf-inst-engine, for strings-exp" << std::endl
;
1314 if(! options::rewriteDivk.wasSetByUser()) {
1315 options::rewriteDivk.set( true );
1316 Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
1319 if(! options::stringFMF.wasSetByUser()) {
1320 options::stringFMF.set( true );
1321 Trace("smt") << "turning on strings-fmf, for strings-exp" << std::endl;
1326 // sygus inference may require datatypes
1327 if (options::sygusInference())
1329 d_logic
= d_logic
.getUnlockedCopy();
1330 d_logic
.enableTheory(THEORY_DATATYPES
);
1332 // since we are trying to recast as sygus, we assume the input is sygus
1336 if ((options::checkModels() || options::checkSynthSol())
1337 && !options::produceAssertions())
1339 Notice() << "SmtEngine: turning on produce-assertions to support "
1340 << "check-models or check-synth-sol." << endl
;
1341 setOption("produce-assertions", SExpr("true"));
1344 // Disable options incompatible with incremental solving, unsat cores, and
1345 // proofs or output an error if enabled explicitly
1346 if (options::incrementalSolving() || options::unsatCores()
1347 || options::proof())
1349 if (options::unconstrainedSimp())
1351 if (options::unconstrainedSimp
.wasSetByUser())
1353 throw OptionException(
1354 "unconstrained simplification not supported with unsat "
1355 "cores/proofs/incremental solving");
1357 Notice() << "SmtEngine: turning off unconstrained simplification to "
1358 "support unsat cores/proofs/incremental solving"
1360 options::unconstrainedSimp
.set(false);
1365 // Turn on unconstrained simplification for QF_AUFBV
1366 if (!options::unconstrainedSimp
.wasSetByUser())
1368 // bool qf_sat = d_logic.isPure(THEORY_BOOL) &&
1369 // !d_logic.isQuantified(); bool uncSimp = false && !qf_sat &&
1370 // !options::incrementalSolving();
1371 bool uncSimp
= !d_logic
.isQuantified() && !options::produceModels()
1372 && !options::produceAssignments()
1373 && !options::checkModels()
1374 && (d_logic
.isTheoryEnabled(THEORY_ARRAYS
)
1375 && d_logic
.isTheoryEnabled(THEORY_BV
));
1376 Trace("smt") << "setting unconstrained simplification to " << uncSimp
1378 options::unconstrainedSimp
.set(uncSimp
);
1382 // Disable options incompatible with unsat cores and proofs or output an
1383 // error if enabled explicitly
1384 if (options::unsatCores() || options::proof())
1386 if (options::simplificationMode() != SIMPLIFICATION_MODE_NONE
)
1388 if (options::simplificationMode
.wasSetByUser())
1390 throw OptionException(
1391 "simplification not supported with unsat cores/proofs");
1393 Notice() << "SmtEngine: turning off simplification to support unsat "
1396 options::simplificationMode
.set(SIMPLIFICATION_MODE_NONE
);
1399 if (options::pbRewrites())
1401 if (options::pbRewrites
.wasSetByUser())
1403 throw OptionException(
1404 "pseudoboolean rewrites not supported with unsat cores/proofs");
1406 Notice() << "SmtEngine: turning off pseudoboolean rewrites to support "
1407 "unsat cores/proofs"
1409 setOption("pb-rewrites", false);
1412 if (options::sortInference())
1414 if (options::sortInference
.wasSetByUser())
1416 throw OptionException(
1417 "sort inference not supported with unsat cores/proofs");
1419 Notice() << "SmtEngine: turning off sort inference to support unsat "
1422 options::sortInference
.set(false);
1425 if (options::preSkolemQuant())
1427 if (options::preSkolemQuant
.wasSetByUser())
1429 throw OptionException(
1430 "pre-skolemization not supported with unsat cores/proofs");
1432 Notice() << "SmtEngine: turning off pre-skolemization to support unsat "
1435 options::preSkolemQuant
.set(false);
1438 if (options::bitvectorToBool())
1440 if (options::bitvectorToBool
.wasSetByUser())
1442 throw OptionException(
1443 "bv-to-bool not supported with unsat cores/proofs");
1445 Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat "
1448 options::bitvectorToBool
.set(false);
1451 if (options::boolToBitvector())
1453 if (options::boolToBitvector
.wasSetByUser())
1455 throw OptionException(
1456 "bool-to-bv not supported with unsat cores/proofs");
1458 Notice() << "SmtEngine: turning off bool-to-bitvector to support unsat "
1461 options::boolToBitvector
.set(false);
1464 if (options::bvIntroducePow2())
1466 if (options::bvIntroducePow2
.wasSetByUser())
1468 throw OptionException(
1469 "bv-intro-pow2 not supported with unsat cores/proofs");
1471 Notice() << "SmtEngine: turning off bv-intro-pow2 to support "
1472 "unsat-cores/proofs"
1474 setOption("bv-intro-pow2", false);
1477 if (options::repeatSimp())
1479 if (options::repeatSimp
.wasSetByUser())
1481 throw OptionException(
1482 "repeat-simp not supported with unsat cores/proofs");
1484 Notice() << "SmtEngine: turning off repeat-simp to support unsat "
1487 setOption("repeat-simp", false);
1490 if (options::globalNegate())
1492 if (options::globalNegate
.wasSetByUser())
1494 throw OptionException(
1495 "global-negate not supported with unsat cores/proofs");
1497 Notice() << "SmtEngine: turning off global-negate to support unsat "
1500 setOption("global-negate", false);
1505 // by default, nonclausal simplification is off for QF_SAT
1506 if (!options::simplificationMode
.wasSetByUser())
1508 bool qf_sat
= d_logic
.isPure(THEORY_BOOL
) && !d_logic
.isQuantified();
1509 Trace("smt") << "setting simplification mode to <"
1510 << d_logic
.getLogicString() << "> " << (!qf_sat
) << endl
;
1511 // simplification=none works better for SMT LIB benchmarks with
1512 // quantifiers, not others options::simplificationMode.set(qf_sat ||
1513 // quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
1514 options::simplificationMode
.set(qf_sat
? SIMPLIFICATION_MODE_NONE
1515 : SIMPLIFICATION_MODE_BATCH
);
1519 if (options::cbqiBv() && d_logic
.isQuantified())
1521 if(options::boolToBitvector
.wasSetByUser()) {
1522 throw OptionException(
1523 "bool-to-bv not supported with CBQI BV for quantified logics");
1525 Notice() << "SmtEngine: turning off bool-to-bitvector to support CBQI BV"
1527 options::boolToBitvector
.set(false);
1530 // cases where we need produce models
1531 if (!options::produceModels()
1532 && (options::produceAssignments() || options::sygusRewSynthCheck()
1535 Notice() << "SmtEngine: turning on produce-models" << endl
;
1536 setOption("produce-models", SExpr("true"));
1539 // Set the options for the theoryOf
1540 if(!options::theoryOfMode
.wasSetByUser()) {
1541 if(d_logic
.isSharingEnabled() &&
1542 !d_logic
.isTheoryEnabled(THEORY_BV
) &&
1543 !d_logic
.isTheoryEnabled(THEORY_STRINGS
) &&
1544 !d_logic
.isTheoryEnabled(THEORY_SETS
) ) {
1545 Trace("smt") << "setting theoryof-mode to term-based" << endl
;
1546 options::theoryOfMode
.set(THEORY_OF_TERM_BASED
);
1550 // strings require LIA, UF; widen the logic
1551 if(d_logic
.isTheoryEnabled(THEORY_STRINGS
)) {
1552 LogicInfo
log(d_logic
.getUnlockedCopy());
1553 // Strings requires arith for length constraints, and also UF
1554 if(!d_logic
.isTheoryEnabled(THEORY_UF
)) {
1555 Trace("smt") << "because strings are enabled, also enabling UF" << endl
;
1556 log
.enableTheory(THEORY_UF
);
1558 if(!d_logic
.isTheoryEnabled(THEORY_ARITH
) || d_logic
.isDifferenceLogic() || !d_logic
.areIntegersUsed()) {
1559 Trace("smt") << "because strings are enabled, also enabling linear integer arithmetic" << endl
;
1560 log
.enableTheory(THEORY_ARITH
);
1561 log
.enableIntegers();
1562 log
.arithOnlyLinear();
1567 if(d_logic
.isTheoryEnabled(THEORY_ARRAYS
) || d_logic
.isTheoryEnabled(THEORY_DATATYPES
) || d_logic
.isTheoryEnabled(THEORY_SETS
)) {
1568 if(!d_logic
.isTheoryEnabled(THEORY_UF
)) {
1569 LogicInfo
log(d_logic
.getUnlockedCopy());
1570 Trace("smt") << "because a theory that permits Boolean terms is enabled, also enabling UF" << endl
;
1571 log
.enableTheory(THEORY_UF
);
1577 // by default, symmetry breaker is on only for non-incremental QF_UF
1578 if(! options::ufSymmetryBreaker
.wasSetByUser()) {
1579 bool qf_uf_noinc
= d_logic
.isPure(THEORY_UF
) && !d_logic
.isQuantified()
1580 && !options::incrementalSolving() && !options::proof()
1581 && !options::unsatCores();
1582 Trace("smt") << "setting uf symmetry breaker to " << qf_uf_noinc
<< endl
;
1583 options::ufSymmetryBreaker
.set(qf_uf_noinc
);
1586 // If in arrays, set the UF handler to arrays
1587 if(d_logic
.isTheoryEnabled(THEORY_ARRAYS
) && ( !d_logic
.isQuantified() ||
1588 (d_logic
.isQuantified() && !d_logic
.isTheoryEnabled(THEORY_UF
)))) {
1589 Theory::setUninterpretedSortOwner(THEORY_ARRAYS
);
1591 Theory::setUninterpretedSortOwner(THEORY_UF
);
1594 // Turn on ite simplification for QF_LIA and QF_AUFBV
1595 // WARNING: These checks match much more than just QF_AUFBV and
1596 // QF_LIA logics. --K [2014/10/15]
1597 if(! options::doITESimp
.wasSetByUser()) {
1598 bool qf_aufbv
= !d_logic
.isQuantified() &&
1599 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1600 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1601 d_logic
.isTheoryEnabled(THEORY_BV
);
1602 bool qf_lia
= !d_logic
.isQuantified() &&
1603 d_logic
.isPure(THEORY_ARITH
) &&
1604 d_logic
.isLinear() &&
1605 !d_logic
.isDifferenceLogic() &&
1606 !d_logic
.areRealsUsed();
1608 bool iteSimp
= (qf_aufbv
|| qf_lia
);
1609 Trace("smt") << "setting ite simplification to " << iteSimp
<< endl
;
1610 options::doITESimp
.set(iteSimp
);
1612 if(! options::compressItes
.wasSetByUser() ){
1613 bool qf_lia
= !d_logic
.isQuantified() &&
1614 d_logic
.isPure(THEORY_ARITH
) &&
1615 d_logic
.isLinear() &&
1616 !d_logic
.isDifferenceLogic() &&
1617 !d_logic
.areRealsUsed();
1619 bool compressIte
= qf_lia
;
1620 Trace("smt") << "setting ite compression to " << compressIte
<< endl
;
1621 options::compressItes
.set(compressIte
);
1623 if(! options::simplifyWithCareEnabled
.wasSetByUser() ){
1624 bool qf_aufbv
= !d_logic
.isQuantified() &&
1625 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1626 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1627 d_logic
.isTheoryEnabled(THEORY_BV
);
1629 bool withCare
= qf_aufbv
;
1630 Trace("smt") << "setting ite simplify with care to " << withCare
<< endl
;
1631 options::simplifyWithCareEnabled
.set(withCare
);
1633 // Turn off array eager index splitting for QF_AUFLIA
1634 if(! options::arraysEagerIndexSplitting
.wasSetByUser()) {
1635 if (not d_logic
.isQuantified() &&
1636 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1637 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1638 d_logic
.isTheoryEnabled(THEORY_ARITH
)) {
1639 Trace("smt") << "setting array eager index splitting to false" << endl
;
1640 options::arraysEagerIndexSplitting
.set(false);
1643 // Turn on model-based arrays for QF_AX (unless models are enabled)
1644 // if(! options::arraysModelBased.wasSetByUser()) {
1645 // if (not d_logic.isQuantified() &&
1646 // d_logic.isTheoryEnabled(THEORY_ARRAYS) &&
1647 // d_logic.isPure(THEORY_ARRAYS) &&
1648 // !options::produceModels() &&
1649 // !options::checkModels()) {
1650 // Trace("smt") << "turning on model-based array solver" << endl;
1651 // options::arraysModelBased.set(true);
1654 // Turn on multiple-pass non-clausal simplification for QF_AUFBV
1655 if(! options::repeatSimp
.wasSetByUser()) {
1656 bool repeatSimp
= !d_logic
.isQuantified() &&
1657 (d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1658 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1659 d_logic
.isTheoryEnabled(THEORY_BV
)) &&
1660 !options::unsatCores();
1661 Trace("smt") << "setting repeat simplification to " << repeatSimp
<< endl
;
1662 options::repeatSimp
.set(repeatSimp
);
1664 // Unconstrained simp currently does *not* support model generation
1665 if (options::unconstrainedSimp
.wasSetByUser() && options::unconstrainedSimp()) {
1666 if (options::produceModels()) {
1667 if (options::produceModels
.wasSetByUser()) {
1668 throw OptionException("Cannot use unconstrained-simp with model generation.");
1670 Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl
;
1671 setOption("produce-models", SExpr("false"));
1673 if (options::produceAssignments()) {
1674 if (options::produceAssignments
.wasSetByUser()) {
1675 throw OptionException("Cannot use unconstrained-simp with model generation (produce-assignments).");
1677 Notice() << "SmtEngine: turning off produce-assignments to support unconstrainedSimp" << endl
;
1678 setOption("produce-assignments", SExpr("false"));
1680 if (options::checkModels()) {
1681 if (options::checkModels
.wasSetByUser()) {
1682 throw OptionException("Cannot use unconstrained-simp with model generation (check-models).");
1684 Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl
;
1685 setOption("check-models", SExpr("false"));
1689 if (! options::bvEagerExplanations
.wasSetByUser() &&
1690 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1691 d_logic
.isTheoryEnabled(THEORY_BV
)) {
1692 Trace("smt") << "enabling eager bit-vector explanations " << endl
;
1693 options::bvEagerExplanations
.set(true);
1696 // Turn on arith rewrite equalities only for pure arithmetic
1697 if(! options::arithRewriteEq
.wasSetByUser()) {
1698 bool arithRewriteEq
= d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isQuantified();
1699 Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq
<< endl
;
1700 options::arithRewriteEq
.set(arithRewriteEq
);
1702 if(! options::arithHeuristicPivots
.wasSetByUser()) {
1703 int16_t heuristicPivots
= 5;
1704 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()) {
1705 if(d_logic
.isDifferenceLogic()) {
1706 heuristicPivots
= -1;
1707 } else if(!d_logic
.areIntegersUsed()) {
1708 heuristicPivots
= 0;
1711 Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots
<< endl
;
1712 options::arithHeuristicPivots
.set(heuristicPivots
);
1714 if(! options::arithPivotThreshold
.wasSetByUser()){
1715 uint16_t pivotThreshold
= 2;
1716 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()){
1717 if(d_logic
.isDifferenceLogic()){
1718 pivotThreshold
= 16;
1721 Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold
<< endl
;
1722 options::arithPivotThreshold
.set(pivotThreshold
);
1724 if(! options::arithStandardCheckVarOrderPivots
.wasSetByUser()){
1725 int16_t varOrderPivots
= -1;
1726 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()){
1727 varOrderPivots
= 200;
1729 Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots
<< endl
;
1730 options::arithStandardCheckVarOrderPivots
.set(varOrderPivots
);
1732 // Turn off early theory preprocessing if arithRewriteEq is on
1733 if (options::arithRewriteEq()) {
1734 d_earlyTheoryPP
= false;
1736 if (d_logic
.isPure(THEORY_ARITH
) && !d_logic
.areRealsUsed())
1738 if (!options::nlExtTangentPlanesInterleave
.wasSetByUser())
1740 Trace("smt") << "setting nlExtTangentPlanesInterleave to true" << endl
;
1741 options::nlExtTangentPlanesInterleave
.set(true);
1745 // Set decision mode based on logic (if not set by user)
1746 if(!options::decisionMode
.wasSetByUser()) {
1747 decision::DecisionMode decMode
=
1749 d_logic
.hasEverything() ? decision::DECISION_STRATEGY_JUSTIFICATION
:
1751 (not d_logic
.isQuantified() &&
1752 d_logic
.isPure(THEORY_BV
)
1754 // QF_AUFBV or QF_ABV or QF_UFBV
1755 (not d_logic
.isQuantified() &&
1756 (d_logic
.isTheoryEnabled(THEORY_ARRAYS
) ||
1757 d_logic
.isTheoryEnabled(THEORY_UF
)) &&
1758 d_logic
.isTheoryEnabled(THEORY_BV
)
1760 // QF_AUFLIA (and may be ends up enabling QF_AUFLRA?)
1761 (not d_logic
.isQuantified() &&
1762 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1763 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1764 d_logic
.isTheoryEnabled(THEORY_ARITH
)
1767 (not d_logic
.isQuantified() &&
1768 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
1771 d_logic
.isQuantified() ||
1773 d_logic
.isTheoryEnabled(THEORY_STRINGS
)
1774 ? decision::DECISION_STRATEGY_JUSTIFICATION
1775 : decision::DECISION_STRATEGY_INTERNAL
1780 d_logic
.hasEverything() || d_logic
.isTheoryEnabled(THEORY_STRINGS
) ? false :
1782 (not d_logic
.isQuantified() &&
1783 d_logic
.isTheoryEnabled(THEORY_ARRAYS
) &&
1784 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1785 d_logic
.isTheoryEnabled(THEORY_ARITH
)
1788 (not d_logic
.isQuantified() &&
1789 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
1794 Trace("smt") << "setting decision mode to " << decMode
<< endl
;
1795 options::decisionMode
.set(decMode
);
1796 options::decisionStopOnly
.set(stoponly
);
1798 if( options::incrementalSolving() ){
1799 //disable modes not supported by incremental
1800 options::sortInference
.set( false );
1801 options::ufssFairnessMonotone
.set( false );
1802 options::quantEpr
.set( false );
1803 options::globalNegate
.set(false);
1805 if( d_logic
.hasCardinalityConstraints() ){
1806 //must have finite model finding on
1807 options::finiteModelFind
.set( true );
1810 //if it contains a theory with non-termination, do not strictly enforce that quantifiers and theory combination must be interleaved
1811 if( d_logic
.isTheoryEnabled(THEORY_STRINGS
) || (d_logic
.isTheoryEnabled(THEORY_ARITH
) && !d_logic
.isLinear()) ){
1812 if( !options::instWhenStrictInterleave
.wasSetByUser() ){
1813 options::instWhenStrictInterleave
.set( false );
1817 //local theory extensions
1818 if( options::localTheoryExt() ){
1819 if( !options::instMaxLevel
.wasSetByUser() ){
1820 options::instMaxLevel
.set( 0 );
1823 if( options::instMaxLevel()!=-1 ){
1824 Notice() << "SmtEngine: turning off cbqi to support instMaxLevel" << endl
;
1825 options::cbqi
.set(false);
1827 //track instantiations?
1828 if( options::cbqiNestedQE() || ( options::proof() && !options::trackInstLemmas
.wasSetByUser() ) ){
1829 options::trackInstLemmas
.set( true );
1832 if( ( options::fmfBoundLazy
.wasSetByUser() && options::fmfBoundLazy() ) ||
1833 ( options::fmfBoundInt
.wasSetByUser() && options::fmfBoundInt() ) ) {
1834 options::fmfBound
.set( true );
1836 //now have determined whether fmfBoundInt is on/off
1837 //apply fmfBoundInt options
1838 if( options::fmfBound() ){
1839 //must have finite model finding on
1840 options::finiteModelFind
.set( true );
1841 if (!options::mbqiMode
.wasSetByUser()
1842 || (options::mbqiMode() != quantifiers::MBQI_NONE
1843 && options::mbqiMode() != quantifiers::MBQI_FMC
))
1845 //if bounded integers are set, use no MBQI by default
1846 options::mbqiMode
.set( quantifiers::MBQI_NONE
);
1848 if( ! options::prenexQuant
.wasSetByUser() ){
1849 options::prenexQuant
.set( quantifiers::PRENEX_QUANT_NONE
);
1852 if( options::ufHo() ){
1853 //if higher-order, then current variants of model-based instantiation cannot be used
1854 if( options::mbqiMode()!=quantifiers::MBQI_NONE
){
1855 options::mbqiMode
.set( quantifiers::MBQI_NONE
);
1858 if( options::mbqiMode()==quantifiers::MBQI_ABS
){
1859 if( !d_logic
.isPure(THEORY_UF
) ){
1860 //MBQI_ABS is only supported in pure quantified UF
1861 options::mbqiMode
.set( quantifiers::MBQI_FMC
);
1864 if( options::fmfFunWellDefinedRelevant() ){
1865 if( !options::fmfFunWellDefined
.wasSetByUser() ){
1866 options::fmfFunWellDefined
.set( true );
1869 if( options::fmfFunWellDefined() ){
1870 if( !options::finiteModelFind
.wasSetByUser() ){
1871 options::finiteModelFind
.set( true );
1875 if( options::quantEpr() ){
1876 if( !options::preSkolemQuant
.wasSetByUser() ){
1877 options::preSkolemQuant
.set( true );
1881 //now, have determined whether finite model find is on/off
1882 //apply finite model finding options
1883 if( options::finiteModelFind() ){
1884 //apply conservative quantifiers splitting
1885 if( !options::quantDynamicSplit
.wasSetByUser() ){
1886 options::quantDynamicSplit
.set( quantifiers::QUANT_DSPLIT_MODE_DEFAULT
);
1888 //do not eliminate extended arithmetic symbols from quantified formulas
1889 if( !options::elimExtArithQuant
.wasSetByUser() ){
1890 options::elimExtArithQuant
.set( false );
1892 if( !options::eMatching
.wasSetByUser() ){
1893 options::eMatching
.set( options::fmfInstEngine() );
1895 if( !options::instWhenMode
.wasSetByUser() ){
1896 //instantiate only on last call
1897 if( options::eMatching() ){
1898 options::instWhenMode
.set( quantifiers::INST_WHEN_LAST_CALL
);
1901 if( options::mbqiMode()==quantifiers::MBQI_ABS
){
1902 if( !options::preSkolemQuant
.wasSetByUser() ){
1903 options::preSkolemQuant
.set( true );
1905 if( !options::preSkolemQuantNested
.wasSetByUser() ){
1906 options::preSkolemQuantNested
.set( true );
1908 if( !options::fmfOneInstPerRound
.wasSetByUser() ){
1909 options::fmfOneInstPerRound
.set( true );
1914 //apply counterexample guided instantiation options
1915 // if we are attempting to rewrite everything to SyGuS, use ceGuidedInst
1916 if (options::sygusInference())
1918 if (!options::ceGuidedInst
.wasSetByUser())
1920 options::ceGuidedInst
.set(true);
1922 // optimization: apply preskolemization, makes it succeed more often
1923 if (!options::preSkolemQuant
.wasSetByUser())
1925 options::preSkolemQuant
.set(true);
1927 if (!options::preSkolemQuantNested
.wasSetByUser())
1929 options::preSkolemQuantNested
.set(true);
1932 if( options::cegqiSingleInvMode()!=quantifiers::CEGQI_SI_MODE_NONE
){
1933 if( !options::ceGuidedInst
.wasSetByUser() ){
1934 options::ceGuidedInst
.set( true );
1937 if( options::ceGuidedInst() ){
1938 //counterexample-guided instantiation for sygus
1939 if( !options::cegqiSingleInvMode
.wasSetByUser() ){
1940 options::cegqiSingleInvMode
.set( quantifiers::CEGQI_SI_MODE_USE
);
1942 if( !options::quantConflictFind
.wasSetByUser() ){
1943 options::quantConflictFind
.set( false );
1945 if( !options::instNoEntail
.wasSetByUser() ){
1946 options::instNoEntail
.set( false );
1948 if (options::sygusRew())
1950 options::sygusRewSynth
.set(true);
1951 options::sygusRewVerify
.set(true);
1953 if (options::sygusRewSynth() || options::sygusRewVerify())
1955 // rewrite rule synthesis implies that sygus stream must be true
1956 options::sygusStream
.set(true);
1958 if (options::sygusStream())
1960 // PBE and streaming modes are incompatible
1961 if (!options::sygusSymBreakPbe
.wasSetByUser())
1963 options::sygusSymBreakPbe
.set(false);
1965 if (!options::sygusUnifPbe
.wasSetByUser())
1967 options::sygusUnifPbe
.set(false);
1970 //do not allow partial functions
1971 if( !options::bitvectorDivByZeroConst
.wasSetByUser() ){
1972 options::bitvectorDivByZeroConst
.set( true );
1974 if( !options::dtRewriteErrorSel
.wasSetByUser() ){
1975 options::dtRewriteErrorSel
.set( true );
1978 if( !options::miniscopeQuant
.wasSetByUser() ){
1979 options::miniscopeQuant
.set( false );
1981 if( !options::miniscopeQuantFreeVar
.wasSetByUser() ){
1982 options::miniscopeQuantFreeVar
.set( false );
1984 if (!options::quantSplit
.wasSetByUser())
1986 options::quantSplit
.set(false);
1989 if( !options::rewriteDivk
.wasSetByUser()) {
1990 options::rewriteDivk
.set( true );
1993 if( !options::macrosQuant
.wasSetByUser()) {
1994 options::macrosQuant
.set( false );
1996 if( !options::cbqiPreRegInst
.wasSetByUser()) {
1997 options::cbqiPreRegInst
.set( true );
2000 //counterexample-guided instantiation for non-sygus
2001 // enable if any possible quantifiers with arithmetic, datatypes or bitvectors
2002 if (d_logic
.isQuantified()
2003 && ((options::decisionMode() != decision::DECISION_STRATEGY_INTERNAL
2004 && (d_logic
.isTheoryEnabled(THEORY_ARITH
)
2005 || d_logic
.isTheoryEnabled(THEORY_DATATYPES
)
2006 || d_logic
.isTheoryEnabled(THEORY_BV
)
2007 || d_logic
.isTheoryEnabled(THEORY_FP
)))
2008 || d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
)
2009 || options::cbqiAll()))
2011 if( !options::cbqi
.wasSetByUser() ){
2012 options::cbqi
.set( true );
2014 // check whether we should apply full cbqi
2015 if (d_logic
.isPure(THEORY_BV
))
2017 if (!options::cbqiFullEffort
.wasSetByUser())
2019 options::cbqiFullEffort
.set(true);
2023 if( options::cbqi() ){
2025 if( !options::rewriteDivk
.wasSetByUser()) {
2026 options::rewriteDivk
.set( true );
2028 if (options::incrementalSolving())
2030 // cannot do nested quantifier elimination in incremental mode
2031 options::cbqiNestedQE
.set(false);
2033 if (d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
))
2035 options::cbqiAll
.set( false );
2036 if( !options::quantConflictFind
.wasSetByUser() ){
2037 options::quantConflictFind
.set( false );
2039 if( !options::instNoEntail
.wasSetByUser() ){
2040 options::instNoEntail
.set( false );
2042 if( !options::instWhenMode
.wasSetByUser() && options::cbqiModel() ){
2043 //only instantiation should happen at last call when model is avaiable
2044 options::instWhenMode
.set( quantifiers::INST_WHEN_LAST_CALL
);
2047 // only supported in pure arithmetic or pure BV
2048 options::cbqiNestedQE
.set(false);
2051 if (options::cbqiNestedQE()
2052 || options::decisionMode() == decision::DECISION_STRATEGY_INTERNAL
)
2054 // only complete with prenex = disj_normal or normal
2055 if (options::prenexQuant() <= quantifiers::PRENEX_QUANT_DISJ_NORMAL
)
2057 options::prenexQuant
.set(quantifiers::PRENEX_QUANT_DISJ_NORMAL
);
2060 else if (options::globalNegate())
2062 if (!options::prenexQuant
.wasSetByUser())
2064 options::prenexQuant
.set(quantifiers::PRENEX_QUANT_NONE
);
2068 //implied options...
2069 if( options::strictTriggers() ){
2070 if( !options::userPatternsQuant
.wasSetByUser() ){
2071 options::userPatternsQuant
.set( quantifiers::USER_PAT_MODE_TRUST
);
2074 if( options::qcfMode
.wasSetByUser() || options::qcfTConstraint() ){
2075 options::quantConflictFind
.set( true );
2077 if( options::cbqiNestedQE() ){
2078 options::prenexQuantUser
.set( true );
2079 if( !options::preSkolemQuant
.wasSetByUser() ){
2080 options::preSkolemQuant
.set( true );
2083 //for induction techniques
2084 if( options::quantInduction() ){
2085 if( !options::dtStcInduction
.wasSetByUser() ){
2086 options::dtStcInduction
.set( true );
2088 if( !options::intWfInduction
.wasSetByUser() ){
2089 options::intWfInduction
.set( true );
2092 if( options::dtStcInduction() ){
2093 //try to remove ITEs from quantified formulas
2094 if( !options::iteDtTesterSplitQuant
.wasSetByUser() ){
2095 options::iteDtTesterSplitQuant
.set( true );
2097 if( !options::iteLiftQuant
.wasSetByUser() ){
2098 options::iteLiftQuant
.set( quantifiers::ITE_LIFT_QUANT_MODE_ALL
);
2101 if( options::intWfInduction() ){
2102 if( !options::purifyTriggers
.wasSetByUser() ){
2103 options::purifyTriggers
.set( true );
2106 if( options::conjectureNoFilter() ){
2107 if( !options::conjectureFilterActiveTerms
.wasSetByUser() ){
2108 options::conjectureFilterActiveTerms
.set( false );
2110 if( !options::conjectureFilterCanonical
.wasSetByUser() ){
2111 options::conjectureFilterCanonical
.set( false );
2113 if( !options::conjectureFilterModel
.wasSetByUser() ){
2114 options::conjectureFilterModel
.set( false );
2117 if( options::conjectureGenPerRound
.wasSetByUser() ){
2118 if( options::conjectureGenPerRound()>0 ){
2119 options::conjectureGen
.set( true );
2121 options::conjectureGen
.set( false );
2124 //can't pre-skolemize nested quantifiers without UF theory
2125 if( !d_logic
.isTheoryEnabled(THEORY_UF
) && options::preSkolemQuant() ){
2126 if( !options::preSkolemQuantNested
.wasSetByUser() ){
2127 options::preSkolemQuantNested
.set( false );
2130 if( !d_logic
.isTheoryEnabled(THEORY_DATATYPES
) ){
2131 options::quantDynamicSplit
.set( quantifiers::QUANT_DSPLIT_MODE_NONE
);
2134 //until bugs 371,431 are fixed
2135 if( ! options::minisatUseElim
.wasSetByUser()){
2136 // cannot use minisat elimination for logics where a theory solver
2137 // introduces new literals into the search. This includes quantifiers
2138 // (quantifier instantiation), and the lemma schemas used in non-linear
2139 // and sets. We also can't use it if models are enabled.
2140 if (d_logic
.isTheoryEnabled(THEORY_SETS
) || d_logic
.isQuantified()
2141 || options::produceModels() || options::produceAssignments()
2142 || options::checkModels()
2143 || (d_logic
.isTheoryEnabled(THEORY_ARITH
) && !d_logic
.isLinear()))
2145 options::minisatUseElim
.set( false );
2148 else if (options::minisatUseElim()) {
2149 if (options::produceModels()) {
2150 Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl
;
2151 setOption("produce-models", SExpr("false"));
2153 if (options::produceAssignments()) {
2154 Notice() << "SmtEngine: turning off produce-assignments to support minisatUseElim" << endl
;
2155 setOption("produce-assignments", SExpr("false"));
2157 if (options::checkModels()) {
2158 Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl
;
2159 setOption("check-models", SExpr("false"));
2163 // For now, these array theory optimizations do not support model-building
2164 if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
2165 options::arraysOptimizeLinear
.set(false);
2166 options::arraysLazyRIntro1
.set(false);
2169 // Non-linear arithmetic does not support models unless nlExt is enabled
2170 if ((d_logic
.isTheoryEnabled(THEORY_ARITH
) && !d_logic
.isLinear()
2171 && !options::nlExt())
2172 || options::globalNegate())
2174 std::string reason
=
2175 options::globalNegate() ? "--global-negate" : "nonlinear arithmetic";
2176 if (options::produceModels()) {
2177 if(options::produceModels
.wasSetByUser()) {
2178 throw OptionException(
2179 std::string("produce-model not supported with " + reason
));
2182 << "SmtEngine: turning off produce-models because unsupported for "
2184 setOption("produce-models", SExpr("false"));
2186 if (options::produceAssignments()) {
2187 if(options::produceAssignments
.wasSetByUser()) {
2188 throw OptionException(
2189 std::string("produce-assignments not supported with " + reason
));
2191 Warning() << "SmtEngine: turning off produce-assignments because "
2194 setOption("produce-assignments", SExpr("false"));
2196 if (options::checkModels()) {
2197 if(options::checkModels
.wasSetByUser()) {
2198 throw OptionException(
2199 std::string("check-models not supported with " + reason
));
2202 << "SmtEngine: turning off check-models because unsupported for "
2204 setOption("check-models", SExpr("false"));
2208 if(options::incrementalSolving() && options::proof()) {
2209 Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof, try --tear-down-incremental instead)" << endl
;
2210 setOption("incremental", SExpr("false"));
2213 if (options::proof())
2215 if (options::bitvectorAlgebraicSolver())
2217 if (options::bitvectorAlgebraicSolver
.wasSetByUser())
2219 throw OptionException(
2220 "--bv-algebraic-solver is not supported with proofs");
2222 Notice() << "SmtEngine: turning off bv algebraic solver to support proofs"
2224 options::bitvectorAlgebraicSolver
.set(false);
2226 if (options::bitvectorEqualitySolver())
2228 if (options::bitvectorEqualitySolver
.wasSetByUser())
2230 throw OptionException("--bv-eq-solver is not supported with proofs");
2232 Notice() << "SmtEngine: turning off bv eq solver to support proofs"
2234 options::bitvectorEqualitySolver
.set(false);
2236 if (options::bitvectorInequalitySolver())
2238 if (options::bitvectorInequalitySolver
.wasSetByUser())
2240 throw OptionException(
2241 "--bv-inequality-solver is not supported with proofs");
2243 Notice() << "SmtEngine: turning off bv ineq solver to support proofs"
2245 options::bitvectorInequalitySolver
.set(false);
2249 if (!options::bitvectorEqualitySolver())
2251 if (options::bvLazyRewriteExtf())
2253 if (options::bvLazyRewriteExtf
.wasSetByUser())
2255 throw OptionException(
2256 "--bv-lazy-rewrite-extf requires --bv-eq-solver to be set");
2260 << "disabling bvLazyRewriteExtf since equality solver is disabled"
2262 options::bvLazyRewriteExtf
.set(false);
2266 void SmtEngine::setProblemExtended(bool value
)
2268 d_problemExtended
= value
;
2269 if (value
) { d_assumptions
.clear(); }
2272 void SmtEngine::setInfo(const std::string
& key
, const CVC4::SExpr
& value
)
2274 SmtScope
smts(this);
2276 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
2278 if(Dump
.isOn("benchmark")) {
2279 if(key
== "status") {
2280 string s
= value
.getValue();
2281 BenchmarkStatus status
=
2282 (s
== "sat") ? SMT_SATISFIABLE
:
2283 ((s
== "unsat") ? SMT_UNSATISFIABLE
: SMT_UNKNOWN
);
2284 Dump("benchmark") << SetBenchmarkStatusCommand(status
);
2286 Dump("benchmark") << SetInfoCommand(key
, value
);
2290 // Check for CVC4-specific info keys (prefixed with "cvc4-" or "cvc4_")
2291 if(key
.length() > 5) {
2292 string prefix
= key
.substr(0, 5);
2293 if(prefix
== "cvc4-" || prefix
== "cvc4_") {
2294 string cvc4key
= key
.substr(5);
2295 if(cvc4key
== "logic") {
2296 if(! value
.isAtom()) {
2297 throw OptionException("argument to (set-info :cvc4-logic ..) must be a string");
2299 SmtScope
smts(this);
2300 d_logic
= value
.getValue();
2304 throw UnrecognizedOptionException();
2309 // Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
2311 || key
== "category"
2312 || key
== "difficulty"
2314 || key
== "license")
2318 } else if(key
== "name") {
2319 d_filename
= value
.getValue();
2322 else if (key
== "smt-lib-version" && !options::inputLanguage
.wasSetByUser())
2324 language::input::Language ilang
= language::input::LANG_AUTO
;
2325 if( (value
.isInteger() && value
.getIntegerValue() == Integer(2)) ||
2326 (value
.isRational() && value
.getRationalValue() == Rational(2)) ||
2327 value
.getValue() == "2" ||
2328 value
.getValue() == "2.0" ) {
2329 ilang
= language::input::LANG_SMTLIB_V2_0
;
2330 } else if( (value
.isRational() && value
.getRationalValue() == Rational(5, 2)) ||
2331 value
.getValue() == "2.5" ) {
2332 ilang
= language::input::LANG_SMTLIB_V2_5
;
2333 } else if( (value
.isRational() && value
.getRationalValue() == Rational(13, 5)) ||
2334 value
.getValue() == "2.6" ) {
2335 ilang
= language::input::LANG_SMTLIB_V2_6
;
2337 else if (value
.getValue() == "2.6.1")
2339 ilang
= language::input::LANG_SMTLIB_V2_6_1
;
2343 Warning() << "Warning: unsupported smt-lib-version: " << value
<< endl
;
2344 throw UnrecognizedOptionException();
2346 options::inputLanguage
.set(ilang
);
2347 // also update the output language
2348 if (!options::outputLanguage
.wasSetByUser())
2350 language::output::Language olang
= language::toOutputLanguage(ilang
);
2351 if (options::outputLanguage() != olang
)
2353 options::outputLanguage
.set(olang
);
2354 *options::out() << language::SetLanguage(olang
);
2358 } else if(key
== "status") {
2360 if(value
.isAtom()) {
2361 s
= value
.getValue();
2363 if(s
!= "sat" && s
!= "unsat" && s
!= "unknown") {
2364 throw OptionException("argument to (set-info :status ..) must be "
2365 "`sat' or `unsat' or `unknown'");
2367 d_status
= Result(s
, d_filename
);
2370 throw UnrecognizedOptionException();
2373 CVC4::SExpr
SmtEngine::getInfo(const std::string
& key
) const {
2375 SmtScope
smts(this);
2377 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
2378 if(key
== "all-statistics") {
2379 vector
<SExpr
> stats
;
2380 for(StatisticsRegistry::const_iterator i
= NodeManager::fromExprManager(d_exprManager
)->getStatisticsRegistry()->begin();
2381 i
!= NodeManager::fromExprManager(d_exprManager
)->getStatisticsRegistry()->end();
2384 v
.push_back((*i
).first
);
2385 v
.push_back((*i
).second
);
2388 for(StatisticsRegistry::const_iterator i
= d_statisticsRegistry
->begin();
2389 i
!= d_statisticsRegistry
->end();
2392 v
.push_back((*i
).first
);
2393 v
.push_back((*i
).second
);
2396 return SExpr(stats
);
2397 } else if(key
== "error-behavior") {
2398 // immediate-exit | continued-execution
2399 if( options::continuedExecution() || options::interactive() ) {
2400 return SExpr(SExpr::Keyword("continued-execution"));
2402 return SExpr(SExpr::Keyword("immediate-exit"));
2404 } else if(key
== "name") {
2405 return SExpr(Configuration::getName());
2406 } else if(key
== "version") {
2407 return SExpr(Configuration::getVersionString());
2408 } else if(key
== "authors") {
2409 return SExpr(Configuration::about());
2410 } else if(key
== "status") {
2411 // sat | unsat | unknown
2412 switch(d_status
.asSatisfiabilityResult().isSat()) {
2414 return SExpr(SExpr::Keyword("sat"));
2416 return SExpr(SExpr::Keyword("unsat"));
2418 return SExpr(SExpr::Keyword("unknown"));
2420 } else if(key
== "reason-unknown") {
2421 if(!d_status
.isNull() && d_status
.isUnknown()) {
2423 ss
<< d_status
.whyUnknown();
2424 string s
= ss
.str();
2425 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
2426 return SExpr(SExpr::Keyword(s
));
2428 throw ModalException("Can't get-info :reason-unknown when the "
2429 "last result wasn't unknown!");
2431 } else if(key
== "assertion-stack-levels") {
2432 AlwaysAssert(d_userLevels
.size() <=
2433 std::numeric_limits
<unsigned long int>::max());
2434 return SExpr(static_cast<unsigned long int>(d_userLevels
.size()));
2435 } else if(key
== "all-options") {
2436 // get the options, like all-statistics
2437 std::vector
< std::vector
<std::string
> > current_options
=
2438 Options::current()->getOptions();
2439 return SExpr::parseListOfListOfAtoms(current_options
);
2441 throw UnrecognizedOptionException();
2445 void SmtEngine::debugCheckFormals(const std::vector
<Expr
>& formals
, Expr func
)
2447 for(std::vector
<Expr
>::const_iterator i
= formals
.begin(); i
!= formals
.end(); ++i
) {
2448 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
2450 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
2451 << "definition of function " << func
<< ", formal\n"
2452 << " " << *i
<< "\n"
2453 << "has kind " << (*i
).getKind();
2454 throw TypeCheckingException(func
, ss
.str());
2459 void SmtEngine::debugCheckFunctionBody(Expr formula
,
2460 const std::vector
<Expr
>& formals
,
2463 Type formulaType
= formula
.getType(options::typeChecking());
2464 Type funcType
= func
.getType();
2465 // We distinguish here between definitions of constants and functions,
2466 // because the type checking for them is subtly different. Perhaps we
2467 // should instead have SmtEngine::defineFunction() and
2468 // SmtEngine::defineConstant() for better clarity, although then that
2469 // doesn't match the SMT-LIBv2 standard...
2470 if(formals
.size() > 0) {
2471 Type rangeType
= FunctionType(funcType
).getRangeType();
2472 if(! formulaType
.isComparableTo(rangeType
)) {
2474 ss
<< "Type of defined function does not match its declaration\n"
2475 << "The function : " << func
<< "\n"
2476 << "Declared type : " << rangeType
<< "\n"
2477 << "The body : " << formula
<< "\n"
2478 << "Body type : " << formulaType
;
2479 throw TypeCheckingException(func
, ss
.str());
2482 if(! formulaType
.isComparableTo(funcType
)) {
2484 ss
<< "Declared type of defined constant does not match its definition\n"
2485 << "The constant : " << func
<< "\n"
2486 << "Declared type : " << funcType
<< " " << Type::getTypeNode(funcType
)->getId() << "\n"
2487 << "The definition : " << formula
<< "\n"
2488 << "Definition type: " << formulaType
<< " " << Type::getTypeNode(formulaType
)->getId();
2489 throw TypeCheckingException(func
, ss
.str());
2494 void SmtEngine::defineFunction(Expr func
,
2495 const std::vector
<Expr
>& formals
,
2498 SmtScope
smts(this);
2500 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
2501 debugCheckFormals(formals
, func
);
2504 ss
<< language::SetLanguage(
2505 language::SetLanguage::getLanguage(Dump
.getStream()))
2507 DefineFunctionCommand
c(ss
.str(), func
, formals
, formula
);
2508 addToModelCommandAndDump(
2509 c
, ExprManager::VAR_FLAG_DEFINED
, true, "declarations");
2511 PROOF(if (options::checkUnsatCores()) {
2512 d_defineCommands
.push_back(c
.clone());
2516 debugCheckFunctionBody(formula
, formals
, func
);
2518 // Substitute out any abstract values in formula
2520 d_private
->substituteAbstractValues(Node::fromExpr(formula
)).toExpr();
2522 TNode funcNode
= func
.getTNode();
2523 vector
<Node
> formalsNodes
;
2524 for(vector
<Expr
>::const_iterator i
= formals
.begin(),
2525 iend
= formals
.end();
2528 formalsNodes
.push_back((*i
).getNode());
2530 TNode formNode
= form
.getTNode();
2531 DefinedFunction
def(funcNode
, formalsNodes
, formNode
);
2532 // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
2533 // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
2534 // d_haveAdditions = true;
2535 Debug("smt") << "definedFunctions insert " << funcNode
<< " " << formNode
<< endl
;
2536 d_definedFunctions
->insert(funcNode
, def
);
2539 void SmtEngine::defineFunctionsRec(
2540 const std::vector
<Expr
>& funcs
,
2541 const std::vector
<std::vector
<Expr
> >& formals
,
2542 const std::vector
<Expr
>& formulas
)
2544 SmtScope
smts(this);
2545 finalOptionsAreSet();
2547 Trace("smt") << "SMT defineFunctionsRec(...)" << endl
;
2549 if (funcs
.size() != formals
.size() && funcs
.size() != formulas
.size())
2552 ss
<< "Number of functions, formals, and function bodies passed to "
2553 "defineFunctionsRec do not match:"
2555 << " #functions : " << funcs
.size() << "\n"
2556 << " #arg lists : " << formals
.size() << "\n"
2557 << " #function bodies : " << formulas
.size() << "\n";
2558 throw ModalException(ss
.str());
2560 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
2562 // check formal argument list
2563 debugCheckFormals(formals
[i
], funcs
[i
]);
2565 debugCheckFunctionBody(formulas
[i
], formals
[i
], funcs
[i
]);
2568 if (Dump
.isOn("raw-benchmark"))
2570 Dump("raw-benchmark") << DefineFunctionRecCommand(funcs
, formals
, formulas
);
2573 ExprManager
* em
= getExprManager();
2574 for (unsigned i
= 0, size
= funcs
.size(); i
< size
; i
++)
2576 // we assert a quantified formula
2578 // make the function application
2579 if (formals
[i
].empty())
2581 // it has no arguments
2582 func_app
= funcs
[i
];
2586 std::vector
<Expr
> children
;
2587 children
.push_back(funcs
[i
]);
2588 children
.insert(children
.end(), formals
[i
].begin(), formals
[i
].end());
2589 func_app
= em
->mkExpr(kind::APPLY_UF
, children
);
2591 Expr lem
= em
->mkExpr(kind::EQUAL
, func_app
, formulas
[i
]);
2592 if (!formals
[i
].empty())
2594 // set the attribute to denote this is a function definition
2595 std::string
attr_name("fun-def");
2596 Expr aexpr
= em
->mkExpr(kind::INST_ATTRIBUTE
, func_app
);
2597 aexpr
= em
->mkExpr(kind::INST_PATTERN_LIST
, aexpr
);
2598 std::vector
<Expr
> expr_values
;
2599 std::string str_value
;
2600 setUserAttribute(attr_name
, func_app
, expr_values
, str_value
);
2601 // make the quantified formula
2602 Expr boundVars
= em
->mkExpr(kind::BOUND_VAR_LIST
, formals
[i
]);
2603 lem
= em
->mkExpr(kind::FORALL
, boundVars
, lem
, aexpr
);
2605 // assert the quantified formula
2606 // notice we don't call assertFormula directly, since this would
2607 // duplicate the output on raw-benchmark.
2608 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(lem
)).toExpr();
2609 if (d_assertionList
!= NULL
)
2611 d_assertionList
->push_back(e
);
2613 d_private
->addFormula(e
.getNode(), false);
2617 void SmtEngine::defineFunctionRec(Expr func
,
2618 const std::vector
<Expr
>& formals
,
2621 std::vector
<Expr
> funcs
;
2622 funcs
.push_back(func
);
2623 std::vector
<std::vector
<Expr
> > formals_multi
;
2624 formals_multi
.push_back(formals
);
2625 std::vector
<Expr
> formulas
;
2626 formulas
.push_back(formula
);
2627 defineFunctionsRec(funcs
, formals_multi
, formulas
);
2630 bool SmtEngine::isDefinedFunction( Expr func
){
2631 Node nf
= Node::fromExpr( func
);
2632 Debug("smt") << "isDefined function " << nf
<< "?" << std::endl
;
2633 return d_definedFunctions
->find(nf
) != d_definedFunctions
->end();
2636 void SmtEnginePrivate::finishInit()
2638 d_preprocessingPassContext
.reset(
2639 new PreprocessingPassContext(&d_smt
, d_resourceManager
, &d_iteRemover
));
2640 // TODO: register passes here (this will likely change when we add support for
2641 // actually assembling preprocessing pipelines).
2642 std::unique_ptr
<ApplySubsts
> applySubsts(
2643 new ApplySubsts(d_preprocessingPassContext
.get()));
2644 std::unique_ptr
<ApplyToConst
> applyToConst(
2645 new ApplyToConst(d_preprocessingPassContext
.get()));
2646 std::unique_ptr
<BoolToBV
> boolToBv(
2647 new BoolToBV(d_preprocessingPassContext
.get()));
2648 std::unique_ptr
<BvAbstraction
> bvAbstract(
2649 new BvAbstraction(d_preprocessingPassContext
.get()));
2650 std::unique_ptr
<BvEagerAtoms
> bvEagerAtoms(
2651 new BvEagerAtoms(d_preprocessingPassContext
.get()));
2652 std::unique_ptr
<BVAckermann
> bvAckermann(
2653 new BVAckermann(d_preprocessingPassContext
.get()));
2654 std::unique_ptr
<BVGauss
> bvGauss(
2655 new BVGauss(d_preprocessingPassContext
.get()));
2656 std::unique_ptr
<BvIntroPow2
> bvIntroPow2(
2657 new BvIntroPow2(d_preprocessingPassContext
.get()));
2658 std::unique_ptr
<BVToBool
> bvToBool(
2659 new BVToBool(d_preprocessingPassContext
.get()));
2660 std::unique_ptr
<ExtRewPre
> extRewPre(
2661 new ExtRewPre(d_preprocessingPassContext
.get()));
2662 std::unique_ptr
<IntToBV
> intToBV(
2663 new IntToBV(d_preprocessingPassContext
.get()));
2664 std::unique_ptr
<QuantifiersPreprocess
> quantifiersPreprocess(
2665 new QuantifiersPreprocess(d_preprocessingPassContext
.get()));
2666 std::unique_ptr
<PseudoBooleanProcessor
> pbProc(
2667 new PseudoBooleanProcessor(d_preprocessingPassContext
.get()));
2668 std::unique_ptr
<IteRemoval
> iteRemoval(
2669 new IteRemoval(d_preprocessingPassContext
.get()));
2670 std::unique_ptr
<RealToInt
> realToInt(
2671 new RealToInt(d_preprocessingPassContext
.get()));
2672 std::unique_ptr
<Rewrite
> rewrite(
2673 new Rewrite(d_preprocessingPassContext
.get()));
2674 std::unique_ptr
<SortInferencePass
> sortInfer(
2675 new SortInferencePass(d_preprocessingPassContext
.get(),
2676 d_smt
.d_theoryEngine
->getSortInference()));
2677 std::unique_ptr
<StaticLearning
> staticLearning(
2678 new StaticLearning(d_preprocessingPassContext
.get()));
2679 std::unique_ptr
<SymBreakerPass
> sbProc(
2680 new SymBreakerPass(d_preprocessingPassContext
.get()));
2681 std::unique_ptr
<SynthRewRulesPass
> srrProc(
2682 new SynthRewRulesPass(d_preprocessingPassContext
.get()));
2683 std::unique_ptr
<SepSkolemEmp
> sepSkolemEmp(
2684 new SepSkolemEmp(d_preprocessingPassContext
.get()));
2685 d_preprocessingPassRegistry
.registerPass("apply-substs",
2686 std::move(applySubsts
));
2687 d_preprocessingPassRegistry
.registerPass("apply-to-const",
2688 std::move(applyToConst
));
2689 d_preprocessingPassRegistry
.registerPass("bool-to-bv", std::move(boolToBv
));
2690 d_preprocessingPassRegistry
.registerPass("bv-abstraction",
2691 std::move(bvAbstract
));
2692 d_preprocessingPassRegistry
.registerPass("bv-ackermann",
2693 std::move(bvAckermann
));
2694 d_preprocessingPassRegistry
.registerPass("bv-eager-atoms",
2695 std::move(bvEagerAtoms
));
2696 d_preprocessingPassRegistry
.registerPass("bv-gauss", std::move(bvGauss
));
2697 d_preprocessingPassRegistry
.registerPass("bv-intro-pow2",
2698 std::move(bvIntroPow2
));
2699 d_preprocessingPassRegistry
.registerPass("bv-to-bool", std::move(bvToBool
));
2700 d_preprocessingPassRegistry
.registerPass("ext-rew-pre", std::move(extRewPre
));
2701 d_preprocessingPassRegistry
.registerPass("int-to-bv", std::move(intToBV
));
2702 d_preprocessingPassRegistry
.registerPass("quantifiers-preprocess",
2703 std::move(quantifiersPreprocess
));
2704 d_preprocessingPassRegistry
.registerPass("pseudo-boolean-processor",
2706 d_preprocessingPassRegistry
.registerPass("ite-removal",
2707 std::move(iteRemoval
));
2708 d_preprocessingPassRegistry
.registerPass("real-to-int", std::move(realToInt
));
2709 d_preprocessingPassRegistry
.registerPass("rewrite", std::move(rewrite
));
2710 d_preprocessingPassRegistry
.registerPass("sep-skolem-emp",
2711 std::move(sepSkolemEmp
));
2712 d_preprocessingPassRegistry
.registerPass("sort-inference",
2713 std::move(sortInfer
));
2714 d_preprocessingPassRegistry
.registerPass("static-learning",
2715 std::move(staticLearning
));
2716 d_preprocessingPassRegistry
.registerPass("sym-break", std::move(sbProc
));
2717 d_preprocessingPassRegistry
.registerPass("synth-rr", std::move(srrProc
));
2720 Node
SmtEnginePrivate::expandDefinitions(TNode n
, unordered_map
<Node
, Node
, NodeHashFunction
>& cache
, bool expandOnly
)
2722 stack
<std::tuple
<Node
, Node
, bool>> worklist
;
2724 worklist
.push(std::make_tuple(Node(n
), Node(n
), false));
2725 // The worklist is made of triples, each is input / original node then the output / rewritten node
2726 // and finally a flag tracking whether the children have been explored (i.e. if this is a downward
2730 spendResource(options::preprocessStep());
2732 // n is the input / original
2733 // node is the output / result
2735 bool childrenPushed
;
2736 std::tie(n
, node
, childrenPushed
) = worklist
.top();
2739 // Working downwards
2740 if(!childrenPushed
) {
2741 Kind k
= n
.getKind();
2743 // we can short circuit (variable) leaves
2745 SmtEngine::DefinedFunctionMap::const_iterator i
= d_smt
.d_definedFunctions
->find(n
);
2746 if(i
!= d_smt
.d_definedFunctions
->end()) {
2747 // replacement must be closed
2748 if((*i
).second
.getFormals().size() > 0) {
2749 result
.push(d_smt
.d_nodeManager
->mkNode(kind::LAMBDA
, d_smt
.d_nodeManager
->mkNode(kind::BOUND_VAR_LIST
, (*i
).second
.getFormals()), (*i
).second
.getFormula()));
2752 // don't bother putting in the cache
2753 result
.push((*i
).second
.getFormula());
2756 // don't bother putting in the cache
2761 // maybe it's in the cache
2762 unordered_map
<Node
, Node
, NodeHashFunction
>::iterator cacheHit
= cache
.find(n
);
2763 if(cacheHit
!= cache
.end()) {
2764 TNode ret
= (*cacheHit
).second
;
2765 result
.push(ret
.isNull() ? n
: ret
);
2769 // otherwise expand it
2770 bool doExpand
= false;
2771 if (k
== kind::APPLY
)
2775 else if (k
== kind::APPLY_UF
)
2777 // Always do beta-reduction here. The reason is that there may be
2778 // operators such as INTS_MODULUS in the body of the lambda that would
2779 // otherwise be introduced by beta-reduction via the rewriter, but are
2780 // not expanded here since the traversal in this function does not
2781 // traverse the operators of nodes. Hence, we beta-reduce here to
2782 // ensure terms in the body of the lambda are expanded during this
2784 if (n
.getOperator().getKind() == kind::LAMBDA
)
2788 else if (options::macrosQuant() || options::sygusInference())
2790 // The above options assign substitutions to APPLY_UF, thus we check
2791 // here and expand if this operator corresponds to a defined function.
2792 doExpand
= d_smt
.isDefinedFunction(n
.getOperator().toExpr());
2796 vector
<Node
> formals
;
2798 if( n
.getOperator().getKind() == kind::LAMBDA
){
2799 TNode op
= n
.getOperator();
2801 for( unsigned i
=0; i
<op
[0].getNumChildren(); i
++ ){
2802 formals
.push_back( op
[0][i
] );
2806 // application of a user-defined symbol
2807 TNode func
= n
.getOperator();
2808 SmtEngine::DefinedFunctionMap::const_iterator i
= d_smt
.d_definedFunctions
->find(func
);
2809 if(i
== d_smt
.d_definedFunctions
->end()) {
2810 throw TypeCheckingException(n
.toExpr(), string("Undefined function: `") + func
.toString() + "'");
2812 DefinedFunction def
= (*i
).second
;
2813 formals
= def
.getFormals();
2815 if(Debug
.isOn("expand")) {
2816 Debug("expand") << "found: " << n
<< endl
;
2817 Debug("expand") << " func: " << func
<< endl
;
2818 string name
= func
.getAttribute(expr::VarNameAttr());
2819 Debug("expand") << " : \"" << name
<< "\"" << endl
;
2821 if(Debug
.isOn("expand")) {
2822 Debug("expand") << " defn: " << def
.getFunction() << endl
2824 if(formals
.size() > 0) {
2825 copy( formals
.begin(), formals
.end() - 1,
2826 ostream_iterator
<Node
>(Debug("expand"), ", ") );
2827 Debug("expand") << formals
.back();
2829 Debug("expand") << "]" << endl
2830 << " " << def
.getFunction().getType() << endl
2831 << " " << def
.getFormula() << endl
;
2834 fm
= def
.getFormula();
2837 Node instance
= fm
.substitute(formals
.begin(),
2840 n
.begin() + formals
.size());
2841 Debug("expand") << "made : " << instance
<< endl
;
2843 Node expanded
= expandDefinitions(instance
, cache
, expandOnly
);
2844 cache
[n
] = (n
== expanded
? Node::null() : expanded
);
2845 result
.push(expanded
);
2848 } else if(! expandOnly
) {
2849 // do not do any theory stuff if expandOnly is true
2851 theory::Theory
* t
= d_smt
.d_theoryEngine
->theoryOf(node
);
2854 LogicRequest
req(d_smt
);
2855 node
= t
->expandDefinition(req
, n
);
2858 // the partial functions can fall through, in which case we still
2859 // consider their children
2860 worklist
.push(std::make_tuple(
2861 Node(n
), node
, true)); // Original and rewritten result
2863 for(size_t i
= 0; i
< node
.getNumChildren(); ++i
) {
2865 std::make_tuple(node
[i
],
2867 false)); // Rewrite the children of the result only
2872 // Reconstruct the node from it's (now rewritten) children on the stack
2874 Debug("expand") << "cons : " << node
<< endl
;
2875 if(node
.getNumChildren()>0) {
2876 //cout << "cons : " << node << endl;
2877 NodeBuilder
<> nb(node
.getKind());
2878 if(node
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
2879 Debug("expand") << "op : " << node
.getOperator() << endl
;
2880 //cout << "op : " << node.getOperator() << endl;
2881 nb
<< node
.getOperator();
2883 for(size_t i
= 0; i
< node
.getNumChildren(); ++i
) {
2884 Assert(!result
.empty());
2885 Node expanded
= result
.top();
2887 //cout << "exchld : " << expanded << endl;
2888 Debug("expand") << "exchld : " << expanded
<< endl
;
2893 cache
[n
] = n
== node
? Node::null() : node
; // Only cache once all subterms are expanded
2896 } while(!worklist
.empty());
2898 AlwaysAssert(result
.size() == 1);
2900 return result
.top();
2903 typedef std::unordered_map
<Node
, Node
, NodeHashFunction
> NodeMap
;
2905 Node
SmtEnginePrivate::purifyNlTerms(TNode n
, NodeMap
& cache
, NodeMap
& bcache
, std::vector
< Node
>& var_eq
, bool beneathMult
) {
2907 NodeMap::iterator find
= bcache
.find(n
);
2908 if (find
!= bcache
.end()) {
2909 return (*find
).second
;
2912 NodeMap::iterator find
= cache
.find(n
);
2913 if (find
!= cache
.end()) {
2914 return (*find
).second
;
2918 if( n
.getNumChildren()>0 ){
2920 && (n
.getKind() == kind::PLUS
|| n
.getKind() == kind::MINUS
))
2922 // don't do it if it rewrites to a constant
2923 Node nr
= Rewriter::rewrite(n
);
2926 // return the rewritten constant
2932 ret
= NodeManager::currentNM()->mkSkolem(
2935 "Variable introduced in purifyNl pass");
2936 Node np
= purifyNlTerms(n
, cache
, bcache
, var_eq
, false);
2937 var_eq
.push_back(np
.eqNode(ret
));
2938 Trace("nl-ext-purify")
2939 << "Purify : " << ret
<< " -> " << np
<< std::endl
;
2944 bool beneathMultNew
= beneathMult
|| n
.getKind()==kind::MULT
;
2945 bool childChanged
= false;
2946 std::vector
< Node
> children
;
2947 for( unsigned i
=0; i
<n
.getNumChildren(); i
++ ){
2948 Node nc
= purifyNlTerms( n
[i
], cache
, bcache
, var_eq
, beneathMultNew
);
2949 childChanged
= childChanged
|| nc
!=n
[i
];
2950 children
.push_back( nc
);
2953 ret
= NodeManager::currentNM()->mkNode( n
.getKind(), children
);
2965 // do dumping (before/after any preprocessing pass)
2966 static void dumpAssertions(const char* key
,
2967 const AssertionPipeline
& assertionList
) {
2968 if( Dump
.isOn("assertions") &&
2969 Dump
.isOn(string("assertions:") + key
) ) {
2970 // Push the simplified assertions to the dump output stream
2971 for(unsigned i
= 0; i
< assertionList
.size(); ++ i
) {
2972 TNode n
= assertionList
[i
];
2973 Dump("assertions") << AssertCommand(Expr(n
.toExpr()));
2978 // returns false if it learns a conflict
2979 bool SmtEnginePrivate::nonClausalSimplify() {
2980 spendResource(options::preprocessStep());
2981 d_smt
.finalOptionsAreSet();
2983 if(options::unsatCores() || options::fewerPreprocessingHoles()) {
2987 TimerStat::CodeTimer
nonclausalTimer(d_smt
.d_stats
->d_nonclausalSimplificationTime
);
2989 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl
;
2990 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
2991 Trace("simplify") << "Assertion #" << i
<< " : " << d_assertions
[i
] << std::endl
;
2994 if(d_propagatorNeedsFinish
) {
2995 d_propagator
.finish();
2996 d_propagatorNeedsFinish
= false;
2998 d_propagator
.initialize();
3000 // Assert all the assertions to the propagator
3001 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3002 << "asserting to propagator" << endl
;
3003 CDO
<unsigned>& substs_index
= d_assertions
.getSubstitutionsIndex();
3004 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3005 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
3006 // Don't reprocess substitutions
3007 if (substs_index
> 0 && i
== substs_index
)
3011 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertions
[i
] << endl
;
3012 Debug("cores") << "d_propagator assertTrue: " << d_assertions
[i
] << std::endl
;
3013 d_propagator
.assertTrue(d_assertions
[i
]);
3016 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3017 << "propagating" << endl
;
3018 if (d_propagator
.propagate()) {
3019 // If in conflict, just return false
3020 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3021 << "conflict in non-clausal propagation" << endl
;
3022 Node falseNode
= NodeManager::currentNM()->mkConst
<bool>(false);
3023 Assert(!options::unsatCores() && !options::fewerPreprocessingHoles());
3024 d_assertions
.clear();
3025 addFormula(falseNode
, false, false);
3026 d_propagatorNeedsFinish
= true;
3031 Trace("simplify") << "Iterate through " << d_nonClausalLearnedLiterals
.size() << " learned literals." << std::endl
;
3032 // No conflict, go through the literals and solve them
3033 SubstitutionMap
& top_level_substs
= d_assertions
.getTopLevelSubstitutions();
3034 SubstitutionMap
constantPropagations(d_smt
.d_context
);
3035 SubstitutionMap
newSubstitutions(d_smt
.d_context
);
3036 SubstitutionMap::iterator pos
;
3038 for(unsigned i
= 0, i_end
= d_nonClausalLearnedLiterals
.size(); i
< i_end
; ++ i
) {
3039 // Simplify the literal we learned wrt previous substitutions
3040 Node learnedLiteral
= d_nonClausalLearnedLiterals
[i
];
3041 Assert(Rewriter::rewrite(learnedLiteral
) == learnedLiteral
);
3042 Assert(top_level_substs
.apply(learnedLiteral
) == learnedLiteral
);
3043 Trace("simplify") << "Process learnedLiteral : " << learnedLiteral
<< std::endl
;
3044 Node learnedLiteralNew
= newSubstitutions
.apply(learnedLiteral
);
3045 if (learnedLiteral
!= learnedLiteralNew
) {
3046 learnedLiteral
= Rewriter::rewrite(learnedLiteralNew
);
3048 Trace("simplify") << "Process learnedLiteral, after newSubs : " << learnedLiteral
<< std::endl
;
3050 learnedLiteralNew
= constantPropagations
.apply(learnedLiteral
);
3051 if (learnedLiteralNew
== learnedLiteral
) {
3054 ++d_smt
.d_stats
->d_numConstantProps
;
3055 learnedLiteral
= Rewriter::rewrite(learnedLiteralNew
);
3057 Trace("simplify") << "Process learnedLiteral, after constProp : " << learnedLiteral
<< std::endl
;
3058 // It might just simplify to a constant
3059 if (learnedLiteral
.isConst()) {
3060 if (learnedLiteral
.getConst
<bool>()) {
3061 // If the learned literal simplifies to true, it's redundant
3064 // If the learned literal simplifies to false, we're in conflict
3065 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3067 << d_nonClausalLearnedLiterals
[i
] << endl
;
3068 Assert(!options::unsatCores());
3069 d_assertions
.clear();
3070 addFormula(NodeManager::currentNM()->mkConst
<bool>(false), false, false);
3071 d_propagatorNeedsFinish
= true;
3076 // Solve it with the corresponding theory, possibly adding new
3077 // substitutions to newSubstitutions
3078 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3079 << "solving " << learnedLiteral
<< endl
;
3081 Theory::PPAssertStatus solveStatus
=
3082 d_smt
.d_theoryEngine
->solve(learnedLiteral
, newSubstitutions
);
3084 switch (solveStatus
) {
3085 case Theory::PP_ASSERT_STATUS_SOLVED
: {
3086 // The literal should rewrite to true
3087 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3088 << "solved " << learnedLiteral
<< endl
;
3089 Assert(Rewriter::rewrite(newSubstitutions
.apply(learnedLiteral
)).isConst());
3090 // vector<pair<Node, Node> > equations;
3091 // constantPropagations.simplifyLHS(top_level_substs, equations,
3092 // true); if (equations.empty()) {
3095 // Assert(equations[0].first.isConst() &&
3096 // equations[0].second.isConst() && equations[0].first !=
3097 // equations[0].second);
3098 // else fall through
3101 case Theory::PP_ASSERT_STATUS_CONFLICT
:
3102 // If in conflict, we return false
3103 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3104 << "conflict while solving "
3105 << learnedLiteral
<< endl
;
3106 Assert(!options::unsatCores());
3107 d_assertions
.clear();
3108 addFormula(NodeManager::currentNM()->mkConst
<bool>(false), false, false);
3109 d_propagatorNeedsFinish
= true;
3112 if (d_doConstantProp
&& learnedLiteral
.getKind() == kind::EQUAL
&& (learnedLiteral
[0].isConst() || learnedLiteral
[1].isConst())) {
3113 // constant propagation
3116 if (learnedLiteral
[0].isConst()) {
3117 t
= learnedLiteral
[1];
3118 c
= learnedLiteral
[0];
3121 t
= learnedLiteral
[0];
3122 c
= learnedLiteral
[1];
3124 Assert(!t
.isConst());
3125 Assert(constantPropagations
.apply(t
) == t
);
3126 Assert(top_level_substs
.apply(t
) == t
);
3127 Assert(newSubstitutions
.apply(t
) == t
);
3128 constantPropagations
.addSubstitution(t
, c
);
3129 // vector<pair<Node,Node> > equations;
3130 // constantPropagations.simplifyLHS(t, c, equations, true);
3131 // if (!equations.empty()) {
3132 // Assert(equations[0].first.isConst() &&
3133 // equations[0].second.isConst() && equations[0].first !=
3134 // equations[0].second); d_assertions.clear();
3135 // addFormula(NodeManager::currentNM()->mkConst<bool>(false), false,
3138 // top_level_substs.simplifyRHS(constantPropagations);
3142 d_nonClausalLearnedLiterals
[j
++] = d_nonClausalLearnedLiterals
[i
];
3148 #ifdef CVC4_ASSERTIONS
3149 // NOTE: When debugging this code, consider moving this check inside of the
3150 // loop over d_nonClausalLearnedLiterals. This check has been moved outside
3151 // because it is costly for certain inputs (see bug 508).
3153 // Check data structure invariants:
3154 // 1. for each lhs of top_level_substs, does not appear anywhere in rhs of
3155 // top_level_substs or anywhere in constantPropagations
3156 // 2. each lhs of constantPropagations rewrites to itself
3157 // 3. if l -> r is a constant propagation and l is a subterm of l' with l' ->
3158 // r' another constant propagation, then l'[l/r] -> r' should be a
3159 // constant propagation too
3160 // 4. each lhs of constantPropagations is different from each rhs
3161 for (pos
= newSubstitutions
.begin(); pos
!= newSubstitutions
.end(); ++pos
) {
3162 Assert((*pos
).first
.isVar());
3163 Assert(top_level_substs
.apply((*pos
).first
) == (*pos
).first
);
3164 Assert(top_level_substs
.apply((*pos
).second
) == (*pos
).second
);
3165 Assert(newSubstitutions
.apply(newSubstitutions
.apply((*pos
).second
)) == newSubstitutions
.apply((*pos
).second
));
3167 for (pos
= constantPropagations
.begin(); pos
!= constantPropagations
.end(); ++pos
) {
3168 Assert((*pos
).second
.isConst());
3169 Assert(Rewriter::rewrite((*pos
).first
) == (*pos
).first
);
3170 // Node newLeft = top_level_substs.apply((*pos).first);
3171 // if (newLeft != (*pos).first) {
3172 // newLeft = Rewriter::rewrite(newLeft);
3173 // Assert(newLeft == (*pos).second ||
3174 // (constantPropagations.hasSubstitution(newLeft) &&
3175 // constantPropagations.apply(newLeft) == (*pos).second));
3177 // newLeft = constantPropagations.apply((*pos).first);
3178 // if (newLeft != (*pos).first) {
3179 // newLeft = Rewriter::rewrite(newLeft);
3180 // Assert(newLeft == (*pos).second ||
3181 // (constantPropagations.hasSubstitution(newLeft) &&
3182 // constantPropagations.apply(newLeft) == (*pos).second));
3184 Assert(constantPropagations
.apply((*pos
).second
) == (*pos
).second
);
3186 #endif /* CVC4_ASSERTIONS */
3188 // Resize the learnt
3189 Trace("simplify") << "Resize non-clausal learned literals to " << j
<< std::endl
;
3190 d_nonClausalLearnedLiterals
.resize(j
);
3192 unordered_set
<TNode
, TNodeHashFunction
> s
;
3193 Trace("debugging") << "NonClausal simplify pre-preprocess\n";
3194 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3195 Node assertion
= d_assertions
[i
];
3196 Node assertionNew
= newSubstitutions
.apply(assertion
);
3197 Trace("debugging") << "assertion = " << assertion
<< endl
;
3198 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
3199 if (assertion
!= assertionNew
) {
3200 assertion
= Rewriter::rewrite(assertionNew
);
3201 Trace("debugging") << "rewrite(assertion) = " << assertion
<< endl
;
3203 Assert(Rewriter::rewrite(assertion
) == assertion
);
3205 assertionNew
= constantPropagations
.apply(assertion
);
3206 if (assertionNew
== assertion
) {
3209 ++d_smt
.d_stats
->d_numConstantProps
;
3210 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
3211 assertion
= Rewriter::rewrite(assertionNew
);
3212 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
3214 Trace("debugging") << "\n";
3215 s
.insert(assertion
);
3216 d_assertions
.replace(i
, assertion
);
3217 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3218 << "non-clausal preprocessed: "
3219 << assertion
<< endl
;
3222 // If in incremental mode, add substitutions to the list of assertions
3223 if (substs_index
> 0)
3225 NodeBuilder
<> substitutionsBuilder(kind::AND
);
3226 substitutionsBuilder
<< d_assertions
[substs_index
];
3227 pos
= newSubstitutions
.begin();
3228 for (; pos
!= newSubstitutions
.end(); ++pos
) {
3229 // Add back this substitution as an assertion
3230 TNode lhs
= (*pos
).first
, rhs
= newSubstitutions
.apply((*pos
).second
);
3231 Node n
= NodeManager::currentNM()->mkNode(kind::EQUAL
, lhs
, rhs
);
3232 substitutionsBuilder
<< n
;
3233 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n
<< endl
;
3235 if (substitutionsBuilder
.getNumChildren() > 1) {
3236 d_assertions
.replace(substs_index
,
3237 Rewriter::rewrite(Node(substitutionsBuilder
)));
3240 // If not in incremental mode, must add substitutions to model
3241 TheoryModel
* m
= d_smt
.d_theoryEngine
->getModel();
3243 for(pos
= newSubstitutions
.begin(); pos
!= newSubstitutions
.end(); ++pos
) {
3244 Node n
= (*pos
).first
;
3245 Node v
= newSubstitutions
.apply((*pos
).second
);
3246 Trace("model") << "Add substitution : " << n
<< " " << v
<< endl
;
3247 m
->addSubstitution( n
, v
);
3252 NodeBuilder
<> learnedBuilder(kind::AND
);
3253 Assert(d_realAssertionsEnd
<= d_assertions
.size());
3254 learnedBuilder
<< d_assertions
[d_realAssertionsEnd
- 1];
3256 for (unsigned i
= 0; i
< d_nonClausalLearnedLiterals
.size(); ++ i
) {
3257 Node learned
= d_nonClausalLearnedLiterals
[i
];
3258 Assert(top_level_substs
.apply(learned
) == learned
);
3259 Node learnedNew
= newSubstitutions
.apply(learned
);
3260 if (learned
!= learnedNew
) {
3261 learned
= Rewriter::rewrite(learnedNew
);
3263 Assert(Rewriter::rewrite(learned
) == learned
);
3265 learnedNew
= constantPropagations
.apply(learned
);
3266 if (learnedNew
== learned
) {
3269 ++d_smt
.d_stats
->d_numConstantProps
;
3270 learned
= Rewriter::rewrite(learnedNew
);
3272 if (s
.find(learned
) != s
.end()) {
3276 learnedBuilder
<< learned
;
3277 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3278 << "non-clausal learned : "
3281 d_nonClausalLearnedLiterals
.clear();
3283 for (pos
= constantPropagations
.begin(); pos
!= constantPropagations
.end(); ++pos
) {
3284 Node cProp
= (*pos
).first
.eqNode((*pos
).second
);
3285 Assert(top_level_substs
.apply(cProp
) == cProp
);
3286 Node cPropNew
= newSubstitutions
.apply(cProp
);
3287 if (cProp
!= cPropNew
) {
3288 cProp
= Rewriter::rewrite(cPropNew
);
3289 Assert(Rewriter::rewrite(cProp
) == cProp
);
3291 if (s
.find(cProp
) != s
.end()) {
3295 learnedBuilder
<< cProp
;
3296 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
3297 << "non-clausal constant propagation : "
3301 // Add new substitutions to topLevelSubstitutions
3302 // Note that we don't have to keep rhs's in full solved form
3303 // because SubstitutionMap::apply does a fixed-point iteration when substituting
3304 top_level_substs
.addSubstitutions(newSubstitutions
);
3306 if(learnedBuilder
.getNumChildren() > 1) {
3307 d_assertions
.replace(d_realAssertionsEnd
- 1,
3308 Rewriter::rewrite(Node(learnedBuilder
)));
3311 d_propagatorNeedsFinish
= true;
3315 bool SmtEnginePrivate::simpITE() {
3316 TimerStat::CodeTimer
simpITETimer(d_smt
.d_stats
->d_simpITETime
);
3318 spendResource(options::preprocessStep());
3320 Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl
;
3322 unsigned numAssertionOnEntry
= d_assertions
.size();
3323 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
) {
3324 spendResource(options::preprocessStep());
3325 Node result
= d_smt
.d_theoryEngine
->ppSimpITE(d_assertions
[i
]);
3326 d_assertions
.replace(i
, result
);
3327 if(result
.isConst() && !result
.getConst
<bool>()){
3331 bool result
= d_smt
.d_theoryEngine
->donePPSimpITE(d_assertions
.ref());
3332 if(numAssertionOnEntry
< d_assertions
.size()){
3333 compressBeforeRealAssertions(numAssertionOnEntry
);
3338 void SmtEnginePrivate::compressBeforeRealAssertions(size_t before
){
3339 size_t curr
= d_assertions
.size();
3340 if(before
>= curr
||
3341 d_realAssertionsEnd
<= 0 ||
3342 d_realAssertionsEnd
>= curr
){
3347 // original: [0 ... d_realAssertionsEnd)
3349 // ites skolems [d_realAssertionsEnd, before)
3351 // added [before, curr)
3353 Assert(0 < d_realAssertionsEnd
);
3354 Assert(d_realAssertionsEnd
<= before
);
3355 Assert(before
< curr
);
3357 std::vector
<Node
> intoConjunction
;
3358 for(size_t i
= before
; i
<curr
; ++i
){
3359 intoConjunction
.push_back(d_assertions
[i
]);
3361 d_assertions
.resize(before
);
3362 size_t lastBeforeItes
= d_realAssertionsEnd
- 1;
3363 intoConjunction
.push_back(d_assertions
[lastBeforeItes
]);
3364 Node newLast
= util::NaryBuilder::mkAssoc(kind::AND
, intoConjunction
);
3365 d_assertions
.replace(lastBeforeItes
, newLast
);
3366 Assert(d_assertions
.size() == before
);
3369 void SmtEnginePrivate::unconstrainedSimp() {
3370 TimerStat::CodeTimer
unconstrainedSimpTimer(d_smt
.d_stats
->d_unconstrainedSimpTime
);
3371 spendResource(options::preprocessStep());
3372 Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl
;
3373 d_smt
.d_theoryEngine
->ppUnconstrainedSimp(d_assertions
.ref());
3376 void SmtEnginePrivate::traceBackToAssertions(const std::vector
<Node
>& nodes
, std::vector
<TNode
>& assertions
) {
3377 const booleans::CircuitPropagator::BackEdgesMap
& backEdges
= d_propagator
.getBackEdges();
3378 for(vector
<Node
>::const_iterator i
= nodes
.begin(); i
!= nodes
.end(); ++i
) {
3379 booleans::CircuitPropagator::BackEdgesMap::const_iterator j
= backEdges
.find(*i
);
3380 // term must appear in map, otherwise how did we get here?!
3381 Assert(j
!= backEdges
.end());
3382 // if term maps to empty, that means it's a top-level assertion
3383 if(!(*j
).second
.empty()) {
3384 traceBackToAssertions((*j
).second
, assertions
);
3386 assertions
.push_back(*i
);
3391 size_t SmtEnginePrivate::removeFromConjunction(Node
& n
, const std::unordered_set
<unsigned long>& toRemove
) {
3392 Assert(n
.getKind() == kind::AND
);
3393 size_t removals
= 0;
3394 for(Node::iterator j
= n
.begin(); j
!= n
.end(); ++j
) {
3395 size_t subremovals
= 0;
3397 if(toRemove
.find(sub
.getId()) != toRemove
.end() ||
3398 (sub
.getKind() == kind::AND
&& (subremovals
= removeFromConjunction(sub
, toRemove
)) > 0)) {
3399 NodeBuilder
<> b(kind::AND
);
3400 b
.append(n
.begin(), j
);
3401 if(subremovals
> 0) {
3402 removals
+= subremovals
;
3407 for(++j
; j
!= n
.end(); ++j
) {
3408 if(toRemove
.find((*j
).getId()) != toRemove
.end()) {
3410 } else if((*j
).getKind() == kind::AND
) {
3412 if((subremovals
= removeFromConjunction(sub
, toRemove
)) > 0) {
3413 removals
+= subremovals
;
3422 if(b
.getNumChildren() == 0) {
3425 } else if(b
.getNumChildren() == 1) {
3431 n
= Rewriter::rewrite(n
);
3436 Assert(removals
== 0);
3440 void SmtEnginePrivate::doMiplibTrick() {
3441 Assert(d_realAssertionsEnd
== d_assertions
.size());
3442 Assert(!options::incrementalSolving());
3444 const booleans::CircuitPropagator::BackEdgesMap
& backEdges
= d_propagator
.getBackEdges();
3445 unordered_set
<unsigned long> removeAssertions
;
3447 NodeManager
* nm
= NodeManager::currentNM();
3448 Node zero
= nm
->mkConst(Rational(0)), one
= nm
->mkConst(Rational(1));
3450 SubstitutionMap
& top_level_substs
= d_assertions
.getTopLevelSubstitutions();
3451 unordered_map
<TNode
, Node
, TNodeHashFunction
> intVars
;
3452 for(vector
<Node
>::const_iterator i
= d_boolVars
.begin(); i
!= d_boolVars
.end(); ++i
) {
3453 if(d_propagator
.isAssigned(*i
)) {
3454 Debug("miplib") << "ineligible: " << *i
<< " because assigned " << d_propagator
.getAssignment(*i
) << endl
;
3458 vector
<TNode
> assertions
;
3459 booleans::CircuitPropagator::BackEdgesMap::const_iterator j
= backEdges
.find(*i
);
3460 // if not in back edges map, the bool var is unconstrained, showing up in no assertions.
3461 // if maps to an empty vector, that means the bool var was asserted itself.
3462 if(j
!= backEdges
.end()) {
3463 if(!(*j
).second
.empty()) {
3464 traceBackToAssertions((*j
).second
, assertions
);
3466 assertions
.push_back(*i
);
3469 Debug("miplib") << "for " << *i
<< endl
;
3470 bool eligible
= true;
3471 map
<pair
<Node
, Node
>, uint64_t> marks
;
3472 map
<pair
<Node
, Node
>, vector
<Rational
> > coef
;
3473 map
<pair
<Node
, Node
>, vector
<Rational
> > checks
;
3474 map
<pair
<Node
, Node
>, vector
<TNode
> > asserts
;
3475 for(vector
<TNode
>::const_iterator j
= assertions
.begin(); j
!= assertions
.end(); ++j
) {
3476 Debug("miplib") << " found: " << *j
<< endl
;
3477 if((*j
).getKind() != kind::IMPLIES
) {
3479 Debug("miplib") << " -- INELIGIBLE -- (not =>)" << endl
;
3482 Node conj
= BooleanSimplification::simplify((*j
)[0]);
3483 if(conj
.getKind() == kind::AND
&& conj
.getNumChildren() > 6) {
3485 Debug("miplib") << " -- INELIGIBLE -- (N-ary /\\ too big)" << endl
;
3488 if(conj
.getKind() != kind::AND
&& !conj
.isVar() && !(conj
.getKind() == kind::NOT
&& conj
[0].isVar())) {
3490 Debug("miplib") << " -- INELIGIBLE -- (not /\\ or literal)" << endl
;
3493 if((*j
)[1].getKind() != kind::EQUAL
||
3494 !( ( (*j
)[1][0].isVar() &&
3495 (*j
)[1][1].getKind() == kind::CONST_RATIONAL
) ||
3496 ( (*j
)[1][0].getKind() == kind::CONST_RATIONAL
&&
3497 (*j
)[1][1].isVar() ) )) {
3499 Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl
;
3502 if(conj
.getKind() == kind::AND
) {
3504 bool found_x
= false;
3505 map
<TNode
, bool> neg
;
3506 for(Node::iterator ii
= conj
.begin(); ii
!= conj
.end(); ++ii
) {
3508 posv
.push_back(*ii
);
3510 found_x
= found_x
|| *i
== *ii
;
3511 } else if((*ii
).getKind() == kind::NOT
&& (*ii
)[0].isVar()) {
3512 posv
.push_back((*ii
)[0]);
3513 neg
[(*ii
)[0]] = true;
3514 found_x
= found_x
|| *i
== (*ii
)[0];
3517 Debug("miplib") << " -- INELIGIBLE -- (non-var: " << *ii
<< ")" << endl
;
3520 if(d_propagator
.isAssigned(posv
.back())) {
3522 Debug("miplib") << " -- INELIGIBLE -- (" << posv
.back() << " asserted)" << endl
;
3531 Debug("miplib") << " --INELIGIBLE -- (couldn't find " << *i
<< " in conjunction)" << endl
;
3534 sort(posv
.begin(), posv
.end());
3535 const Node pos
= NodeManager::currentNM()->mkNode(kind::AND
, posv
);
3536 const TNode var
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][1] : (*j
)[1][0];
3537 const pair
<Node
, Node
> pos_var(pos
, var
);
3538 const Rational
& constant
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][0].getConst
<Rational
>() : (*j
)[1][1].getConst
<Rational
>();
3540 unsigned countneg
= 0, thepos
= 0;
3541 for(unsigned ii
= 0; ii
< pos
.getNumChildren(); ++ii
) {
3546 mark
|= (0x1 << ii
);
3549 if((marks
[pos_var
] & (1lu << mark
)) != 0) {
3551 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl
;
3554 Debug("miplib") << "mark is " << mark
<< " -- " << (1lu << mark
) << endl
;
3555 marks
[pos_var
] |= (1lu << mark
);
3556 Debug("miplib") << "marks[" << pos
<< "," << var
<< "] now " << marks
[pos_var
] << endl
;
3557 if(countneg
== pos
.getNumChildren()) {
3560 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl
;
3563 } else if(countneg
== pos
.getNumChildren() - 1) {
3564 Assert(coef
[pos_var
].size() <= 6 && thepos
< 6);
3565 if(coef
[pos_var
].size() <= thepos
) {
3566 coef
[pos_var
].resize(thepos
+ 1);
3568 coef
[pos_var
][thepos
] = constant
;
3570 if(checks
[pos_var
].size() <= mark
) {
3571 checks
[pos_var
].resize(mark
+ 1);
3573 checks
[pos_var
][mark
] = constant
;
3575 asserts
[pos_var
].push_back(*j
);
3578 if(x
!= *i
&& x
!= (*i
).notNode()) {
3580 Debug("miplib") << " -- INELIGIBLE -- (x not present where I expect it)" << endl
;
3583 const bool xneg
= (x
.getKind() == kind::NOT
);
3584 x
= xneg
? x
[0] : x
;
3585 Debug("miplib") << " x:" << x
<< " " << xneg
<< endl
;
3586 const TNode var
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][1] : (*j
)[1][0];
3587 const pair
<Node
, Node
> x_var(x
, var
);
3588 const Rational
& constant
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][0].getConst
<Rational
>() : (*j
)[1][1].getConst
<Rational
>();
3589 unsigned mark
= (xneg
? 0 : 1);
3590 if((marks
[x_var
] & (1u << mark
)) != 0) {
3592 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl
;
3595 marks
[x_var
] |= (1u << mark
);
3599 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl
;
3603 Assert(coef
[x_var
].size() <= 6);
3604 coef
[x_var
].resize(6);
3605 coef
[x_var
][0] = constant
;
3607 asserts
[x_var
].push_back(*j
);
3611 for(map
<pair
<Node
, Node
>, uint64_t>::const_iterator j
= marks
.begin(); j
!= marks
.end(); ++j
) {
3612 const TNode pos
= (*j
).first
.first
;
3613 const TNode var
= (*j
).first
.second
;
3614 const pair
<Node
, Node
>& pos_var
= (*j
).first
;
3615 const uint64_t mark
= (*j
).second
;
3616 const unsigned numVars
= pos
.getKind() == kind::AND
? pos
.getNumChildren() : 1;
3617 uint64_t expected
= (uint64_t(1) << (1 << numVars
)) - 1;
3618 expected
= (expected
== 0) ? -1 : expected
; // fix for overflow
3619 Debug("miplib") << "[" << pos
<< "] => " << hex
<< mark
<< " expect " << expected
<< dec
<< endl
;
3620 Assert(pos
.getKind() == kind::AND
|| pos
.isVar());
3621 if(mark
!= expected
) {
3622 Debug("miplib") << " -- INELIGIBLE " << pos
<< " -- (insufficiently marked, got " << mark
<< " for " << numVars
<< " vars, expected " << expected
<< endl
;
3624 if(mark
!= 3) { // exclude single-var case; nothing to check there
3625 uint64_t sz
= (uint64_t(1) << checks
[pos_var
].size()) - 1;
3626 sz
= (sz
== 0) ? -1 : sz
; // fix for overflow
3627 Assert(sz
== mark
, "expected size %u == mark %u", sz
, mark
);
3628 for(size_t k
= 0; k
< checks
[pos_var
].size(); ++k
) {
3629 if((k
& (k
- 1)) != 0) {
3631 Debug("miplib") << k
<< " => " << checks
[pos_var
][k
] << endl
;
3632 for(size_t v
= 1, kk
= k
; kk
!= 0; ++v
, kk
>>= 1) {
3633 if((kk
& 0x1) == 1) {
3634 Assert(pos
.getKind() == kind::AND
);
3635 Debug("miplib") << "var " << v
<< " : " << pos
[v
- 1] << " coef:" << coef
[pos_var
][v
- 1] << endl
;
3636 sum
+= coef
[pos_var
][v
- 1];
3639 Debug("miplib") << "checkSum is " << sum
<< " input says " << checks
[pos_var
][k
] << endl
;
3640 if(sum
!= checks
[pos_var
][k
]) {
3642 Debug("miplib") << " -- INELIGIBLE " << pos
<< " -- (nonlinear combination)" << endl
;
3646 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
3651 eligible
= true; // next is still eligible
3655 Debug("miplib") << " -- ELIGIBLE " << *i
<< " , " << pos
<< " --" << endl
;
3656 vector
<Node
> newVars
;
3657 expr::NodeSelfIterator ii
, iiend
;
3658 if(pos
.getKind() == kind::AND
) {
3662 ii
= expr::NodeSelfIterator::self(pos
);
3663 iiend
= expr::NodeSelfIterator::selfEnd(pos
);
3665 for(; ii
!= iiend
; ++ii
) {
3666 Node
& varRef
= intVars
[*ii
];
3667 if(varRef
.isNull()) {
3669 ss
<< "mipvar_" << *ii
;
3670 Node newVar
= nm
->mkSkolem(ss
.str(), nm
->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME
);
3671 Node geq
= Rewriter::rewrite(nm
->mkNode(kind::GEQ
, newVar
, zero
));
3672 Node leq
= Rewriter::rewrite(nm
->mkNode(kind::LEQ
, newVar
, one
));
3673 addFormula(Rewriter::rewrite(geq
.andNode(leq
)), false, false);
3674 SubstitutionMap
nullMap(&d_fakeContext
);
3675 Theory::PPAssertStatus status CVC4_UNUSED
; // just for assertions
3676 status
= d_smt
.d_theoryEngine
->solve(geq
, nullMap
);
3677 Assert(status
== Theory::PP_ASSERT_STATUS_UNSOLVED
,
3678 "unexpected solution from arith's ppAssert()");
3679 Assert(nullMap
.empty(),
3680 "unexpected substitution from arith's ppAssert()");
3681 status
= d_smt
.d_theoryEngine
->solve(leq
, nullMap
);
3682 Assert(status
== Theory::PP_ASSERT_STATUS_UNSOLVED
,
3683 "unexpected solution from arith's ppAssert()");
3684 Assert(nullMap
.empty(),
3685 "unexpected substitution from arith's ppAssert()");
3686 d_smt
.d_theoryEngine
->getModel()->addSubstitution(*ii
, newVar
.eqNode(one
));
3687 newVars
.push_back(newVar
);
3690 newVars
.push_back(varRef
);
3692 if(!d_smt
.d_logic
.areIntegersUsed()) {
3693 d_smt
.d_logic
= d_smt
.d_logic
.getUnlockedCopy();
3694 d_smt
.d_logic
.enableIntegers();
3695 d_smt
.d_logic
.lock();
3699 if(pos
.getKind() == kind::AND
) {
3700 NodeBuilder
<> sumb(kind::PLUS
);
3701 for(size_t ii
= 0; ii
< pos
.getNumChildren(); ++ii
) {
3702 sumb
<< nm
->mkNode(kind::MULT
, nm
->mkConst(coef
[pos_var
][ii
]), newVars
[ii
]);
3706 sum
= nm
->mkNode(kind::MULT
, nm
->mkConst(coef
[pos_var
][0]), newVars
[0]);
3708 Debug("miplib") << "vars[] " << var
<< endl
3709 << " eq " << Rewriter::rewrite(sum
) << endl
;
3710 Node newAssertion
= var
.eqNode(Rewriter::rewrite(sum
));
3711 if (top_level_substs
.hasSubstitution(newAssertion
[0]))
3713 // Warning() << "RE-SUBSTITUTION " << newAssertion[0] << endl;
3714 // Warning() << "REPLACE " << newAssertion[1] << endl;
3715 // Warning() << "ORIG " <<
3716 // top_level_substs.getSubstitution(newAssertion[0]) << endl;
3717 Assert(top_level_substs
.getSubstitution(newAssertion
[0])
3718 == newAssertion
[1]);
3719 } else if(pos
.getNumChildren() <= options::arithMLTrickSubstitutions()) {
3720 top_level_substs
.addSubstitution(newAssertion
[0], newAssertion
[1]);
3721 Debug("miplib") << "addSubs: " << newAssertion
[0] << " to " << newAssertion
[1] << endl
;
3723 Debug("miplib") << "skipSubs: " << newAssertion
[0] << " to " << newAssertion
[1] << " (threshold is " << options::arithMLTrickSubstitutions() << ")" << endl
;
3725 newAssertion
= Rewriter::rewrite(newAssertion
);
3726 Debug("miplib") << " " << newAssertion
<< endl
;
3727 addFormula(newAssertion
, false, false);
3728 Debug("miplib") << " assertions to remove: " << endl
;
3729 for(vector
<TNode
>::const_iterator k
= asserts
[pos_var
].begin(), k_end
= asserts
[pos_var
].end(); k
!= k_end
; ++k
) {
3730 Debug("miplib") << " " << *k
<< endl
;
3731 removeAssertions
.insert((*k
).getId());
3737 if(!removeAssertions
.empty()) {
3738 Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl
;
3739 for(size_t i
= 0; i
< d_realAssertionsEnd
; ++i
) {
3740 if(removeAssertions
.find(d_assertions
[i
].getId()) != removeAssertions
.end()) {
3741 Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertions
[i
] << endl
;
3742 d_assertions
[i
] = d_true
;
3743 ++d_smt
.d_stats
->d_numMiplibAssertionsRemoved
;
3744 } else if(d_assertions
[i
].getKind() == kind::AND
) {
3745 size_t removals
= removeFromConjunction(d_assertions
[i
], removeAssertions
);
3747 Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertions
[i
] << endl
;
3748 Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals
<< " conjuncts" << endl
;
3749 d_smt
.d_stats
->d_numMiplibAssertionsRemoved
+= removals
;
3752 Debug("miplib") << "had: " << d_assertions
[i
] << endl
;
3754 Rewriter::rewrite(top_level_substs
.apply(d_assertions
[i
]));
3755 Debug("miplib") << "now: " << d_assertions
[i
] << endl
;
3758 Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl
;
3760 d_realAssertionsEnd
= d_assertions
.size();
3764 // returns false if simplification led to "false"
3765 bool SmtEnginePrivate::simplifyAssertions()
3767 spendResource(options::preprocessStep());
3768 Assert(d_smt
.d_pendingPops
== 0);
3770 ScopeCounter
depth(d_simplifyAssertionsDepth
);
3772 Trace("simplify") << "SmtEnginePrivate::simplify()" << endl
;
3774 dumpAssertions("pre-nonclausal", d_assertions
);
3776 if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
3777 // Perform non-clausal simplification
3778 Chat() << "...performing nonclausal simplification..." << endl
;
3779 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3780 << "performing non-clausal simplification" << endl
;
3781 bool noConflict
= nonClausalSimplify();
3786 // We piggy-back off of the BackEdgesMap in the CircuitPropagator to
3787 // do the miplib trick.
3788 if( // check that option is on
3789 options::arithMLTrick() &&
3790 // miplib rewrites aren't safe in incremental mode
3791 ! options::incrementalSolving() &&
3792 // only useful in arith
3793 d_smt
.d_logic
.isTheoryEnabled(THEORY_ARITH
) &&
3794 // we add new assertions and need this (in practice, this
3795 // restriction only disables miplib processing during
3796 // re-simplification, which we don't expect to be useful anyway)
3797 d_realAssertionsEnd
== d_assertions
.size() ) {
3798 Chat() << "...fixing miplib encodings..." << endl
;
3799 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3800 << "looking for miplib pseudobooleans..." << endl
;
3802 TimerStat::CodeTimer
miplibTimer(d_smt
.d_stats
->d_miplibPassTime
);
3806 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3807 << "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl
;
3811 dumpAssertions("post-nonclausal", d_assertions
);
3812 Trace("smt") << "POST nonClausalSimplify" << endl
;
3813 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3815 // before ppRewrite check if only core theory for BV theory
3816 d_smt
.d_theoryEngine
->staticInitializeBVOptions(d_assertions
.ref());
3818 dumpAssertions("pre-theorypp", d_assertions
);
3820 // Theory preprocessing
3821 if (d_smt
.d_earlyTheoryPP
) {
3822 Chat() << "...doing early theory preprocessing..." << endl
;
3823 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
3824 // Call the theory preprocessors
3825 d_smt
.d_theoryEngine
->preprocessStart();
3826 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
3827 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
3828 d_assertions
.replace(i
, d_smt
.d_theoryEngine
->preprocess(d_assertions
[i
]));
3829 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
3833 dumpAssertions("post-theorypp", d_assertions
);
3834 Trace("smt") << "POST theoryPP" << endl
;
3835 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3837 // ITE simplification
3838 if(options::doITESimp() &&
3839 (d_simplifyAssertionsDepth
<= 1 || options::doITESimpOnRepeat())) {
3840 Chat() << "...doing ITE simplification..." << endl
;
3841 bool noConflict
= simpITE();
3843 Chat() << "...ITE simplification found unsat..." << endl
;
3848 dumpAssertions("post-itesimp", d_assertions
);
3849 Trace("smt") << "POST iteSimp" << endl
;
3850 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3852 // Unconstrained simplification
3853 if(options::unconstrainedSimp()) {
3854 Chat() << "...doing unconstrained simplification..." << endl
;
3855 unconstrainedSimp();
3858 dumpAssertions("post-unconstrained", d_assertions
);
3859 Trace("smt") << "POST unconstrainedSimp" << endl
;
3860 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3862 if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
3863 Chat() << "...doing another round of nonclausal simplification..." << endl
;
3864 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3865 << " doing repeated simplification" << endl
;
3866 bool noConflict
= nonClausalSimplify();
3872 dumpAssertions("post-repeatsimp", d_assertions
);
3873 Trace("smt") << "POST repeatSimp" << endl
;
3874 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
3876 } catch(TypeCheckingExceptionPrivate
& tcep
) {
3877 // Calls to this function should have already weeded out any
3878 // typechecking exceptions via (e.g.) ensureBoolean(). But a
3879 // theory could still create a new expression that isn't
3880 // well-typed, and we don't want the C++ runtime to abort our
3881 // process without any error notice.
3883 ss
<< "A bad expression was produced. Original exception follows:\n"
3885 InternalError(ss
.str().c_str());
3890 Result
SmtEngine::check() {
3891 Assert(d_fullyInited
);
3892 Assert(d_pendingPops
== 0);
3894 Trace("smt") << "SmtEngine::check()" << endl
;
3896 ResourceManager
* resourceManager
= d_private
->getResourceManager();
3898 resourceManager
->beginCall();
3900 // Only way we can be out of resource is if cumulative budget is on
3901 if (resourceManager
->cumulativeLimitOn() &&
3902 resourceManager
->out()) {
3903 Result::UnknownExplanation why
= resourceManager
->outOfResources() ?
3904 Result::RESOURCEOUT
: Result::TIMEOUT
;
3905 return Result(Result::VALIDITY_UNKNOWN
, why
, d_filename
);
3908 // Make sure the prop layer has all of the assertions
3909 Trace("smt") << "SmtEngine::check(): processing assertions" << endl
;
3910 d_private
->processAssertions();
3911 Trace("smt") << "SmtEngine::check(): done processing assertions" << endl
;
3913 // Turn off stop only for QF_LRA
3914 // TODO: Bring up in a meeting where to put this
3915 if(options::decisionStopOnly() && !options::decisionMode
.wasSetByUser() ){
3917 (not d_logic
.isQuantified() &&
3918 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
3920 if (d_private
->getIteSkolemMap().empty())
3922 options::decisionStopOnly
.set(false);
3923 d_decisionEngine
->clearStrategies();
3924 Trace("smt") << "SmtEngine::check(): turning off stop only" << endl
;
3929 TimerStat::CodeTimer
solveTimer(d_stats
->d_solveTime
);
3931 Chat() << "solving..." << endl
;
3932 Trace("smt") << "SmtEngine::check(): running check" << endl
;
3933 Result result
= d_propEngine
->checkSat();
3935 resourceManager
->endCall();
3936 Trace("limit") << "SmtEngine::check(): cumulative millis " << resourceManager
->getTimeUsage()
3937 << ", resources " << resourceManager
->getResourceUsage() << endl
;
3940 return Result(result
, d_filename
);
3943 Result
SmtEngine::quickCheck() {
3944 Assert(d_fullyInited
);
3945 Trace("smt") << "SMT quickCheck()" << endl
;
3946 return Result(Result::VALIDITY_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, d_filename
);
3950 void SmtEnginePrivate::collectSkolems(TNode n
, set
<TNode
>& skolemSet
, unordered_map
<Node
, bool, NodeHashFunction
>& cache
)
3952 unordered_map
<Node
, bool, NodeHashFunction
>::iterator it
;
3954 if (it
!= cache
.end()) {
3958 size_t sz
= n
.getNumChildren();
3960 IteSkolemMap::iterator it
= getIteSkolemMap().find(n
);
3961 if (it
!= getIteSkolemMap().end())
3963 skolemSet
.insert(n
);
3970 for (; k
< sz
; ++k
) {
3971 collectSkolems(n
[k
], skolemSet
, cache
);
3977 bool SmtEnginePrivate::checkForBadSkolems(TNode n
, TNode skolem
, unordered_map
<Node
, bool, NodeHashFunction
>& cache
)
3979 unordered_map
<Node
, bool, NodeHashFunction
>::iterator it
;
3981 if (it
!= cache
.end()) {
3982 return (*it
).second
;
3985 size_t sz
= n
.getNumChildren();
3987 IteSkolemMap::iterator it
= getIteSkolemMap().find(n
);
3989 if (it
!= getIteSkolemMap().end())
3991 if (!((*it
).first
< n
)) {
4000 for (; k
< sz
; ++k
) {
4001 if (checkForBadSkolems(n
[k
], skolem
, cache
)) {
4011 void SmtEnginePrivate::processAssertions() {
4012 TimerStat::CodeTimer
paTimer(d_smt
.d_stats
->d_processAssertionsTime
);
4013 spendResource(options::preprocessStep());
4014 Assert(d_smt
.d_fullyInited
);
4015 Assert(d_smt
.d_pendingPops
== 0);
4016 SubstitutionMap
& top_level_substs
= d_assertions
.getTopLevelSubstitutions();
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 d_preprocessingPassRegistry
.getPass("bv-gauss")->apply(&d_assertions
);
4036 if (d_assertionsProcessed
&& options::incrementalSolving()) {
4037 // TODO(b/1255): Substitutions in incremental mode should be managed with a
4038 // proper data structure.
4040 // Placeholder for storing substitutions
4041 d_assertions
.getSubstitutionsIndex() = d_assertions
.size();
4042 d_assertions
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
4045 // Add dummy assertion in last position - to be used as a
4046 // placeholder for any new assertions to get added
4047 d_assertions
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
4048 // any assertions added beyond realAssertionsEnd must NOT affect the
4049 // equisatisfiability
4050 d_realAssertionsEnd
= d_assertions
.size();
4052 // Assertions are NOT guaranteed to be rewritten by this point
4054 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-definition-expansion" << endl
;
4055 dumpAssertions("pre-definition-expansion", d_assertions
);
4057 Chat() << "expanding definitions..." << endl
;
4058 Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl
;
4059 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_definitionExpansionTime
);
4060 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4061 for(unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4062 d_assertions
.replace(i
, expandDefinitions(d_assertions
[i
], cache
));
4065 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-definition-expansion" << endl
;
4066 dumpAssertions("post-definition-expansion", d_assertions
);
4068 // save the assertions now
4071 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
) {
4072 ProofManager::currentPM()->addAssertion(d_assertions
[i
].toExpr());
4076 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4078 if (options::globalNegate())
4080 // global negation of the formula
4081 quantifiers::GlobalNegate gn
;
4082 gn
.simplify(d_assertions
.ref());
4083 d_smt
.d_globalNegation
= !d_smt
.d_globalNegation
;
4086 if( options::nlExtPurify() ){
4087 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4088 unordered_map
<Node
, Node
, NodeHashFunction
> bcache
;
4089 std::vector
< Node
> var_eq
;
4090 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4091 Node a
= d_assertions
[i
];
4092 d_assertions
.replace(i
, purifyNlTerms(a
, cache
, bcache
, var_eq
));
4093 Trace("nl-ext-purify")
4094 << "Purify : " << a
<< " -> " << d_assertions
[i
] << std::endl
;
4096 if( !var_eq
.empty() ){
4097 unsigned lastIndex
= d_assertions
.size()-1;
4098 var_eq
.insert( var_eq
.begin(), d_assertions
[lastIndex
] );
4099 d_assertions
.replace(lastIndex
, NodeManager::currentNM()->mkNode( kind::AND
, var_eq
) );
4103 if( options::ceGuidedInst() ){
4104 //register sygus conjecture pre-rewrite (motivated by solution reconstruction)
4105 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4106 d_smt
.d_theoryEngine
->getQuantifiersEngine()->getCegInstantiation()->preregisterAssertion( d_assertions
[i
] );
4110 if (options::solveRealAsInt()) {
4111 d_preprocessingPassRegistry
.getPass("real-to-int")->apply(&d_assertions
);
4114 if (options::solveIntAsBV() > 0)
4116 d_preprocessingPassRegistry
.getPass("int-to-bv")->apply(&d_assertions
);
4119 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
&&
4120 !d_smt
.d_logic
.isPure(THEORY_BV
) &&
4121 d_smt
.d_logic
.getLogicString() != "QF_UFBV" &&
4122 d_smt
.d_logic
.getLogicString() != "QF_ABV") {
4123 throw ModalException("Eager bit-blasting does not currently support theory combination. "
4124 "Note that in a QF_BV problem UF symbols can be introduced for division. "
4125 "Try --bv-div-zero-const to interpret division by zero as a constant.");
4128 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
4129 && !options::incrementalSolving())
4131 d_preprocessingPassRegistry
.getPass("bv-ackermann")->apply(&d_assertions
);
4134 if (options::bvAbstraction() && !options::incrementalSolving())
4136 d_preprocessingPassRegistry
.getPass("bv-abstraction")->apply(&d_assertions
);
4139 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4141 bool noConflict
= true;
4143 if (options::extRewPrep())
4145 d_preprocessingPassRegistry
.getPass("ext-rew-pre")->apply(&d_assertions
);
4148 // Unconstrained simplification
4149 if(options::unconstrainedSimp()) {
4150 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-unconstrained-simp" << endl
;
4151 dumpAssertions("pre-unconstrained-simp", d_assertions
);
4152 d_preprocessingPassRegistry
.getPass("rewrite")->apply(&d_assertions
);
4153 unconstrainedSimp();
4154 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-unconstrained-simp" << endl
;
4155 dumpAssertions("post-unconstrained-simp", d_assertions
);
4158 if(options::bvIntroducePow2())
4160 d_preprocessingPassRegistry
.getPass("bv-intro-pow2")->apply(&d_assertions
);
4163 if (options::unsatCores())
4165 // special rewriting pass for unsat cores, since many of the passes below
4167 d_preprocessingPassRegistry
.getPass("rewrite")->apply(&d_assertions
);
4171 d_preprocessingPassRegistry
.getPass("apply-substs")->apply(&d_assertions
);
4174 // Assertions ARE guaranteed to be rewritten by this point
4175 #ifdef CVC4_ASSERTIONS
4176 for (unsigned i
= 0; i
< d_assertions
.size(); ++i
)
4178 Assert(Rewriter::rewrite(d_assertions
[i
]) == d_assertions
[i
]);
4182 // Lift bit-vectors of size 1 to bool
4183 if (options::bitvectorToBool())
4185 d_preprocessingPassRegistry
.getPass("bv-to-bool")->apply(&d_assertions
);
4187 // Convert non-top-level Booleans to bit-vectors of size 1
4188 if (options::boolToBitvector())
4190 d_preprocessingPassRegistry
.getPass("bool-to-bv")->apply(&d_assertions
);
4192 if(options::sepPreSkolemEmp()) {
4193 d_preprocessingPassRegistry
.getPass("sep-skolem-emp")->apply(&d_assertions
);
4196 if( d_smt
.d_logic
.isQuantified() ){
4197 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-quant-preprocess" << endl
;
4199 dumpAssertions("pre-skolem-quant", d_assertions
);
4200 //remove rewrite rules, apply pre-skolemization to existential quantifiers
4201 d_preprocessingPassRegistry
.getPass("quantifiers-preprocess")
4202 ->apply(&d_assertions
);
4203 dumpAssertions("post-skolem-quant", d_assertions
);
4204 if( options::macrosQuant() ){
4205 //quantifiers macro expansion
4206 quantifiers::QuantifierMacros
qm( d_smt
.d_theoryEngine
->getQuantifiersEngine() );
4209 success
= qm
.simplify( d_assertions
.ref(), true );
4211 //finalize the definitions
4212 qm
.finalizeDefinitions();
4215 //fmf-fun : assume admissible functions, applying preprocessing reduction to FMF
4216 if( options::fmfFunWellDefined() ){
4217 quantifiers::FunDefFmf fdf
;
4218 Assert( d_smt
.d_fmfRecFunctionsDefined
!=NULL
);
4219 //must carry over current definitions (for incremental)
4220 for( context::CDList
<Node
>::const_iterator fit
= d_smt
.d_fmfRecFunctionsDefined
->begin();
4221 fit
!= d_smt
.d_fmfRecFunctionsDefined
->end(); ++fit
) {
4223 Assert( d_smt
.d_fmfRecFunctionsAbs
.find( f
)!=d_smt
.d_fmfRecFunctionsAbs
.end() );
4224 TypeNode ft
= d_smt
.d_fmfRecFunctionsAbs
[f
];
4225 fdf
.d_sorts
[f
] = ft
;
4226 std::map
< Node
, std::vector
< Node
> >::iterator fcit
= d_smt
.d_fmfRecFunctionsConcrete
.find( f
);
4227 Assert( fcit
!=d_smt
.d_fmfRecFunctionsConcrete
.end() );
4228 for( unsigned j
=0; j
<fcit
->second
.size(); j
++ ){
4229 fdf
.d_input_arg_inj
[f
].push_back( fcit
->second
[j
] );
4232 fdf
.simplify( d_assertions
.ref() );
4233 //must store new definitions (for incremental)
4234 for( unsigned i
=0; i
<fdf
.d_funcs
.size(); i
++ ){
4235 Node f
= fdf
.d_funcs
[i
];
4236 d_smt
.d_fmfRecFunctionsAbs
[f
] = fdf
.d_sorts
[f
];
4237 d_smt
.d_fmfRecFunctionsConcrete
[f
].clear();
4238 for( unsigned j
=0; j
<fdf
.d_input_arg_inj
[f
].size(); j
++ ){
4239 d_smt
.d_fmfRecFunctionsConcrete
[f
].push_back( fdf
.d_input_arg_inj
[f
][j
] );
4241 d_smt
.d_fmfRecFunctionsDefined
->push_back( f
);
4244 if (options::sygusInference())
4246 // try recast as sygus
4247 quantifiers::SygusInference si
;
4248 if (si
.simplify(d_assertions
.ref()))
4250 Trace("smt-proc") << "...converted to sygus conjecture." << std::endl
;
4253 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-quant-preprocess" << endl
;
4256 if( options::sortInference() || options::ufssFairnessMonotone() ){
4257 d_preprocessingPassRegistry
.getPass("sort-inference")->apply(&d_assertions
);
4260 if( options::pbRewrites() ){
4261 d_preprocessingPassRegistry
.getPass("pseudo-boolean-processor")
4262 ->apply(&d_assertions
);
4265 if (options::synthRrPrep())
4267 // do candidate rewrite rule synthesis
4268 d_preprocessingPassRegistry
.getPass("synth-rr")->apply(&d_assertions
);
4271 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-simplify" << endl
;
4272 dumpAssertions("pre-simplify", d_assertions
);
4273 Chat() << "simplifying assertions..." << endl
;
4274 noConflict
= simplifyAssertions();
4276 ++(d_smt
.d_stats
->d_simplifiedToFalse
);
4278 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-simplify" << endl
;
4279 dumpAssertions("post-simplify", d_assertions
);
4281 if (options::symmetryBreakerExp() && !options::incrementalSolving())
4283 // apply symmetry breaking if not in incremental mode
4284 d_preprocessingPassRegistry
.getPass("sym-break")->apply(&d_assertions
);
4287 if(options::doStaticLearning()) {
4288 d_preprocessingPassRegistry
.getPass("static-learning")
4289 ->apply(&d_assertions
);
4291 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4294 d_smt
.d_stats
->d_numAssertionsPre
+= d_assertions
.size();
4295 d_preprocessingPassRegistry
.getPass("ite-removal")->apply(&d_assertions
);
4296 // This is needed because when solving incrementally, removeITEs may introduce
4297 // skolems that were solved for earlier and thus appear in the substitution
4299 d_preprocessingPassRegistry
.getPass("apply-substs")->apply(&d_assertions
);
4300 d_smt
.d_stats
->d_numAssertionsPost
+= d_assertions
.size();
4303 dumpAssertions("pre-repeat-simplify", d_assertions
);
4304 if(options::repeatSimp()) {
4305 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-repeat-simplify" << endl
;
4306 Chat() << "re-simplifying assertions..." << endl
;
4307 ScopeCounter
depth(d_simplifyAssertionsDepth
);
4308 noConflict
&= simplifyAssertions();
4310 // Need to fix up assertion list to maintain invariants:
4311 // Let Sk be the set of Skolem variables introduced by ITE's. Let <_sk be the order in which these variables were introduced
4312 // during ite removal.
4313 // For each skolem variable sk, let iteExpr = iteMap(sk) be the ite expr mapped to by sk.
4315 // cache for expression traversal
4316 unordered_map
<Node
, bool, NodeHashFunction
> cache
;
4318 // First, find all skolems that appear in the substitution map - their associated iteExpr will need
4319 // to be moved to the main assertion set
4320 set
<TNode
> skolemSet
;
4321 SubstitutionMap::iterator pos
= top_level_substs
.begin();
4322 for (; pos
!= top_level_substs
.end(); ++pos
)
4324 collectSkolems((*pos
).first
, skolemSet
, cache
);
4325 collectSkolems((*pos
).second
, skolemSet
, cache
);
4328 // We need to ensure:
4329 // 1. iteExpr has the form (ite cond (sk = t) (sk = e))
4330 // 2. if some sk' in Sk appears in cond, t, or e, then sk' <_sk sk
4331 // If either of these is violated, we must add iteExpr as a proper assertion
4332 IteSkolemMap::iterator it
= getIteSkolemMap().begin();
4333 IteSkolemMap::iterator iend
= getIteSkolemMap().end();
4334 NodeBuilder
<> builder(kind::AND
);
4335 builder
<< d_assertions
[d_realAssertionsEnd
- 1];
4336 vector
<TNode
> toErase
;
4337 for (; it
!= iend
; ++it
) {
4338 if (skolemSet
.find((*it
).first
) == skolemSet
.end()) {
4339 TNode iteExpr
= d_assertions
[(*it
).second
];
4340 if (iteExpr
.getKind() == kind::ITE
&&
4341 iteExpr
[1].getKind() == kind::EQUAL
&&
4342 iteExpr
[1][0] == (*it
).first
&&
4343 iteExpr
[2].getKind() == kind::EQUAL
&&
4344 iteExpr
[2][0] == (*it
).first
) {
4346 bool bad
= checkForBadSkolems(iteExpr
[0], (*it
).first
, cache
);
4347 bad
= bad
|| checkForBadSkolems(iteExpr
[1][1], (*it
).first
, cache
);
4348 bad
= bad
|| checkForBadSkolems(iteExpr
[2][1], (*it
).first
, cache
);
4354 // Move this iteExpr into the main assertions
4355 builder
<< d_assertions
[(*it
).second
];
4356 d_assertions
[(*it
).second
] = NodeManager::currentNM()->mkConst
<bool>(true);
4357 toErase
.push_back((*it
).first
);
4359 if(builder
.getNumChildren() > 1) {
4360 while (!toErase
.empty()) {
4361 getIteSkolemMap().erase(toErase
.back());
4364 d_assertions
[d_realAssertionsEnd
- 1] = Rewriter::rewrite(Node(builder
));
4366 // TODO(b/1256): For some reason this is needed for some benchmarks, such as
4367 // QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
4368 d_preprocessingPassRegistry
.getPass("ite-removal")->apply(&d_assertions
);
4369 d_preprocessingPassRegistry
.getPass("apply-substs")->apply(&d_assertions
);
4370 // Assert(iteRewriteAssertionsEnd == d_assertions.size());
4372 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-repeat-simplify" << endl
;
4374 dumpAssertions("post-repeat-simplify", d_assertions
);
4376 if (options::rewriteApplyToConst())
4378 d_preprocessingPassRegistry
.getPass("apply-to-const")->apply(&d_assertions
);
4381 // begin: INVARIANT to maintain: no reordering of assertions or
4382 // introducing new ones
4383 #ifdef CVC4_ASSERTIONS
4384 unsigned iteRewriteAssertionsEnd
= d_assertions
.size();
4387 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4389 Debug("smt") << "SmtEnginePrivate::processAssertions() POST SIMPLIFICATION" << endl
;
4390 Debug("smt") << " d_assertions : " << d_assertions
.size() << endl
;
4392 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : pre-theory-preprocessing" << endl
;
4393 dumpAssertions("pre-theory-preprocessing", d_assertions
);
4395 Chat() << "theory preprocessing..." << endl
;
4396 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
4397 // Call the theory preprocessors
4398 d_smt
.d_theoryEngine
->preprocessStart();
4399 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4400 d_assertions
.replace(i
, d_smt
.d_theoryEngine
->preprocess(d_assertions
[i
]));
4403 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() : post-theory-preprocessing" << endl
;
4404 dumpAssertions("post-theory-preprocessing", d_assertions
);
4406 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
)
4408 d_preprocessingPassRegistry
.getPass("bv-eager-atoms")->apply(&d_assertions
);
4411 //notify theory engine new preprocessed assertions
4412 d_smt
.d_theoryEngine
->notifyPreprocessedAssertions( d_assertions
.ref() );
4414 // Push the formula to decision engine
4416 Chat() << "pushing to decision engine..." << endl
;
4417 Assert(iteRewriteAssertionsEnd
== d_assertions
.size());
4418 d_smt
.d_decisionEngine
->addAssertions(
4419 d_assertions
.ref(), d_realAssertionsEnd
, getIteSkolemMap());
4422 // end: INVARIANT to maintain: no reordering of assertions or
4423 // introducing new ones
4425 Trace("smt-proc") << "SmtEnginePrivate::processAssertions() end" << endl
;
4426 dumpAssertions("post-everything", d_assertions
);
4428 // Push the formula to SAT
4430 Chat() << "converting to CNF..." << endl
;
4431 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_cnfConversionTime
);
4432 for (unsigned i
= 0; i
< d_assertions
.size(); ++ i
) {
4433 Chat() << "+ " << d_assertions
[i
] << std::endl
;
4434 d_smt
.d_propEngine
->assertFormula(d_assertions
[i
]);
4438 d_assertionsProcessed
= true;
4440 d_assertions
.clear();
4441 getIteSkolemMap().clear();
4444 void SmtEnginePrivate::addFormula(TNode n
, bool inUnsatCore
, bool inInput
)
4451 Trace("smt") << "SmtEnginePrivate::addFormula(" << n
<< "), inUnsatCore = " << inUnsatCore
<< ", inInput = " << inInput
<< endl
;
4453 // Give it to proof manager
4456 // n is an input assertion
4457 if (inUnsatCore
|| options::unsatCores() || options::dumpUnsatCores() || options::checkUnsatCores() || options::fewerPreprocessingHoles()) {
4459 ProofManager::currentPM()->addCoreAssertion(n
.toExpr());
4462 // n is the result of an unknown preprocessing step, add it to dependency map to null
4463 ProofManager::currentPM()->addDependence(n
, Node::null());
4465 // rewrite rules are by default in the unsat core because
4466 // they need to be applied until saturation
4467 if(options::unsatCores() &&
4468 n
.getKind() == kind::REWRITE_RULE
){
4469 ProofManager::currentPM()->addUnsatCore(n
.toExpr());
4473 // Add the normalized formula to the queue
4474 d_assertions
.push_back(n
);
4475 //d_assertions.push_back(Rewriter::rewrite(n));
4478 void SmtEngine::ensureBoolean(const Expr
& e
)
4480 Type type
= e
.getType(options::typeChecking());
4481 Type boolType
= d_exprManager
->booleanType();
4482 if(type
!= boolType
) {
4484 ss
<< "Expected " << boolType
<< "\n"
4485 << "The assertion : " << e
<< "\n"
4486 << "Its type : " << type
;
4487 throw TypeCheckingException(e
, ss
.str());
4491 Result
SmtEngine::checkSat(const Expr
& assumption
, bool inUnsatCore
)
4493 return checkSatisfiability(assumption
, inUnsatCore
, false);
4496 Result
SmtEngine::checkSat(const vector
<Expr
>& assumptions
, bool inUnsatCore
)
4498 return checkSatisfiability(assumptions
, inUnsatCore
, false);
4501 Result
SmtEngine::query(const Expr
& assumption
, bool inUnsatCore
)
4503 Assert(!assumption
.isNull());
4504 return checkSatisfiability(assumption
, inUnsatCore
, true);
4507 Result
SmtEngine::query(const vector
<Expr
>& assumptions
, bool inUnsatCore
)
4509 return checkSatisfiability(assumptions
, inUnsatCore
, true);
4512 Result
SmtEngine::checkSatisfiability(const Expr
& expr
,
4516 return checkSatisfiability(
4517 expr
.isNull() ? vector
<Expr
>() : vector
<Expr
>{expr
},
4522 Result
SmtEngine::checkSatisfiability(const vector
<Expr
>& assumptions
,
4528 SmtScope
smts(this);
4529 finalOptionsAreSet();
4532 Trace("smt") << "SmtEngine::" << (isQuery
? "query" : "checkSat") << "("
4533 << assumptions
<< ")" << endl
;
4535 if(d_queryMade
&& !options::incrementalSolving()) {
4536 throw ModalException("Cannot make multiple queries unless "
4537 "incremental solving is enabled "
4538 "(try --incremental)");
4541 // check to see if a postsolve() is pending
4542 if(d_needPostsolve
) {
4543 d_theoryEngine
->postsolve();
4544 d_needPostsolve
= false;
4546 // Note that a query has been made
4548 // reset global negation
4549 d_globalNegation
= false;
4551 bool didInternalPush
= false;
4553 setProblemExtended(true);
4557 size_t size
= assumptions
.size();
4560 /* Assume: not (BIGAND assumptions) */
4561 d_assumptions
.push_back(
4562 d_exprManager
->mkExpr(kind::AND
, assumptions
).notExpr());
4566 /* Assume: not expr */
4567 d_assumptions
.push_back(assumptions
[0].notExpr());
4572 /* Assume: BIGAND assumptions */
4573 d_assumptions
= assumptions
;
4576 if (!d_assumptions
.empty())
4579 didInternalPush
= true;
4582 Result
r(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
4583 for (Expr e
: d_assumptions
)
4585 // Substitute out any abstract values in ex.
4586 e
= d_private
->substituteAbstractValues(Node::fromExpr(e
)).toExpr();
4587 Assert(e
.getExprManager() == d_exprManager
);
4588 // Ensure expr is type-checked at this point.
4591 /* Add assumption */
4592 if (d_assertionList
!= NULL
)
4594 d_assertionList
->push_back(e
);
4596 d_private
->addFormula(e
.getNode(), inUnsatCore
);
4599 r
= isQuery
? check().asValidityResult() : check().asSatisfiabilityResult();
4601 if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
4602 && r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
4604 r
= Result(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
4606 // flipped if we did a global negation
4607 if (d_globalNegation
)
4609 Trace("smt") << "SmtEngine::process global negate " << r
<< std::endl
;
4610 if (r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
4612 r
= Result(Result::SAT
);
4614 else if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
4616 // only if satisfaction complete
4617 if (d_logic
.isPure(THEORY_ARITH
) || d_logic
.isPure(THEORY_BV
))
4619 r
= Result(Result::UNSAT
);
4623 r
= Result(Result::SAT_UNKNOWN
, Result::UNKNOWN_REASON
);
4626 Trace("smt") << "SmtEngine::global negate returned " << r
<< std::endl
;
4629 d_needPostsolve
= true;
4631 // Dump the query if requested
4632 if (Dump
.isOn("benchmark"))
4634 size_t size
= assumptions
.size();
4635 // the expr already got dumped out if assertion-dumping is on
4636 if (isQuery
&& size
== 1)
4638 Dump("benchmark") << QueryCommand(assumptions
[0]);
4642 Dump("benchmark") << CheckSatCommand();
4646 Dump("benchmark") << CheckSatAssumingCommand(d_assumptions
,
4651 d_propEngine
->resetTrail();
4654 if (didInternalPush
)
4659 // Remember the status
4662 setProblemExtended(false);
4664 Trace("smt") << "SmtEngine::" << (isQuery
? "query" : "checkSat") << "("
4665 << assumptions
<< ") => " << r
<< endl
;
4667 // Check that SAT results generate a model correctly.
4668 if(options::checkModels()) {
4669 // TODO (#1693) check model when unknown result?
4670 if (r
.asSatisfiabilityResult().isSat() == Result::SAT
)
4675 // Check that UNSAT results generate a proof correctly.
4676 if(options::checkProofs()) {
4677 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
4678 TimerStat::CodeTimer
checkProofTimer(d_stats
->d_checkProofTime
);
4682 // Check that UNSAT results generate an unsat core correctly.
4683 if(options::checkUnsatCores()) {
4684 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
4685 TimerStat::CodeTimer
checkUnsatCoreTimer(d_stats
->d_checkUnsatCoreTime
);
4689 // Check that synthesis solutions satisfy the conjecture
4690 if (options::checkSynthSol()
4691 && r
.asSatisfiabilityResult().isSat() == Result::UNSAT
)
4693 checkSynthSolution();
4697 } catch (UnsafeInterruptException
& e
) {
4698 AlwaysAssert(d_private
->getResourceManager()->out());
4699 Result::UnknownExplanation why
= d_private
->getResourceManager()->outOfResources() ?
4700 Result::RESOURCEOUT
: Result::TIMEOUT
;
4701 return Result(Result::SAT_UNKNOWN
, why
, d_filename
);
4705 vector
<Expr
> SmtEngine::getUnsatAssumptions(void)
4707 Trace("smt") << "SMT getUnsatAssumptions()" << endl
;
4708 SmtScope
smts(this);
4709 if (!options::unsatAssumptions())
4711 throw ModalException(
4712 "Cannot get unsat assumptions when produce-unsat-assumptions option "
4715 if (d_status
.isNull()
4716 || d_status
.asSatisfiabilityResult() != Result::UNSAT
4717 || d_problemExtended
)
4719 throw RecoverableModalException(
4720 "Cannot get unsat assumptions unless immediately preceded by "
4721 "UNSAT/VALID response.");
4723 finalOptionsAreSet();
4724 if (Dump
.isOn("benchmark"))
4726 Dump("benchmark") << GetUnsatAssumptionsCommand();
4728 UnsatCore core
= getUnsatCoreInternal();
4730 for (const Expr
& e
: d_assumptions
)
4732 if (find(core
.begin(), core
.end(), e
) != core
.end()) { res
.push_back(e
); }
4737 Result
SmtEngine::checkSynth(const Expr
& e
)
4739 SmtScope
smts(this);
4740 Trace("smt") << "Check synth: " << e
<< std::endl
;
4741 Trace("smt-synth") << "Check synthesis conjecture: " << e
<< std::endl
;
4742 return checkSatisfiability(e
, true, false);
4745 Result
SmtEngine::assertFormula(const Expr
& ex
, bool inUnsatCore
)
4747 Assert(ex
.getExprManager() == d_exprManager
);
4748 SmtScope
smts(this);
4749 finalOptionsAreSet();
4752 Trace("smt") << "SmtEngine::assertFormula(" << ex
<< ")" << endl
;
4754 if (Dump
.isOn("raw-benchmark")) {
4755 Dump("raw-benchmark") << AssertCommand(ex
);
4758 // Substitute out any abstract values in ex
4759 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4762 if(d_assertionList
!= NULL
) {
4763 d_assertionList
->push_back(e
);
4765 d_private
->addFormula(e
.getNode(), inUnsatCore
);
4766 return quickCheck().asValidityResult();
4767 }/* SmtEngine::assertFormula() */
4769 Node
SmtEngine::postprocess(TNode node
, TypeNode expectedType
) const {
4773 Expr
SmtEngine::simplify(const Expr
& ex
)
4775 Assert(ex
.getExprManager() == d_exprManager
);
4776 SmtScope
smts(this);
4777 finalOptionsAreSet();
4779 Trace("smt") << "SMT simplify(" << ex
<< ")" << endl
;
4781 if(Dump
.isOn("benchmark")) {
4782 Dump("benchmark") << SimplifyCommand(ex
);
4785 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4786 if( options::typeChecking() ) {
4787 e
.getType(true); // ensure expr is type-checked at this point
4790 // Make sure all preprocessing is done
4791 d_private
->processAssertions();
4792 Node n
= d_private
->simplify(Node::fromExpr(e
));
4793 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
4797 Expr
SmtEngine::expandDefinitions(const Expr
& ex
)
4799 d_private
->spendResource(options::preprocessStep());
4801 Assert(ex
.getExprManager() == d_exprManager
);
4802 SmtScope
smts(this);
4803 finalOptionsAreSet();
4805 Trace("smt") << "SMT expandDefinitions(" << ex
<< ")" << endl
;
4807 // Substitute out any abstract values in ex.
4808 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4809 if(options::typeChecking()) {
4810 // Ensure expr is type-checked at this point.
4813 if(Dump
.isOn("benchmark")) {
4814 Dump("benchmark") << ExpandDefinitionsCommand(e
);
4816 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4817 Node n
= d_private
->expandDefinitions(Node::fromExpr(e
), cache
, /* expandOnly = */ true);
4818 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
4823 // TODO(#1108): Simplify the error reporting of this method.
4824 Expr
SmtEngine::getValue(const Expr
& ex
) const
4826 Assert(ex
.getExprManager() == d_exprManager
);
4827 SmtScope
smts(this);
4829 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
4830 if(Dump
.isOn("benchmark")) {
4831 Dump("benchmark") << GetValueCommand(ex
);
4834 if(!options::produceModels()) {
4836 "Cannot get value when produce-models options is off.";
4837 throw ModalException(msg
);
4839 if(d_status
.isNull() ||
4840 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
4841 d_problemExtended
) {
4843 "Cannot get value unless immediately preceded by SAT/INVALID or UNKNOWN response.";
4844 throw RecoverableModalException(msg
);
4847 // Substitute out any abstract values in ex.
4848 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4850 // Ensure expr is type-checked at this point.
4851 e
.getType(options::typeChecking());
4853 // do not need to apply preprocessing substitutions (should be recorded
4854 // in model already)
4856 Node n
= Node::fromExpr(e
);
4857 Trace("smt") << "--- getting value of " << n
<< endl
;
4858 TypeNode expectedType
= n
.getType();
4860 // Expand, then normalize
4861 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4862 n
= d_private
->expandDefinitions(n
, cache
);
4863 // There are two ways model values for terms are computed (for historical
4864 // reasons). One way is that used in check-model; the other is that
4865 // used by the Model classes. It's not clear to me exactly how these
4866 // two are different, but they need to be unified. This ugly hack here
4867 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
4870 if(!n
.getType().isFunction()) {
4871 n
= Rewriter::rewrite(n
);
4874 Trace("smt") << "--- getting value of " << n
<< endl
;
4875 TheoryModel
* m
= d_theoryEngine
->getModel();
4878 resultNode
= m
->getValue(n
);
4880 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
4881 resultNode
= postprocess(resultNode
, expectedType
);
4882 Trace("smt") << "--- model-post returned " << resultNode
<< endl
;
4883 Trace("smt") << "--- model-post returned " << resultNode
.getType() << endl
;
4884 Trace("smt") << "--- model-post expected " << expectedType
<< endl
;
4886 // type-check the result we got
4887 Assert(resultNode
.isNull() || resultNode
.getType().isSubtypeOf(expectedType
),
4888 "Run with -t smt for details.");
4890 // ensure it's a constant
4891 Assert(resultNode
.getKind() == kind::LAMBDA
|| resultNode
.isConst());
4893 if(options::abstractValues() && resultNode
.getType().isArray()) {
4894 resultNode
= d_private
->mkAbstractValue(resultNode
);
4895 Trace("smt") << "--- abstract value >> " << resultNode
<< endl
;
4898 return resultNode
.toExpr();
4901 bool SmtEngine::addToAssignment(const Expr
& ex
) {
4902 SmtScope
smts(this);
4903 finalOptionsAreSet();
4905 // Substitute out any abstract values in ex
4906 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
4907 Type type
= e
.getType(options::typeChecking());
4909 PrettyCheckArgument(
4910 type
.isBoolean(), e
,
4911 "expected Boolean-typed variable or function application "
4912 "in addToAssignment()" );
4913 Node n
= e
.getNode();
4914 // must be an APPLY of a zero-ary defined function, or a variable
4915 PrettyCheckArgument(
4916 ( ( n
.getKind() == kind::APPLY
&&
4917 ( d_definedFunctions
->find(n
.getOperator()) !=
4918 d_definedFunctions
->end() ) &&
4919 n
.getNumChildren() == 0 ) ||
4921 "expected variable or defined-function application "
4922 "in addToAssignment(),\ngot %s", e
.toString().c_str() );
4923 if(!options::produceAssignments()) {
4926 if(d_assignments
== NULL
) {
4927 d_assignments
= new(true) AssignmentSet(d_context
);
4929 d_assignments
->insert(n
);
4934 // TODO(#1108): Simplify the error reporting of this method.
4935 vector
<pair
<Expr
, Expr
>> SmtEngine::getAssignment()
4937 Trace("smt") << "SMT getAssignment()" << endl
;
4938 SmtScope
smts(this);
4939 finalOptionsAreSet();
4940 if(Dump
.isOn("benchmark")) {
4941 Dump("benchmark") << GetAssignmentCommand();
4943 if(!options::produceAssignments()) {
4945 "Cannot get the current assignment when "
4946 "produce-assignments option is off.";
4947 throw ModalException(msg
);
4949 if(d_status
.isNull() ||
4950 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
4951 d_problemExtended
) {
4953 "Cannot get the current assignment unless immediately "
4954 "preceded by SAT/INVALID or UNKNOWN response.";
4955 throw RecoverableModalException(msg
);
4958 vector
<pair
<Expr
,Expr
>> res
;
4959 if (d_assignments
!= nullptr)
4961 TypeNode boolType
= d_nodeManager
->booleanType();
4962 TheoryModel
* m
= d_theoryEngine
->getModel();
4963 for (AssignmentSet::key_iterator i
= d_assignments
->key_begin(),
4964 iend
= d_assignments
->key_end();
4969 Assert(as
.getType() == boolType
);
4971 Trace("smt") << "--- getting value of " << as
<< endl
;
4973 // Expand, then normalize
4974 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
4975 Node n
= d_private
->expandDefinitions(as
, cache
);
4976 n
= Rewriter::rewrite(n
);
4978 Trace("smt") << "--- getting value of " << n
<< endl
;
4982 resultNode
= m
->getValue(n
);
4985 // type-check the result we got
4986 Assert(resultNode
.isNull() || resultNode
.getType() == boolType
);
4988 // ensure it's a constant
4989 Assert(resultNode
.isConst());
4991 Assert(as
.getKind() == kind::APPLY
|| as
.isVar());
4992 Assert(as
.getKind() != kind::APPLY
|| as
.getNumChildren() == 0);
4993 res
.emplace_back(as
.toExpr(), resultNode
.toExpr());
4999 void SmtEngine::addToModelCommandAndDump(const Command
& c
, uint32_t flags
, bool userVisible
, const char* dumpTag
) {
5000 Trace("smt") << "SMT addToModelCommandAndDump(" << c
<< ")" << endl
;
5001 SmtScope
smts(this);
5002 // If we aren't yet fully inited, the user might still turn on
5003 // produce-models. So let's keep any commands around just in
5004 // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
5005 // sort "U" in QF_UF before setLogic() is run and we still want to
5006 // support finding card(U) with --finite-model-find, and (2) to
5007 // decouple SmtEngine and ExprManager if the user does a few
5008 // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
5009 // and expects to find their cardinalities in the model.
5010 if(/* userVisible && */
5011 (!d_fullyInited
|| options::produceModels()) &&
5012 (flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
5014 if(flags
& ExprManager::VAR_FLAG_GLOBAL
) {
5015 d_modelGlobalCommands
.push_back(c
.clone());
5017 d_modelCommands
->push_back(c
.clone());
5020 if(Dump
.isOn(dumpTag
)) {
5024 d_dumpCommands
.push_back(c
.clone());
5029 // TODO(#1108): Simplify the error reporting of this method.
5030 Model
* SmtEngine::getModel() {
5031 Trace("smt") << "SMT getModel()" << endl
;
5032 SmtScope
smts(this);
5034 finalOptionsAreSet();
5036 if(Dump
.isOn("benchmark")) {
5037 Dump("benchmark") << GetModelCommand();
5040 if (!options::assignFunctionValues())
5043 "Cannot get the model when --assign-function-values is false.";
5044 throw RecoverableModalException(msg
);
5047 if(d_status
.isNull() ||
5048 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
5049 d_problemExtended
) {
5051 "Cannot get the current model unless immediately "
5052 "preceded by SAT/INVALID or UNKNOWN response.";
5053 throw RecoverableModalException(msg
);
5055 if(!options::produceModels()) {
5057 "Cannot get model when produce-models options is off.";
5058 throw ModalException(msg
);
5060 TheoryModel
* m
= d_theoryEngine
->getModel();
5061 m
->d_inputName
= d_filename
;
5065 std::pair
<Expr
, Expr
> SmtEngine::getSepHeapAndNilExpr(void)
5067 if (!d_logic
.isTheoryEnabled(THEORY_SEP
))
5070 "Cannot obtain separation logic expressions if not using the "
5071 "separation logic theory.";
5072 throw RecoverableModalException(msg
);
5074 NodeManagerScope
nms(d_nodeManager
);
5077 Model
* m
= getModel();
5078 if (m
->getHeapModel(heap
, nil
))
5080 return std::make_pair(heap
, nil
);
5083 "SmtEngine::getSepHeapAndNilExpr(): failed to obtain heap/nil "
5084 "expressions from theory model.");
5087 Expr
SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first
; }
5089 Expr
SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second
; }
5091 UnsatCore
SmtEngine::getUnsatCoreInternal()
5094 if (!options::unsatCores())
5096 throw ModalException(
5097 "Cannot get an unsat core when produce-unsat-cores option is off.");
5099 if (d_status
.isNull() || d_status
.asSatisfiabilityResult() != Result::UNSAT
5100 || d_problemExtended
)
5102 throw RecoverableModalException(
5103 "Cannot get an unsat core unless immediately preceded by UNSAT/VALID "
5107 d_proofManager
->traceUnsatCore(); // just to trigger core creation
5108 return UnsatCore(this, d_proofManager
->extractUnsatCore());
5109 #else /* IS_PROOFS_BUILD */
5110 throw ModalException(
5111 "This build of CVC4 doesn't have proof support (required for unsat "
5113 #endif /* IS_PROOFS_BUILD */
5116 void SmtEngine::checkUnsatCore() {
5117 Assert(options::unsatCores(), "cannot check unsat core if unsat cores are turned off");
5119 Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl
;
5120 UnsatCore core
= getUnsatCore();
5122 SmtEngine
coreChecker(d_exprManager
);
5123 coreChecker
.setLogic(getLogicInfo());
5126 std::vector
<Command
*>::const_iterator itg
= d_defineCommands
.begin();
5127 for (; itg
!= d_defineCommands
.end(); ++itg
) {
5128 (*itg
)->invoke(&coreChecker
);
5132 Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions (size == " << core
.size() << ")" << endl
;
5133 for(UnsatCore::iterator i
= core
.begin(); i
!= core
.end(); ++i
) {
5134 Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
<< endl
;
5135 coreChecker
.assertFormula(*i
);
5137 const bool checkUnsatCores
= options::checkUnsatCores();
5140 options::checkUnsatCores
.set(false);
5141 options::checkProofs
.set(false);
5142 r
= coreChecker
.checkSat();
5144 options::checkUnsatCores
.set(checkUnsatCores
);
5147 Notice() << "SmtEngine::checkUnsatCore(): result is " << r
<< endl
;
5148 if(r
.asSatisfiabilityResult().isUnknown()) {
5149 InternalError("SmtEngine::checkUnsatCore(): could not check core result unknown.");
5152 if(r
.asSatisfiabilityResult().isSat()) {
5153 InternalError("SmtEngine::checkUnsatCore(): produced core was satisfiable.");
5157 void SmtEngine::checkModel(bool hardFailure
) {
5158 // --check-model implies --produce-assertions, which enables the
5159 // assertion list, so we should be ok.
5160 Assert(d_assertionList
!= NULL
, "don't have an assertion list to check in SmtEngine::checkModel()");
5162 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
5164 // Throughout, we use Notice() to give diagnostic output.
5166 // If this function is running, the user gave --check-model (or equivalent),
5167 // and if Notice() is on, the user gave --verbose (or equivalent).
5169 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
5170 TheoryModel
* m
= d_theoryEngine
->getModel();
5172 // check-model is not guaranteed to succeed if approximate values were used
5173 if (m
->hasApproximations())
5176 << "WARNING: running check-model on a model with approximate values..."
5180 // Check individual theory assertions
5181 d_theoryEngine
->checkTheoryAssertionsWithModel(hardFailure
);
5186 // We have a "fake context" for the substitution map (we don't need it
5187 // to be context-dependent)
5188 context::Context fakeContext
;
5189 SubstitutionMap
substitutions(&fakeContext
, /* substituteUnderQuantifiers = */ false);
5191 for(size_t k
= 0; k
< m
->getNumCommands(); ++k
) {
5192 const DeclareFunctionCommand
* c
= dynamic_cast<const DeclareFunctionCommand
*>(m
->getCommand(k
));
5193 Notice() << "SmtEngine::checkModel(): model command " << k
<< " : " << m
->getCommand(k
) << endl
;
5195 // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
5196 Notice() << "SmtEngine::checkModel(): skipping..." << endl
;
5198 // We have a DECLARE-FUN:
5200 // We'll first do some checks, then add to our substitution map
5201 // the mapping: function symbol |-> value
5203 Expr func
= c
->getFunction();
5204 Node val
= m
->getValue(func
);
5206 Notice() << "SmtEngine::checkModel(): adding substitution: " << func
<< " |-> " << val
<< endl
;
5208 // (1) if the value is a lambda, ensure the lambda doesn't contain the
5209 // function symbol (since then the definition is recursive)
5210 if (val
.getKind() == kind::LAMBDA
) {
5211 // first apply the model substitutions we have so far
5212 Debug("boolean-terms") << "applying subses to " << val
[1] << endl
;
5213 Node n
= substitutions
.apply(val
[1]);
5214 Debug("boolean-terms") << "++ got " << n
<< endl
;
5215 // now check if n contains func by doing a substitution
5216 // [func->func2] and checking equality of the Nodes.
5217 // (this just a way to check if func is in n.)
5218 SubstitutionMap
subs(&fakeContext
);
5219 Node func2
= NodeManager::currentNM()->mkSkolem("", TypeNode::fromType(func
.getType()), "", NodeManager::SKOLEM_NO_NOTIFY
);
5220 subs
.addSubstitution(func
, func2
);
5221 if(subs
.apply(n
) != n
) {
5222 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED IN TERMS OF ITSELF ***" << endl
;
5224 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5225 << "considering model value for " << func
<< endl
5226 << "body of lambda is: " << val
<< endl
;
5228 ss
<< "body substitutes to: " << n
<< endl
;
5230 ss
<< "so " << func
<< " is defined in terms of itself." << endl
5231 << "Run with `--check-models -v' for additional diagnostics.";
5232 InternalError(ss
.str());
5236 // (2) check that the value is actually a value
5237 else if (!val
.isConst()) {
5238 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT A CONSTANT ***" << endl
;
5240 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5241 << "model value for " << func
<< endl
5242 << " is " << val
<< endl
5243 << "and that is not a constant (.isConst() == false)." << endl
5244 << "Run with `--check-models -v' for additional diagnostics.";
5245 InternalError(ss
.str());
5248 // (3) check that it's the correct (sub)type
5249 // This was intended to be a more general check, but for now we can't do that because
5250 // e.g. "1" is an INT, which isn't a subrange type [1..10] (etc.).
5251 else if(func
.getType().isInteger() && !val
.getType().isInteger()) {
5252 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT CORRECT TYPE ***" << endl
;
5254 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5255 << "model value for " << func
<< endl
5256 << " is " << val
<< endl
5257 << "value type is " << val
.getType() << endl
5258 << "should be of type " << func
.getType() << endl
5259 << "Run with `--check-models -v' for additional diagnostics.";
5260 InternalError(ss
.str());
5263 // (4) checks complete, add the substitution
5264 Debug("boolean-terms") << "cm: adding subs " << func
<< " :=> " << val
<< endl
;
5265 substitutions
.addSubstitution(func
, val
);
5269 // Now go through all our user assertions checking if they're satisfied.
5270 for(AssertionList::const_iterator i
= d_assertionList
->begin(); i
!= d_assertionList
->end(); ++i
) {
5271 Notice() << "SmtEngine::checkModel(): checking assertion " << *i
<< endl
;
5272 Node n
= Node::fromExpr(*i
);
5274 // Apply any define-funs from the problem.
5276 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
5277 n
= d_private
->expandDefinitions(n
, cache
);
5279 Notice() << "SmtEngine::checkModel(): -- expands to " << n
<< endl
;
5281 // Apply our model value substitutions.
5282 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
5283 n
= substitutions
.apply(n
);
5284 Debug("boolean-terms") << "++ got " << n
<< endl
;
5285 Notice() << "SmtEngine::checkModel(): -- substitutes to " << n
<< endl
;
5287 if( n
.getKind() != kind::REWRITE_RULE
){
5288 // In case it's a quantifier (or contains one), look up its value before
5289 // simplifying, or the quantifier might be irreparably altered.
5291 Notice() << "SmtEngine::checkModel(): -- get value : " << n
<< std::endl
;
5293 // Note this "skip" is done here, rather than above. This is
5294 // because (1) the quantifier could in principle simplify to false,
5295 // which should be reported, and (2) checking for the quantifier
5296 // above, before simplification, doesn't catch buried quantifiers
5297 // anyway (those not at the top-level).
5298 Notice() << "SmtEngine::checkModel(): -- skipping rewrite-rules assertion"
5303 // Simplify the result.
5304 n
= d_private
->simplify(n
);
5305 Notice() << "SmtEngine::checkModel(): -- simplifies to " << n
<< endl
;
5307 // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
5308 n
= d_private
->d_iteRemover
.replace(n
);
5309 Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n
<< endl
;
5311 // Apply our model value substitutions (again), as things may have been simplified.
5312 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
5313 n
= substitutions
.apply(n
);
5314 Debug("boolean-terms") << "++ got " << n
<< endl
;
5315 Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n
<< endl
;
5317 // As a last-ditch effort, ask model to simplify it.
5318 // Presently, this is only an issue for quantifiers, which can have a value
5319 // but don't show up in our substitution map above.
5321 Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n
<< endl
;
5323 if( d_logic
.isQuantified() ){
5324 // AJR: since quantified formulas are not checkable, we assign them to true/false based on the satisfying assignment.
5325 // however, quantified formulas can be modified during preprocess, so they may not correspond to those in the satisfying assignment.
5326 // hence we use a relaxed version of check model here.
5327 // this is necessary until preprocessing passes explicitly record how they rewrite quantified formulas
5328 if( hardFailure
&& !n
.isConst() && n
.getKind() != kind::LAMBDA
){
5329 Notice() << "SmtEngine::checkModel(): -- relax check model wrt quantified formulas..." << endl
;
5330 AlwaysAssert( quantifiers::QuantifiersRewriter::containsQuantifiers( n
) );
5331 Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified assertion : " << n
<< endl
;
5335 AlwaysAssert(!hardFailure
|| n
.isConst() || n
.getKind() == kind::LAMBDA
);
5337 // The result should be == true.
5338 if(n
!= NodeManager::currentNM()->mkConst(true)) {
5339 Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
5342 ss
<< "SmtEngine::checkModel(): "
5343 << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
5344 << "assertion: " << *i
<< endl
5345 << "simplifies to: " << n
<< endl
5346 << "expected `true'." << endl
5347 << "Run with `--check-models -v' for additional diagnostics.";
5349 InternalError(ss
.str());
5351 Warning() << ss
.str() << endl
;
5355 Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl
;
5358 void SmtEngine::checkSynthSolution()
5360 NodeManager
* nm
= NodeManager::currentNM();
5361 Notice() << "SmtEngine::checkSynthSolution(): checking synthesis solution" << endl
;
5362 map
<Node
, Node
> sol_map
;
5363 /* Get solutions and build auxiliary vectors for substituting */
5364 d_theoryEngine
->getSynthSolutions(sol_map
);
5365 if (sol_map
.empty())
5367 Trace("check-synth-sol") << "No solution to check!\n";
5370 Trace("check-synth-sol") << "Got solution map:\n";
5371 std::vector
<Node
> function_vars
, function_sols
;
5372 for (const auto& pair
: sol_map
)
5374 Trace("check-synth-sol") << pair
.first
<< " --> " << pair
.second
<< "\n";
5375 function_vars
.push_back(pair
.first
);
5376 function_sols
.push_back(pair
.second
);
5378 Trace("check-synth-sol") << "Starting new SMT Engine\n";
5379 /* Start new SMT engine to check solutions */
5380 SmtEngine
solChecker(d_exprManager
);
5381 solChecker
.setLogic(getLogicInfo());
5382 setOption("check-synth-sol", SExpr("false"));
5384 Trace("check-synth-sol") << "Retrieving assertions\n";
5385 // Build conjecture from original assertions
5386 if (d_assertionList
== NULL
)
5388 Trace("check-synth-sol") << "No assertions to check\n";
5391 for (AssertionList::const_iterator i
= d_assertionList
->begin();
5392 i
!= d_assertionList
->end();
5395 Notice() << "SmtEngine::checkSynthSolution(): checking assertion " << *i
<< endl
;
5396 Trace("check-synth-sol") << "Retrieving assertion " << *i
<< "\n";
5397 Node conj
= Node::fromExpr(*i
);
5398 // Apply any define-funs from the problem.
5400 unordered_map
<Node
, Node
, NodeHashFunction
> cache
;
5401 conj
= d_private
->expandDefinitions(conj
, cache
);
5403 Notice() << "SmtEngine::checkSynthSolution(): -- expands to " << conj
<< endl
;
5404 Trace("check-synth-sol") << "Expanded assertion " << conj
<< "\n";
5405 if (conj
.getKind() != kind::FORALL
)
5407 Trace("check-synth-sol") << "Not a checkable assertion.\n";
5411 // Apply solution map to conjecture body
5413 /* Whether property is quantifier free */
5414 if (conj
[1].getKind() != kind::EXISTS
)
5416 conjBody
= conj
[1].substitute(function_vars
.begin(),
5417 function_vars
.end(),
5418 function_sols
.begin(),
5419 function_sols
.end());
5423 conjBody
= conj
[1][1].substitute(function_vars
.begin(),
5424 function_vars
.end(),
5425 function_sols
.begin(),
5426 function_sols
.end());
5428 /* Skolemize property */
5429 std::vector
<Node
> vars
, skos
;
5430 for (unsigned j
= 0, size
= conj
[1][0].getNumChildren(); j
< size
; ++j
)
5432 vars
.push_back(conj
[1][0][j
]);
5433 std::stringstream ss
;
5435 skos
.push_back(nm
->mkSkolem(ss
.str(), conj
[1][0][j
].getType()));
5436 Trace("check-synth-sol") << "\tSkolemizing " << conj
[1][0][j
] << " to "
5437 << skos
.back() << "\n";
5439 conjBody
= conjBody
.substitute(
5440 vars
.begin(), vars
.end(), skos
.begin(), skos
.end());
5442 Notice() << "SmtEngine::checkSynthSolution(): -- body substitutes to "
5443 << conjBody
<< endl
;
5444 Trace("check-synth-sol") << "Substituted body of assertion to " << conjBody
5446 solChecker
.assertFormula(conjBody
.toExpr());
5447 Result r
= solChecker
.checkSat();
5448 Notice() << "SmtEngine::checkSynthSolution(): result is " << r
<< endl
;
5449 Trace("check-synth-sol") << "Satsifiability check: " << r
<< "\n";
5450 if (r
.asSatisfiabilityResult().isUnknown())
5453 "SmtEngine::checkSynthSolution(): could not check solution, result "
5456 else if (r
.asSatisfiabilityResult().isSat())
5459 "SmtEngine::checkSynthSolution(): produced solution leads to "
5460 "satisfiable negated conjecture.");
5462 solChecker
.resetAssertions();
5466 // TODO(#1108): Simplify the error reporting of this method.
5467 UnsatCore
SmtEngine::getUnsatCore() {
5468 Trace("smt") << "SMT getUnsatCore()" << endl
;
5469 SmtScope
smts(this);
5470 finalOptionsAreSet();
5471 if(Dump
.isOn("benchmark")) {
5472 Dump("benchmark") << GetUnsatCoreCommand();
5474 return getUnsatCoreInternal();
5477 // TODO(#1108): Simplify the error reporting of this method.
5478 const Proof
& SmtEngine::getProof()
5480 Trace("smt") << "SMT getProof()" << endl
;
5481 SmtScope
smts(this);
5482 finalOptionsAreSet();
5483 if(Dump
.isOn("benchmark")) {
5484 Dump("benchmark") << GetProofCommand();
5487 if(!options::proof()) {
5488 throw ModalException("Cannot get a proof when produce-proofs option is off.");
5490 if(d_status
.isNull() ||
5491 d_status
.asSatisfiabilityResult() != Result::UNSAT
||
5492 d_problemExtended
) {
5493 throw RecoverableModalException(
5494 "Cannot get a proof unless immediately preceded by UNSAT/VALID "
5498 return ProofManager::getProof(this);
5499 #else /* IS_PROOFS_BUILD */
5500 throw ModalException("This build of CVC4 doesn't have proof support.");
5501 #endif /* IS_PROOFS_BUILD */
5504 void SmtEngine::printInstantiations( std::ostream
& out
) {
5505 SmtScope
smts(this);
5506 if( options::instFormatMode()==INST_FORMAT_MODE_SZS
){
5507 out
<< "% SZS output start Proof for " << d_filename
.c_str() << std::endl
;
5509 if( d_theoryEngine
){
5510 d_theoryEngine
->printInstantiations( out
);
5514 if( options::instFormatMode()==INST_FORMAT_MODE_SZS
){
5515 out
<< "% SZS output end Proof for " << d_filename
.c_str() << std::endl
;
5519 void SmtEngine::printSynthSolution( std::ostream
& out
) {
5520 SmtScope
smts(this);
5521 if( d_theoryEngine
){
5522 d_theoryEngine
->printSynthSolution( out
);
5528 void SmtEngine::getSynthSolutions(std::map
<Expr
, Expr
>& sol_map
)
5530 SmtScope
smts(this);
5531 map
<Node
, Node
> sol_mapn
;
5532 Assert(d_theoryEngine
!= nullptr);
5533 d_theoryEngine
->getSynthSolutions(sol_mapn
);
5534 for (std::pair
<const Node
, Node
>& s
: sol_mapn
)
5536 sol_map
[s
.first
.toExpr()] = s
.second
.toExpr();
5540 Expr
SmtEngine::doQuantifierElimination(const Expr
& e
, bool doFull
, bool strict
)
5542 SmtScope
smts(this);
5543 if(!d_logic
.isPure(THEORY_ARITH
) && strict
){
5544 Warning() << "Unexpected logic for quantifier elimination " << d_logic
<< endl
;
5546 Trace("smt-qe") << "Do quantifier elimination " << e
<< std::endl
;
5547 Node n_e
= Node::fromExpr( e
);
5548 if (n_e
.getKind() != kind::EXISTS
&& n_e
.getKind() != kind::FORALL
)
5550 throw ModalException(
5551 "Expecting a quantified formula as argument to get-qe.");
5553 //tag the quantified formula with the quant-elim attribute
5554 TypeNode t
= NodeManager::currentNM()->booleanType();
5555 Node n_attr
= NodeManager::currentNM()->mkSkolem("qe", t
, "Auxiliary variable for qe attr.");
5556 std::vector
< Node
> node_values
;
5557 d_theoryEngine
->setUserAttribute( doFull
? "quant-elim" : "quant-elim-partial", n_attr
, node_values
, "");
5558 n_attr
= NodeManager::currentNM()->mkNode(kind::INST_ATTRIBUTE
, n_attr
);
5559 n_attr
= NodeManager::currentNM()->mkNode(kind::INST_PATTERN_LIST
, n_attr
);
5560 std::vector
< Node
> e_children
;
5561 e_children
.push_back( n_e
[0] );
5562 e_children
.push_back(n_e
.getKind() == kind::EXISTS
? n_e
[1]
5564 e_children
.push_back( n_attr
);
5565 Node nn_e
= NodeManager::currentNM()->mkNode( kind::EXISTS
, e_children
);
5566 Trace("smt-qe-debug") << "Query for quantifier elimination : " << nn_e
<< std::endl
;
5567 Assert( nn_e
.getNumChildren()==3 );
5568 Result r
= checkSatisfiability(nn_e
.toExpr(), true, true);
5569 Trace("smt-qe") << "Query returned " << r
<< std::endl
;
5570 if(r
.asSatisfiabilityResult().isSat() != Result::UNSAT
) {
5571 if( r
.asSatisfiabilityResult().isSat() != Result::SAT
&& doFull
){
5573 ss
<< "While performing quantifier elimination, unexpected result : " << r
<< " for query.";
5574 InternalError(ss
.str().c_str());
5576 std::vector
< Node
> inst_qs
;
5577 d_theoryEngine
->getInstantiatedQuantifiedFormulas( inst_qs
);
5578 Assert( inst_qs
.size()<=1 );
5580 if( inst_qs
.size()==1 ){
5581 Node top_q
= inst_qs
[0];
5582 //Node top_q = Rewriter::rewrite( nn_e ).negate();
5583 Assert( top_q
.getKind()==kind::FORALL
);
5584 Trace("smt-qe") << "Get qe for " << top_q
<< std::endl
;
5585 ret_n
= d_theoryEngine
->getInstantiatedConjunction( top_q
);
5586 Trace("smt-qe") << "Returned : " << ret_n
<< std::endl
;
5587 if (n_e
.getKind() == kind::EXISTS
)
5589 ret_n
= Rewriter::rewrite(ret_n
.negate());
5592 ret_n
= NodeManager::currentNM()->mkConst(n_e
.getKind() != kind::EXISTS
);
5594 // do extended rewrite to minimize the size of the formula aggressively
5595 theory::quantifiers::ExtendedRewriter
extr(true);
5596 ret_n
= extr
.extendedRewrite(ret_n
);
5597 return ret_n
.toExpr();
5599 return NodeManager::currentNM()
5600 ->mkConst(n_e
.getKind() == kind::EXISTS
)
5605 void SmtEngine::getInstantiatedQuantifiedFormulas( std::vector
< Expr
>& qs
) {
5606 SmtScope
smts(this);
5607 if( d_theoryEngine
){
5608 std::vector
< Node
> qs_n
;
5609 d_theoryEngine
->getInstantiatedQuantifiedFormulas( qs_n
);
5610 for( unsigned i
=0; i
<qs_n
.size(); i
++ ){
5611 qs
.push_back( qs_n
[i
].toExpr() );
5618 void SmtEngine::getInstantiations( Expr q
, std::vector
< Expr
>& insts
) {
5619 SmtScope
smts(this);
5620 if( d_theoryEngine
){
5621 std::vector
< Node
> insts_n
;
5622 d_theoryEngine
->getInstantiations( Node::fromExpr( q
), insts_n
);
5623 for( unsigned i
=0; i
<insts_n
.size(); i
++ ){
5624 insts
.push_back( insts_n
[i
].toExpr() );
5631 void SmtEngine::getInstantiationTermVectors( Expr q
, std::vector
< std::vector
< Expr
> >& tvecs
) {
5632 SmtScope
smts(this);
5633 Assert(options::trackInstLemmas());
5634 if( d_theoryEngine
){
5635 std::vector
< std::vector
< Node
> > tvecs_n
;
5636 d_theoryEngine
->getInstantiationTermVectors( Node::fromExpr( q
), tvecs_n
);
5637 for( unsigned i
=0; i
<tvecs_n
.size(); i
++ ){
5638 std::vector
< Expr
> tvec
;
5639 for( unsigned j
=0; j
<tvecs_n
[i
].size(); j
++ ){
5640 tvec
.push_back( tvecs_n
[i
][j
].toExpr() );
5642 tvecs
.push_back( tvec
);
5649 vector
<Expr
> SmtEngine::getAssertions() {
5650 SmtScope
smts(this);
5651 finalOptionsAreSet();
5653 if(Dump
.isOn("benchmark")) {
5654 Dump("benchmark") << GetAssertionsCommand();
5656 Trace("smt") << "SMT getAssertions()" << endl
;
5657 if(!options::produceAssertions()) {
5659 "Cannot query the current assertion list when not in produce-assertions mode.";
5660 throw ModalException(msg
);
5662 Assert(d_assertionList
!= NULL
);
5663 // copy the result out
5664 return vector
<Expr
>(d_assertionList
->begin(), d_assertionList
->end());
5667 void SmtEngine::push()
5669 SmtScope
smts(this);
5670 finalOptionsAreSet();
5672 Trace("smt") << "SMT push()" << endl
;
5673 d_private
->notifyPush();
5674 d_private
->processAssertions();
5675 if(Dump
.isOn("benchmark")) {
5676 Dump("benchmark") << PushCommand();
5678 if(!options::incrementalSolving()) {
5679 throw ModalException("Cannot push when not solving incrementally (use --incremental)");
5682 // check to see if a postsolve() is pending
5683 if(d_needPostsolve
) {
5684 d_theoryEngine
->postsolve();
5685 d_needPostsolve
= false;
5688 // The problem isn't really "extended" yet, but this disallows
5689 // get-model after a push, simplifying our lives somewhat and
5690 // staying symmtric with pop.
5691 setProblemExtended(true);
5693 d_userLevels
.push_back(d_userContext
->getLevel());
5695 Trace("userpushpop") << "SmtEngine: pushed to level "
5696 << d_userContext
->getLevel() << endl
;
5699 void SmtEngine::pop() {
5700 SmtScope
smts(this);
5701 finalOptionsAreSet();
5702 Trace("smt") << "SMT pop()" << endl
;
5703 if(Dump
.isOn("benchmark")) {
5704 Dump("benchmark") << PopCommand();
5706 if(!options::incrementalSolving()) {
5707 throw ModalException("Cannot pop when not solving incrementally (use --incremental)");
5709 if(d_userLevels
.size() == 0) {
5710 throw ModalException("Cannot pop beyond the first user frame");
5713 // check to see if a postsolve() is pending
5714 if(d_needPostsolve
) {
5715 d_theoryEngine
->postsolve();
5716 d_needPostsolve
= false;
5719 // The problem isn't really "extended" yet, but this disallows
5720 // get-model after a pop, simplifying our lives somewhat. It might
5721 // not be strictly necessary to do so, since the pops occur lazily,
5722 // but also it would be weird to have a legally-executed (get-model)
5723 // that only returns a subset of the assignment (because the rest
5724 // is no longer in scope!).
5725 setProblemExtended(true);
5727 AlwaysAssert(d_userContext
->getLevel() > 0);
5728 AlwaysAssert(d_userLevels
.back() < d_userContext
->getLevel());
5729 while (d_userLevels
.back() < d_userContext
->getLevel()) {
5732 d_userLevels
.pop_back();
5734 // Clear out assertion queues etc., in case anything is still in there
5735 d_private
->notifyPop();
5737 Trace("userpushpop") << "SmtEngine: popped to level "
5738 << d_userContext
->getLevel() << endl
;
5739 // FIXME: should we reset d_status here?
5740 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
5743 void SmtEngine::internalPush() {
5744 Assert(d_fullyInited
);
5745 Trace("smt") << "SmtEngine::internalPush()" << endl
;
5747 if(options::incrementalSolving()) {
5748 d_private
->processAssertions();
5749 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
5750 d_userContext
->push();
5751 // the d_context push is done inside of the SAT solver
5752 d_propEngine
->push();
5756 void SmtEngine::internalPop(bool immediate
) {
5757 Assert(d_fullyInited
);
5758 Trace("smt") << "SmtEngine::internalPop()" << endl
;
5759 if(options::incrementalSolving()) {
5767 void SmtEngine::doPendingPops() {
5768 Assert(d_pendingPops
== 0 || options::incrementalSolving());
5769 while(d_pendingPops
> 0) {
5770 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
5771 d_propEngine
->pop();
5772 // the d_context pop is done inside of the SAT solver
5773 d_userContext
->pop();
5778 void SmtEngine::reset()
5780 SmtScope
smts(this);
5781 ExprManager
*em
= d_exprManager
;
5782 Trace("smt") << "SMT reset()" << endl
;
5783 if(Dump
.isOn("benchmark")) {
5784 Dump("benchmark") << ResetCommand();
5787 opts
.copyValues(d_originalOptions
);
5789 NodeManager::fromExprManager(em
)->getOptions().copyValues(opts
);
5790 new(this) SmtEngine(em
);
5793 void SmtEngine::resetAssertions()
5795 SmtScope
smts(this);
5798 Trace("smt") << "SMT resetAssertions()" << endl
;
5799 if(Dump
.isOn("benchmark")) {
5800 Dump("benchmark") << ResetAssertionsCommand();
5803 while(!d_userLevels
.empty()) {
5807 // Also remember the global push/pop around everything.
5808 Assert(d_userLevels
.size() == 0 && d_userContext
->getLevel() == 1);
5809 d_context
->popto(0);
5810 d_userContext
->popto(0);
5811 DeleteAndClearCommandVector(d_modelGlobalCommands
);
5812 d_userContext
->push();
5816 void SmtEngine::interrupt()
5818 if(!d_fullyInited
) {
5821 d_propEngine
->interrupt();
5822 d_theoryEngine
->interrupt();
5825 void SmtEngine::setResourceLimit(unsigned long units
, bool cumulative
) {
5826 d_private
->getResourceManager()->setResourceLimit(units
, cumulative
);
5828 void SmtEngine::setTimeLimit(unsigned long milis
, bool cumulative
) {
5829 d_private
->getResourceManager()->setTimeLimit(milis
, cumulative
);
5832 unsigned long SmtEngine::getResourceUsage() const {
5833 return d_private
->getResourceManager()->getResourceUsage();
5836 unsigned long SmtEngine::getTimeUsage() const {
5837 return d_private
->getResourceManager()->getTimeUsage();
5840 unsigned long SmtEngine::getResourceRemaining() const
5842 return d_private
->getResourceManager()->getResourceRemaining();
5845 unsigned long SmtEngine::getTimeRemaining() const
5847 return d_private
->getResourceManager()->getTimeRemaining();
5850 Statistics
SmtEngine::getStatistics() const
5852 return Statistics(*d_statisticsRegistry
);
5855 SExpr
SmtEngine::getStatistic(std::string name
) const
5857 return d_statisticsRegistry
->getStatistic(name
);
5860 void SmtEngine::safeFlushStatistics(int fd
) const {
5861 d_statisticsRegistry
->safeFlushInformation(fd
);
5864 void SmtEngine::setUserAttribute(const std::string
& attr
,
5866 const std::vector
<Expr
>& expr_values
,
5867 const std::string
& str_value
)
5869 SmtScope
smts(this);
5870 std::vector
<Node
> node_values
;
5871 for( unsigned i
=0; i
<expr_values
.size(); i
++ ){
5872 node_values
.push_back( expr_values
[i
].getNode() );
5874 d_theoryEngine
->setUserAttribute(attr
, expr
.getNode(), node_values
, str_value
);
5877 void SmtEngine::setPrintFuncInModel(Expr f
, bool p
) {
5878 Trace("setp-model") << "Set printInModel " << f
<< " to " << p
<< std::endl
;
5879 for( unsigned i
=0; i
<d_modelGlobalCommands
.size(); i
++ ){
5880 Command
* c
= d_modelGlobalCommands
[i
];
5881 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
5883 if( dfc
->getFunction()==f
){
5884 dfc
->setPrintInModel( p
);
5888 for( unsigned i
=0; i
<d_modelCommands
->size(); i
++ ){
5889 Command
* c
= (*d_modelCommands
)[i
];
5890 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
5892 if( dfc
->getFunction()==f
){
5893 dfc
->setPrintInModel( p
);
5899 void SmtEngine::beforeSearch()
5902 throw ModalException(
5903 "SmtEngine::beforeSearch called after initialization.");
5908 void SmtEngine::setOption(const std::string
& key
, const CVC4::SExpr
& value
)
5910 NodeManagerScope
nms(d_nodeManager
);
5911 Trace("smt") << "SMT setOption(" << key
<< ", " << value
<< ")" << endl
;
5913 if(Dump
.isOn("benchmark")) {
5914 Dump("benchmark") << SetOptionCommand(key
, value
);
5917 if(key
== "command-verbosity") {
5918 if(!value
.isAtom()) {
5919 const vector
<SExpr
>& cs
= value
.getChildren();
5920 if(cs
.size() == 2 &&
5921 (cs
[0].isKeyword() || cs
[0].isString()) &&
5922 cs
[1].isInteger()) {
5923 string c
= cs
[0].getValue();
5924 const Integer
& v
= cs
[1].getIntegerValue();
5925 if(v
< 0 || v
> 2) {
5926 throw OptionException("command-verbosity must be 0, 1, or 2");
5928 d_commandVerbosity
[c
] = v
;
5932 throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
5935 if(!value
.isAtom()) {
5936 throw OptionException("bad value for :" + key
);
5939 string optionarg
= value
.getValue();
5940 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
5941 nodeManagerOptions
.setOption(key
, optionarg
);
5944 CVC4::SExpr
SmtEngine::getOption(const std::string
& key
) const
5946 NodeManagerScope
nms(d_nodeManager
);
5948 Trace("smt") << "SMT getOption(" << key
<< ")" << endl
;
5950 if(key
.length() >= 18 &&
5951 key
.compare(0, 18, "command-verbosity:") == 0) {
5952 map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.find(key
.c_str() + 18);
5953 if(i
!= d_commandVerbosity
.end()) {
5954 return SExpr((*i
).second
);
5956 i
= d_commandVerbosity
.find("*");
5957 if(i
!= d_commandVerbosity
.end()) {
5958 return SExpr((*i
).second
);
5960 return SExpr(Integer(2));
5963 if(Dump
.isOn("benchmark")) {
5964 Dump("benchmark") << GetOptionCommand(key
);
5967 if(key
== "command-verbosity") {
5968 vector
<SExpr
> result
;
5969 SExpr defaultVerbosity
;
5970 for(map
<string
, Integer
>::const_iterator i
= d_commandVerbosity
.begin();
5971 i
!= d_commandVerbosity
.end();
5974 v
.push_back(SExpr((*i
).first
));
5975 v
.push_back(SExpr((*i
).second
));
5976 if((*i
).first
== "*") {
5977 // put the default at the end of the SExpr
5978 defaultVerbosity
= SExpr(v
);
5980 result
.push_back(SExpr(v
));
5983 // put the default at the end of the SExpr
5984 if(!defaultVerbosity
.isAtom()) {
5985 result
.push_back(defaultVerbosity
);
5987 // ensure the default is always listed
5989 v
.push_back(SExpr("*"));
5990 v
.push_back(SExpr(Integer(2)));
5991 result
.push_back(SExpr(v
));
5993 return SExpr(result
);
5996 Options
& nodeManagerOptions
= NodeManager::currentNM()->getOptions();
5997 return SExpr::parseAtom(nodeManagerOptions
.getOption(key
));
6000 void SmtEngine::setReplayStream(ExprStream
* replayStream
) {
6001 AlwaysAssert(!d_fullyInited
,
6002 "Cannot set replay stream once fully initialized");
6003 d_replayStream
= replayStream
;
6006 bool SmtEngine::getExpressionName(Expr e
, std::string
& name
) const {
6007 return d_private
->getExpressionName(e
, name
);
6010 void SmtEngine::setExpressionName(Expr e
, const std::string
& name
) {
6011 Trace("smt-debug") << "Set expression name " << e
<< " to " << name
<< std::endl
;
6012 d_private
->setExpressionName(e
,name
);
6015 }/* CVC4 namespace */