1 /********************* */
2 /*! \file smt_engine.cpp
4 ** Original author: Morgan Deters
5 ** Major contributors: Clark Barrett
6 ** Minor contributors (to current version): Christopher L. Conway, Tianyi Liang, Martin Brain <>, Kshitij Bansal, Liana Hadarean, Dejan Jovanovic, Tim King, Andrew Reynolds
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2014 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** 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.
25 #include <ext/hash_map>
27 #include "context/cdlist.h"
28 #include "context/cdhashset.h"
29 #include "context/context.h"
30 #include "decision/decision_engine.h"
31 #include "decision/decision_mode.h"
32 #include "decision/options.h"
33 #include "expr/command.h"
34 #include "expr/expr.h"
35 #include "expr/kind.h"
36 #include "expr/metakind.h"
37 #include "expr/node_builder.h"
38 #include "expr/node.h"
39 #include "expr/node_self_iterator.h"
40 #include "prop/prop_engine.h"
41 #include "proof/theory_proof.h"
42 #include "smt/modal_exception.h"
43 #include "smt/smt_engine.h"
44 #include "smt/smt_engine_scope.h"
45 #include "smt/model_postprocessor.h"
46 #include "smt/logic_request.h"
47 #include "theory/theory_engine.h"
48 #include "theory/bv/theory_bv_rewriter.h"
49 #include "proof/proof_manager.h"
50 #include "main/options.h"
51 #include "util/proof.h"
52 #include "proof/proof.h"
53 #include "proof/proof_manager.h"
54 #include "util/boolean_simplification.h"
55 #include "util/node_visitor.h"
56 #include "util/configuration.h"
57 #include "util/exception.h"
58 #include "util/nary_builder.h"
59 #include "smt/command_list.h"
60 #include "smt/boolean_terms.h"
61 #include "smt/options.h"
62 #include "options/option_exception.h"
63 #include "util/output.h"
64 #include "util/hash.h"
65 #include "theory/substitutions.h"
66 #include "theory/uf/options.h"
67 #include "theory/arith/options.h"
68 #include "theory/strings/options.h"
69 #include "theory/bv/options.h"
70 #include "theory/theory_traits.h"
71 #include "theory/logic_info.h"
72 #include "theory/options.h"
73 #include "theory/booleans/circuit_propagator.h"
74 #include "theory/booleans/boolean_term_conversion_mode.h"
75 #include "theory/booleans/options.h"
76 #include "util/ite_removal.h"
77 #include "theory/theory_model.h"
78 #include "printer/printer.h"
79 #include "prop/options.h"
80 #include "theory/arrays/options.h"
81 #include "util/sort_inference.h"
82 #include "theory/quantifiers/quant_conflict_find.h"
83 #include "theory/quantifiers/macros.h"
84 #include "theory/quantifiers/first_order_reasoning.h"
85 #include "theory/quantifiers/quantifiers_rewriter.h"
86 #include "theory/quantifiers/options.h"
87 #include "theory/datatypes/options.h"
88 #include "theory/strings/theory_strings_preprocess.h"
89 #include "printer/options.h"
91 #include "theory/arith/pseudoboolean_proc.h"
92 #include "theory/bv/bvintropow2.h"
96 using namespace CVC4::smt
;
97 using namespace CVC4::prop
;
98 using namespace CVC4::context
;
99 using namespace CVC4::theory
;
105 /** Useful for counting the number of recursive calls. */
110 ScopeCounter(unsigned& d
) : d_depth(d
) {
119 * Representation of a defined function. We keep these around in
120 * SmtEngine to permit expanding definitions late (and lazily), to
121 * support getValue() over defined functions, to support user output
122 * in terms of defined functions, etc.
124 class DefinedFunction
{
126 vector
<Node
> d_formals
;
130 DefinedFunction(Node func
, vector
<Node
> formals
, Node formula
) :
135 Node
getFunction() const { return d_func
; }
136 vector
<Node
> getFormals() const { return d_formals
; }
137 Node
getFormula() const { return d_formula
; }
138 };/* class DefinedFunction */
140 struct SmtEngineStatistics
{
141 /** time spent in definition-expansion */
142 TimerStat d_definitionExpansionTime
;
143 /** time spent in Boolean term rewriting */
144 TimerStat d_rewriteBooleanTermsTime
;
145 /** time spent in non-clausal simplification */
146 TimerStat d_nonclausalSimplificationTime
;
147 /** time spent in miplib pass */
148 TimerStat d_miplibPassTime
;
149 /** number of assertions removed by miplib pass */
150 IntStat d_numMiplibAssertionsRemoved
;
151 /** number of constant propagations found during nonclausal simp */
152 IntStat d_numConstantProps
;
153 /** time spent in static learning */
154 TimerStat d_staticLearningTime
;
155 /** time spent in simplifying ITEs */
156 TimerStat d_simpITETime
;
157 /** time spent in simplifying ITEs */
158 TimerStat d_unconstrainedSimpTime
;
159 /** time spent removing ITEs */
160 TimerStat d_iteRemovalTime
;
161 /** time spent in theory preprocessing */
162 TimerStat d_theoryPreprocessTime
;
163 /** time spent converting to CNF */
164 TimerStat d_cnfConversionTime
;
165 /** Num of assertions before ite removal */
166 IntStat d_numAssertionsPre
;
167 /** Num of assertions after ite removal */
168 IntStat d_numAssertionsPost
;
169 /** time spent in checkModel() */
170 TimerStat d_checkModelTime
;
171 /** time spent in checkProof() */
172 TimerStat d_checkProofTime
;
173 /** time spent in PropEngine::checkSat() */
174 TimerStat d_solveTime
;
175 /** time spent in pushing/popping */
176 TimerStat d_pushPopTime
;
177 /** time spent in processAssertions() */
178 TimerStat d_processAssertionsTime
;
180 /** Has something simplified to false? */
181 IntStat d_simplifiedToFalse
;
183 SmtEngineStatistics() :
184 d_definitionExpansionTime("smt::SmtEngine::definitionExpansionTime"),
185 d_rewriteBooleanTermsTime("smt::SmtEngine::rewriteBooleanTermsTime"),
186 d_nonclausalSimplificationTime("smt::SmtEngine::nonclausalSimplificationTime"),
187 d_miplibPassTime("smt::SmtEngine::miplibPassTime"),
188 d_numMiplibAssertionsRemoved("smt::SmtEngine::numMiplibAssertionsRemoved", 0),
189 d_numConstantProps("smt::SmtEngine::numConstantProps", 0),
190 d_staticLearningTime("smt::SmtEngine::staticLearningTime"),
191 d_simpITETime("smt::SmtEngine::simpITETime"),
192 d_unconstrainedSimpTime("smt::SmtEngine::unconstrainedSimpTime"),
193 d_iteRemovalTime("smt::SmtEngine::iteRemovalTime"),
194 d_theoryPreprocessTime("smt::SmtEngine::theoryPreprocessTime"),
195 d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
196 d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
197 d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
198 d_checkModelTime("smt::SmtEngine::checkModelTime"),
199 d_checkProofTime("smt::SmtEngine::checkProofTime"),
200 d_solveTime("smt::SmtEngine::solveTime"),
201 d_pushPopTime("smt::SmtEngine::pushPopTime"),
202 d_processAssertionsTime("smt::SmtEngine::processAssertionsTime"),
203 d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0)
206 StatisticsRegistry::registerStat(&d_definitionExpansionTime
);
207 StatisticsRegistry::registerStat(&d_rewriteBooleanTermsTime
);
208 StatisticsRegistry::registerStat(&d_nonclausalSimplificationTime
);
209 StatisticsRegistry::registerStat(&d_miplibPassTime
);
210 StatisticsRegistry::registerStat(&d_numMiplibAssertionsRemoved
);
211 StatisticsRegistry::registerStat(&d_numConstantProps
);
212 StatisticsRegistry::registerStat(&d_staticLearningTime
);
213 StatisticsRegistry::registerStat(&d_simpITETime
);
214 StatisticsRegistry::registerStat(&d_unconstrainedSimpTime
);
215 StatisticsRegistry::registerStat(&d_iteRemovalTime
);
216 StatisticsRegistry::registerStat(&d_theoryPreprocessTime
);
217 StatisticsRegistry::registerStat(&d_cnfConversionTime
);
218 StatisticsRegistry::registerStat(&d_numAssertionsPre
);
219 StatisticsRegistry::registerStat(&d_numAssertionsPost
);
220 StatisticsRegistry::registerStat(&d_checkModelTime
);
221 StatisticsRegistry::registerStat(&d_solveTime
);
222 StatisticsRegistry::registerStat(&d_pushPopTime
);
223 StatisticsRegistry::registerStat(&d_processAssertionsTime
);
224 StatisticsRegistry::registerStat(&d_simplifiedToFalse
);
227 ~SmtEngineStatistics() {
228 StatisticsRegistry::unregisterStat(&d_definitionExpansionTime
);
229 StatisticsRegistry::unregisterStat(&d_rewriteBooleanTermsTime
);
230 StatisticsRegistry::unregisterStat(&d_nonclausalSimplificationTime
);
231 StatisticsRegistry::unregisterStat(&d_miplibPassTime
);
232 StatisticsRegistry::unregisterStat(&d_numMiplibAssertionsRemoved
);
233 StatisticsRegistry::unregisterStat(&d_numConstantProps
);
234 StatisticsRegistry::unregisterStat(&d_staticLearningTime
);
235 StatisticsRegistry::unregisterStat(&d_simpITETime
);
236 StatisticsRegistry::unregisterStat(&d_unconstrainedSimpTime
);
237 StatisticsRegistry::unregisterStat(&d_iteRemovalTime
);
238 StatisticsRegistry::unregisterStat(&d_theoryPreprocessTime
);
239 StatisticsRegistry::unregisterStat(&d_cnfConversionTime
);
240 StatisticsRegistry::unregisterStat(&d_numAssertionsPre
);
241 StatisticsRegistry::unregisterStat(&d_numAssertionsPost
);
242 StatisticsRegistry::unregisterStat(&d_checkModelTime
);
243 StatisticsRegistry::unregisterStat(&d_solveTime
);
244 StatisticsRegistry::unregisterStat(&d_pushPopTime
);
245 StatisticsRegistry::unregisterStat(&d_processAssertionsTime
);
246 StatisticsRegistry::unregisterStat(&d_simplifiedToFalse
);
248 };/* struct SmtEngineStatistics */
251 * This is an inelegant solution, but for the present, it will work.
252 * The point of this is to separate the public and private portions of
253 * the SmtEngine class, so that smt_engine.h doesn't
254 * include "expr/node.h", which is a private CVC4 header (and can lead
255 * to linking errors due to the improper inlining of non-visible symbols
258 * The "real" solution (that which is usually implemented) is to move
259 * ALL the implementation to SmtEnginePrivate and maintain a
260 * heap-allocated instance of it in SmtEngine. SmtEngine (the public
261 * one) becomes an "interface shell" which simply acts as a forwarder
264 class SmtEnginePrivate
: public NodeManagerListener
{
267 /** The assertions yet to be preprocessed */
268 vector
<Node
> d_assertionsToPreprocess
;
270 /** Learned literals */
271 vector
<Node
> d_nonClausalLearnedLiterals
;
273 /** Size of assertions array when preprocessing starts */
274 unsigned d_realAssertionsEnd
;
276 /** The converter for Boolean terms -> BITVECTOR(1). */
277 BooleanTermConverter
* d_booleanTermConverter
;
279 /** A circuit propagator for non-clausal propositional deduction */
280 booleans::CircuitPropagator d_propagator
;
281 bool d_propagatorNeedsFinish
;
282 std::vector
<Node
> d_boolVars
;
284 /** Assertions to push to sat */
285 vector
<Node
> d_assertionsToCheck
;
287 /** Whether any assertions have been processed */
288 CDO
<bool> d_assertionsProcessed
;
290 /** Index for where to store substitutions */
291 CDO
<unsigned> d_substitutionsIndex
;
297 * A context that never pushes/pops, for use by CD structures (like
298 * SubstitutionMaps) that should be "global".
300 context::Context d_fakeContext
;
303 * A map of AbsractValues to their actual constants. Only used if
304 * options::abstractValues() is on.
306 SubstitutionMap d_abstractValueMap
;
309 * A mapping of all abstract values (actual value |-> abstract) that
310 * we've handed out. This is necessary to ensure that we give the
311 * same AbstractValues for the same real constants. Only used if
312 * options::abstractValues() is on.
314 hash_map
<Node
, Node
, NodeHashFunction
> d_abstractValues
;
316 /** Number of calls of simplify assertions active.
318 unsigned d_simplifyAssertionsDepth
;
322 * Map from skolem variables to index in d_assertionsToCheck containing
323 * corresponding introduced Boolean ite
325 IteSkolemMap d_iteSkolemMap
;
327 /** Instance of the ITE remover */
328 RemoveITE d_iteRemover
;
332 theory::arith::PseudoBooleanProcessor d_pbsProcessor
;
334 /** The top level substitutions */
335 SubstitutionMap d_topLevelSubstitutions
;
337 static const bool d_doConstantProp
= true;
340 * Runs the nonclausal solver and tries to solve all the assigned
343 * Returns false if the formula simplifies to "false"
345 bool nonClausalSimplify();
348 * Performs static learning on the assertions.
350 void staticLearning();
353 * Remove ITEs from the assertions.
358 * Helper function to fix up assertion list to restore invariants needed after ite removal
360 void collectSkolems(TNode n
, set
<TNode
>& skolemSet
, hash_map
<Node
, bool, NodeHashFunction
>& cache
);
363 * Helper function to fix up assertion list to restore invariants needed after ite removal
365 bool checkForBadSkolems(TNode n
, TNode skolem
, hash_map
<Node
, bool, NodeHashFunction
>& cache
);
367 // Lift bit-vectors of size 1 to booleans
370 // Abstract common structure over small domains to UF
371 // return true if changes were made.
372 void bvAbstraction();
374 // Simplify ITE structure
377 // Simplify based on unconstrained values
378 void unconstrainedSimp(std::vector
<Node
>& assertions
);
380 // Ensures the assertions asserted after before now
381 // effectively come before d_realAssertionsEnd
382 void compressBeforeRealAssertions(size_t before
);
385 * Any variable in an assertion that is declared as a subtype type
386 * (predicate subtype or integer subrange type) must be constrained
387 * to be in that type.
389 void constrainSubtypes(TNode n
, std::vector
<Node
>& assertions
)
392 // trace nodes back to their assertions using CircuitPropagator's BackEdgesMap
393 void traceBackToAssertions(const std::vector
<Node
>& nodes
, std::vector
<TNode
>& assertions
);
394 // remove conjuncts in toRemove from conjunction n; return # of removed conjuncts
395 size_t removeFromConjunction(Node
& n
, const std::hash_set
<unsigned long>& toRemove
);
397 // scrub miplib encodings
398 void doMiplibTrick();
401 * Perform non-clausal simplification of a Node. This involves
402 * Theory implementations, but does NOT involve the SAT solver in
405 * Returns false if the formula simplifies to "false"
407 bool simplifyAssertions() throw(TypeCheckingException
, LogicException
);
411 SmtEnginePrivate(SmtEngine
& smt
) :
413 d_assertionsToPreprocess(),
414 d_nonClausalLearnedLiterals(),
415 d_realAssertionsEnd(0),
416 d_booleanTermConverter(NULL
),
417 d_propagator(d_nonClausalLearnedLiterals
, true, true),
418 d_propagatorNeedsFinish(false),
419 d_assertionsToCheck(),
420 d_assertionsProcessed(smt
.d_userContext
, false),
421 d_substitutionsIndex(smt
.d_userContext
, 0),
423 d_abstractValueMap(&d_fakeContext
),
425 d_simplifyAssertionsDepth(0),
427 d_iteRemover(smt
.d_userContext
),
428 d_pbsProcessor(smt
.d_userContext
),
429 d_topLevelSubstitutions(smt
.d_userContext
)
431 d_smt
.d_nodeManager
->subscribeEvents(this);
432 d_true
= NodeManager::currentNM()->mkConst(true);
435 ~SmtEnginePrivate() {
436 if(d_propagatorNeedsFinish
) {
437 d_propagator
.finish();
438 d_propagatorNeedsFinish
= false;
440 if(d_booleanTermConverter
!= NULL
) {
441 delete d_booleanTermConverter
;
442 d_booleanTermConverter
= NULL
;
444 d_smt
.d_nodeManager
->unsubscribeEvents(this);
447 void nmNotifyNewSort(TypeNode tn
, uint32_t flags
) {
448 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
451 if((flags
& ExprManager::SORT_FLAG_PLACEHOLDER
) == 0) {
452 d_smt
.addToModelCommandAndDump(c
, flags
);
456 void nmNotifyNewSortConstructor(TypeNode tn
) {
457 DeclareTypeCommand
c(tn
.getAttribute(expr::VarNameAttr()),
458 tn
.getAttribute(expr::SortArityAttr()),
460 d_smt
.addToModelCommandAndDump(c
);
463 void nmNotifyNewDatatypes(const std::vector
<DatatypeType
>& dtts
) {
464 DatatypeDeclarationCommand
c(dtts
);
465 d_smt
.addToModelCommandAndDump(c
);
468 void nmNotifyNewVar(TNode n
, uint32_t flags
) {
469 DeclareFunctionCommand
c(n
.getAttribute(expr::VarNameAttr()),
471 n
.getType().toType());
472 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
473 d_smt
.addToModelCommandAndDump(c
, flags
);
475 if(n
.getType().isBoolean() && !options::incrementalSolving()) {
476 d_boolVars
.push_back(n
);
480 void nmNotifyNewSkolem(TNode n
, const std::string
& comment
, uint32_t flags
) {
481 string id
= n
.getAttribute(expr::VarNameAttr());
482 DeclareFunctionCommand
c(id
,
484 n
.getType().toType());
485 if(Dump
.isOn("skolems") && comment
!= "") {
486 Dump("skolems") << CommentCommand(id
+ " is " + comment
);
488 if((flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
489 d_smt
.addToModelCommandAndDump(c
, flags
, false, "skolems");
491 if(n
.getType().isBoolean() && !options::incrementalSolving()) {
492 d_boolVars
.push_back(n
);
496 Node
applySubstitutions(TNode node
) const {
497 return Rewriter::rewrite(d_topLevelSubstitutions
.apply(node
));
501 * Process the assertions that have been asserted.
503 void processAssertions();
506 * Process a user pop. Clears out the non-context-dependent stuff in this
507 * SmtEnginePrivate. Necessary to clear out our assertion vectors in case
508 * someone does a push-assert-pop without a check-sat.
511 d_assertionsToPreprocess
.clear();
512 d_nonClausalLearnedLiterals
.clear();
513 d_assertionsToCheck
.clear();
514 d_realAssertionsEnd
= 0;
515 d_iteSkolemMap
.clear();
519 * Adds a formula to the current context. Action here depends on
520 * the SimplificationMode (in the current Options scope); the
521 * formula might be pushed out to the propositional layer
522 * immediately, or it might be simplified and kept, or it might not
523 * even be simplified.
525 void addFormula(TNode n
)
526 throw(TypeCheckingException
, LogicException
);
529 * Expand definitions in n.
531 Node
expandDefinitions(TNode n
, hash_map
<Node
, Node
, NodeHashFunction
>& cache
, bool expandOnly
= false)
532 throw(TypeCheckingException
, LogicException
);
535 * Rewrite Boolean terms in a Node.
537 Node
rewriteBooleanTerms(TNode n
);
540 * Simplify node "in" by expanding definitions and applying any
541 * substitutions learned from preprocessing.
543 Node
simplify(TNode in
) {
544 // Substitute out any abstract values in ex.
545 // Expand definitions.
546 hash_map
<Node
, Node
, NodeHashFunction
> cache
;
547 Node n
= expandDefinitions(in
, cache
).toExpr();
548 // Make sure we've done all preprocessing, etc.
549 Assert(d_assertionsToCheck
.size() == 0 && d_assertionsToPreprocess
.size() == 0);
550 return applySubstitutions(n
).toExpr();
554 * Substitute away all AbstractValues in a node.
556 Node
substituteAbstractValues(TNode n
) {
557 // We need to do this even if options::abstractValues() is off,
558 // since the setting might have changed after we already gave out
559 // some abstract values.
560 return d_abstractValueMap
.apply(n
);
564 * Make a new (or return an existing) abstract value for a node.
565 * Can only use this if options::abstractValues() is on.
567 Node
mkAbstractValue(TNode n
) {
568 Assert(options::abstractValues());
569 Node
& val
= d_abstractValues
[n
];
571 val
= d_smt
.d_nodeManager
->mkAbstractValue(n
.getType());
572 d_abstractValueMap
.addSubstitution(val
, n
);
577 std::hash_map
<Node
, Node
, NodeHashFunction
> rewriteApplyToConstCache
;
578 Node
rewriteApplyToConst(TNode n
) {
579 Trace("rewriteApplyToConst") << "rewriteApplyToConst :: " << n
<< std::endl
;
581 if(n
.getMetaKind() == kind::metakind::CONSTANT
|| n
.getMetaKind() == kind::metakind::VARIABLE
) {
585 if(rewriteApplyToConstCache
.find(n
) != rewriteApplyToConstCache
.end()) {
586 Trace("rewriteApplyToConst") << "in cache :: " << rewriteApplyToConstCache
[n
] << std::endl
;
587 return rewriteApplyToConstCache
[n
];
589 if(n
.getKind() == kind::APPLY_UF
) {
590 if(n
.getNumChildren() == 1 && n
[0].isConst() && n
[0].getType().isInteger()) {
592 ss
<< n
.getOperator() << "_";
593 if(n
[0].getConst
<Rational
>() < 0) {
594 ss
<< "m" << -n
[0].getConst
<Rational
>();
598 Node newvar
= NodeManager::currentNM()->mkSkolem(ss
.str(), n
.getType(), "rewriteApplyToConst skolem", NodeManager::SKOLEM_EXACT_NAME
);
599 rewriteApplyToConstCache
[n
] = newvar
;
600 Trace("rewriteApplyToConst") << "made :: " << newvar
<< std::endl
;
604 ss
<< "The rewrite-apply-to-const preprocessor is currently limited;\n"
605 << "it only works if all function symbols are unary and with Integer\n"
606 << "domain, and all applications are to integer values.\n"
607 << "Found application: " << n
;
612 NodeBuilder
<> builder(n
.getKind());
613 if(n
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
614 builder
<< n
.getOperator();
616 for(unsigned i
= 0; i
< n
.getNumChildren(); ++i
) {
617 builder
<< rewriteApplyToConst(n
[i
]);
620 rewriteApplyToConstCache
[n
] = rewr
;
621 Trace("rewriteApplyToConst") << "built :: " << rewr
<< std::endl
;
625 };/* class SmtEnginePrivate */
627 }/* namespace CVC4::smt */
629 SmtEngine::SmtEngine(ExprManager
* em
) throw() :
630 d_context(em
->getContext()),
632 d_userContext(new UserContext()),
634 d_nodeManager(d_exprManager
->getNodeManager()),
635 d_decisionEngine(NULL
),
636 d_theoryEngine(NULL
),
638 d_proofManager(NULL
),
639 d_definedFunctions(NULL
),
640 d_assertionList(NULL
),
642 d_modelGlobalCommands(),
643 d_modelCommands(NULL
),
647 d_fullyInited(false),
648 d_problemExtended(false),
650 d_needPostsolve(false),
651 d_earlyTheoryPP(true),
652 d_timeBudgetCumulative(0),
653 d_timeBudgetPerCall(0),
654 d_resourceBudgetCumulative(0),
655 d_resourceBudgetPerCall(0),
656 d_cumulativeTimeUsed(0),
657 d_cumulativeResourceUsed(0),
660 d_statisticsRegistry(NULL
),
664 d_private
= new smt::SmtEnginePrivate(*this);
665 d_statisticsRegistry
= new StatisticsRegistry();
666 d_stats
= new SmtEngineStatistics();
668 PROOF( d_proofManager
= new ProofManager(); );
670 // We have mutual dependency here, so we add the prop engine to the theory
671 // engine later (it is non-essential there)
672 d_theoryEngine
= new TheoryEngine(d_context
, d_userContext
, d_private
->d_iteRemover
, const_cast<const LogicInfo
&>(d_logic
));
675 for(TheoryId id
= theory::THEORY_FIRST
; id
< theory::THEORY_LAST
; ++id
) {
676 TheoryConstructor::addTheory(d_theoryEngine
, id
);
679 // global push/pop around everything, to ensure proper destruction
680 // of context-dependent data structures
681 d_userContext
->push();
684 d_definedFunctions
= new(true) DefinedFunctionMap(d_userContext
);
685 d_modelCommands
= new(true) smt::CommandList(d_userContext
);
688 void SmtEngine::finishInit() {
689 // ensure that our heuristics are properly set up
692 d_decisionEngine
= new DecisionEngine(d_context
, d_userContext
);
693 d_decisionEngine
->init(); // enable appropriate strategies
695 d_propEngine
= new PropEngine(d_theoryEngine
, d_decisionEngine
, d_context
, d_userContext
);
697 d_theoryEngine
->setPropEngine(d_propEngine
);
698 d_theoryEngine
->setDecisionEngine(d_decisionEngine
);
699 d_theoryEngine
->finishInit();
701 // [MGD 10/20/2011] keep around in incremental mode, due to a
702 // cleanup ordering issue and Nodes/TNodes. If SAT is popped
703 // first, some user-context-dependent TNodes might still exist
705 if(options::interactive() ||
706 options::incrementalSolving()) {
707 // In the case of incremental solving, we appear to need these to
708 // ensure the relevant Nodes remain live.
709 d_assertionList
= new(true) AssertionList(d_userContext
);
712 // dump out a set-logic command
713 if(Dump
.isOn("benchmark")) {
714 // Dump("benchmark") << SetBenchmarkLogicCommand(logic.getLogicString());
715 LogicInfo everything
;
717 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.")
718 << SetBenchmarkLogicCommand(everything
.getLogicString());
721 // dump out any pending declaration commands
722 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
723 Dump("declarations") << *d_dumpCommands
[i
];
724 delete d_dumpCommands
[i
];
726 d_dumpCommands
.clear();
728 if(options::perCallResourceLimit() != 0) {
729 setResourceLimit(options::perCallResourceLimit(), false);
731 if(options::cumulativeResourceLimit() != 0) {
732 setResourceLimit(options::cumulativeResourceLimit(), true);
734 if(options::perCallMillisecondLimit() != 0) {
735 setTimeLimit(options::perCallMillisecondLimit(), false);
737 if(options::cumulativeMillisecondLimit() != 0) {
738 setTimeLimit(options::cumulativeMillisecondLimit(), true);
741 PROOF( ProofManager::currentPM()->setLogic(d_logic
.getLogicString()); );
744 void SmtEngine::finalOptionsAreSet() {
749 if(! d_logic
.isLocked()) {
753 // finish initialization, create the prop engine, etc.
756 AlwaysAssert( d_propEngine
->getAssertionLevel() == 0,
757 "The PropEngine has pushed but the SmtEngine "
758 "hasn't finished initializing!" );
760 d_fullyInited
= true;
761 Assert(d_logic
.isLocked());
763 d_propEngine
->assertFormula(NodeManager::currentNM()->mkConst
<bool>(true));
764 d_propEngine
->assertFormula(NodeManager::currentNM()->mkConst
<bool>(false).notNode());
767 void SmtEngine::shutdown() {
770 while(options::incrementalSolving() && d_userContext
->getLevel() > 1) {
774 // check to see if a postsolve() is pending
775 if(d_needPostsolve
) {
776 d_theoryEngine
->postsolve();
777 d_needPostsolve
= false;
780 if(d_propEngine
!= NULL
) {
781 d_propEngine
->shutdown();
783 if(d_theoryEngine
!= NULL
) {
784 d_theoryEngine
->shutdown();
786 if(d_decisionEngine
!= NULL
) {
787 d_decisionEngine
->shutdown();
791 SmtEngine::~SmtEngine() throw() {
797 // global push/pop around everything, to ensure proper destruction
798 // of context-dependent data structures
800 d_userContext
->popto(0);
802 if(d_assignments
!= NULL
) {
803 d_assignments
->deleteSelf();
806 if(d_assertionList
!= NULL
) {
807 d_assertionList
->deleteSelf();
810 for(unsigned i
= 0; i
< d_dumpCommands
.size(); ++i
) {
811 delete d_dumpCommands
[i
];
812 d_dumpCommands
[i
] = NULL
;
814 d_dumpCommands
.clear();
816 if(d_modelCommands
!= NULL
) {
817 d_modelCommands
->deleteSelf();
820 d_definedFunctions
->deleteSelf();
822 delete d_theoryEngine
;
823 d_theoryEngine
= NULL
;
826 delete d_decisionEngine
;
827 d_decisionEngine
= NULL
;
831 delete d_statisticsRegistry
;
832 d_statisticsRegistry
= NULL
;
837 delete d_userContext
;
838 d_userContext
= NULL
;
840 } catch(Exception
& e
) {
841 Warning() << "CVC4 threw an exception during cleanup." << endl
846 void SmtEngine::setLogic(const LogicInfo
& logic
) throw(ModalException
) {
849 throw ModalException("Cannot set logic in SmtEngine after the engine has finished initializing");
855 void SmtEngine::setLogic(const std::string
& s
) throw(ModalException
, LogicException
) {
858 setLogic(LogicInfo(s
));
859 } catch(IllegalArgumentException
& e
) {
860 throw LogicException(e
.what());
864 void SmtEngine::setLogic(const char* logic
) throw(ModalException
, LogicException
) {
865 setLogic(string(logic
));
868 LogicInfo
SmtEngine::getLogicInfo() const {
872 void SmtEngine::setLogicInternal() throw() {
873 Assert(!d_fullyInited
, "setting logic in SmtEngine but the engine has already finished initializing for this run");
877 void SmtEngine::setDefaults() {
878 if(options::forceLogic
.wasSetByUser()) {
879 d_logic
= options::forceLogic();
883 /* - disabled for 1.4 release [MGD 2014.06.25]
884 if(!d_logic.hasEverything() && d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
885 if(! options::stringExp.wasSetByUser()) {
886 options::stringExp.set( true );
887 Trace("smt") << "turning on strings-exp, for the theory of strings" << std::endl;
892 if(options::stringExp()) {
893 if( !d_logic
.isQuantified() ) {
894 d_logic
= d_logic
.getUnlockedCopy();
895 d_logic
.enableQuantifiers();
897 Trace("smt") << "turning on quantifier logic, for strings-exp" << std::endl
;
899 if(! options::finiteModelFind
.wasSetByUser()) {
900 options::finiteModelFind
.set( true );
901 Trace("smt") << "turning on finite-model-find, for strings-exp" << std::endl
;
903 if(! options::fmfBoundInt
.wasSetByUser()) {
904 if(! options::fmfBoundIntLazy
.wasSetByUser()) {
905 options::fmfBoundIntLazy
.set( true );
907 options::fmfBoundInt
.set( true );
908 Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl
;
911 if(! options::rewriteDivk.wasSetByUser()) {
912 options::rewriteDivk.set( true );
913 Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
916 if(! options::stringFMF.wasSetByUser()) {
917 options::stringFMF.set( true );
918 Trace("smt") << "turning on strings-fmf, for strings-exp" << std::endl;
923 if(options::checkModels()) {
924 if(! options::interactive()) {
925 Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl
;
926 setOption("interactive-mode", SExpr("true"));
930 if(options::produceAssignments() && !options::produceModels()) {
931 Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl
;
932 setOption("produce-models", SExpr("true"));
935 // Set the options for the theoryOf
936 if(!options::theoryOfMode
.wasSetByUser()) {
937 if(d_logic
.isSharingEnabled() && !d_logic
.isTheoryEnabled(THEORY_BV
) && !d_logic
.isTheoryEnabled(THEORY_STRINGS
)) {
938 Trace("smt") << "setting theoryof-mode to term-based" << endl
;
939 options::theoryOfMode
.set(THEORY_OF_TERM_BASED
);
943 // by default, symmetry breaker is on only for QF_UF
944 if(! options::ufSymmetryBreaker
.wasSetByUser()) {
945 bool qf_uf
= d_logic
.isPure(THEORY_UF
) && !d_logic
.isQuantified();
946 Trace("smt") << "setting uf symmetry breaker to " << qf_uf
<< endl
;
947 options::ufSymmetryBreaker
.set(qf_uf
);
949 // by default, nonclausal simplification is off for QF_SAT
950 if(! options::simplificationMode
.wasSetByUser()) {
951 bool qf_sat
= d_logic
.isPure(THEORY_BOOL
) && !d_logic
.isQuantified();
952 Trace("smt") << "setting simplification mode to <" << d_logic
.getLogicString() << "> " << (!qf_sat
) << endl
;
953 //simplification=none works better for SMT LIB benchmarks with quantifiers, not others
954 //options::simplificationMode.set(qf_sat || quantifiers ? SIMPLIFICATION_MODE_NONE : SIMPLIFICATION_MODE_BATCH);
955 options::simplificationMode
.set(qf_sat
? SIMPLIFICATION_MODE_NONE
: SIMPLIFICATION_MODE_BATCH
);
958 // If in arrays, set the UF handler to arrays
959 if(d_logic
.isTheoryEnabled(THEORY_ARRAY
) && ( !d_logic
.isQuantified() ||
960 (d_logic
.isQuantified() && !d_logic
.isTheoryEnabled(THEORY_UF
)))) {
961 Theory::setUninterpretedSortOwner(THEORY_ARRAY
);
963 Theory::setUninterpretedSortOwner(THEORY_UF
);
965 // Turn on ite simplification for QF_LIA and QF_AUFBV
966 if(! options::doITESimp
.wasSetByUser()) {
967 bool qf_aufbv
= !d_logic
.isQuantified() &&
968 d_logic
.isTheoryEnabled(THEORY_ARRAY
) &&
969 d_logic
.isTheoryEnabled(THEORY_UF
) &&
970 d_logic
.isTheoryEnabled(THEORY_BV
);
971 bool qf_lia
= !d_logic
.isQuantified() &&
972 d_logic
.isPure(THEORY_ARITH
) &&
973 d_logic
.isLinear() &&
974 !d_logic
.isDifferenceLogic() &&
975 !d_logic
.areRealsUsed();
977 bool iteSimp
= (qf_aufbv
|| qf_lia
);
978 Trace("smt") << "setting ite simplification to " << iteSimp
<< endl
;
979 options::doITESimp
.set(iteSimp
);
981 if(! options::compressItes
.wasSetByUser() ){
982 bool qf_lia
= !d_logic
.isQuantified() &&
983 d_logic
.isPure(THEORY_ARITH
) &&
984 d_logic
.isLinear() &&
985 !d_logic
.isDifferenceLogic() &&
986 !d_logic
.areRealsUsed();
988 bool compressIte
= qf_lia
;
989 Trace("smt") << "setting ite compression to " << compressIte
<< endl
;
990 options::compressItes
.set(compressIte
);
992 if(! options::simplifyWithCareEnabled
.wasSetByUser() ){
993 bool qf_aufbv
= !d_logic
.isQuantified() &&
994 d_logic
.isTheoryEnabled(THEORY_ARRAY
) &&
995 d_logic
.isTheoryEnabled(THEORY_UF
) &&
996 d_logic
.isTheoryEnabled(THEORY_BV
);
998 bool withCare
= qf_aufbv
;
999 Trace("smt") << "setting ite simplify with care to " << withCare
<< endl
;
1000 options::simplifyWithCareEnabled
.set(withCare
);
1002 // Turn off array eager index splitting for QF_AUFLIA
1003 if(! options::arraysEagerIndexSplitting
.wasSetByUser()) {
1004 if (not d_logic
.isQuantified() &&
1005 d_logic
.isTheoryEnabled(THEORY_ARRAY
) &&
1006 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1007 d_logic
.isTheoryEnabled(THEORY_ARITH
)) {
1008 Trace("smt") << "setting array eager index splitting to false" << endl
;
1009 options::arraysEagerIndexSplitting
.set(false);
1012 // Turn on model-based arrays for QF_AX (unless models are enabled)
1013 // if(! options::arraysModelBased.wasSetByUser()) {
1014 // if (not d_logic.isQuantified() &&
1015 // d_logic.isTheoryEnabled(THEORY_ARRAY) &&
1016 // d_logic.isPure(THEORY_ARRAY) &&
1017 // !options::produceModels() &&
1018 // !options::checkModels()) {
1019 // Trace("smt") << "turning on model-based array solver" << endl;
1020 // options::arraysModelBased.set(true);
1023 // Turn on multiple-pass non-clausal simplification for QF_AUFBV
1024 if(! options::repeatSimp
.wasSetByUser()) {
1025 bool repeatSimp
= !d_logic
.isQuantified() &&
1026 (d_logic
.isTheoryEnabled(THEORY_ARRAY
) && d_logic
.isTheoryEnabled(THEORY_UF
) && d_logic
.isTheoryEnabled(THEORY_BV
));
1027 Trace("smt") << "setting repeat simplification to " << repeatSimp
<< endl
;
1028 options::repeatSimp
.set(repeatSimp
);
1030 // Turn on unconstrained simplification for QF_AUFBV
1031 if(! options::unconstrainedSimp
.wasSetByUser() || options::incrementalSolving()) {
1032 // bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
1033 // bool uncSimp = false && !qf_sat && !options::incrementalSolving();
1034 bool uncSimp
= !options::incrementalSolving() && !d_logic
.isQuantified() && !options::produceModels() && !options::produceAssignments() && !options::checkModels() &&
1035 (d_logic
.isTheoryEnabled(THEORY_ARRAY
) && d_logic
.isTheoryEnabled(THEORY_BV
));
1036 Trace("smt") << "setting unconstrained simplification to " << uncSimp
<< endl
;
1037 options::unconstrainedSimp
.set(uncSimp
);
1039 // Unconstrained simp currently does *not* support model generation
1040 if (options::unconstrainedSimp
.wasSetByUser() && options::unconstrainedSimp()) {
1041 if (options::produceModels()) {
1042 if (options::produceModels
.wasSetByUser()) {
1043 throw OptionException("Cannot use unconstrained-simp with model generation.");
1045 Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl
;
1046 setOption("produce-models", SExpr("false"));
1048 if (options::produceAssignments()) {
1049 if (options::produceAssignments
.wasSetByUser()) {
1050 throw OptionException("Cannot use unconstrained-simp with model generation (produce-assignments).");
1052 Notice() << "SmtEngine: turning off produce-assignments to support unconstrainedSimp" << endl
;
1053 setOption("produce-assignments", SExpr("false"));
1055 if (options::checkModels()) {
1056 if (options::checkModels
.wasSetByUser()) {
1057 throw OptionException("Cannot use unconstrained-simp with model generation (check-models).");
1059 Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl
;
1060 setOption("check-models", SExpr("false"));
1065 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
&&
1066 options::incrementalSolving()) {
1067 if (options::incrementalSolving
.wasSetByUser()) {
1068 throw OptionException(std::string("Eager bit-blasting does not currently support incremental mode. \n\
1069 Try --bitblast=lazy"));
1071 Notice() << "SmtEngine: turning off incremental to support eager bit-blasting" << endl
;
1072 setOption("incremental", SExpr("false"));
1075 if (! options::bvEagerExplanations
.wasSetByUser() &&
1076 d_logic
.isTheoryEnabled(THEORY_ARRAY
) &&
1077 d_logic
.isTheoryEnabled(THEORY_BV
)) {
1078 Trace("smt") << "enabling eager bit-vector explanations " << endl
;
1079 options::bvEagerExplanations
.set(true);
1082 // Turn on arith rewrite equalities only for pure arithmetic
1083 if(! options::arithRewriteEq
.wasSetByUser()) {
1084 bool arithRewriteEq
= d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified();
1085 Trace("smt") << "setting arith rewrite equalities " << arithRewriteEq
<< endl
;
1086 options::arithRewriteEq
.set(arithRewriteEq
);
1088 if(! options::arithHeuristicPivots
.wasSetByUser()) {
1089 int16_t heuristicPivots
= 5;
1090 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()) {
1091 if(d_logic
.isDifferenceLogic()) {
1092 heuristicPivots
= -1;
1093 } else if(!d_logic
.areIntegersUsed()) {
1094 heuristicPivots
= 0;
1097 Trace("smt") << "setting arithHeuristicPivots " << heuristicPivots
<< endl
;
1098 options::arithHeuristicPivots
.set(heuristicPivots
);
1100 if(! options::arithPivotThreshold
.wasSetByUser()){
1101 uint16_t pivotThreshold
= 2;
1102 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()){
1103 if(d_logic
.isDifferenceLogic()){
1104 pivotThreshold
= 16;
1107 Trace("smt") << "setting arith arithPivotThreshold " << pivotThreshold
<< endl
;
1108 options::arithPivotThreshold
.set(pivotThreshold
);
1110 if(! options::arithStandardCheckVarOrderPivots
.wasSetByUser()){
1111 int16_t varOrderPivots
= -1;
1112 if(d_logic
.isPure(THEORY_ARITH
) && !d_logic
.isQuantified()){
1113 varOrderPivots
= 200;
1115 Trace("smt") << "setting arithStandardCheckVarOrderPivots " << varOrderPivots
<< endl
;
1116 options::arithStandardCheckVarOrderPivots
.set(varOrderPivots
);
1118 // Turn off early theory preprocessing if arithRewriteEq is on
1119 if (options::arithRewriteEq()) {
1120 d_earlyTheoryPP
= false;
1122 // Turn on justification heuristic of the decision engine for QF_BV and QF_AUFBV
1123 // and also use it in stop-only mode for QF_AUFLIA, QF_LRA and Quantifiers
1124 // BUT use neither in ALL_SUPPORTED mode (since it doesn't yet work well
1125 // with incrementality)
1126 if(!options::decisionMode
.wasSetByUser()) {
1127 decision::DecisionMode decMode
=
1129 d_logic
.hasEverything() ? decision::DECISION_STRATEGY_JUSTIFICATION
:
1131 (not d_logic
.isQuantified() &&
1132 d_logic
.isPure(THEORY_BV
)
1134 // QF_AUFBV or QF_ABV or QF_UFBV
1135 (not d_logic
.isQuantified() &&
1136 (d_logic
.isTheoryEnabled(THEORY_ARRAY
) ||
1137 d_logic
.isTheoryEnabled(THEORY_UF
)) &&
1138 d_logic
.isTheoryEnabled(THEORY_BV
)
1140 // QF_AUFLIA (and may be ends up enabling QF_AUFLRA?)
1141 (not d_logic
.isQuantified() &&
1142 d_logic
.isTheoryEnabled(THEORY_ARRAY
) &&
1143 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1144 d_logic
.isTheoryEnabled(THEORY_ARITH
)
1147 (not d_logic
.isQuantified() &&
1148 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
1151 d_logic
.isQuantified() ||
1153 d_logic
.isTheoryEnabled(THEORY_STRINGS
)
1154 ? decision::DECISION_STRATEGY_JUSTIFICATION
1155 : decision::DECISION_STRATEGY_INTERNAL
1160 d_logic
.hasEverything() || d_logic
.isTheoryEnabled(THEORY_STRINGS
) ? false :
1162 (not d_logic
.isQuantified() &&
1163 d_logic
.isTheoryEnabled(THEORY_ARRAY
) &&
1164 d_logic
.isTheoryEnabled(THEORY_UF
) &&
1165 d_logic
.isTheoryEnabled(THEORY_ARITH
)
1168 (not d_logic
.isQuantified() &&
1169 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
1174 Trace("smt") << "setting decision mode to " << decMode
<< endl
;
1175 options::decisionMode
.set(decMode
);
1176 options::decisionStopOnly
.set(stoponly
);
1179 //for finite model finding
1180 if( ! options::instWhenMode
.wasSetByUser()){
1181 //instantiate only on last call
1182 if( options::fmfInstEngine() ){
1183 Trace("smt") << "setting inst when mode to LAST_CALL" << endl
;
1184 options::instWhenMode
.set( quantifiers::INST_WHEN_LAST_CALL
);
1187 if( d_logic
.hasCardinalityConstraints() ){
1188 //must have finite model finding on
1189 options::finiteModelFind
.set( true );
1191 if( options::recurseCbqi() ){
1192 options::cbqi
.set( true );
1194 if(options::fmfBoundIntLazy
.wasSetByUser() && options::fmfBoundIntLazy()) {
1195 options::fmfBoundInt
.set( true );
1197 if( options::fmfBoundInt() ){
1198 //must have finite model finding on
1199 options::finiteModelFind
.set( true );
1200 if( ! options::mbqiMode
.wasSetByUser() ||
1201 ( options::mbqiMode()!=quantifiers::MBQI_NONE
&&
1202 options::mbqiMode()!=quantifiers::MBQI_FMC
&&
1203 options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL
) ){
1204 //if bounded integers are set, use no MBQI by default
1205 options::mbqiMode
.set( quantifiers::MBQI_NONE
);
1208 if( options::mbqiMode()==quantifiers::MBQI_INTERVAL
){
1209 //must do pre-skolemization
1210 options::preSkolemQuant
.set( true );
1212 if( options::ufssSymBreak() ){
1213 options::sortInference
.set( true );
1215 if( options::qcfMode
.wasSetByUser() || options::qcfTConstraint() ){
1216 options::quantConflictFind
.set( true );
1219 //until bugs 371,431 are fixed
1220 if( ! options::minisatUseElim
.wasSetByUser()){
1221 if( d_logic
.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
1222 options::minisatUseElim
.set( false );
1225 else if (options::minisatUseElim()) {
1226 if (options::produceModels()) {
1227 Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl
;
1228 setOption("produce-models", SExpr("false"));
1230 if (options::produceAssignments()) {
1231 Notice() << "SmtEngine: turning off produce-assignments to support minisatUseElim" << endl
;
1232 setOption("produce-assignments", SExpr("false"));
1234 if (options::checkModels()) {
1235 Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl
;
1236 setOption("check-models", SExpr("false"));
1240 // For now, these array theory optimizations do not support model-building
1241 if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
1242 options::arraysOptimizeLinear
.set(false);
1243 options::arraysLazyRIntro1
.set(false);
1246 // Non-linear arithmetic does not support models
1247 if (d_logic
.isTheoryEnabled(THEORY_ARITH
) &&
1248 !d_logic
.isLinear()) {
1249 if (options::produceModels()) {
1250 Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << endl
;
1251 setOption("produce-models", SExpr("false"));
1253 if (options::produceAssignments()) {
1254 Warning() << "SmtEngine: turning off produce-assignments because unsupported for nonlinear arith" << endl
;
1255 setOption("produce-assignments", SExpr("false"));
1257 if (options::checkModels()) {
1258 Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << endl
;
1259 setOption("check-models", SExpr("false"));
1263 if (options::incrementalSolving() && options::proof()) {
1264 Warning() << "SmtEngine: turning off incremental solving mode (not yet supported with --proof" << endl
;
1265 setOption("incremental", SExpr("false"));
1268 // datatypes theory should assign values to all datatypes terms if logic is quantified
1269 if (d_logic
.isQuantified() && d_logic
.isTheoryEnabled(THEORY_DATATYPES
)) {
1270 if( !options::dtForceAssignment
.wasSetByUser() ){
1271 options::dtForceAssignment
.set(true);
1276 void SmtEngine::setInfo(const std::string
& key
, const CVC4::SExpr
& value
)
1277 throw(OptionException
, ModalException
) {
1279 SmtScope
smts(this);
1281 Trace("smt") << "SMT setInfo(" << key
<< ", " << value
<< ")" << endl
;
1282 if(Dump
.isOn("benchmark")) {
1283 if(key
== "status") {
1284 string s
= value
.getValue();
1285 BenchmarkStatus status
=
1286 (s
== "sat") ? SMT_SATISFIABLE
:
1287 ((s
== "unsat") ? SMT_UNSATISFIABLE
: SMT_UNKNOWN
);
1288 Dump("benchmark") << SetBenchmarkStatusCommand(status
);
1290 Dump("benchmark") << SetInfoCommand(key
, value
);
1294 // Check for CVC4-specific info keys (prefixed with "cvc4-" or "cvc4_")
1295 if(key
.length() > 5) {
1296 string prefix
= key
.substr(0, 5);
1297 if(prefix
== "cvc4-" || prefix
== "cvc4_") {
1298 string cvc4key
= key
.substr(5);
1299 if(cvc4key
== "logic") {
1300 if(! value
.isAtom()) {
1301 throw OptionException("argument to (set-info :cvc4-logic ..) must be a string");
1303 SmtScope
smts(this);
1304 d_logic
= value
.getValue();
1308 throw UnrecognizedOptionException();
1313 // Check for standard info keys (SMT-LIB v1, SMT-LIB v2, ...)
1314 if(key
== "source" ||
1315 key
== "category" ||
1316 key
== "difficulty" ||
1320 } else if(key
== "name") {
1321 d_filename
= value
.getValue();
1323 } else if(key
== "smt-lib-version") {
1324 if( (value
.isInteger() && value
.getIntegerValue() == Integer(2)) ||
1325 (value
.isRational() && value
.getRationalValue() == Rational(2)) ||
1326 (value
.getValue() == "2") ) {
1327 // supported SMT-LIB version
1330 Warning() << "Warning: unsupported smt-lib-version: " << value
<< endl
;
1331 throw UnrecognizedOptionException();
1332 } else if(key
== "status") {
1334 if(value
.isAtom()) {
1335 s
= value
.getValue();
1337 if(s
!= "sat" && s
!= "unsat" && s
!= "unknown") {
1338 throw OptionException("argument to (set-info :status ..) must be "
1339 "`sat' or `unsat' or `unknown'");
1341 d_status
= Result(s
, d_filename
);
1344 throw UnrecognizedOptionException();
1347 CVC4::SExpr
SmtEngine::getInfo(const std::string
& key
) const
1348 throw(OptionException
, ModalException
) {
1350 SmtScope
smts(this);
1352 Trace("smt") << "SMT getInfo(" << key
<< ")" << endl
;
1353 if(key
== "all-statistics") {
1354 vector
<SExpr
> stats
;
1355 for(StatisticsRegistry::const_iterator i
= NodeManager::fromExprManager(d_exprManager
)->getStatisticsRegistry()->begin();
1356 i
!= NodeManager::fromExprManager(d_exprManager
)->getStatisticsRegistry()->end();
1359 v
.push_back((*i
).first
);
1360 v
.push_back((*i
).second
);
1363 for(StatisticsRegistry::const_iterator i
= d_statisticsRegistry
->begin();
1364 i
!= d_statisticsRegistry
->end();
1367 v
.push_back((*i
).first
);
1368 v
.push_back((*i
).second
);
1372 } else if(key
== "error-behavior") {
1373 // immediate-exit | continued-execution
1374 if( options::continuedExecution() || options::interactive() ) {
1375 return SExpr::Keyword("continued-execution");
1377 return SExpr::Keyword("immediate-exit");
1379 } else if(key
== "name") {
1380 return Configuration::getName();
1381 } else if(key
== "version") {
1382 return Configuration::getVersionString();
1383 } else if(key
== "authors") {
1384 return Configuration::about();
1385 } else if(key
== "status") {
1386 // sat | unsat | unknown
1387 switch(d_status
.asSatisfiabilityResult().isSat()) {
1389 return SExpr::Keyword("sat");
1391 return SExpr::Keyword("unsat");
1393 return SExpr::Keyword("unknown");
1395 } else if(key
== "reason-unknown") {
1396 if(!d_status
.isNull() && d_status
.isUnknown()) {
1398 ss
<< d_status
.whyUnknown();
1399 string s
= ss
.str();
1400 transform(s
.begin(), s
.end(), s
.begin(), ::tolower
);
1401 return SExpr::Keyword(s
);
1403 throw ModalException("Can't get-info :reason-unknown when the "
1404 "last result wasn't unknown!");
1406 } else if(key
== "all-options") {
1407 // get the options, like all-statistics
1408 return Options::current().getOptions();
1410 throw UnrecognizedOptionException();
1414 void SmtEngine::defineFunction(Expr func
,
1415 const std::vector
<Expr
>& formals
,
1417 Trace("smt") << "SMT defineFunction(" << func
<< ")" << endl
;
1418 for(std::vector
<Expr
>::const_iterator i
= formals
.begin(); i
!= formals
.end(); ++i
) {
1419 if((*i
).getKind() != kind::BOUND_VARIABLE
) {
1421 ss
<< "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
1422 << "definition of function " << func
<< ", formal\n"
1423 << " " << *i
<< "\n"
1424 << "has kind " << (*i
).getKind();
1425 throw TypeCheckingException(func
, ss
.str());
1430 ss
<< Expr::setlanguage(Expr::setlanguage::getLanguage(Dump
.getStream()))
1432 DefineFunctionCommand
c(ss
.str(), func
, formals
, formula
);
1433 addToModelCommandAndDump(c
, ExprManager::VAR_FLAG_DEFINED
, true, "declarations");
1435 SmtScope
smts(this);
1437 // Substitute out any abstract values in formula
1438 Expr form
= d_private
->substituteAbstractValues(Node::fromExpr(formula
)).toExpr();
1441 Type formulaType
= form
.getType(options::typeChecking());
1443 Type funcType
= func
.getType();
1444 // We distinguish here between definitions of constants and functions,
1445 // because the type checking for them is subtly different. Perhaps we
1446 // should instead have SmtEngine::defineFunction() and
1447 // SmtEngine::defineConstant() for better clarity, although then that
1448 // doesn't match the SMT-LIBv2 standard...
1449 if(formals
.size() > 0) {
1450 Type rangeType
= FunctionType(funcType
).getRangeType();
1451 if(! formulaType
.isComparableTo(rangeType
)) {
1453 ss
<< "Type of defined function does not match its declaration\n"
1454 << "The function : " << func
<< "\n"
1455 << "Declared type : " << rangeType
<< "\n"
1456 << "The body : " << formula
<< "\n"
1457 << "Body type : " << formulaType
;
1458 throw TypeCheckingException(func
, ss
.str());
1461 if(! formulaType
.isComparableTo(funcType
)) {
1463 ss
<< "Declared type of defined constant does not match its definition\n"
1464 << "The constant : " << func
<< "\n"
1465 << "Declared type : " << funcType
<< " " << Type::getTypeNode(funcType
)->getId() << "\n"
1466 << "The definition : " << formula
<< "\n"
1467 << "Definition type: " << formulaType
<< " " << Type::getTypeNode(formulaType
)->getId();
1468 throw TypeCheckingException(func
, ss
.str());
1471 TNode funcNode
= func
.getTNode();
1472 vector
<Node
> formalsNodes
;
1473 for(vector
<Expr
>::const_iterator i
= formals
.begin(),
1474 iend
= formals
.end();
1477 formalsNodes
.push_back((*i
).getNode());
1479 TNode formNode
= form
.getTNode();
1480 DefinedFunction
def(funcNode
, formalsNodes
, formNode
);
1481 // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
1482 // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
1483 // d_haveAdditions = true;
1484 Debug("smt") << "definedFunctions insert " << funcNode
<< " " << formNode
<< endl
;
1485 d_definedFunctions
->insert(funcNode
, def
);
1488 Node
SmtEnginePrivate::expandDefinitions(TNode n
, hash_map
<Node
, Node
, NodeHashFunction
>& cache
, bool expandOnly
)
1489 throw(TypeCheckingException
, LogicException
) {
1491 stack
< triple
<Node
, Node
, bool> > worklist
;
1493 worklist
.push(make_triple(Node(n
), Node(n
), false));
1494 // The worklist is made of triples, each is input / original node then the output / rewritten node
1495 // and finally a flag tracking whether the children have been explored (i.e. if this is a downward
1499 n
= worklist
.top().first
; // n is the input / original
1500 Node node
= worklist
.top().second
; // node is the output / result
1501 bool childrenPushed
= worklist
.top().third
;
1504 // Working downwards
1505 if(!childrenPushed
) {
1506 Kind k
= n
.getKind();
1508 // Apart from apply, we can short circuit leaves
1509 if(k
!= kind::APPLY
&& n
.getNumChildren() == 0) {
1510 SmtEngine::DefinedFunctionMap::const_iterator i
= d_smt
.d_definedFunctions
->find(n
);
1511 if(i
!= d_smt
.d_definedFunctions
->end()) {
1512 // replacement must be closed
1513 if((*i
).second
.getFormals().size() > 0) {
1514 result
.push(d_smt
.d_nodeManager
->mkNode(kind::LAMBDA
, d_smt
.d_nodeManager
->mkNode(kind::BOUND_VAR_LIST
, (*i
).second
.getFormals()), (*i
).second
.getFormula()));
1517 // don't bother putting in the cache
1518 result
.push((*i
).second
.getFormula());
1521 // don't bother putting in the cache
1526 // maybe it's in the cache
1527 hash_map
<Node
, Node
, NodeHashFunction
>::iterator cacheHit
= cache
.find(n
);
1528 if(cacheHit
!= cache
.end()) {
1529 TNode ret
= (*cacheHit
).second
;
1530 result
.push(ret
.isNull() ? n
: ret
);
1534 // otherwise expand it
1535 if (k
== kind::APPLY
) {
1536 // application of a user-defined symbol
1537 TNode func
= n
.getOperator();
1538 SmtEngine::DefinedFunctionMap::const_iterator i
=
1539 d_smt
.d_definedFunctions
->find(func
);
1540 DefinedFunction def
= (*i
).second
;
1541 vector
<Node
> formals
= def
.getFormals();
1543 if(Debug
.isOn("expand")) {
1544 Debug("expand") << "found: " << n
<< endl
;
1545 Debug("expand") << " func: " << func
<< endl
;
1546 string name
= func
.getAttribute(expr::VarNameAttr());
1547 Debug("expand") << " : \"" << name
<< "\"" << endl
;
1549 if(i
== d_smt
.d_definedFunctions
->end()) {
1550 throw TypeCheckingException(n
.toExpr(), string("Undefined function: `") + func
.toString() + "'");
1552 if(Debug
.isOn("expand")) {
1553 Debug("expand") << " defn: " << def
.getFunction() << endl
1555 if(formals
.size() > 0) {
1556 copy( formals
.begin(), formals
.end() - 1,
1557 ostream_iterator
<Node
>(Debug("expand"), ", ") );
1558 Debug("expand") << formals
.back();
1560 Debug("expand") << "]" << endl
1561 << " " << def
.getFunction().getType() << endl
1562 << " " << def
.getFormula() << endl
;
1565 TNode fm
= def
.getFormula();
1566 Node instance
= fm
.substitute(formals
.begin(), formals
.end(),
1567 n
.begin(), n
.end());
1568 Debug("expand") << "made : " << instance
<< endl
;
1570 Node expanded
= expandDefinitions(instance
, cache
, expandOnly
);
1571 cache
[n
] = (n
== expanded
? Node::null() : expanded
);
1572 result
.push(expanded
);
1575 } else if(! expandOnly
) {
1576 // do not do any theory stuff if expandOnly is true
1578 theory::Theory
* t
= d_smt
.d_theoryEngine
->theoryOf(node
);
1581 LogicRequest
req(d_smt
);
1582 node
= t
->expandDefinition(req
, n
);
1585 // there should be children here, otherwise we short-circuited a result-push/continue, above
1586 if (node
.getNumChildren() == 0) {
1587 Debug("expand") << "Unexpectedly no children..." << node
<< endl
;
1589 // This invariant holds at the moment but it is concievable that a new theory
1590 // might introduce a kind which can have children before definition expansion but doesn't
1591 // afterwards. If this happens, remove this assertion.
1592 Assert(node
.getNumChildren() > 0);
1594 // the partial functions can fall through, in which case we still
1595 // consider their children
1596 worklist
.push(make_triple(Node(n
), node
, true)); // Original and rewritten result
1598 for(size_t i
= 0; i
< node
.getNumChildren(); ++i
) {
1599 worklist
.push(make_triple(node
[i
], node
[i
], false)); // Rewrite the children of the result only
1604 // Reconstruct the node from it's (now rewritten) children on the stack
1606 Debug("expand") << "cons : " << node
<< endl
;
1607 //cout << "cons : " << node << endl;
1608 NodeBuilder
<> nb(node
.getKind());
1609 if(node
.getMetaKind() == kind::metakind::PARAMETERIZED
) {
1610 Debug("expand") << "op : " << node
.getOperator() << endl
;
1611 //cout << "op : " << node.getOperator() << endl;
1612 nb
<< node
.getOperator();
1614 for(size_t i
= 0; i
< node
.getNumChildren(); ++i
) {
1615 Assert(!result
.empty());
1616 Node expanded
= result
.top();
1618 //cout << "exchld : " << expanded << endl;
1619 Debug("expand") << "exchld : " << expanded
<< endl
;
1623 cache
[n
] = n
== node
? Node::null() : node
; // Only cache once all subterms are expanded
1626 } while(!worklist
.empty());
1628 AlwaysAssert(result
.size() == 1);
1630 return result
.top();
1633 void SmtEnginePrivate::removeITEs() {
1634 d_smt
.finalOptionsAreSet();
1636 Trace("simplify") << "SmtEnginePrivate::removeITEs()" << endl
;
1638 // Remove all of the ITE occurrences and normalize
1639 d_iteRemover
.run(d_assertionsToCheck
, d_iteSkolemMap
);
1640 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++ i
) {
1641 d_assertionsToCheck
[i
] = Rewriter::rewrite(d_assertionsToCheck
[i
]);
1646 void SmtEnginePrivate::staticLearning() {
1647 d_smt
.finalOptionsAreSet();
1649 TimerStat::CodeTimer
staticLearningTimer(d_smt
.d_stats
->d_staticLearningTime
);
1651 Trace("simplify") << "SmtEnginePrivate::staticLearning()" << endl
;
1653 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++ i
) {
1655 NodeBuilder
<> learned(kind::AND
);
1656 learned
<< d_assertionsToCheck
[i
];
1657 d_smt
.d_theoryEngine
->ppStaticLearn(d_assertionsToCheck
[i
], learned
);
1658 if(learned
.getNumChildren() == 1) {
1661 d_assertionsToCheck
[i
] = learned
;
1666 // do dumping (before/after any preprocessing pass)
1667 static void dumpAssertions(const char* key
,
1668 const std::vector
<Node
>& assertionList
) {
1669 if( Dump
.isOn("assertions") &&
1670 Dump
.isOn(string("assertions:") + key
) ) {
1671 // Push the simplified assertions to the dump output stream
1672 for(unsigned i
= 0; i
< assertionList
.size(); ++ i
) {
1673 TNode n
= assertionList
[i
];
1674 Dump("assertions") << AssertCommand(Expr(n
.toExpr()));
1679 // returns false if it learns a conflict
1680 bool SmtEnginePrivate::nonClausalSimplify() {
1681 d_smt
.finalOptionsAreSet();
1683 TimerStat::CodeTimer
nonclausalTimer(d_smt
.d_stats
->d_nonclausalSimplificationTime
);
1686 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify()" << endl
;
1688 if(d_propagatorNeedsFinish
) {
1689 d_propagator
.finish();
1690 d_propagatorNeedsFinish
= false;
1692 d_propagator
.initialize();
1694 // Assert all the assertions to the propagator
1695 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1696 << "asserting to propagator" << endl
;
1697 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
1698 Assert(Rewriter::rewrite(d_assertionsToPreprocess
[i
]) == d_assertionsToPreprocess
[i
]);
1699 // Don't reprocess substitutions
1700 if (d_substitutionsIndex
> 0 && i
== d_substitutionsIndex
) {
1703 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): asserting " << d_assertionsToPreprocess
[i
] << endl
;
1704 d_propagator
.assertTrue(d_assertionsToPreprocess
[i
]);
1707 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1708 << "propagating" << endl
;
1709 if (d_propagator
.propagate()) {
1710 // If in conflict, just return false
1711 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1712 << "conflict in non-clausal propagation" << endl
;
1713 d_assertionsToPreprocess
.clear();
1714 d_assertionsToCheck
.push_back(NodeManager::currentNM()->mkConst
<bool>(false));
1715 d_propagatorNeedsFinish
= true;
1719 // No conflict, go through the literals and solve them
1720 SubstitutionMap
constantPropagations(d_smt
.d_context
);
1721 SubstitutionMap
newSubstitutions(d_smt
.d_context
);
1722 SubstitutionMap::iterator pos
;
1724 for(unsigned i
= 0, i_end
= d_nonClausalLearnedLiterals
.size(); i
< i_end
; ++ i
) {
1725 // Simplify the literal we learned wrt previous substitutions
1726 Node learnedLiteral
= d_nonClausalLearnedLiterals
[i
];
1727 Assert(Rewriter::rewrite(learnedLiteral
) == learnedLiteral
);
1728 Assert(d_topLevelSubstitutions
.apply(learnedLiteral
) == learnedLiteral
);
1729 Node learnedLiteralNew
= newSubstitutions
.apply(learnedLiteral
);
1730 if (learnedLiteral
!= learnedLiteralNew
) {
1731 learnedLiteral
= Rewriter::rewrite(learnedLiteralNew
);
1734 learnedLiteralNew
= constantPropagations
.apply(learnedLiteral
);
1735 if (learnedLiteralNew
== learnedLiteral
) {
1738 ++d_smt
.d_stats
->d_numConstantProps
;
1739 learnedLiteral
= Rewriter::rewrite(learnedLiteralNew
);
1741 // It might just simplify to a constant
1742 if (learnedLiteral
.isConst()) {
1743 if (learnedLiteral
.getConst
<bool>()) {
1744 // If the learned literal simplifies to true, it's redundant
1747 // If the learned literal simplifies to false, we're in conflict
1748 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1750 << d_nonClausalLearnedLiterals
[i
] << endl
;
1751 d_assertionsToPreprocess
.clear();
1752 d_assertionsToCheck
.push_back(NodeManager::currentNM()->mkConst
<bool>(false));
1753 d_propagatorNeedsFinish
= true;
1758 // Solve it with the corresponding theory, possibly adding new
1759 // substitutions to newSubstitutions
1760 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1761 << "solving " << learnedLiteral
<< endl
;
1763 Theory::PPAssertStatus solveStatus
=
1764 d_smt
.d_theoryEngine
->solve(learnedLiteral
, newSubstitutions
);
1766 switch (solveStatus
) {
1767 case Theory::PP_ASSERT_STATUS_SOLVED
: {
1768 // The literal should rewrite to true
1769 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1770 << "solved " << learnedLiteral
<< endl
;
1771 Assert(Rewriter::rewrite(newSubstitutions
.apply(learnedLiteral
)).isConst());
1772 // vector<pair<Node, Node> > equations;
1773 // constantPropagations.simplifyLHS(d_topLevelSubstitutions, equations, true);
1774 // if (equations.empty()) {
1777 // Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
1778 // else fall through
1781 case Theory::PP_ASSERT_STATUS_CONFLICT
:
1782 // If in conflict, we return false
1783 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1784 << "conflict while solving "
1785 << learnedLiteral
<< endl
;
1786 d_assertionsToPreprocess
.clear();
1787 d_assertionsToCheck
.push_back(NodeManager::currentNM()->mkConst
<bool>(false));
1788 d_propagatorNeedsFinish
= true;
1791 if (d_doConstantProp
&& learnedLiteral
.getKind() == kind::EQUAL
&& (learnedLiteral
[0].isConst() || learnedLiteral
[1].isConst())) {
1792 // constant propagation
1795 if (learnedLiteral
[0].isConst()) {
1796 t
= learnedLiteral
[1];
1797 c
= learnedLiteral
[0];
1800 t
= learnedLiteral
[0];
1801 c
= learnedLiteral
[1];
1803 Assert(!t
.isConst());
1804 Assert(constantPropagations
.apply(t
) == t
);
1805 Assert(d_topLevelSubstitutions
.apply(t
) == t
);
1806 Assert(newSubstitutions
.apply(t
) == t
);
1807 constantPropagations
.addSubstitution(t
, c
);
1808 // vector<pair<Node,Node> > equations;
1809 // constantPropagations.simplifyLHS(t, c, equations, true);
1810 // if (!equations.empty()) {
1811 // Assert(equations[0].first.isConst() && equations[0].second.isConst() && equations[0].first != equations[0].second);
1812 // d_assertionsToPreprocess.clear();
1813 // d_assertionsToCheck.push_back(NodeManager::currentNM()->mkConst<bool>(false));
1816 // d_topLevelSubstitutions.simplifyRHS(constantPropagations);
1820 d_nonClausalLearnedLiterals
[j
++] = d_nonClausalLearnedLiterals
[i
];
1825 #ifdef CVC4_ASSERTIONS
1826 // Check data structure invariants:
1827 // 1. for each lhs of d_topLevelSubstitutions, does not appear anywhere in rhs of d_topLevelSubstitutions or anywhere in constantPropagations
1828 // 2. each lhs of constantPropagations rewrites to itself
1829 // 3. if l -> r is a constant propagation and l is a subterm of l' with l' -> r' another constant propagation, then l'[l/r] -> r' should be a
1830 // constant propagation too
1831 // 4. each lhs of constantPropagations is different from each rhs
1832 for (pos
= newSubstitutions
.begin(); pos
!= newSubstitutions
.end(); ++pos
) {
1833 Assert((*pos
).first
.isVar());
1834 Assert(d_topLevelSubstitutions
.apply((*pos
).first
) == (*pos
).first
);
1835 Assert(d_topLevelSubstitutions
.apply((*pos
).second
) == (*pos
).second
);
1836 Assert(newSubstitutions
.apply(newSubstitutions
.apply((*pos
).second
)) == newSubstitutions
.apply((*pos
).second
));
1838 for (pos
= constantPropagations
.begin(); pos
!= constantPropagations
.end(); ++pos
) {
1839 Assert((*pos
).second
.isConst());
1840 Assert(Rewriter::rewrite((*pos
).first
) == (*pos
).first
);
1841 // Node newLeft = d_topLevelSubstitutions.apply((*pos).first);
1842 // if (newLeft != (*pos).first) {
1843 // newLeft = Rewriter::rewrite(newLeft);
1844 // Assert(newLeft == (*pos).second ||
1845 // (constantPropagations.hasSubstitution(newLeft) && constantPropagations.apply(newLeft) == (*pos).second));
1847 // newLeft = constantPropagations.apply((*pos).first);
1848 // if (newLeft != (*pos).first) {
1849 // newLeft = Rewriter::rewrite(newLeft);
1850 // Assert(newLeft == (*pos).second ||
1851 // (constantPropagations.hasSubstitution(newLeft) && constantPropagations.apply(newLeft) == (*pos).second));
1853 Assert(constantPropagations
.apply((*pos
).second
) == (*pos
).second
);
1855 #endif /* CVC4_ASSERTIONS */
1857 // Resize the learnt
1858 d_nonClausalLearnedLiterals
.resize(j
);
1860 hash_set
<TNode
, TNodeHashFunction
> s
;
1861 Trace("debugging") << "NonClausal simplify pre-preprocess\n";
1862 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
1863 Node assertion
= d_assertionsToPreprocess
[i
];
1864 Node assertionNew
= newSubstitutions
.apply(assertion
);
1865 Trace("debugging") << "assertion = " << assertion
<< endl
;
1866 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
1867 if (assertion
!= assertionNew
) {
1868 assertion
= Rewriter::rewrite(assertionNew
);
1869 Trace("debugging") << "rewrite(assertion) = " << assertion
<< endl
;
1871 Assert(Rewriter::rewrite(assertion
) == assertion
);
1873 assertionNew
= constantPropagations
.apply(assertion
);
1874 if (assertionNew
== assertion
) {
1877 ++d_smt
.d_stats
->d_numConstantProps
;
1878 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
1879 assertion
= Rewriter::rewrite(assertionNew
);
1880 Trace("debugging") << "assertionNew = " << assertionNew
<< endl
;
1882 Trace("debugging") << "\n";
1883 s
.insert(assertion
);
1884 d_assertionsToCheck
.push_back(assertion
);
1885 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1886 << "non-clausal preprocessed: "
1887 << assertion
<< endl
;
1889 d_assertionsToPreprocess
.clear();
1891 // If in incremental mode, add substitutions to the list of assertions
1892 if (d_substitutionsIndex
> 0) {
1893 NodeBuilder
<> substitutionsBuilder(kind::AND
);
1894 substitutionsBuilder
<< d_assertionsToCheck
[d_substitutionsIndex
];
1895 pos
= newSubstitutions
.begin();
1896 for (; pos
!= newSubstitutions
.end(); ++pos
) {
1897 // Add back this substitution as an assertion
1898 TNode lhs
= (*pos
).first
, rhs
= newSubstitutions
.apply((*pos
).second
);
1899 Node n
= NodeManager::currentNM()->mkNode(lhs
.getType().isBoolean() ? kind::IFF
: kind::EQUAL
, lhs
, rhs
);
1900 substitutionsBuilder
<< n
;
1901 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): will notify SAT layer of substitution: " << n
<< endl
;
1903 if (substitutionsBuilder
.getNumChildren() > 1) {
1904 d_assertionsToCheck
[d_substitutionsIndex
] =
1905 Rewriter::rewrite(Node(substitutionsBuilder
));
1908 // If not in incremental mode, must add substitutions to model
1909 TheoryModel
* m
= d_smt
.d_theoryEngine
->getModel();
1911 for(pos
= newSubstitutions
.begin(); pos
!= newSubstitutions
.end(); ++pos
) {
1912 Node n
= (*pos
).first
;
1913 Node v
= newSubstitutions
.apply((*pos
).second
);
1914 Trace("model") << "Add substitution : " << n
<< " " << v
<< endl
;
1915 m
->addSubstitution( n
, v
);
1920 NodeBuilder
<> learnedBuilder(kind::AND
);
1921 Assert(d_realAssertionsEnd
<= d_assertionsToCheck
.size());
1922 learnedBuilder
<< d_assertionsToCheck
[d_realAssertionsEnd
- 1];
1924 for (unsigned i
= 0; i
< d_nonClausalLearnedLiterals
.size(); ++ i
) {
1925 Node learned
= d_nonClausalLearnedLiterals
[i
];
1926 Assert(d_topLevelSubstitutions
.apply(learned
) == learned
);
1927 Node learnedNew
= newSubstitutions
.apply(learned
);
1928 if (learned
!= learnedNew
) {
1929 learned
= Rewriter::rewrite(learnedNew
);
1931 Assert(Rewriter::rewrite(learned
) == learned
);
1933 learnedNew
= constantPropagations
.apply(learned
);
1934 if (learnedNew
== learned
) {
1937 ++d_smt
.d_stats
->d_numConstantProps
;
1938 learned
= Rewriter::rewrite(learnedNew
);
1940 if (s
.find(learned
) != s
.end()) {
1944 learnedBuilder
<< learned
;
1945 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1946 << "non-clausal learned : "
1949 d_nonClausalLearnedLiterals
.clear();
1952 for (pos
= constantPropagations
.begin(); pos
!= constantPropagations
.end(); ++pos
) {
1953 Node cProp
= (*pos
).first
.eqNode((*pos
).second
);
1954 Assert(d_topLevelSubstitutions
.apply(cProp
) == cProp
);
1955 Node cPropNew
= newSubstitutions
.apply(cProp
);
1956 if (cProp
!= cPropNew
) {
1957 cProp
= Rewriter::rewrite(cPropNew
);
1958 Assert(Rewriter::rewrite(cProp
) == cProp
);
1960 if (s
.find(cProp
) != s
.end()) {
1964 learnedBuilder
<< cProp
;
1965 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
1966 << "non-clausal constant propagation : "
1970 // Add new substitutions to topLevelSubstitutions
1971 // Note that we don't have to keep rhs's in full solved form
1972 // because SubstitutionMap::apply does a fixed-point iteration when substituting
1973 d_topLevelSubstitutions
.addSubstitutions(newSubstitutions
);
1975 if(learnedBuilder
.getNumChildren() > 1) {
1976 d_assertionsToCheck
[d_realAssertionsEnd
- 1] =
1977 Rewriter::rewrite(Node(learnedBuilder
));
1980 d_propagatorNeedsFinish
= true;
1984 void SmtEnginePrivate::bvAbstraction() {
1985 Trace("bv-abstraction") << "SmtEnginePrivate::bvAbstraction()" << endl
;
1986 std::vector
<Node
> new_assertions
;
1987 bool changed
= d_smt
.d_theoryEngine
->ppBvAbstraction(d_assertionsToPreprocess
, new_assertions
);
1988 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
1989 d_assertionsToPreprocess
[i
] = Rewriter::rewrite(new_assertions
[i
]);
1991 // if we are using the lazy solver and the abstraction
1992 // applies, then UF symbols were introduced
1993 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_LAZY
&&
1995 LogicRequest
req(d_smt
);
1996 req
.widenLogic(THEORY_UF
);
2001 void SmtEnginePrivate::bvToBool() {
2002 Trace("bv-to-bool") << "SmtEnginePrivate::bvToBool()" << endl
;
2003 std::vector
<Node
> new_assertions
;
2004 d_smt
.d_theoryEngine
->ppBvToBool(d_assertionsToPreprocess
, new_assertions
);
2005 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
2006 d_assertionsToPreprocess
[i
] = Rewriter::rewrite(new_assertions
[i
]);
2010 bool SmtEnginePrivate::simpITE() {
2011 TimerStat::CodeTimer
simpITETimer(d_smt
.d_stats
->d_simpITETime
);
2013 Trace("simplify") << "SmtEnginePrivate::simpITE()" << endl
;
2015 unsigned numAssertionOnEntry
= d_assertionsToCheck
.size();
2016 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++i
) {
2017 Node result
= d_smt
.d_theoryEngine
->ppSimpITE(d_assertionsToCheck
[i
]);
2018 d_assertionsToCheck
[i
] = result
;
2019 if(result
.isConst() && !result
.getConst
<bool>()){
2023 bool result
= d_smt
.d_theoryEngine
->donePPSimpITE(d_assertionsToCheck
);
2024 if(numAssertionOnEntry
< d_assertionsToCheck
.size()){
2025 compressBeforeRealAssertions(numAssertionOnEntry
);
2030 void SmtEnginePrivate::compressBeforeRealAssertions(size_t before
){
2031 size_t curr
= d_assertionsToCheck
.size();
2032 if(before
>= curr
||
2033 d_realAssertionsEnd
<= 0 ||
2034 d_realAssertionsEnd
>= curr
){
2039 // original: [0 ... d_realAssertionsEnd)
2041 // ites skolems [d_realAssertionsEnd, before)
2043 // added [before, curr)
2045 Assert(0 < d_realAssertionsEnd
);
2046 Assert(d_realAssertionsEnd
<= before
);
2047 Assert(before
< curr
);
2049 std::vector
<Node
> intoConjunction
;
2050 for(size_t i
= before
; i
<curr
; ++i
){
2051 intoConjunction
.push_back(d_assertionsToCheck
[i
]);
2053 d_assertionsToCheck
.resize(before
);
2054 size_t lastBeforeItes
= d_realAssertionsEnd
- 1;
2055 intoConjunction
.push_back(d_assertionsToCheck
[lastBeforeItes
]);
2056 Node newLast
= util::NaryBuilder::mkAssoc(kind::AND
, intoConjunction
);
2057 d_assertionsToCheck
[lastBeforeItes
] = newLast
;
2058 Assert(d_assertionsToCheck
.size() == before
);
2061 void SmtEnginePrivate::unconstrainedSimp(std::vector
<Node
>& assertions
) {
2062 TimerStat::CodeTimer
unconstrainedSimpTimer(d_smt
.d_stats
->d_unconstrainedSimpTime
);
2063 Trace("simplify") << "SmtEnginePrivate::unconstrainedSimp()" << endl
;
2064 d_smt
.d_theoryEngine
->ppUnconstrainedSimp(assertions
);
2068 void SmtEnginePrivate::constrainSubtypes(TNode top
, std::vector
<Node
>& assertions
)
2071 Trace("constrainSubtypes") << "constrainSubtypes(): looking at " << top
<< endl
;
2074 stack
<TNode
> worklist
;
2079 TNode n
= worklist
.top();
2082 TypeNode t
= n
.getType();
2083 if(t
.isPredicateSubtype()) {
2084 WarningOnce() << "Warning: CVC4 doesn't yet do checking that predicate subtypes are nonempty domains" << endl
;
2085 Node pred
= t
.getSubtypePredicate();
2087 // pred can be a LAMBDA, a function constant, or a datatype tester
2088 Trace("constrainSubtypes") << "constrainSubtypes(): pred.getType() == " << pred
.getType() << endl
;
2089 if(d_smt
.d_definedFunctions
->find(pred
) != d_smt
.d_definedFunctions
->end()) {
2091 } else if(pred
.getType().isTester()) {
2092 k
= kind::APPLY_TESTER
;
2096 Node app
= NodeManager::currentNM()->mkNode(k
, pred
, n
);
2097 Trace("constrainSubtypes") << "constrainSubtypes(): assert(" << k
<< ") " << app
<< endl
;
2098 assertions
.push_back(app
);
2099 } else if(t
.isSubrange()) {
2100 SubrangeBounds bounds
= t
.getSubrangeBounds();
2101 Trace("constrainSubtypes") << "constrainSubtypes(): got bounds " << bounds
<< endl
;
2102 if(bounds
.lower
.hasBound()) {
2103 Node c
= NodeManager::currentNM()->mkConst(Rational(bounds
.lower
.getBound()));
2104 Node lb
= NodeManager::currentNM()->mkNode(kind::LEQ
, c
, n
);
2105 Trace("constrainSubtypes") << "constrainSubtypes(): assert " << lb
<< endl
;
2106 assertions
.push_back(lb
);
2108 if(bounds
.upper
.hasBound()) {
2109 Node c
= NodeManager::currentNM()->mkConst(Rational(bounds
.upper
.getBound()));
2110 Node ub
= NodeManager::currentNM()->mkNode(kind::LEQ
, n
, c
);
2111 Trace("constrainSubtypes") << "constrainSubtypes(): assert " << ub
<< endl
;
2112 assertions
.push_back(ub
);
2116 for(TNode::iterator i
= n
.begin(); i
!= n
.end(); ++i
) {
2117 if(done
.find(*i
) == done
.end()) {
2122 } while(! worklist
.empty());
2125 void SmtEnginePrivate::traceBackToAssertions(const std::vector
<Node
>& nodes
, std::vector
<TNode
>& assertions
) {
2126 const booleans::CircuitPropagator::BackEdgesMap
& backEdges
= d_propagator
.getBackEdges();
2127 for(vector
<Node
>::const_iterator i
= nodes
.begin(); i
!= nodes
.end(); ++i
) {
2128 booleans::CircuitPropagator::BackEdgesMap::const_iterator j
= backEdges
.find(*i
);
2129 // term must appear in map, otherwise how did we get here?!
2130 Assert(j
!= backEdges
.end());
2131 // if term maps to empty, that means it's a top-level assertion
2132 if(!(*j
).second
.empty()) {
2133 traceBackToAssertions((*j
).second
, assertions
);
2135 assertions
.push_back(*i
);
2140 size_t SmtEnginePrivate::removeFromConjunction(Node
& n
, const std::hash_set
<unsigned long>& toRemove
) {
2141 Assert(n
.getKind() == kind::AND
);
2142 size_t removals
= 0;
2143 for(Node::iterator j
= n
.begin(); j
!= n
.end(); ++j
) {
2144 size_t subremovals
= 0;
2146 if(toRemove
.find(sub
.getId()) != toRemove
.end() ||
2147 (sub
.getKind() == kind::AND
&& (subremovals
= removeFromConjunction(sub
, toRemove
)) > 0)) {
2148 NodeBuilder
<> b(kind::AND
);
2149 b
.append(n
.begin(), j
);
2150 if(subremovals
> 0) {
2151 removals
+= subremovals
;
2156 for(++j
; j
!= n
.end(); ++j
) {
2157 if(toRemove
.find((*j
).getId()) != toRemove
.end()) {
2159 } else if((*j
).getKind() == kind::AND
) {
2161 if((subremovals
= removeFromConjunction(sub
, toRemove
)) > 0) {
2162 removals
+= subremovals
;
2171 if(b
.getNumChildren() == 0) {
2174 } else if(b
.getNumChildren() == 1) {
2180 n
= Rewriter::rewrite(n
);
2185 Assert(removals
== 0);
2189 void SmtEnginePrivate::doMiplibTrick() {
2190 Assert(d_assertionsToPreprocess
.empty());
2191 Assert(d_realAssertionsEnd
== d_assertionsToCheck
.size());
2192 Assert(!options::incrementalSolving());
2194 const booleans::CircuitPropagator::BackEdgesMap
& backEdges
= d_propagator
.getBackEdges();
2195 hash_set
<unsigned long> removeAssertions
;
2197 NodeManager
* nm
= NodeManager::currentNM();
2198 Node zero
= nm
->mkConst(Rational(0)), one
= nm
->mkConst(Rational(1));
2200 hash_map
<TNode
, Node
, TNodeHashFunction
> intVars
;
2201 for(vector
<Node
>::const_iterator i
= d_boolVars
.begin(); i
!= d_boolVars
.end(); ++i
) {
2202 if(d_propagator
.isAssigned(*i
)) {
2203 Debug("miplib") << "ineligible: " << *i
<< " because assigned " << d_propagator
.getAssignment(*i
) << endl
;
2207 vector
<TNode
> assertions
;
2208 booleans::CircuitPropagator::BackEdgesMap::const_iterator j
= backEdges
.find(*i
);
2209 // if not in back edges map, the bool var is unconstrained, showing up in no assertions.
2210 // if maps to an empty vector, that means the bool var was asserted itself.
2211 if(j
!= backEdges
.end()) {
2212 if(!(*j
).second
.empty()) {
2213 traceBackToAssertions((*j
).second
, assertions
);
2215 assertions
.push_back(*i
);
2218 Debug("miplib") << "for " << *i
<< endl
;
2219 bool eligible
= true;
2220 map
<pair
<Node
, Node
>, uint64_t> marks
;
2221 map
<pair
<Node
, Node
>, vector
<Rational
> > coef
;
2222 map
<pair
<Node
, Node
>, vector
<Rational
> > checks
;
2223 map
<pair
<Node
, Node
>, vector
<TNode
> > asserts
;
2224 for(vector
<TNode
>::const_iterator j
= assertions
.begin(); j
!= assertions
.end(); ++j
) {
2225 Debug("miplib") << " found: " << *j
<< endl
;
2226 if((*j
).getKind() != kind::IMPLIES
) {
2228 Debug("miplib") << " -- INELIGIBLE -- (not =>)" << endl
;
2231 Node conj
= BooleanSimplification::simplify((*j
)[0]);
2232 if(conj
.getKind() == kind::AND
&& conj
.getNumChildren() > 6) {
2234 Debug("miplib") << " -- INELIGIBLE -- (N-ary /\\ too big)" << endl
;
2237 if(conj
.getKind() != kind::AND
&& !conj
.isVar() && !(conj
.getKind() == kind::NOT
&& conj
[0].isVar())) {
2239 Debug("miplib") << " -- INELIGIBLE -- (not /\\ or literal)" << endl
;
2242 if((*j
)[1].getKind() != kind::EQUAL
||
2243 !( ( (*j
)[1][0].isVar() &&
2244 (*j
)[1][1].getKind() == kind::CONST_RATIONAL
) ||
2245 ( (*j
)[1][0].getKind() == kind::CONST_RATIONAL
&&
2246 (*j
)[1][1].isVar() ) )) {
2248 Debug("miplib") << " -- INELIGIBLE -- (=> (and X X) X)" << endl
;
2251 if(conj
.getKind() == kind::AND
) {
2253 bool found_x
= false;
2254 map
<TNode
, bool> neg
;
2255 for(Node::iterator ii
= conj
.begin(); ii
!= conj
.end(); ++ii
) {
2257 posv
.push_back(*ii
);
2259 found_x
= found_x
|| *i
== *ii
;
2260 } else if((*ii
).getKind() == kind::NOT
&& (*ii
)[0].isVar()) {
2261 posv
.push_back((*ii
)[0]);
2262 neg
[(*ii
)[0]] = true;
2263 found_x
= found_x
|| *i
== (*ii
)[0];
2266 Debug("miplib") << " -- INELIGIBLE -- (non-var: " << *ii
<< ")" << endl
;
2269 if(d_propagator
.isAssigned(posv
.back())) {
2271 Debug("miplib") << " -- INELIGIBLE -- (" << posv
.back() << " asserted)" << endl
;
2280 Debug("miplib") << " --INELIGIBLE -- (couldn't find " << *i
<< " in conjunction)" << endl
;
2283 sort(posv
.begin(), posv
.end());
2284 const Node pos
= NodeManager::currentNM()->mkNode(kind::AND
, posv
);
2285 const TNode var
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][1] : (*j
)[1][0];
2286 const pair
<Node
, Node
> pos_var(pos
, var
);
2287 const Rational
& constant
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][0].getConst
<Rational
>() : (*j
)[1][1].getConst
<Rational
>();
2289 unsigned countneg
= 0, thepos
= 0;
2290 for(unsigned ii
= 0; ii
< pos
.getNumChildren(); ++ii
) {
2295 mark
|= (0x1 << ii
);
2298 if((marks
[pos_var
] & (1lu << mark
)) != 0) {
2300 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl
;
2303 Debug("miplib") << "mark is " << mark
<< " -- " << (1lu << mark
) << endl
;
2304 marks
[pos_var
] |= (1lu << mark
);
2305 Debug("miplib") << "marks[" << pos
<< "," << var
<< "] now " << marks
[pos_var
] << endl
;
2306 if(countneg
== pos
.getNumChildren()) {
2309 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl
;
2312 } else if(countneg
== pos
.getNumChildren() - 1) {
2313 Assert(coef
[pos_var
].size() <= 6 && thepos
< 6);
2314 if(coef
[pos_var
].size() <= thepos
) {
2315 coef
[pos_var
].resize(thepos
+ 1);
2317 coef
[pos_var
][thepos
] = constant
;
2319 if(checks
[pos_var
].size() <= mark
) {
2320 checks
[pos_var
].resize(mark
+ 1);
2322 checks
[pos_var
][mark
] = constant
;
2324 asserts
[pos_var
].push_back(*j
);
2327 if(x
!= *i
&& x
!= (*i
).notNode()) {
2329 Debug("miplib") << " -- INELIGIBLE -- (x not present where I expect it)" << endl
;
2332 const bool xneg
= (x
.getKind() == kind::NOT
);
2333 x
= xneg
? x
[0] : x
;
2334 Debug("miplib") << " x:" << x
<< " " << xneg
<< endl
;
2335 const TNode var
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][1] : (*j
)[1][0];
2336 const pair
<Node
, Node
> x_var(x
, var
);
2337 const Rational
& constant
= ((*j
)[1][0].getKind() == kind::CONST_RATIONAL
) ? (*j
)[1][0].getConst
<Rational
>() : (*j
)[1][1].getConst
<Rational
>();
2338 unsigned mark
= (xneg
? 0 : 1);
2339 if((marks
[x_var
] & (1u << mark
)) != 0) {
2341 Debug("miplib") << " -- INELIGIBLE -- (remarked)" << endl
;
2344 marks
[x_var
] |= (1u << mark
);
2348 Debug("miplib") << " -- INELIGIBLE -- (nonzero constant)" << endl
;
2352 Assert(coef
[x_var
].size() <= 6);
2353 coef
[x_var
].resize(6);
2354 coef
[x_var
][0] = constant
;
2356 asserts
[x_var
].push_back(*j
);
2360 for(map
<pair
<Node
, Node
>, uint64_t>::const_iterator j
= marks
.begin(); j
!= marks
.end(); ++j
) {
2361 const TNode pos
= (*j
).first
.first
;
2362 const TNode var
= (*j
).first
.second
;
2363 const pair
<Node
, Node
>& pos_var
= (*j
).first
;
2364 const uint64_t mark
= (*j
).second
;
2365 const unsigned numVars
= pos
.getKind() == kind::AND
? pos
.getNumChildren() : 1;
2366 uint64_t expected
= (uint64_t(1) << (1 << numVars
)) - 1;
2367 expected
= (expected
== 0) ? -1 : expected
; // fix for overflow
2368 Debug("miplib") << "[" << pos
<< "] => " << hex
<< mark
<< " expect " << expected
<< dec
<< endl
;
2369 Assert(pos
.getKind() == kind::AND
|| pos
.isVar());
2370 if(mark
!= expected
) {
2371 Debug("miplib") << " -- INELIGIBLE " << pos
<< " -- (insufficiently marked, got " << mark
<< " for " << numVars
<< " vars, expected " << expected
<< endl
;
2373 if(mark
!= 3) { // exclude single-var case; nothing to check there
2374 uint64_t sz
= (uint64_t(1) << checks
[pos_var
].size()) - 1;
2375 sz
= (sz
== 0) ? -1 : sz
; // fix for overflow
2376 Assert(sz
== mark
, "expected size %u == mark %u", sz
, mark
);
2377 for(size_t k
= 0; k
< checks
[pos_var
].size(); ++k
) {
2378 if((k
& (k
- 1)) != 0) {
2380 Debug("miplib") << k
<< " => " << checks
[pos_var
][k
] << endl
;
2381 for(size_t v
= 1, kk
= k
; kk
!= 0; ++v
, kk
>>= 1) {
2382 if((kk
& 0x1) == 1) {
2383 Assert(pos
.getKind() == kind::AND
);
2384 Debug("miplib") << "var " << v
<< " : " << pos
[v
- 1] << " coef:" << coef
[pos_var
][v
- 1] << endl
;
2385 sum
+= coef
[pos_var
][v
- 1];
2388 Debug("miplib") << "checkSum is " << sum
<< " input says " << checks
[pos_var
][k
] << endl
;
2389 if(sum
!= checks
[pos_var
][k
]) {
2391 Debug("miplib") << " -- INELIGIBLE " << pos
<< " -- (nonlinear combination)" << endl
;
2395 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
2400 eligible
= true; // next is still eligible
2404 Debug("miplib") << " -- ELIGIBLE " << *i
<< " , " << pos
<< " --" << endl
;
2405 vector
<Node
> newVars
;
2406 expr::NodeSelfIterator ii
, iiend
;
2407 if(pos
.getKind() == kind::AND
) {
2411 ii
= expr::NodeSelfIterator::self(pos
);
2412 iiend
= expr::NodeSelfIterator::selfEnd(pos
);
2414 for(; ii
!= iiend
; ++ii
) {
2415 Node
& varRef
= intVars
[*ii
];
2416 if(varRef
.isNull()) {
2418 ss
<< "mipvar_" << *ii
;
2419 Node newVar
= nm
->mkSkolem(ss
.str(), nm
->integerType(), "a variable introduced due to scrubbing a miplib encoding", NodeManager::SKOLEM_EXACT_NAME
);
2420 Node geq
= Rewriter::rewrite(nm
->mkNode(kind::GEQ
, newVar
, zero
));
2421 Node leq
= Rewriter::rewrite(nm
->mkNode(kind::LEQ
, newVar
, one
));
2422 d_assertionsToCheck
.push_back(Rewriter::rewrite(geq
.andNode(leq
)));
2423 SubstitutionMap
nullMap(&d_fakeContext
);
2424 Theory::PPAssertStatus status CVC4_UNUSED
; // just for assertions
2425 status
= d_smt
.d_theoryEngine
->solve(geq
, nullMap
);
2426 Assert(status
== Theory::PP_ASSERT_STATUS_UNSOLVED
,
2427 "unexpected solution from arith's ppAssert()");
2428 Assert(nullMap
.empty(),
2429 "unexpected substitution from arith's ppAssert()");
2430 status
= d_smt
.d_theoryEngine
->solve(leq
, nullMap
);
2431 Assert(status
== Theory::PP_ASSERT_STATUS_UNSOLVED
,
2432 "unexpected solution from arith's ppAssert()");
2433 Assert(nullMap
.empty(),
2434 "unexpected substitution from arith's ppAssert()");
2435 d_smt
.d_theoryEngine
->getModel()->addSubstitution(*ii
, newVar
.eqNode(one
));
2436 newVars
.push_back(newVar
);
2439 newVars
.push_back(varRef
);
2441 if(!d_smt
.d_logic
.areIntegersUsed()) {
2442 d_smt
.d_logic
= d_smt
.d_logic
.getUnlockedCopy();
2443 d_smt
.d_logic
.enableIntegers();
2444 d_smt
.d_logic
.lock();
2448 if(pos
.getKind() == kind::AND
) {
2449 NodeBuilder
<> sumb(kind::PLUS
);
2450 for(size_t ii
= 0; ii
< pos
.getNumChildren(); ++ii
) {
2451 sumb
<< nm
->mkNode(kind::MULT
, nm
->mkConst(coef
[pos_var
][ii
]), newVars
[ii
]);
2455 sum
= nm
->mkNode(kind::MULT
, nm
->mkConst(coef
[pos_var
][0]), newVars
[0]);
2457 Debug("miplib") << "vars[] " << var
<< endl
2458 << " eq " << Rewriter::rewrite(sum
) << endl
;
2459 Node newAssertion
= var
.eqNode(Rewriter::rewrite(sum
));
2460 if(d_topLevelSubstitutions
.hasSubstitution(newAssertion
[0])) {
2461 //Warning() << "RE-SUBSTITUTION " << newAssertion[0] << endl;
2462 //Warning() << "REPLACE " << newAssertion[1] << endl;
2463 //Warning() << "ORIG " << d_topLevelSubstitutions.getSubstitution(newAssertion[0]) << endl;
2464 Assert(d_topLevelSubstitutions
.getSubstitution(newAssertion
[0]) == newAssertion
[1]);
2465 } else if(pos
.getNumChildren() <= options::arithMLTrickSubstitutions()) {
2466 d_topLevelSubstitutions
.addSubstitution(newAssertion
[0], newAssertion
[1]);
2467 Debug("miplib") << "addSubs: " << newAssertion
[0] << " to " << newAssertion
[1] << endl
;
2469 Debug("miplib") << "skipSubs: " << newAssertion
[0] << " to " << newAssertion
[1] << " (threshold is " << options::arithMLTrickSubstitutions() << ")" << endl
;
2471 newAssertion
= Rewriter::rewrite(newAssertion
);
2472 Debug("miplib") << " " << newAssertion
<< endl
;
2473 d_assertionsToCheck
.push_back(newAssertion
);
2474 Debug("miplib") << " assertions to remove: " << endl
;
2475 for(vector
<TNode
>::const_iterator k
= asserts
[pos_var
].begin(), k_end
= asserts
[pos_var
].end(); k
!= k_end
; ++k
) {
2476 Debug("miplib") << " " << *k
<< endl
;
2477 removeAssertions
.insert((*k
).getId());
2483 if(!removeAssertions
.empty()) {
2484 Debug("miplib") << "SmtEnginePrivate::simplify(): scrubbing miplib encoding..." << endl
;
2485 for(size_t i
= 0; i
< d_realAssertionsEnd
; ++i
) {
2486 if(removeAssertions
.find(d_assertionsToCheck
[i
].getId()) != removeAssertions
.end()) {
2487 Debug("miplib") << "SmtEnginePrivate::simplify(): - removing " << d_assertionsToCheck
[i
] << endl
;
2488 d_assertionsToCheck
[i
] = d_true
;
2489 ++d_smt
.d_stats
->d_numMiplibAssertionsRemoved
;
2490 } else if(d_assertionsToCheck
[i
].getKind() == kind::AND
) {
2491 size_t removals
= removeFromConjunction(d_assertionsToCheck
[i
], removeAssertions
);
2493 Debug("miplib") << "SmtEnginePrivate::simplify(): - reduced " << d_assertionsToCheck
[i
] << endl
;
2494 Debug("miplib") << "SmtEnginePrivate::simplify(): - by " << removals
<< " conjuncts" << endl
;
2495 d_smt
.d_stats
->d_numMiplibAssertionsRemoved
+= removals
;
2498 Debug("miplib") << "had: " << d_assertionsToCheck
[i
] << endl
;
2499 d_assertionsToCheck
[i
] = Rewriter::rewrite(d_topLevelSubstitutions
.apply(d_assertionsToCheck
[i
]));
2500 Debug("miplib") << "now: " << d_assertionsToCheck
[i
] << endl
;
2503 Debug("miplib") << "SmtEnginePrivate::simplify(): miplib pass found nothing." << endl
;
2505 d_realAssertionsEnd
= d_assertionsToCheck
.size();
2509 // returns false if simplification led to "false"
2510 bool SmtEnginePrivate::simplifyAssertions()
2511 throw(TypeCheckingException
, LogicException
) {
2512 Assert(d_smt
.d_pendingPops
== 0);
2514 ScopeCounter
depth(d_simplifyAssertionsDepth
);
2516 Trace("simplify") << "SmtEnginePrivate::simplify()" << endl
;
2518 if(options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
2519 // Perform non-clausal simplification
2520 Chat() << "...performing nonclausal simplification..." << endl
;
2521 Trace("simplify") << "SmtEnginePrivate::simplify(): "
2522 << "performing non-clausal simplification" << endl
;
2523 bool noConflict
= nonClausalSimplify();
2528 // We piggy-back off of the BackEdgesMap in the CircuitPropagator to
2529 // do the miplib trick.
2530 if( // check that option is on
2531 options::arithMLTrick() &&
2532 // miplib rewrites aren't safe in incremental mode
2533 ! options::incrementalSolving() &&
2534 // only useful in arith
2535 d_smt
.d_logic
.isTheoryEnabled(THEORY_ARITH
) &&
2536 // we add new assertions and need this (in practice, this
2537 // restriction only disables miplib processing during
2538 // re-simplification, which we don't expect to be useful anyway)
2539 d_realAssertionsEnd
== d_assertionsToCheck
.size() ) {
2540 Chat() << "...fixing miplib encodings..." << endl
;
2541 Trace("simplify") << "SmtEnginePrivate::simplify(): "
2542 << "looking for miplib pseudobooleans..." << endl
;
2544 TimerStat::CodeTimer
miplibTimer(d_smt
.d_stats
->d_miplibPassTime
);
2548 Trace("simplify") << "SmtEnginePrivate::simplify(): "
2549 << "skipping miplib pseudobooleans pass (either incrementalSolving is on, or miplib pbs are turned off)..." << endl
;
2552 Assert(d_assertionsToCheck
.empty());
2553 d_assertionsToCheck
.swap(d_assertionsToPreprocess
);
2556 dumpAssertions("post-nonclausal", d_assertionsToCheck
);
2557 Trace("smt") << "POST nonClausalSimplify" << endl
;
2558 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2559 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2561 // before ppRewrite check if only core theory for BV theory
2562 d_smt
.d_theoryEngine
->staticInitializeBVOptions(d_assertionsToCheck
);
2564 // Theory preprocessing
2565 if (d_smt
.d_earlyTheoryPP
) {
2566 Chat() << "...doing early theory preprocessing..." << endl
;
2567 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
2568 // Call the theory preprocessors
2569 d_smt
.d_theoryEngine
->preprocessStart();
2570 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++ i
) {
2571 Assert(Rewriter::rewrite(d_assertionsToCheck
[i
]) == d_assertionsToCheck
[i
]);
2572 d_assertionsToCheck
[i
] = d_smt
.d_theoryEngine
->preprocess(d_assertionsToCheck
[i
]);
2573 Assert(Rewriter::rewrite(d_assertionsToCheck
[i
]) == d_assertionsToCheck
[i
]);
2577 dumpAssertions("post-theorypp", d_assertionsToCheck
);
2578 Trace("smt") << "POST theoryPP" << endl
;
2579 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2580 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2582 // ITE simplification
2583 if(options::doITESimp() &&
2584 (d_simplifyAssertionsDepth
<= 1 || options::doITESimpOnRepeat())) {
2585 Chat() << "...doing ITE simplification..." << endl
;
2586 bool noConflict
= simpITE();
2588 Chat() << "...ITE simplification found unsat..." << endl
;
2593 dumpAssertions("post-itesimp", d_assertionsToCheck
);
2594 Trace("smt") << "POST iteSimp" << endl
;
2595 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2596 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2598 // Unconstrained simplification
2599 if(options::unconstrainedSimp()) {
2600 Chat() << "...doing unconstrained simplification..." << endl
;
2601 unconstrainedSimp(d_assertionsToCheck
);
2604 dumpAssertions("post-unconstrained", d_assertionsToCheck
);
2605 Trace("smt") << "POST unconstrainedSimp" << endl
;
2606 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2607 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2609 if(options::repeatSimp() && options::simplificationMode() != SIMPLIFICATION_MODE_NONE
) {
2610 Chat() << "...doing another round of nonclausal simplification..." << endl
;
2611 Trace("simplify") << "SmtEnginePrivate::simplify(): "
2612 << " doing repeated simplification" << endl
;
2613 d_assertionsToCheck
.swap(d_assertionsToPreprocess
);
2614 Assert(d_assertionsToCheck
.empty());
2615 bool noConflict
= nonClausalSimplify();
2621 dumpAssertions("post-repeatsimp", d_assertionsToCheck
);
2622 Trace("smt") << "POST repeatSimp" << endl
;
2623 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2624 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2626 } catch(TypeCheckingExceptionPrivate
& tcep
) {
2627 // Calls to this function should have already weeded out any
2628 // typechecking exceptions via (e.g.) ensureBoolean(). But a
2629 // theory could still create a new expression that isn't
2630 // well-typed, and we don't want the C++ runtime to abort our
2631 // process without any error notice.
2633 ss
<< "A bad expression was produced. Original exception follows:\n"
2635 InternalError(ss
.str().c_str());
2640 Result
SmtEngine::check() {
2641 Assert(d_fullyInited
);
2642 Assert(d_pendingPops
== 0);
2644 Trace("smt") << "SmtEngine::check()" << endl
;
2646 // Make sure the prop layer has all of the assertions
2647 Trace("smt") << "SmtEngine::check(): processing assertions" << endl
;
2648 d_private
->processAssertions();
2650 // Turn off stop only for QF_LRA
2651 // TODO: Bring up in a meeting where to put this
2652 if(options::decisionStopOnly() && !options::decisionMode
.wasSetByUser() ){
2654 (not d_logic
.isQuantified() &&
2655 d_logic
.isPure(THEORY_ARITH
) && d_logic
.isLinear() && !d_logic
.isDifferenceLogic() && !d_logic
.areIntegersUsed()
2657 if(d_private
->d_iteSkolemMap
.empty()){
2658 options::decisionStopOnly
.set(false);
2659 d_decisionEngine
->clearStrategies();
2660 Trace("smt") << "SmtEngine::check(): turning off stop only" << endl
;
2665 unsigned long millis
= 0;
2666 if(d_timeBudgetCumulative
!= 0) {
2667 millis
= getTimeRemaining();
2669 return Result(Result::VALIDITY_UNKNOWN
, Result::TIMEOUT
, d_filename
);
2672 if(d_timeBudgetPerCall
!= 0 && (millis
== 0 || d_timeBudgetPerCall
< millis
)) {
2673 millis
= d_timeBudgetPerCall
;
2676 unsigned long resource
= 0;
2677 if(d_resourceBudgetCumulative
!= 0) {
2678 resource
= getResourceRemaining();
2680 return Result(Result::VALIDITY_UNKNOWN
, Result::RESOURCEOUT
, d_filename
);
2683 if(d_resourceBudgetPerCall
!= 0 && (resource
== 0 || d_resourceBudgetPerCall
< resource
)) {
2684 resource
= d_resourceBudgetPerCall
;
2687 TimerStat::CodeTimer
solveTimer(d_stats
->d_solveTime
);
2689 Chat() << "solving..." << endl
;
2690 Trace("smt") << "SmtEngine::check(): running check" << endl
;
2691 Result result
= d_propEngine
->checkSat(millis
, resource
);
2693 // PropEngine::checkSat() returns the actual amount used in these
2695 d_cumulativeTimeUsed
+= millis
;
2696 d_cumulativeResourceUsed
+= resource
;
2698 Trace("limit") << "SmtEngine::check(): cumulative millis " << d_cumulativeTimeUsed
2699 << ", conflicts " << d_cumulativeResourceUsed
<< endl
;
2701 return Result(result
, d_filename
);
2704 Result
SmtEngine::quickCheck() {
2705 Assert(d_fullyInited
);
2706 Trace("smt") << "SMT quickCheck()" << endl
;
2707 return Result(Result::VALIDITY_UNKNOWN
, Result::REQUIRES_FULL_CHECK
, d_filename
);
2711 void SmtEnginePrivate::collectSkolems(TNode n
, set
<TNode
>& skolemSet
, hash_map
<Node
, bool, NodeHashFunction
>& cache
)
2713 hash_map
<Node
, bool, NodeHashFunction
>::iterator it
;
2715 if (it
!= cache
.end()) {
2719 size_t sz
= n
.getNumChildren();
2721 IteSkolemMap::iterator it
= d_iteSkolemMap
.find(n
);
2722 if (it
!= d_iteSkolemMap
.end()) {
2723 skolemSet
.insert(n
);
2730 for (; k
< sz
; ++k
) {
2731 collectSkolems(n
[k
], skolemSet
, cache
);
2737 bool SmtEnginePrivate::checkForBadSkolems(TNode n
, TNode skolem
, hash_map
<Node
, bool, NodeHashFunction
>& cache
)
2739 hash_map
<Node
, bool, NodeHashFunction
>::iterator it
;
2741 if (it
!= cache
.end()) {
2742 return (*it
).second
;
2745 size_t sz
= n
.getNumChildren();
2747 IteSkolemMap::iterator it
= d_iteSkolemMap
.find(n
);
2749 if (it
!= d_iteSkolemMap
.end()) {
2750 if (!((*it
).first
< n
)) {
2759 for (; k
< sz
; ++k
) {
2760 if (checkForBadSkolems(n
[k
], skolem
, cache
)) {
2770 Node
SmtEnginePrivate::rewriteBooleanTerms(TNode n
) {
2771 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_rewriteBooleanTermsTime
);
2772 if(d_booleanTermConverter
== NULL
) {
2773 // This needs to be initialized _after_ the whole SMT framework is in place, subscribed
2774 // to ExprManager notifications, etc. Otherwise we might miss the "BooleanTerm" datatype
2775 // definition, and not dump it properly.
2776 d_booleanTermConverter
= new BooleanTermConverter(d_smt
);
2778 Node retval
= d_booleanTermConverter
->rewriteBooleanTerms(n
);
2780 switch(booleans::BooleanTermConversionMode mode
= options::booleanTermConversionMode()) {
2781 case booleans::BOOLEAN_TERM_CONVERT_TO_BITVECTORS
:
2782 case booleans::BOOLEAN_TERM_CONVERT_NATIVE
:
2783 if(!d_smt
.d_logic
.isTheoryEnabled(THEORY_BV
)) {
2784 d_smt
.d_logic
= d_smt
.d_logic
.getUnlockedCopy();
2785 d_smt
.d_logic
.enableTheory(THEORY_BV
);
2786 d_smt
.d_logic
.lock();
2789 case booleans::BOOLEAN_TERM_CONVERT_TO_DATATYPES
:
2790 if(!d_smt
.d_logic
.isTheoryEnabled(THEORY_DATATYPES
)) {
2791 d_smt
.d_logic
= d_smt
.d_logic
.getUnlockedCopy();
2792 d_smt
.d_logic
.enableTheory(THEORY_DATATYPES
);
2793 d_smt
.d_logic
.lock();
2803 void SmtEnginePrivate::processAssertions() {
2804 TimerStat::CodeTimer
paTimer(d_smt
.d_stats
->d_processAssertionsTime
);
2806 Assert(d_smt
.d_fullyInited
);
2807 Assert(d_smt
.d_pendingPops
== 0);
2809 // Dump the assertions
2810 dumpAssertions("pre-everything", d_assertionsToPreprocess
);
2812 Trace("smt") << "SmtEnginePrivate::processAssertions()" << endl
;
2814 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2815 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2817 Assert(d_assertionsToCheck
.size() == 0);
2819 if (d_assertionsToPreprocess
.size() == 0) {
2824 if (d_assertionsProcessed
&&
2825 ( options::incrementalSolving() ||
2826 options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL
)) {
2827 // Placeholder for storing substitutions
2828 d_substitutionsIndex
= d_assertionsToPreprocess
.size();
2829 d_assertionsToPreprocess
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
2832 // Add dummy assertion in last position - to be used as a
2833 // placeholder for any new assertions to get added
2834 d_assertionsToPreprocess
.push_back(NodeManager::currentNM()->mkConst
<bool>(true));
2835 // any assertions added beyond realAssertionsEnd must NOT affect the
2836 // equisatisfiability
2837 d_realAssertionsEnd
= d_assertionsToPreprocess
.size();
2839 // Assertions are NOT guaranteed to be rewritten by this point
2841 dumpAssertions("pre-definition-expansion", d_assertionsToPreprocess
);
2843 Chat() << "expanding definitions..." << endl
;
2844 Trace("simplify") << "SmtEnginePrivate::simplify(): expanding definitions" << endl
;
2845 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_definitionExpansionTime
);
2846 hash_map
<Node
, Node
, NodeHashFunction
> cache
;
2847 for(unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
2848 d_assertionsToPreprocess
[i
] =
2849 expandDefinitions(d_assertionsToPreprocess
[i
], cache
);
2852 dumpAssertions("post-definition-expansion", d_assertionsToPreprocess
);
2854 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2855 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2857 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
&&
2858 !d_smt
.d_logic
.isPure(THEORY_BV
)) {
2859 throw ModalException("Eager bit-blasting does not currently support theory combination. "
2860 "Note that in a QF_BV problem UF symbols can be introduced for division. "
2861 "Try --bv-div-zero-const to interpret division by zero as a constant.");
2864 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
) {
2865 d_smt
.d_theoryEngine
->mkAckermanizationAsssertions(d_assertionsToPreprocess
);
2868 if ( options::bvAbstraction() &&
2869 !options::incrementalSolving()) {
2870 dumpAssertions("pre-bv-abstraction", d_assertionsToPreprocess
);
2872 dumpAssertions("post-bv-abstraction", d_assertionsToPreprocess
);
2875 dumpAssertions("pre-boolean-terms", d_assertionsToPreprocess
);
2877 Chat() << "rewriting Boolean terms..." << endl
;
2878 for(unsigned i
= 0, i_end
= d_assertionsToPreprocess
.size(); i
!= i_end
; ++i
) {
2879 d_assertionsToPreprocess
[i
] = rewriteBooleanTerms(d_assertionsToPreprocess
[i
]);
2882 dumpAssertions("post-boolean-terms", d_assertionsToPreprocess
);
2884 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2885 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2887 dumpAssertions("pre-constrain-subtypes", d_assertionsToPreprocess
);
2889 // Any variables of subtype types need to be constrained properly.
2890 // Careful, here: constrainSubtypes() adds to the back of
2891 // d_assertionsToPreprocess, but we don't need to reprocess those.
2892 // We also can't use an iterator, because the vector may be moved in
2893 // memory during this loop.
2894 Chat() << "constraining subtypes..." << endl
;
2895 for(unsigned i
= 0, i_end
= d_assertionsToPreprocess
.size(); i
!= i_end
; ++i
) {
2896 constrainSubtypes(d_assertionsToPreprocess
[i
], d_assertionsToPreprocess
);
2899 dumpAssertions("post-constrain-subtypes", d_assertionsToPreprocess
);
2901 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
2902 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
2905 // Unconstrained simplification
2906 if(options::unconstrainedSimp()) {
2907 dumpAssertions("pre-unconstrained-simp", d_assertionsToPreprocess
);
2908 Chat() << "...doing unconstrained simplification..." << endl
;
2909 unconstrainedSimp(d_assertionsToPreprocess
);
2910 dumpAssertions("post-unconstrained-simp", d_assertionsToPreprocess
);
2913 if(options::bvIntroducePow2()){
2914 theory::bv::BVIntroducePow2::pow2Rewrite(d_assertionsToPreprocess
);
2917 dumpAssertions("pre-substitution", d_assertionsToPreprocess
);
2919 // Apply the substitutions we already have, and normalize
2920 Chat() << "applying substitutions..." << endl
;
2921 Trace("simplify") << "SmtEnginePrivate::nonClausalSimplify(): "
2922 << "applying substitutions" << endl
;
2923 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
2924 Trace("simplify") << "applying to " << d_assertionsToPreprocess
[i
] << endl
;
2925 d_assertionsToPreprocess
[i
] =
2926 Rewriter::rewrite(d_topLevelSubstitutions
.apply(d_assertionsToPreprocess
[i
]));
2927 Trace("simplify") << " got " << d_assertionsToPreprocess
[i
] << endl
;
2929 dumpAssertions("post-substitution", d_assertionsToPreprocess
);
2931 // Assertions ARE guaranteed to be rewritten by this point
2934 // Lift bit-vectors of size 1 to bool
2935 if(options::bitvectorToBool()) {
2936 dumpAssertions("pre-bv-to-bool", d_assertionsToPreprocess
);
2937 Chat() << "...doing bvToBool..." << endl
;
2939 dumpAssertions("post-bv-to-bool", d_assertionsToPreprocess
);
2942 if( d_smt
.d_logic
.isTheoryEnabled(THEORY_STRINGS
) ) {
2943 dumpAssertions("pre-strings-pp", d_assertionsToPreprocess
);
2944 CVC4::theory::strings::StringsPreprocess sp
;
2945 std::vector
<Node
> newNodes
;
2946 newNodes
.push_back(d_assertionsToPreprocess
[d_realAssertionsEnd
- 1]);
2947 sp
.simplify( d_assertionsToPreprocess
, newNodes
);
2948 if(newNodes
.size() > 1) {
2949 d_assertionsToPreprocess
[d_realAssertionsEnd
- 1] = NodeManager::currentNM()->mkNode(kind::AND
, newNodes
);
2951 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
2952 d_assertionsToPreprocess
[i
] = Rewriter::rewrite( d_assertionsToPreprocess
[i
] );
2954 dumpAssertions("post-strings-pp", d_assertionsToPreprocess
);
2956 if( d_smt
.d_logic
.isQuantified() ){
2957 //remove rewrite rules
2958 for( unsigned i
=0; i
< d_assertionsToPreprocess
.size(); i
++ ) {
2959 if( d_assertionsToPreprocess
[i
].getKind() == kind::REWRITE_RULE
){
2960 Node prev
= d_assertionsToPreprocess
[i
];
2961 Trace("quantifiers-rewrite-debug") << "Rewrite rewrite rule " << prev
<< "..." << std::endl
;
2962 d_assertionsToPreprocess
[i
] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertionsToPreprocess
[i
] ) );
2963 Trace("quantifiers-rewrite") << "*** rr-rewrite " << prev
<< endl
;
2964 Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess
[i
] << endl
;
2968 dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess
);
2969 if( options::preSkolemQuant() ){
2970 //apply pre-skolemization to existential quantifiers
2971 for (unsigned i
= 0; i
< d_assertionsToPreprocess
.size(); ++ i
) {
2972 Node prev
= d_assertionsToPreprocess
[i
];
2973 Trace("quantifiers-rewrite-debug") << "Pre-skolemize " << prev
<< "..." << std::endl
;
2974 vector
< TypeNode
> fvTypes
;
2975 vector
< TNode
> fvs
;
2976 d_assertionsToPreprocess
[i
] = quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev
, true, fvTypes
, fvs
);
2977 if( prev
!=d_assertionsToPreprocess
[i
] ){
2978 d_assertionsToPreprocess
[i
] = Rewriter::rewrite( d_assertionsToPreprocess
[i
] );
2979 Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev
<< endl
;
2980 Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess
[i
] << endl
;
2984 dumpAssertions("post-skolem-quant", d_assertionsToPreprocess
);
2985 if( options::macrosQuant() ){
2986 //quantifiers macro expansion
2989 quantifiers::QuantifierMacros qm
;
2990 success
= qm
.simplify( d_assertionsToPreprocess
, true );
2994 Trace("fo-rsn-enable") << std::endl
;
2995 if( options::foPropQuant() ){
2996 quantifiers::FirstOrderPropagation fop
;
2997 fop
.simplify( d_assertionsToPreprocess
);
3001 if( options::sortInference() ){
3002 //sort inference technique
3003 SortInference
* si
= d_smt
.d_theoryEngine
->getSortInference();
3004 si
->simplify( d_assertionsToPreprocess
);
3005 for( std::map
< Node
, Node
>::iterator it
= si
->d_model_replace_f
.begin(); it
!= si
->d_model_replace_f
.end(); ++it
){
3006 d_smt
.setPrintFuncInModel( it
->first
.toExpr(), false );
3007 d_smt
.setPrintFuncInModel( it
->second
.toExpr(), true );
3011 //if( options::quantConflictFind() ){
3012 // d_smt.d_theoryEngine->getQuantConflictFind()->registerAssertions( d_assertionsToPreprocess );
3015 if( options::pbRewrites() ){
3016 d_pbsProcessor
.learn(d_assertionsToPreprocess
);
3017 if(d_pbsProcessor
.likelyToHelp()){
3018 d_pbsProcessor
.applyReplacements(d_assertionsToPreprocess
);
3022 dumpAssertions("pre-simplify", d_assertionsToPreprocess
);
3023 Chat() << "simplifying assertions..." << endl
;
3024 bool noConflict
= simplifyAssertions();
3026 ++(d_smt
.d_stats
->d_simplifiedToFalse
);
3028 dumpAssertions("post-simplify", d_assertionsToCheck
);
3030 dumpAssertions("pre-static-learning", d_assertionsToCheck
);
3031 if(options::doStaticLearning()) {
3032 // Perform static learning
3033 Chat() << "doing static learning..." << endl
;
3034 Trace("simplify") << "SmtEnginePrivate::simplify(): "
3035 << "performing static learning" << endl
;
3038 dumpAssertions("post-static-learning", d_assertionsToCheck
);
3040 Trace("smt") << "POST bvToBool" << endl
;
3041 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
3042 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
3045 dumpAssertions("pre-ite-removal", d_assertionsToCheck
);
3047 Chat() << "removing term ITEs..." << endl
;
3048 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_iteRemovalTime
);
3049 // Remove ITEs, updating d_iteSkolemMap
3050 d_smt
.d_stats
->d_numAssertionsPre
+= d_assertionsToCheck
.size();
3052 d_smt
.d_stats
->d_numAssertionsPost
+= d_assertionsToCheck
.size();
3054 dumpAssertions("post-ite-removal", d_assertionsToCheck
);
3056 dumpAssertions("pre-repeat-simplify", d_assertionsToCheck
);
3057 if(options::repeatSimp()) {
3058 d_assertionsToCheck
.swap(d_assertionsToPreprocess
);
3059 Chat() << "re-simplifying assertions..." << endl
;
3060 ScopeCounter
depth(d_simplifyAssertionsDepth
);
3061 noConflict
&= simplifyAssertions();
3063 // Need to fix up assertion list to maintain invariants:
3064 // Let Sk be the set of Skolem variables introduced by ITE's. Let <_sk be the order in which these variables were introduced
3065 // during ite removal.
3066 // For each skolem variable sk, let iteExpr = iteMap(sk) be the ite expr mapped to by sk.
3068 // cache for expression traversal
3069 hash_map
<Node
, bool, NodeHashFunction
> cache
;
3071 // First, find all skolems that appear in the substitution map - their associated iteExpr will need
3072 // to be moved to the main assertion set
3073 set
<TNode
> skolemSet
;
3074 SubstitutionMap::iterator pos
= d_topLevelSubstitutions
.begin();
3075 for (; pos
!= d_topLevelSubstitutions
.end(); ++pos
) {
3076 collectSkolems((*pos
).first
, skolemSet
, cache
);
3077 collectSkolems((*pos
).second
, skolemSet
, cache
);
3080 // We need to ensure:
3081 // 1. iteExpr has the form (ite cond (sk = t) (sk = e))
3082 // 2. if some sk' in Sk appears in cond, t, or e, then sk' <_sk sk
3083 // If either of these is violated, we must add iteExpr as a proper assertion
3084 IteSkolemMap::iterator it
= d_iteSkolemMap
.begin();
3085 IteSkolemMap::iterator iend
= d_iteSkolemMap
.end();
3086 NodeBuilder
<> builder(kind::AND
);
3087 builder
<< d_assertionsToCheck
[d_realAssertionsEnd
- 1];
3088 vector
<TNode
> toErase
;
3089 for (; it
!= iend
; ++it
) {
3090 if (skolemSet
.find((*it
).first
) == skolemSet
.end()) {
3091 TNode iteExpr
= d_assertionsToCheck
[(*it
).second
];
3092 if (iteExpr
.getKind() == kind::ITE
&&
3093 iteExpr
[1].getKind() == kind::EQUAL
&&
3094 iteExpr
[1][0] == (*it
).first
&&
3095 iteExpr
[2].getKind() == kind::EQUAL
&&
3096 iteExpr
[2][0] == (*it
).first
) {
3098 bool bad
= checkForBadSkolems(iteExpr
[0], (*it
).first
, cache
);
3099 bad
= bad
|| checkForBadSkolems(iteExpr
[1][1], (*it
).first
, cache
);
3100 bad
= bad
|| checkForBadSkolems(iteExpr
[2][1], (*it
).first
, cache
);
3106 // Move this iteExpr into the main assertions
3107 builder
<< d_assertionsToCheck
[(*it
).second
];
3108 d_assertionsToCheck
[(*it
).second
] = NodeManager::currentNM()->mkConst
<bool>(true);
3109 toErase
.push_back((*it
).first
);
3111 if(builder
.getNumChildren() > 1) {
3112 while (!toErase
.empty()) {
3113 d_iteSkolemMap
.erase(toErase
.back());
3116 d_assertionsToCheck
[d_realAssertionsEnd
- 1] =
3117 Rewriter::rewrite(Node(builder
));
3119 // For some reason this is needed for some benchmarks, such as
3120 // http://cvc4.cs.nyu.edu/benchmarks/smtlib2/QF_AUFBV/dwp_formulas/try5_small_difret_functions_dwp_tac.re_node_set_remove_at.il.dwp.smt2
3121 // Figure it out later
3123 // Assert(iteRewriteAssertionsEnd == d_assertionsToCheck.size());
3126 dumpAssertions("post-repeat-simplify", d_assertionsToCheck
);
3128 dumpAssertions("pre-rewrite-apply-to-const", d_assertionsToCheck
);
3129 if(options::rewriteApplyToConst()) {
3130 Chat() << "Rewriting applies to constants..." << endl
;
3131 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
3132 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++ i
) {
3133 d_assertionsToCheck
[i
] = Rewriter::rewrite(rewriteApplyToConst(d_assertionsToCheck
[i
]));
3136 dumpAssertions("post-rewrite-apply-to-const", d_assertionsToCheck
);
3138 // begin: INVARIANT to maintain: no reordering of assertions or
3139 // introducing new ones
3140 #ifdef CVC4_ASSERTIONS
3141 unsigned iteRewriteAssertionsEnd
= d_assertionsToCheck
.size();
3144 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
3145 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
3147 Debug("smt") << "SmtEnginePrivate::processAssertions() POST SIMPLIFICATION" << endl
;
3148 Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess
.size() << endl
;
3149 Debug("smt") << " d_assertionsToCheck : " << d_assertionsToCheck
.size() << endl
;
3151 dumpAssertions("pre-theory-preprocessing", d_assertionsToCheck
);
3153 Chat() << "theory preprocessing..." << endl
;
3154 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_theoryPreprocessTime
);
3155 // Call the theory preprocessors
3156 d_smt
.d_theoryEngine
->preprocessStart();
3157 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++ i
) {
3158 d_assertionsToCheck
[i
] = d_smt
.d_theoryEngine
->preprocess(d_assertionsToCheck
[i
]);
3161 dumpAssertions("post-theory-preprocessing", d_assertionsToCheck
);
3163 // If we are using eager bit-blasting wrap assertions in fake atom so that
3164 // everything gets bit-blasted to internal SAT solver
3165 if (options::bitblastMode() == theory::bv::BITBLAST_MODE_EAGER
) {
3166 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++i
) {
3167 TNode atom
= d_assertionsToCheck
[i
];
3168 Node eager_atom
= NodeManager::currentNM()->mkNode(kind::BITVECTOR_EAGER_ATOM
, atom
);
3169 d_assertionsToCheck
[i
] = eager_atom
;
3170 TheoryModel
* m
= d_smt
.d_theoryEngine
->getModel();
3171 m
->addSubstitution(eager_atom
, atom
);
3175 // Push the formula to decision engine
3177 Chat() << "pushing to decision engine..." << endl
;
3178 Assert(iteRewriteAssertionsEnd
== d_assertionsToCheck
.size());
3179 d_smt
.d_decisionEngine
->addAssertions
3180 (d_assertionsToCheck
, d_realAssertionsEnd
, d_iteSkolemMap
);
3183 // end: INVARIANT to maintain: no reordering of assertions or
3184 // introducing new ones
3186 dumpAssertions("post-everything", d_assertionsToCheck
);
3188 // Push the formula to SAT
3190 Chat() << "converting to CNF..." << endl
;
3191 TimerStat::CodeTimer
codeTimer(d_smt
.d_stats
->d_cnfConversionTime
);
3192 for (unsigned i
= 0; i
< d_assertionsToCheck
.size(); ++ i
) {
3193 d_smt
.d_propEngine
->assertFormula(d_assertionsToCheck
[i
]);
3197 d_assertionsProcessed
= true;
3199 d_assertionsToCheck
.clear();
3200 d_iteSkolemMap
.clear();
3203 void SmtEnginePrivate::addFormula(TNode n
)
3204 throw(TypeCheckingException
, LogicException
) {
3211 Trace("smt") << "SmtEnginePrivate::addFormula(" << n
<< ")" << endl
;
3213 // Add the normalized formula to the queue
3214 d_assertionsToPreprocess
.push_back(n
);
3215 //d_assertionsToPreprocess.push_back(Rewriter::rewrite(n));
3217 // If the mode of processing is incremental prepreocess and assert immediately
3218 if (options::simplificationMode() == SIMPLIFICATION_MODE_INCREMENTAL
) {
3219 processAssertions();
3223 void SmtEngine::ensureBoolean(const Expr
& e
) throw(TypeCheckingException
) {
3224 Type type
= e
.getType(options::typeChecking());
3225 Type boolType
= d_exprManager
->booleanType();
3226 if(type
!= boolType
) {
3228 ss
<< "Expected " << boolType
<< "\n"
3229 << "The assertion : " << e
<< "\n"
3230 << "Its type : " << type
;
3231 throw TypeCheckingException(e
, ss
.str());
3235 Result
SmtEngine::checkSat(const Expr
& ex
) throw(TypeCheckingException
, ModalException
, LogicException
) {
3236 Assert(ex
.isNull() || ex
.getExprManager() == d_exprManager
);
3237 SmtScope
smts(this);
3238 finalOptionsAreSet();
3241 Trace("smt") << "SmtEngine::checkSat(" << ex
<< ")" << endl
;
3243 if(d_queryMade
&& !options::incrementalSolving()) {
3244 throw ModalException("Cannot make multiple queries unless "
3245 "incremental solving is enabled "
3246 "(try --incremental)");
3251 // Substitute out any abstract values in ex.
3252 e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3253 // Ensure expr is type-checked at this point.
3255 // Give it to proof manager
3256 PROOF( ProofManager::currentPM()->addAssertion(e
); );
3259 // check to see if a postsolve() is pending
3260 if(d_needPostsolve
) {
3261 d_theoryEngine
->postsolve();
3262 d_needPostsolve
= false;
3268 // Note that a query has been made
3273 d_problemExtended
= true;
3274 if(d_assertionList
!= NULL
) {
3275 d_assertionList
->push_back(e
);
3277 d_private
->addFormula(e
.getNode());
3281 Result r
= check().asSatisfiabilityResult();
3282 d_needPostsolve
= true;
3284 // Dump the query if requested
3285 if(Dump
.isOn("benchmark")) {
3286 // the expr already got dumped out if assertion-dumping is on
3287 Dump("benchmark") << CheckSatCommand();
3293 // Remember the status
3296 d_problemExtended
= false;
3298 Trace("smt") << "SmtEngine::checkSat(" << e
<< ") => " << r
<< endl
;
3300 // Check that SAT results generate a model correctly.
3301 if(options::checkModels()) {
3302 if(r
.asSatisfiabilityResult().isSat() == Result::SAT
||
3303 (r
.isUnknown() && r
.whyUnknown() == Result::INCOMPLETE
) ){
3304 checkModel(/* hard failure iff */ ! r
.isUnknown());
3307 // Check that UNSAT results generate a proof correctly.
3308 if(options::checkProofs()) {
3309 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
3310 TimerStat::CodeTimer
checkProofTimer(d_stats
->d_checkProofTime
);
3316 }/* SmtEngine::checkSat() */
3318 Result
SmtEngine::query(const Expr
& ex
) throw(TypeCheckingException
, ModalException
, LogicException
) {
3319 Assert(!ex
.isNull());
3320 Assert(ex
.getExprManager() == d_exprManager
);
3321 SmtScope
smts(this);
3322 finalOptionsAreSet();
3324 Trace("smt") << "SMT query(" << ex
<< ")" << endl
;
3326 if(d_queryMade
&& !options::incrementalSolving()) {
3327 throw ModalException("Cannot make multiple queries unless "
3328 "incremental solving is enabled "
3329 "(try --incremental)");
3332 // Substitute out any abstract values in ex
3333 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3334 // Ensure that the expression is type-checked at this point, and Boolean
3336 // Give it to proof manager
3337 PROOF( ProofManager::currentPM()->addAssertion(e
.notExpr()); );
3339 // check to see if a postsolve() is pending
3340 if(d_needPostsolve
) {
3341 d_theoryEngine
->postsolve();
3342 d_needPostsolve
= false;
3348 // Note that a query has been made
3352 d_problemExtended
= true;
3353 if(d_assertionList
!= NULL
) {
3354 d_assertionList
->push_back(e
.notExpr());
3356 d_private
->addFormula(e
.getNode().notNode());
3359 Result r
= check().asValidityResult();
3360 d_needPostsolve
= true;
3362 // Dump the query if requested
3363 if(Dump
.isOn("benchmark")) {
3364 // the expr already got dumped out if assertion-dumping is on
3365 Dump("benchmark") << CheckSatCommand();
3371 // Remember the status
3374 d_problemExtended
= false;
3376 Trace("smt") << "SMT query(" << e
<< ") ==> " << r
<< endl
;
3378 // Check that SAT results generate a model correctly.
3379 if(options::checkModels()) {
3380 if(r
.asSatisfiabilityResult().isSat() == Result::SAT
||
3381 (r
.isUnknown() && r
.whyUnknown() == Result::INCOMPLETE
) ){
3382 checkModel(/* hard failure iff */ ! r
.isUnknown());
3385 // Check that UNSAT results generate a proof correctly.
3386 if(options::checkProofs()) {
3387 if(r
.asSatisfiabilityResult().isSat() == Result::UNSAT
) {
3388 TimerStat::CodeTimer
checkProofTimer(d_stats
->d_checkProofTime
);
3394 }/* SmtEngine::query() */
3396 Result
SmtEngine::assertFormula(const Expr
& ex
) throw(TypeCheckingException
, LogicException
) {
3397 Assert(ex
.getExprManager() == d_exprManager
);
3398 SmtScope
smts(this);
3399 finalOptionsAreSet();
3402 PROOF( ProofManager::currentPM()->addAssertion(ex
); );
3404 Trace("smt") << "SmtEngine::assertFormula(" << ex
<< ")" << endl
;
3406 // Substitute out any abstract values in ex
3407 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3410 if(d_assertionList
!= NULL
) {
3411 d_assertionList
->push_back(e
);
3413 d_private
->addFormula(e
.getNode());
3414 return quickCheck().asValidityResult();
3417 Node
SmtEngine::postprocess(TNode node
, TypeNode expectedType
) const {
3418 ModelPostprocessor mpost
;
3419 NodeVisitor
<ModelPostprocessor
> visitor
;
3420 Node value
= visitor
.run(mpost
, node
);
3421 Debug("boolean-terms") << "postproc: got " << value
<< " expect type " << expectedType
<< endl
;
3422 Node realValue
= mpost
.rewriteAs(value
, expectedType
);
3423 Debug("boolean-terms") << "postproc: realval " << realValue
<< " expect type " << expectedType
<< endl
;
3427 Expr
SmtEngine::simplify(const Expr
& ex
) throw(TypeCheckingException
, LogicException
) {
3428 Assert(ex
.getExprManager() == d_exprManager
);
3429 SmtScope
smts(this);
3430 finalOptionsAreSet();
3432 Trace("smt") << "SMT simplify(" << ex
<< ")" << endl
;
3434 if(Dump
.isOn("benchmark")) {
3435 Dump("benchmark") << SimplifyCommand(ex
);
3438 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3439 if( options::typeChecking() ) {
3440 e
.getType(true); // ensure expr is type-checked at this point
3443 // Make sure all preprocessing is done
3444 d_private
->processAssertions();
3445 Node n
= d_private
->simplify(Node::fromExpr(e
));
3446 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
3450 Expr
SmtEngine::expandDefinitions(const Expr
& ex
) throw(TypeCheckingException
, LogicException
) {
3451 Assert(ex
.getExprManager() == d_exprManager
);
3452 SmtScope
smts(this);
3453 finalOptionsAreSet();
3455 Trace("smt") << "SMT expandDefinitions(" << ex
<< ")" << endl
;
3457 // Substitute out any abstract values in ex.
3458 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3459 if(options::typeChecking()) {
3460 // Ensure expr is type-checked at this point.
3463 if(Dump
.isOn("benchmark")) {
3464 Dump("benchmark") << ExpandDefinitionsCommand(e
);
3466 hash_map
<Node
, Node
, NodeHashFunction
> cache
;
3467 Node n
= d_private
->expandDefinitions(Node::fromExpr(e
), cache
, /* expandOnly = */ true);
3468 n
= postprocess(n
, TypeNode::fromType(e
.getType()));
3473 Expr
SmtEngine::getValue(const Expr
& ex
) const throw(ModalException
, TypeCheckingException
, LogicException
) {
3474 Assert(ex
.getExprManager() == d_exprManager
);
3475 SmtScope
smts(this);
3477 Trace("smt") << "SMT getValue(" << ex
<< ")" << endl
;
3478 if(Dump
.isOn("benchmark")) {
3479 Dump("benchmark") << GetValueCommand(ex
);
3482 if(!options::produceModels()) {
3484 "Cannot get value when produce-models options is off.";
3485 throw ModalException(msg
);
3487 if(d_status
.isNull() ||
3488 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
3489 d_problemExtended
) {
3491 "Cannot get value unless immediately preceded by SAT/INVALID or UNKNOWN response.";
3492 throw ModalException(msg
);
3495 // Substitute out any abstract values in ex.
3496 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3498 // Ensure expr is type-checked at this point.
3499 e
.getType(options::typeChecking());
3501 // do not need to apply preprocessing substitutions (should be recorded
3502 // in model already)
3504 Node n
= Node::fromExpr(e
);
3505 Trace("smt") << "--- getting value of " << n
<< endl
;
3506 TypeNode expectedType
= n
.getType();
3508 // Expand, then normalize
3509 hash_map
<Node
, Node
, NodeHashFunction
> cache
;
3510 n
= d_private
->expandDefinitions(n
, cache
);
3511 // There are two ways model values for terms are computed (for historical
3512 // reasons). One way is that used in check-model; the other is that
3513 // used by the Model classes. It's not clear to me exactly how these
3514 // two are different, but they need to be unified. This ugly hack here
3515 // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
3516 if(!n
.getType().isFunction()) {
3517 n
= d_private
->rewriteBooleanTerms(n
);
3518 n
= Rewriter::rewrite(n
);
3521 Trace("smt") << "--- getting value of " << n
<< endl
;
3522 TheoryModel
* m
= d_theoryEngine
->getModel();
3525 resultNode
= m
->getValue(n
);
3527 Trace("smt") << "--- got value " << n
<< " = " << resultNode
<< endl
;
3528 resultNode
= postprocess(resultNode
, expectedType
);
3529 Trace("smt") << "--- model-post returned " << resultNode
<< endl
;
3530 Trace("smt") << "--- model-post returned " << resultNode
.getType() << endl
;
3531 Trace("smt") << "--- model-post expected " << expectedType
<< endl
;
3533 // type-check the result we got
3534 Assert(resultNode
.isNull() || resultNode
.getType().isSubtypeOf(expectedType
),
3535 "Run with -t smt for details.");
3537 // ensure it's a constant
3538 Assert(resultNode
.getKind() == kind::LAMBDA
|| resultNode
.isConst());
3540 if(options::abstractValues() && resultNode
.getType().isArray()) {
3541 resultNode
= d_private
->mkAbstractValue(resultNode
);
3544 return resultNode
.toExpr();
3547 bool SmtEngine::addToAssignment(const Expr
& ex
) throw() {
3548 SmtScope
smts(this);
3549 finalOptionsAreSet();
3551 // Substitute out any abstract values in ex
3552 Expr e
= d_private
->substituteAbstractValues(Node::fromExpr(ex
)).toExpr();
3553 Type type
= e
.getType(options::typeChecking());
3555 CheckArgument( type
.isBoolean(), e
,
3556 "expected Boolean-typed variable or function application "
3557 "in addToAssignment()" );
3558 Node n
= e
.getNode();
3559 // must be an APPLY of a zero-ary defined function, or a variable
3560 CheckArgument( ( ( n
.getKind() == kind::APPLY
&&
3561 ( d_definedFunctions
->find(n
.getOperator()) !=
3562 d_definedFunctions
->end() ) &&
3563 n
.getNumChildren() == 0 ) ||
3565 "expected variable or defined-function application "
3566 "in addToAssignment(),\ngot %s", e
.toString().c_str() );
3567 if(!options::produceAssignments()) {
3570 if(d_assignments
== NULL
) {
3571 d_assignments
= new(true) AssignmentSet(d_context
);
3573 d_assignments
->insert(n
);
3578 CVC4::SExpr
SmtEngine::getAssignment() throw(ModalException
) {
3579 Trace("smt") << "SMT getAssignment()" << endl
;
3580 SmtScope
smts(this);
3581 finalOptionsAreSet();
3582 if(Dump
.isOn("benchmark")) {
3583 Dump("benchmark") << GetAssignmentCommand();
3585 if(!options::produceAssignments()) {
3587 "Cannot get the current assignment when "
3588 "produce-assignments option is off.";
3589 throw ModalException(msg
);
3591 if(d_status
.isNull() ||
3592 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
3593 d_problemExtended
) {
3595 "Cannot get the current assignment unless immediately "
3596 "preceded by SAT/INVALID or UNKNOWN response.";
3597 throw ModalException(msg
);
3600 if(d_assignments
== NULL
) {
3601 return SExpr(vector
<SExpr
>());
3604 vector
<SExpr
> sexprs
;
3605 TypeNode boolType
= d_nodeManager
->booleanType();
3606 TheoryModel
* m
= d_theoryEngine
->getModel();
3607 for(AssignmentSet::const_iterator i
= d_assignments
->begin(),
3608 iend
= d_assignments
->end();
3611 Assert((*i
).getType() == boolType
);
3613 Trace("smt") << "--- getting value of " << *i
<< endl
;
3615 // Expand, then normalize
3616 hash_map
<Node
, Node
, NodeHashFunction
> cache
;
3617 Node n
= d_private
->expandDefinitions(*i
, cache
);
3618 n
= d_private
->rewriteBooleanTerms(n
);
3619 n
= Rewriter::rewrite(n
);
3621 Trace("smt") << "--- getting value of " << n
<< endl
;
3624 resultNode
= m
->getValue(n
);
3627 // type-check the result we got
3628 Assert(resultNode
.isNull() || resultNode
.getType() == boolType
);
3630 // ensure it's a constant
3631 Assert(resultNode
.isConst());
3634 if((*i
).getKind() == kind::APPLY
) {
3635 Assert((*i
).getNumChildren() == 0);
3636 v
.push_back(SExpr::Keyword((*i
).getOperator().toString()));
3638 Assert((*i
).isVar());
3639 v
.push_back(SExpr::Keyword((*i
).toString()));
3641 v
.push_back(SExpr::Keyword(resultNode
.toString()));
3642 sexprs
.push_back(v
);
3644 return SExpr(sexprs
);
3647 void SmtEngine::addToModelCommandAndDump(const Command
& c
, uint32_t flags
, bool userVisible
, const char* dumpTag
) {
3648 Trace("smt") << "SMT addToModelCommandAndDump(" << c
<< ")" << endl
;
3649 SmtScope
smts(this);
3650 // If we aren't yet fully inited, the user might still turn on
3651 // produce-models. So let's keep any commands around just in
3652 // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
3653 // sort "U" in QF_UF before setLogic() is run and we still want to
3654 // support finding card(U) with --finite-model-find, and (2) to
3655 // decouple SmtEngine and ExprManager if the user does a few
3656 // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
3657 // and expects to find their cardinalities in the model.
3658 if(/* userVisible && */
3659 (!d_fullyInited
|| options::produceModels()) &&
3660 (flags
& ExprManager::VAR_FLAG_DEFINED
) == 0) {
3662 if(flags
& ExprManager::VAR_FLAG_GLOBAL
) {
3663 d_modelGlobalCommands
.push_back(c
.clone());
3665 d_modelCommands
->push_back(c
.clone());
3668 if(Dump
.isOn(dumpTag
)) {
3672 d_dumpCommands
.push_back(c
.clone());
3677 Model
* SmtEngine::getModel() throw(ModalException
) {
3678 Trace("smt") << "SMT getModel()" << endl
;
3679 SmtScope
smts(this);
3681 finalOptionsAreSet();
3683 if(Dump
.isOn("benchmark")) {
3684 Dump("benchmark") << GetModelCommand();
3687 if(d_status
.isNull() ||
3688 d_status
.asSatisfiabilityResult() == Result::UNSAT
||
3689 d_problemExtended
) {
3691 "Cannot get the current model unless immediately "
3692 "preceded by SAT/INVALID or UNKNOWN response.";
3693 throw ModalException(msg
);
3695 if(!options::produceModels()) {
3697 "Cannot get model when produce-models options is off.";
3698 throw ModalException(msg
);
3700 TheoryModel
* m
= d_theoryEngine
->getModel();
3701 m
->d_inputName
= d_filename
;
3705 void SmtEngine::checkModel(bool hardFailure
) {
3706 // --check-model implies --interactive, which enables the assertion list,
3707 // so we should be ok.
3708 Assert(d_assertionList
!= NULL
, "don't have an assertion list to check in SmtEngine::checkModel()");
3710 TimerStat::CodeTimer
checkModelTimer(d_stats
->d_checkModelTime
);
3712 // Throughout, we use Notice() to give diagnostic output.
3714 // If this function is running, the user gave --check-model (or equivalent),
3715 // and if Notice() is on, the user gave --verbose (or equivalent).
3717 Notice() << "SmtEngine::checkModel(): generating model" << endl
;
3718 TheoryModel
* m
= d_theoryEngine
->getModel();
3720 // Check individual theory assertions
3721 d_theoryEngine
->checkTheoryAssertionsWithModel();
3726 // We have a "fake context" for the substitution map (we don't need it
3727 // to be context-dependent)
3728 context::Context fakeContext
;
3729 SubstitutionMap
substitutions(&fakeContext
, /* substituteUnderQuantifiers = */ false);
3731 for(size_t k
= 0; k
< m
->getNumCommands(); ++k
) {
3732 const DeclareFunctionCommand
* c
= dynamic_cast<const DeclareFunctionCommand
*>(m
->getCommand(k
));
3733 Notice() << "SmtEngine::checkModel(): model command " << k
<< " : " << m
->getCommand(k
) << endl
;
3735 // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
3736 Notice() << "SmtEngine::checkModel(): skipping..." << endl
;
3738 // We have a DECLARE-FUN:
3740 // We'll first do some checks, then add to our substitution map
3741 // the mapping: function symbol |-> value
3743 Expr func
= c
->getFunction();
3744 Node val
= m
->getValue(func
);
3746 Notice() << "SmtEngine::checkModel(): adding substitution: " << func
<< " |-> " << val
<< endl
;
3748 // (1) if the value is a lambda, ensure the lambda doesn't contain the
3749 // function symbol (since then the definition is recursive)
3750 if (val
.getKind() == kind::LAMBDA
) {
3751 // first apply the model substitutions we have so far
3752 Debug("boolean-terms") << "applying subses to " << val
[1] << endl
;
3753 Node n
= substitutions
.apply(val
[1]);
3754 Debug("boolean-terms") << "++ got " << n
<< endl
;
3755 // now check if n contains func by doing a substitution
3756 // [func->func2] and checking equality of the Nodes.
3757 // (this just a way to check if func is in n.)
3758 SubstitutionMap
subs(&fakeContext
);
3759 Node func2
= NodeManager::currentNM()->mkSkolem("", TypeNode::fromType(func
.getType()), "", NodeManager::SKOLEM_NO_NOTIFY
);
3760 subs
.addSubstitution(func
, func2
);
3761 if(subs
.apply(n
) != n
) {
3762 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED IN TERMS OF ITSELF ***" << endl
;
3764 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
3765 << "considering model value for " << func
<< endl
3766 << "body of lambda is: " << val
<< endl
;
3768 ss
<< "body substitutes to: " << n
<< endl
;
3770 ss
<< "so " << func
<< " is defined in terms of itself." << endl
3771 << "Run with `--check-models -v' for additional diagnostics.";
3772 InternalError(ss
.str());
3776 // (2) check that the value is actually a value
3777 else if (!val
.isConst()) {
3778 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT A CONSTANT ***" << endl
;
3780 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
3781 << "model value for " << func
<< endl
3782 << " is " << val
<< endl
3783 << "and that is not a constant (.isConst() == false)." << endl
3784 << "Run with `--check-models -v' for additional diagnostics.";
3785 InternalError(ss
.str());
3788 // (3) check that it's the correct (sub)type
3789 // This was intended to be a more general check, but for now we can't do that because
3790 // e.g. "1" is an INT, which isn't a subrange type [1..10] (etc.).
3791 else if(func
.getType().isInteger() && !val
.getType().isInteger()) {
3792 Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT CORRECT TYPE ***" << endl
;
3794 ss
<< "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
3795 << "model value for " << func
<< endl
3796 << " is " << val
<< endl
3797 << "value type is " << val
.getType() << endl
3798 << "should be of type " << func
.getType() << endl
3799 << "Run with `--check-models -v' for additional diagnostics.";
3800 InternalError(ss
.str());
3803 // (4) checks complete, add the substitution
3804 Debug("boolean-terms") << "cm: adding subs " << func
<< " :=> " << val
<< endl
;
3805 substitutions
.addSubstitution(func
, val
);
3809 // Now go through all our user assertions checking if they're satisfied.
3810 for(AssertionList::const_iterator i
= d_assertionList
->begin(); i
!= d_assertionList
->end(); ++i
) {
3811 Notice() << "SmtEngine::checkModel(): checking assertion " << *i
<< endl
;
3812 Node n
= Node::fromExpr(*i
);
3814 // Apply any define-funs from the problem.
3816 hash_map
<Node
, Node
, NodeHashFunction
> cache
;
3817 n
= d_private
->expandDefinitions(n
, cache
);
3819 Notice() << "SmtEngine::checkModel(): -- expands to " << n
<< endl
;
3821 // Apply our model value substitutions.
3822 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
3823 n
= substitutions
.apply(n
);
3824 Debug("boolean-terms") << "++ got " << n
<< endl
;
3825 Notice() << "SmtEngine::checkModel(): -- substitutes to " << n
<< endl
;
3827 //AJR : FIXME need to ignore quantifiers too?
3828 if( n
.getKind() != kind::REWRITE_RULE
){
3829 // In case it's a quantifier (or contains one), look up its value before
3830 // simplifying, or the quantifier might be irreparably altered.
3833 // Note this "skip" is done here, rather than above. This is
3834 // because (1) the quantifier could in principle simplify to false,
3835 // which should be reported, and (2) checking for the quantifier
3836 // above, before simplification, doesn't catch buried quantifiers
3837 // anyway (those not at the top-level).
3838 Notice() << "SmtEngine::checkModel(): -- skipping quantifiers/rewrite-rules assertion"
3843 // Simplify the result.
3844 n
= d_private
->simplify(n
);
3845 Notice() << "SmtEngine::checkModel(): -- simplifies to " << n
<< endl
;
3847 // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
3848 n
= d_private
->d_iteRemover
.replace(n
);
3849 Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n
<< endl
;
3851 // Apply our model value substitutions (again), as things may have been simplified.
3852 Debug("boolean-terms") << "applying subses to " << n
<< endl
;
3853 n
= substitutions
.apply(n
);
3854 Debug("boolean-terms") << "++ got " << n
<< endl
;
3855 Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n
<< endl
;
3857 // As a last-ditch effort, ask model to simplify it.
3858 // Presently, this is only an issue for quantifiers, which can have a value
3859 // but don't show up in our substitution map above.
3861 Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n
<< endl
;
3862 AlwaysAssert(!hardFailure
|| n
.isConst() || n
.getKind() == kind::LAMBDA
);
3864 // The result should be == true.
3865 if(n
!= NodeManager::currentNM()->mkConst(true)) {
3866 Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
3869 ss
<< "SmtEngine::checkModel(): "
3870 << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
3871 << "assertion: " << *i
<< endl
3872 << "simplifies to: " << n
<< endl
3873 << "expected `true'." << endl
3874 << "Run with `--check-models -v' for additional diagnostics.";
3876 InternalError(ss
.str());
3878 Warning() << ss
.str() << endl
;
3882 Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl
;
3885 Proof
* SmtEngine::getProof() throw(ModalException
) {
3886 Trace("smt") << "SMT getProof()" << endl
;
3887 SmtScope
smts(this);
3888 finalOptionsAreSet();
3889 if(Dump
.isOn("benchmark")) {
3890 Dump("benchmark") << GetProofCommand();
3893 if(!options::proof()) {
3895 "Cannot get a proof when produce-proofs option is off.";
3896 throw ModalException(msg
);
3898 if(d_status
.isNull() ||
3899 d_status
.asSatisfiabilityResult() != Result::UNSAT
||
3900 d_problemExtended
) {
3902 "Cannot get a proof unless immediately preceded by UNSAT/VALID response.";
3903 throw ModalException(msg
);
3906 return ProofManager::getProof(this);
3907 #else /* CVC4_PROOF */
3908 throw ModalException("This build of CVC4 doesn't have proof support.");
3909 #endif /* CVC4_PROOF */
3912 void SmtEngine::printInstantiations( std::ostream
& out
) {
3913 SmtScope
smts(this);
3914 if( options::instFormatMode()==INST_FORMAT_MODE_SZS
){
3915 out
<< "% SZS output start Proof for " << d_filename
.c_str() << std::endl
;
3917 if( d_theoryEngine
){
3918 d_theoryEngine
->printInstantiations( out
);
3920 if( options::instFormatMode()==INST_FORMAT_MODE_SZS
){
3921 out
<< "% SZS output end Proof for " << d_filename
.c_str() << std::endl
;
3925 vector
<Expr
> SmtEngine::getAssertions() throw(ModalException
) {
3926 SmtScope
smts(this);
3927 finalOptionsAreSet();
3928 if(Dump
.isOn("benchmark")) {
3929 Dump("benchmark") << GetAssertionsCommand();
3931 Trace("smt") << "SMT getAssertions()" << endl
;
3932 if(!options::interactive()) {
3934 "Cannot query the current assertion list when not in interactive mode.";
3935 throw ModalException(msg
);
3937 Assert(d_assertionList
!= NULL
);
3938 // copy the result out
3939 return vector
<Expr
>(d_assertionList
->begin(), d_assertionList
->end());
3942 void SmtEngine::push() throw(ModalException
, LogicException
) {
3943 SmtScope
smts(this);
3944 finalOptionsAreSet();
3946 Trace("smt") << "SMT push()" << endl
;
3947 d_private
->processAssertions();
3948 if(Dump
.isOn("benchmark")) {
3949 Dump("benchmark") << PushCommand();
3951 if(!options::incrementalSolving()) {
3952 throw ModalException("Cannot push when not solving incrementally (use --incremental)");
3955 // check to see if a postsolve() is pending
3956 if(d_needPostsolve
) {
3957 d_theoryEngine
->postsolve();
3958 d_needPostsolve
= false;
3961 // The problem isn't really "extended" yet, but this disallows
3962 // get-model after a push, simplifying our lives somewhat and
3963 // staying symmtric with pop.
3964 d_problemExtended
= true;
3966 d_userLevels
.push_back(d_userContext
->getLevel());
3968 Trace("userpushpop") << "SmtEngine: pushed to level "
3969 << d_userContext
->getLevel() << endl
;
3972 void SmtEngine::pop() throw(ModalException
) {
3973 SmtScope
smts(this);
3974 finalOptionsAreSet();
3975 Trace("smt") << "SMT pop()" << endl
;
3976 if(Dump
.isOn("benchmark")) {
3977 Dump("benchmark") << PopCommand();
3979 if(!options::incrementalSolving()) {
3980 throw ModalException("Cannot pop when not solving incrementally (use --incremental)");
3982 if(d_userLevels
.size() == 0) {
3983 throw ModalException("Cannot pop beyond the first user frame");
3986 // check to see if a postsolve() is pending
3987 if(d_needPostsolve
) {
3988 d_theoryEngine
->postsolve();
3989 d_needPostsolve
= false;
3992 // The problem isn't really "extended" yet, but this disallows
3993 // get-model after a pop, simplifying our lives somewhat. It might
3994 // not be strictly necessary to do so, since the pops occur lazily,
3995 // but also it would be weird to have a legally-executed (get-model)
3996 // that only returns a subset of the assignment (because the rest
3997 // is no longer in scope!).
3998 d_problemExtended
= true;
4000 AlwaysAssert(d_userContext
->getLevel() > 0);
4001 AlwaysAssert(d_userLevels
.back() < d_userContext
->getLevel());
4002 while (d_userLevels
.back() < d_userContext
->getLevel()) {
4005 d_userLevels
.pop_back();
4007 // Clear out assertion queues etc., in case anything is still in there
4008 d_private
->notifyPop();
4010 Trace("userpushpop") << "SmtEngine: popped to level "
4011 << d_userContext
->getLevel() << endl
;
4012 // FIXME: should we reset d_status here?
4013 // SMT-LIBv2 spec seems to imply no, but it would make sense to..
4016 void SmtEngine::internalPush() {
4017 Assert(d_fullyInited
);
4018 Trace("smt") << "SmtEngine::internalPush()" << endl
;
4020 if(options::incrementalSolving()) {
4021 d_private
->processAssertions();
4022 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
4023 d_userContext
->push();
4024 // the d_context push is done inside of the SAT solver
4025 d_propEngine
->push();
4029 void SmtEngine::internalPop(bool immediate
) {
4030 Assert(d_fullyInited
);
4031 Trace("smt") << "SmtEngine::internalPop()" << endl
;
4032 if(options::incrementalSolving()) {
4040 void SmtEngine::doPendingPops() {
4041 Assert(d_pendingPops
== 0 || options::incrementalSolving());
4042 while(d_pendingPops
> 0) {
4043 TimerStat::CodeTimer
pushPopTimer(d_stats
->d_pushPopTime
);
4044 d_propEngine
->pop();
4045 // the d_context pop is done inside of the SAT solver
4046 d_userContext
->pop();
4051 void SmtEngine::interrupt() throw(ModalException
) {
4052 if(!d_fullyInited
) {
4055 d_propEngine
->interrupt();
4056 d_theoryEngine
->interrupt();
4059 void SmtEngine::setResourceLimit(unsigned long units
, bool cumulative
) {
4061 Trace("limit") << "SmtEngine: setting cumulative resource limit to " << units
<< endl
;
4062 d_resourceBudgetCumulative
= (units
== 0) ? 0 : (d_cumulativeResourceUsed
+ units
);
4064 Trace("limit") << "SmtEngine: setting per-call resource limit to " << units
<< endl
;
4065 d_resourceBudgetPerCall
= units
;
4069 void SmtEngine::setTimeLimit(unsigned long millis
, bool cumulative
) {
4071 Trace("limit") << "SmtEngine: setting cumulative time limit to " << millis
<< " ms" << endl
;
4072 d_timeBudgetCumulative
= (millis
== 0) ? 0 : (d_cumulativeTimeUsed
+ millis
);
4074 Trace("limit") << "SmtEngine: setting per-call time limit to " << millis
<< " ms" << endl
;
4075 d_timeBudgetPerCall
= millis
;
4079 unsigned long SmtEngine::getResourceUsage() const {
4080 return d_cumulativeResourceUsed
;
4083 unsigned long SmtEngine::getTimeUsage() const {
4084 return d_cumulativeTimeUsed
;
4087 unsigned long SmtEngine::getResourceRemaining() const throw(ModalException
) {
4088 if(d_resourceBudgetCumulative
== 0) {
4089 throw ModalException("No cumulative resource limit is currently set");
4092 return d_resourceBudgetCumulative
<= d_cumulativeResourceUsed
? 0 :
4093 d_resourceBudgetCumulative
- d_cumulativeResourceUsed
;
4096 unsigned long SmtEngine::getTimeRemaining() const throw(ModalException
) {
4097 if(d_timeBudgetCumulative
== 0) {
4098 throw ModalException("No cumulative time limit is currently set");
4101 return d_timeBudgetCumulative
<= d_cumulativeTimeUsed
? 0 :
4102 d_timeBudgetCumulative
- d_cumulativeTimeUsed
;
4105 Statistics
SmtEngine::getStatistics() const throw() {
4106 return Statistics(*d_statisticsRegistry
);
4109 SExpr
SmtEngine::getStatistic(std::string name
) const throw() {
4110 return d_statisticsRegistry
->getStatistic(name
);
4113 void SmtEngine::setUserAttribute(const std::string
& attr
, Expr expr
) {
4114 SmtScope
smts(this);
4115 d_theoryEngine
->setUserAttribute(attr
, expr
.getNode());
4118 void SmtEngine::setPrintFuncInModel(Expr f
, bool p
) {
4119 Trace("setp-model") << "Set printInModel " << f
<< " to " << p
<< std::endl
;
4120 for( unsigned i
=0; i
<d_modelGlobalCommands
.size(); i
++ ){
4121 Command
* c
= d_modelGlobalCommands
[i
];
4122 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
4124 if( dfc
->getFunction()==f
){
4125 dfc
->setPrintInModel( p
);
4129 for( unsigned i
=0; i
<d_modelCommands
->size(); i
++ ){
4130 Command
* c
= (*d_modelCommands
)[i
];
4131 DeclareFunctionCommand
* dfc
= dynamic_cast<DeclareFunctionCommand
*>(c
);
4133 if( dfc
->getFunction()==f
){
4134 dfc
->setPrintInModel( p
);
4140 }/* CVC4 namespace */