Fix cegqi assertions for quantified non-linear cases. (#1999)
[cvc5.git] / src / theory / theory_engine.cpp
1 /********************* */
2 /*! \file theory_engine.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Dejan Jovanovic, Morgan Deters, Guy Katz
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2018 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
11 **
12 ** \brief The theory engine
13 **
14 ** The theory engine.
15 **/
16
17 #include "theory/theory_engine.h"
18
19 #include <list>
20 #include <vector>
21
22 #include "decision/decision_engine.h"
23 #include "expr/attribute.h"
24 #include "expr/node.h"
25 #include "expr/node_builder.h"
26 #include "options/bv_options.h"
27 #include "options/options.h"
28 #include "options/proof_options.h"
29 #include "options/quantifiers_options.h"
30 #include "proof/cnf_proof.h"
31 #include "proof/lemma_proof.h"
32 #include "proof/proof_manager.h"
33 #include "proof/theory_proof.h"
34 #include "smt/term_formula_removal.h"
35 #include "smt/logic_exception.h"
36 #include "smt_util/lemma_output_channel.h"
37 #include "smt_util/node_visitor.h"
38 #include "theory/arith/arith_ite_utils.h"
39 #include "theory/bv/theory_bv_utils.h"
40 #include "theory/care_graph.h"
41 #include "theory/ite_utilities.h"
42 #include "theory/quantifiers/first_order_model.h"
43 #include "theory/quantifiers/fmf/model_engine.h"
44 #include "theory/quantifiers/theory_quantifiers.h"
45 #include "theory/quantifiers_engine.h"
46 #include "theory/rewriter.h"
47 #include "theory/theory.h"
48 #include "theory/theory_model.h"
49 #include "theory/theory_traits.h"
50 #include "theory/uf/equality_engine.h"
51 #include "theory/unconstrained_simplifier.h"
52 #include "util/resource_manager.h"
53
54 using namespace std;
55
56 using namespace CVC4::theory;
57
58 namespace CVC4 {
59
60 inline void flattenAnd(Node n, std::vector<TNode>& out){
61 Assert(n.getKind() == kind::AND);
62 for(Node::iterator i=n.begin(), i_end=n.end(); i != i_end; ++i){
63 Node curr = *i;
64 if(curr.getKind() == kind::AND){
65 flattenAnd(curr, out);
66 }else{
67 out.push_back(curr);
68 }
69 }
70 }
71
72 inline Node flattenAnd(Node n){
73 std::vector<TNode> out;
74 flattenAnd(n, out);
75 return NodeManager::currentNM()->mkNode(kind::AND, out);
76 }
77
78 theory::LemmaStatus TheoryEngine::EngineOutputChannel::lemma(TNode lemma,
79 ProofRule rule,
80 bool removable,
81 bool preprocess,
82 bool sendAtoms) {
83 Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma("
84 << lemma << ")"
85 << ", preprocess = " << preprocess << std::endl;
86 ++d_statistics.lemmas;
87 d_engine->d_outputChannelUsed = true;
88
89 PROOF({ registerLemmaRecipe(lemma, lemma, preprocess, d_theory); });
90
91 theory::LemmaStatus result =
92 d_engine->lemma(lemma, rule, false, removable, preprocess,
93 sendAtoms ? d_theory : theory::THEORY_LAST);
94 return result;
95 }
96
97 void TheoryEngine::EngineOutputChannel::registerLemmaRecipe(Node lemma, Node originalLemma, bool preprocess, theory::TheoryId theoryId) {
98 // During CNF conversion, conjunctions will be broken down into
99 // multiple lemmas. In order for the recipes to match, we have to do
100 // the same here.
101 NodeManager* nm = NodeManager::currentNM();
102
103 if (preprocess)
104 lemma = d_engine->preprocess(lemma);
105
106 bool negated = (lemma.getKind() == kind::NOT);
107 Node nnLemma = negated ? lemma[0] : lemma;
108
109 switch (nnLemma.getKind()) {
110
111 case kind::AND:
112 if (!negated) {
113 for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i)
114 registerLemmaRecipe(nnLemma[i], originalLemma, false, theoryId);
115 } else {
116 NodeBuilder<> builder(kind::OR);
117 for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i)
118 builder << nnLemma[i].negate();
119
120 Node disjunction = (builder.getNumChildren() == 1) ? builder[0] : builder;
121 registerLemmaRecipe(disjunction, originalLemma, false, theoryId);
122 }
123 break;
124
125 case kind::EQUAL:
126 if( nnLemma[0].getType().isBoolean() ){
127 if (!negated) {
128 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[1].negate()), originalLemma, false, theoryId);
129 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1]), originalLemma, false, theoryId);
130 } else {
131 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[1]), originalLemma, false, theoryId);
132 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1].negate()), originalLemma, false, theoryId);
133 }
134 }
135 break;
136
137 case kind::ITE:
138 if (!negated) {
139 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1]), originalLemma, false, theoryId);
140 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[2]), originalLemma, false, theoryId);
141 } else {
142 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0].negate(), nnLemma[1].negate()), originalLemma, false, theoryId);
143 registerLemmaRecipe(nm->mkNode(kind::OR, nnLemma[0], nnLemma[2].negate()), originalLemma, false, theoryId);
144 }
145 break;
146
147 default:
148 break;
149 }
150
151 // Theory lemmas have one step that proves the empty clause
152 LemmaProofRecipe proofRecipe;
153 Node emptyNode;
154 LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
155
156 // Remember the original lemma, so we can report this later when asked to
157 proofRecipe.setOriginalLemma(originalLemma);
158
159 // Record the assertions and rewrites
160 Node rewritten;
161 if (lemma.getKind() == kind::OR) {
162 for (unsigned i = 0; i < lemma.getNumChildren(); ++i) {
163 rewritten = theory::Rewriter::rewrite(lemma[i]);
164 if (rewritten != lemma[i]) {
165 proofRecipe.addRewriteRule(lemma[i].negate(), rewritten.negate());
166 }
167 proofStep.addAssertion(lemma[i]);
168 proofRecipe.addBaseAssertion(rewritten);
169 }
170 } else {
171 rewritten = theory::Rewriter::rewrite(lemma);
172 if (rewritten != lemma) {
173 proofRecipe.addRewriteRule(lemma.negate(), rewritten.negate());
174 }
175 proofStep.addAssertion(lemma);
176 proofRecipe.addBaseAssertion(rewritten);
177 }
178 proofRecipe.addStep(proofStep);
179 ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
180 }
181
182 theory::LemmaStatus TheoryEngine::EngineOutputChannel::splitLemma(
183 TNode lemma, bool removable) {
184 Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma("
185 << lemma << ")" << std::endl;
186 ++d_statistics.lemmas;
187 d_engine->d_outputChannelUsed = true;
188
189 Debug("pf::explain") << "TheoryEngine::EngineOutputChannel::splitLemma( "
190 << lemma << " )" << std::endl;
191 theory::LemmaStatus result =
192 d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory);
193 return result;
194 }
195
196 bool TheoryEngine::EngineOutputChannel::propagate(TNode literal) {
197 Debug("theory::propagate") << "EngineOutputChannel<" << d_theory
198 << ">::propagate(" << literal << ")" << std::endl;
199 ++d_statistics.propagations;
200 d_engine->d_outputChannelUsed = true;
201 return d_engine->propagate(literal, d_theory);
202 }
203
204 void TheoryEngine::EngineOutputChannel::conflict(TNode conflictNode,
205 std::unique_ptr<Proof> proof)
206 {
207 Trace("theory::conflict")
208 << "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode
209 << ")" << std::endl;
210 Assert(!proof); // Theory shouldn't be producing proofs yet
211 ++d_statistics.conflicts;
212 d_engine->d_outputChannelUsed = true;
213 d_engine->conflict(conflictNode, d_theory);
214 }
215
216 void TheoryEngine::finishInit() {
217
218 //initialize the quantifiers engine, master equality engine, model, model builder
219 if( d_logicInfo.isQuantified() ) {
220 // initialize the quantifiers engine
221 d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
222 Assert(d_masterEqualityEngine == 0);
223 d_masterEqualityEngine = new eq::EqualityEngine(d_masterEENotify,getSatContext(), "theory::master", false);
224
225 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
226 if (d_theoryTable[theoryId]) {
227 d_theoryTable[theoryId]->setQuantifiersEngine(d_quantEngine);
228 d_theoryTable[theoryId]->setMasterEqualityEngine(d_masterEqualityEngine);
229 }
230 }
231
232 d_curr_model_builder = d_quantEngine->getModelBuilder();
233 d_curr_model = d_quantEngine->getModel();
234 } else {
235 d_curr_model = new theory::TheoryModel(
236 d_userContext, "DefaultModel", options::assignFunctionValues());
237 d_aloc_curr_model = true;
238 }
239 //make the default builder, e.g. in the case that the quantifiers engine does not have a model builder
240 if( d_curr_model_builder==NULL ){
241 d_curr_model_builder = new theory::TheoryEngineModelBuilder(this);
242 d_aloc_curr_model_builder = true;
243 }
244
245 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
246 if (d_theoryTable[theoryId]) {
247 d_theoryTable[theoryId]->finishInit();
248 }
249 }
250 }
251
252 void TheoryEngine::eqNotifyNewClass(TNode t){
253 if (d_logicInfo.isQuantified()) {
254 d_quantEngine->eqNotifyNewClass( t );
255 }
256 }
257
258 void TheoryEngine::eqNotifyPreMerge(TNode t1, TNode t2){
259 if (d_logicInfo.isQuantified()) {
260 d_quantEngine->eqNotifyPreMerge( t1, t2 );
261 }
262 }
263
264 void TheoryEngine::eqNotifyPostMerge(TNode t1, TNode t2){
265 if (d_logicInfo.isQuantified()) {
266 d_quantEngine->eqNotifyPostMerge( t1, t2 );
267 }
268 }
269
270 void TheoryEngine::eqNotifyDisequal(TNode t1, TNode t2, TNode reason){
271 if (d_logicInfo.isQuantified()) {
272 d_quantEngine->eqNotifyDisequal( t1, t2, reason );
273 }
274 }
275
276
277 TheoryEngine::TheoryEngine(context::Context* context,
278 context::UserContext* userContext,
279 RemoveTermFormulas& iteRemover,
280 const LogicInfo& logicInfo,
281 LemmaChannels* channels)
282 : d_propEngine(NULL),
283 d_decisionEngine(NULL),
284 d_context(context),
285 d_userContext(userContext),
286 d_logicInfo(logicInfo),
287 d_sharedTerms(this, context),
288 d_masterEqualityEngine(NULL),
289 d_masterEENotify(*this),
290 d_quantEngine(NULL),
291 d_curr_model(NULL),
292 d_aloc_curr_model(false),
293 d_curr_model_builder(NULL),
294 d_aloc_curr_model_builder(false),
295 d_ppCache(),
296 d_possiblePropagations(context),
297 d_hasPropagated(context),
298 d_inConflict(context, false),
299 d_hasShutDown(false),
300 d_incomplete(context, false),
301 d_propagationMap(context),
302 d_propagationMapTimestamp(context, 0),
303 d_propagatedLiterals(context),
304 d_propagatedLiteralsIndex(context, 0),
305 d_atomRequests(context),
306 d_tform_remover(iteRemover),
307 d_combineTheoriesTime("TheoryEngine::combineTheoriesTime"),
308 d_true(),
309 d_false(),
310 d_interrupted(false),
311 d_resourceManager(NodeManager::currentResourceManager()),
312 d_channels(channels),
313 d_inPreregister(false),
314 d_factsAsserted(context, false),
315 d_preRegistrationVisitor(this, context),
316 d_sharedTermsVisitor(d_sharedTerms),
317 d_unconstrainedSimp(new UnconstrainedSimplifier(context, logicInfo)),
318 d_theoryAlternatives(),
319 d_attr_handle(),
320 d_arithSubstitutionsAdded("theory::arith::zzz::arith::substitutions", 0)
321 {
322 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST;
323 ++ theoryId)
324 {
325 d_theoryTable[theoryId] = NULL;
326 d_theoryOut[theoryId] = NULL;
327 }
328
329 smtStatisticsRegistry()->registerStat(&d_combineTheoriesTime);
330 d_true = NodeManager::currentNM()->mkConst<bool>(true);
331 d_false = NodeManager::currentNM()->mkConst<bool>(false);
332
333 #ifdef CVC4_PROOF
334 ProofManager::currentPM()->initTheoryProofEngine();
335 #endif
336
337 d_iteUtilities = new ITEUtilities();
338
339 smtStatisticsRegistry()->registerStat(&d_arithSubstitutionsAdded);
340 }
341
342 TheoryEngine::~TheoryEngine() {
343 Assert(d_hasShutDown);
344
345 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
346 if(d_theoryTable[theoryId] != NULL) {
347 delete d_theoryTable[theoryId];
348 delete d_theoryOut[theoryId];
349 }
350 }
351
352 if( d_aloc_curr_model_builder ){
353 delete d_curr_model_builder;
354 }
355 if( d_aloc_curr_model ){
356 delete d_curr_model;
357 }
358
359 delete d_quantEngine;
360
361 delete d_masterEqualityEngine;
362
363 smtStatisticsRegistry()->unregisterStat(&d_combineTheoriesTime);
364
365 delete d_unconstrainedSimp;
366
367 delete d_iteUtilities;
368
369 smtStatisticsRegistry()->unregisterStat(&d_arithSubstitutionsAdded);
370 }
371
372 void TheoryEngine::interrupt() { d_interrupted = true; }
373 void TheoryEngine::preRegister(TNode preprocessed) {
374
375 Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")" << std::endl;
376 if(Dump.isOn("missed-t-propagations")) {
377 d_possiblePropagations.push_back(preprocessed);
378 }
379 d_preregisterQueue.push(preprocessed);
380
381 if (!d_inPreregister) {
382 // We're in pre-register
383 d_inPreregister = true;
384
385 // Process the pre-registration queue
386 while (!d_preregisterQueue.empty()) {
387 // Get the next atom to pre-register
388 preprocessed = d_preregisterQueue.front();
389 d_preregisterQueue.pop();
390
391 if (d_logicInfo.isSharingEnabled() && preprocessed.getKind() == kind::EQUAL) {
392 // When sharing is enabled, we propagate from the shared terms manager also
393 d_sharedTerms.addEqualityToPropagate(preprocessed);
394 }
395
396 // the atom should not have free variables
397 Debug("theory") << "TheoryEngine::preRegister: " << preprocessed
398 << std::endl;
399 Assert(!preprocessed.hasFreeVar());
400 // Pre-register the terms in the atom
401 Theory::Set theories = NodeVisitor<PreRegisterVisitor>::run(d_preRegistrationVisitor, preprocessed);
402 theories = Theory::setRemove(THEORY_BOOL, theories);
403 // Remove the top theory, if any more that means multiple theories were involved
404 bool multipleTheories = Theory::setRemove(Theory::theoryOf(preprocessed), theories);
405 TheoryId i;
406 // These checks don't work with finite model finding, because it
407 // uses Rational constants to represent cardinality constraints,
408 // even though arithmetic isn't actually involved.
409 if(!options::finiteModelFind()) {
410 while((i = Theory::setPop(theories)) != THEORY_LAST) {
411 if(!d_logicInfo.isTheoryEnabled(i)) {
412 LogicInfo newLogicInfo = d_logicInfo.getUnlockedCopy();
413 newLogicInfo.enableTheory(i);
414 newLogicInfo.lock();
415 stringstream ss;
416 ss << "The logic was specified as " << d_logicInfo.getLogicString()
417 << ", which doesn't include " << i
418 << ", but found a term in that theory." << endl
419 << "You might want to extend your logic to "
420 << newLogicInfo.getLogicString() << endl;
421 throw LogicException(ss.str());
422 }
423 }
424 }
425 if (multipleTheories) {
426 // Collect the shared terms if there are multiple theories
427 NodeVisitor<SharedTermsVisitor>::run(d_sharedTermsVisitor, preprocessed);
428 }
429 }
430
431 // Leaving pre-register
432 d_inPreregister = false;
433 }
434 }
435
436 void TheoryEngine::printAssertions(const char* tag) {
437 if (Trace.isOn(tag)) {
438
439 for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
440 Theory* theory = d_theoryTable[theoryId];
441 if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
442 Trace(tag) << "--------------------------------------------" << endl;
443 Trace(tag) << "Assertions of " << theory->getId() << ": " << endl;
444 context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
445 for (unsigned i = 0; it != it_end; ++ it, ++i) {
446 if ((*it).isPreregistered) {
447 Trace(tag) << "[" << i << "]: ";
448 } else {
449 Trace(tag) << "(" << i << "): ";
450 }
451 Trace(tag) << (*it).assertion << endl;
452 }
453
454 if (d_logicInfo.isSharingEnabled()) {
455 Trace(tag) << "Shared terms of " << theory->getId() << ": " << endl;
456 context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
457 for (unsigned i = 0; it != it_end; ++ it, ++i) {
458 Trace(tag) << "[" << i << "]: " << (*it) << endl;
459 }
460 }
461 }
462 }
463 }
464 }
465
466 void TheoryEngine::dumpAssertions(const char* tag) {
467 if (Dump.isOn(tag)) {
468 Dump(tag) << CommentCommand("Starting completeness check");
469 for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
470 Theory* theory = d_theoryTable[theoryId];
471 if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
472 Dump(tag) << CommentCommand("Completeness check");
473 Dump(tag) << PushCommand();
474
475 // Dump the shared terms
476 if (d_logicInfo.isSharingEnabled()) {
477 Dump(tag) << CommentCommand("Shared terms");
478 context::CDList<TNode>::const_iterator it = theory->shared_terms_begin(), it_end = theory->shared_terms_end();
479 for (unsigned i = 0; it != it_end; ++ it, ++i) {
480 stringstream ss;
481 ss << (*it);
482 Dump(tag) << CommentCommand(ss.str());
483 }
484 }
485
486 // Dump the assertions
487 Dump(tag) << CommentCommand("Assertions");
488 context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
489 for (; it != it_end; ++ it) {
490 // Get the assertion
491 Node assertionNode = (*it).assertion;
492 // Purify all the terms
493
494 if ((*it).isPreregistered) {
495 Dump(tag) << CommentCommand("Preregistered");
496 } else {
497 Dump(tag) << CommentCommand("Shared assertion");
498 }
499 Dump(tag) << AssertCommand(assertionNode.toExpr());
500 }
501 Dump(tag) << CheckSatCommand();
502
503 Dump(tag) << PopCommand();
504 }
505 }
506 }
507 }
508
509 /**
510 * Check all (currently-active) theories for conflicts.
511 * @param effort the effort level to use
512 */
513 void TheoryEngine::check(Theory::Effort effort) {
514 // spendResource();
515
516 // Reset the interrupt flag
517 d_interrupted = false;
518
519 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
520 #undef CVC4_FOR_EACH_THEORY_STATEMENT
521 #endif
522 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
523 if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \
524 theoryOf(THEORY)->check(effort); \
525 if (d_inConflict) { \
526 Debug("conflict") << THEORY << " in conflict. " << std::endl; \
527 break; \
528 } \
529 }
530
531 // Do the checking
532 try {
533
534 // Mark the output channel unused (if this is FULL_EFFORT, and nothing
535 // is done by the theories, no additional check will be needed)
536 d_outputChannelUsed = false;
537
538 // Mark the lemmas flag (no lemmas added)
539 d_lemmasAdded = false;
540
541 Debug("theory") << "TheoryEngine::check(" << effort << "): d_factsAsserted = " << (d_factsAsserted ? "true" : "false") << endl;
542
543 // If in full effort, we have a fake new assertion just to jumpstart the checking
544 if (Theory::fullEffort(effort)) {
545 d_factsAsserted = true;
546 }
547
548 // Check until done
549 while (d_factsAsserted && !d_inConflict && !d_lemmasAdded) {
550
551 Debug("theory") << "TheoryEngine::check(" << effort << "): running check" << endl;
552
553 Trace("theory::assertions") << endl;
554 if (Trace.isOn("theory::assertions")) {
555 printAssertions("theory::assertions");
556 }
557
558 if(Theory::fullEffort(effort)) {
559 Trace("theory::assertions::fulleffort") << endl;
560 if (Trace.isOn("theory::assertions::fulleffort")) {
561 printAssertions("theory::assertions::fulleffort");
562 }
563 }
564
565 // Note that we've discharged all the facts
566 d_factsAsserted = false;
567
568 // Do the checking
569 CVC4_FOR_EACH_THEORY;
570
571 if(Dump.isOn("missed-t-conflicts")) {
572 Dump("missed-t-conflicts")
573 << CommentCommand("Completeness check for T-conflicts; expect sat")
574 << CheckSatCommand();
575 }
576
577 Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl;
578
579 // We are still satisfiable, propagate as much as possible
580 propagate(effort);
581
582 // We do combination if all has been processed and we are in fullcheck
583 if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded && !d_inConflict) {
584 // Do the combination
585 Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
586 combineTheories();
587 if(d_logicInfo.isQuantified()){
588 d_quantEngine->notifyCombineTheories();
589 }
590 }
591 }
592
593 // Must consult quantifiers theory for last call to ensure sat, or otherwise add a lemma
594 if( Theory::fullEffort(effort) && ! d_inConflict && ! needCheck() ) {
595 Trace("theory::assertions-model") << endl;
596 if (Trace.isOn("theory::assertions-model")) {
597 printAssertions("theory::assertions-model");
598 }
599 //checks for theories requiring the model go at last call
600 d_curr_model->reset();
601 for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
602 if( theoryId!=THEORY_QUANTIFIERS ){
603 Theory* theory = d_theoryTable[theoryId];
604 if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
605 if( theory->needsCheckLastEffort() ){
606 if( !d_curr_model->isBuilt() ){
607 if( !d_curr_model_builder->buildModel(d_curr_model) ){
608 break;
609 }
610 }
611 theory->check(Theory::EFFORT_LAST_CALL);
612 }
613 }
614 }
615 }
616 if (!d_inConflict)
617 {
618 if(d_logicInfo.isQuantified()) {
619 // quantifiers engine must check at last call effort
620 d_quantEngine->check(Theory::EFFORT_LAST_CALL);
621 }
622 }
623 if (!d_inConflict && !needCheck())
624 {
625 if (options::produceModels() && !d_curr_model->isBuilt())
626 {
627 // must build model at this point
628 d_curr_model_builder->buildModel(d_curr_model);
629 }
630 }
631 }
632
633 Debug("theory") << "TheoryEngine::check(" << effort << "): done, we are " << (d_inConflict ? "unsat" : "sat") << (d_lemmasAdded ? " with new lemmas" : " with no new lemmas");
634 Debug("theory") << ", need check = " << (needCheck() ? "YES" : "NO") << endl;
635
636 if( Theory::fullEffort(effort) && !d_inConflict && !needCheck()) {
637 // case where we are about to answer SAT
638 if( d_masterEqualityEngine != NULL ){
639 AlwaysAssert(d_masterEqualityEngine->consistent());
640 }
641 if (d_curr_model->isBuilt())
642 {
643 // model construction should always succeed unless lemmas were added
644 AlwaysAssert(d_curr_model->isBuiltSuccess());
645 if (options::produceModels())
646 {
647 // if we are incomplete, there is no guarantee on the model.
648 // thus, we do not check the model here. (related to #1693)
649 // we also don't debug-check the model if the checkModels()
650 // is not enabled.
651 if (!d_incomplete && options::checkModels())
652 {
653 d_curr_model_builder->debugCheckModel(d_curr_model);
654 }
655 // Do post-processing of model from the theories (used for THEORY_SEP
656 // to construct heap model)
657 postProcessModel(d_curr_model);
658 }
659 }
660 }
661 } catch(const theory::Interrupted&) {
662 Trace("theory") << "TheoryEngine::check() => interrupted" << endl;
663 }
664 // If fulleffort, check all theories
665 if(Dump.isOn("theory::fullcheck") && Theory::fullEffort(effort)) {
666 if (!d_inConflict && !needCheck()) {
667 dumpAssertions("theory::fullcheck");
668 }
669 }
670 }
671
672 void TheoryEngine::combineTheories() {
673
674 Trace("combineTheories") << "TheoryEngine::combineTheories()" << endl;
675
676 TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
677
678 // Care graph we'll be building
679 CareGraph careGraph;
680
681 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
682 #undef CVC4_FOR_EACH_THEORY_STATEMENT
683 #endif
684 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
685 if (theory::TheoryTraits<THEORY>::isParametric && d_logicInfo.isTheoryEnabled(THEORY)) { \
686 theoryOf(THEORY)->getCareGraph(&careGraph); \
687 }
688
689 // Call on each parametric theory to give us its care graph
690 CVC4_FOR_EACH_THEORY;
691
692 Trace("combineTheories") << "TheoryEngine::combineTheories(): care graph size = " << careGraph.size() << endl;
693
694 // Now add splitters for the ones we are interested in
695 CareGraph::const_iterator care_it = careGraph.begin();
696 CareGraph::const_iterator care_it_end = careGraph.end();
697
698 for (; care_it != care_it_end; ++ care_it) {
699 const CarePair& carePair = *care_it;
700
701 Debug("combineTheories") << "TheoryEngine::combineTheories(): checking " << carePair.a << " = " << carePair.b << " from " << carePair.theory << endl;
702
703 Assert(d_sharedTerms.isShared(carePair.a) || carePair.a.isConst());
704 Assert(d_sharedTerms.isShared(carePair.b) || carePair.b.isConst());
705
706 // The equality in question (order for no repetition)
707 Node equality = carePair.a.eqNode(carePair.b);
708 // EqualityStatus es = getEqualityStatus(carePair.a, carePair.b);
709 // Debug("combineTheories") << "TheoryEngine::combineTheories(): " <<
710 // (es == EQUALITY_TRUE_AND_PROPAGATED ? "EQUALITY_TRUE_AND_PROPAGATED" :
711 // es == EQUALITY_FALSE_AND_PROPAGATED ? "EQUALITY_FALSE_AND_PROPAGATED" :
712 // es == EQUALITY_TRUE ? "EQUALITY_TRUE" :
713 // es == EQUALITY_FALSE ? "EQUALITY_FALSE" :
714 // es == EQUALITY_TRUE_IN_MODEL ? "EQUALITY_TRUE_IN_MODEL" :
715 // es == EQUALITY_FALSE_IN_MODEL ? "EQUALITY_FALSE_IN_MODEL" :
716 // es == EQUALITY_UNKNOWN ? "EQUALITY_UNKNOWN" :
717 // "Unexpected case") << endl;
718
719 // We need to split on it
720 Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
721
722 lemma(equality.orNode(equality.notNode()), RULE_INVALID, false, false, false, carePair.theory);
723
724 // This code is supposed to force preference to follow what the theory models already have
725 // but it doesn't seem to make a big difference - need to explore more -Clark
726 // if (true) {
727 // if (es == EQUALITY_TRUE || es == EQUALITY_TRUE_IN_MODEL) {
728 Node e = ensureLiteral(equality);
729 d_propEngine->requirePhase(e, true);
730 // }
731 // else if (es == EQUALITY_FALSE_IN_MODEL) {
732 // Node e = ensureLiteral(equality);
733 // d_propEngine->requirePhase(e, false);
734 // }
735 // }
736 }
737 }
738
739 void TheoryEngine::propagate(Theory::Effort effort) {
740 // Reset the interrupt flag
741 d_interrupted = false;
742
743 // Definition of the statement that is to be run by every theory
744 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
745 #undef CVC4_FOR_EACH_THEORY_STATEMENT
746 #endif
747 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
748 if (theory::TheoryTraits<THEORY>::hasPropagate && d_logicInfo.isTheoryEnabled(THEORY)) { \
749 theoryOf(THEORY)->propagate(effort); \
750 }
751
752 // Reset the interrupt flag
753 d_interrupted = false;
754
755 // Propagate for each theory using the statement above
756 CVC4_FOR_EACH_THEORY;
757
758 if(Dump.isOn("missed-t-propagations")) {
759 for(unsigned i = 0; i < d_possiblePropagations.size(); ++i) {
760 Node atom = d_possiblePropagations[i];
761 bool value;
762 if(d_propEngine->hasValue(atom, value)) {
763 continue;
764 }
765 // Doesn't have a value, check it (and the negation)
766 if(d_hasPropagated.find(atom) == d_hasPropagated.end()) {
767 Dump("missed-t-propagations")
768 << CommentCommand("Completeness check for T-propagations; expect invalid")
769 << EchoCommand(atom.toString())
770 << QueryCommand(atom.toExpr())
771 << EchoCommand(atom.notNode().toString())
772 << QueryCommand(atom.notNode().toExpr());
773 }
774 }
775 }
776 }
777
778 Node TheoryEngine::getNextDecisionRequest() {
779 // Definition of the statement that is to be run by every theory
780 unsigned min_priority = 0;
781 Node dec;
782 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
783 #undef CVC4_FOR_EACH_THEORY_STATEMENT
784 #endif
785 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
786 if (theory::TheoryTraits<THEORY>::hasGetNextDecisionRequest && d_logicInfo.isTheoryEnabled(THEORY)) { \
787 unsigned priority; \
788 Node n = theoryOf(THEORY)->getNextDecisionRequest( priority ); \
789 if(! n.isNull() && ( dec.isNull() || priority<min_priority ) ) { \
790 dec = n; \
791 min_priority = priority; \
792 } \
793 }
794
795 // Request decision from each theory using the statement above
796 CVC4_FOR_EACH_THEORY;
797
798 return dec;
799 }
800
801 bool TheoryEngine::properConflict(TNode conflict) const {
802 bool value;
803 if (conflict.getKind() == kind::AND) {
804 for (unsigned i = 0; i < conflict.getNumChildren(); ++ i) {
805 if (! getPropEngine()->hasValue(conflict[i], value)) {
806 Debug("properConflict") << "Bad conflict is due to unassigned atom: "
807 << conflict[i] << endl;
808 return false;
809 }
810 if (! value) {
811 Debug("properConflict") << "Bad conflict is due to false atom: "
812 << conflict[i] << endl;
813 return false;
814 }
815 if (conflict[i] != Rewriter::rewrite(conflict[i])) {
816 Debug("properConflict") << "Bad conflict is due to atom not in normal form: "
817 << conflict[i] << " vs " << Rewriter::rewrite(conflict[i]) << endl;
818 return false;
819 }
820 }
821 } else {
822 if (! getPropEngine()->hasValue(conflict, value)) {
823 Debug("properConflict") << "Bad conflict is due to unassigned atom: "
824 << conflict << endl;
825 return false;
826 }
827 if(! value) {
828 Debug("properConflict") << "Bad conflict is due to false atom: "
829 << conflict << endl;
830 return false;
831 }
832 if (conflict != Rewriter::rewrite(conflict)) {
833 Debug("properConflict") << "Bad conflict is due to atom not in normal form: "
834 << conflict << " vs " << Rewriter::rewrite(conflict) << endl;
835 return false;
836 }
837 }
838 return true;
839 }
840
841 bool TheoryEngine::properPropagation(TNode lit) const {
842 if(!getPropEngine()->isSatLiteral(lit)) {
843 return false;
844 }
845 bool b;
846 return !getPropEngine()->hasValue(lit, b);
847 }
848
849 bool TheoryEngine::properExplanation(TNode node, TNode expl) const {
850 // Explanation must be either a conjunction of true literals that have true SAT values already
851 // or a singled literal that has a true SAT value already.
852 if (expl.getKind() == kind::AND) {
853 for (unsigned i = 0; i < expl.getNumChildren(); ++ i) {
854 bool value;
855 if (!d_propEngine->hasValue(expl[i], value) || !value) {
856 return false;
857 }
858 }
859 } else {
860 bool value;
861 return d_propEngine->hasValue(expl, value) && value;
862 }
863 return true;
864 }
865
866 bool TheoryEngine::collectModelInfo(theory::TheoryModel* m)
867 {
868 //have shared term engine collectModelInfo
869 // d_sharedTerms.collectModelInfo( m );
870 // Consult each active theory to get all relevant information
871 // concerning the model.
872 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
873 if(d_logicInfo.isTheoryEnabled(theoryId)) {
874 Trace("model-builder") << " CollectModelInfo on theory: " << theoryId << endl;
875 if (!d_theoryTable[theoryId]->collectModelInfo(m))
876 {
877 return false;
878 }
879 }
880 }
881 // Get the Boolean variables
882 vector<TNode> boolVars;
883 d_propEngine->getBooleanVariables(boolVars);
884 vector<TNode>::iterator it, iend = boolVars.end();
885 bool hasValue, value;
886 for (it = boolVars.begin(); it != iend; ++it) {
887 TNode var = *it;
888 hasValue = d_propEngine->hasValue(var, value);
889 // TODO: Assert that hasValue is true?
890 if (!hasValue) {
891 value = false;
892 }
893 Trace("model-builder-assertions") << "(assert" << (value ? " " : " (not ") << var << (value ? ");" : "));") << endl;
894 if (!m->assertPredicate(var, value))
895 {
896 return false;
897 }
898 }
899 return true;
900 }
901
902 void TheoryEngine::postProcessModel( theory::TheoryModel* m ){
903 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
904 if(d_logicInfo.isTheoryEnabled(theoryId)) {
905 Trace("model-builder-debug") << " PostProcessModel on theory: " << theoryId << endl;
906 d_theoryTable[theoryId]->postProcessModel( m );
907 }
908 }
909 }
910
911 /* get model */
912 TheoryModel* TheoryEngine::getModel() {
913 return d_curr_model;
914 }
915
916 void TheoryEngine::getSynthSolutions(std::map<Node, Node>& sol_map)
917 {
918 if (d_quantEngine)
919 {
920 d_quantEngine->getSynthSolutions(sol_map);
921 }
922 else
923 {
924 Assert(false);
925 }
926 }
927
928 bool TheoryEngine::presolve() {
929 // Reset the interrupt flag
930 d_interrupted = false;
931
932 try {
933 // Definition of the statement that is to be run by every theory
934 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
935 #undef CVC4_FOR_EACH_THEORY_STATEMENT
936 #endif
937 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
938 if (theory::TheoryTraits<THEORY>::hasPresolve) { \
939 theoryOf(THEORY)->presolve(); \
940 if(d_inConflict) { \
941 return true; \
942 } \
943 }
944
945 // Presolve for each theory using the statement above
946 CVC4_FOR_EACH_THEORY;
947 } catch(const theory::Interrupted&) {
948 Trace("theory") << "TheoryEngine::presolve() => interrupted" << endl;
949 }
950 // return whether we have a conflict
951 return false;
952 }/* TheoryEngine::presolve() */
953
954 void TheoryEngine::postsolve() {
955 // Reset the interrupt flag
956 d_interrupted = false;
957 bool CVC4_UNUSED wasInConflict = d_inConflict;
958
959 try {
960 // Definition of the statement that is to be run by every theory
961 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
962 #undef CVC4_FOR_EACH_THEORY_STATEMENT
963 #endif
964 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
965 if (theory::TheoryTraits<THEORY>::hasPostsolve) { \
966 theoryOf(THEORY)->postsolve(); \
967 Assert(! d_inConflict || wasInConflict, "conflict raised during postsolve()"); \
968 }
969
970 // Postsolve for each theory using the statement above
971 CVC4_FOR_EACH_THEORY;
972 } catch(const theory::Interrupted&) {
973 Trace("theory") << "TheoryEngine::postsolve() => interrupted" << endl;
974 }
975 }/* TheoryEngine::postsolve() */
976
977
978 void TheoryEngine::notifyRestart() {
979 // Reset the interrupt flag
980 d_interrupted = false;
981
982 // Definition of the statement that is to be run by every theory
983 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
984 #undef CVC4_FOR_EACH_THEORY_STATEMENT
985 #endif
986 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
987 if (theory::TheoryTraits<THEORY>::hasNotifyRestart && d_logicInfo.isTheoryEnabled(THEORY)) { \
988 theoryOf(THEORY)->notifyRestart(); \
989 }
990
991 // notify each theory using the statement above
992 CVC4_FOR_EACH_THEORY;
993 }
994
995 void TheoryEngine::ppStaticLearn(TNode in, NodeBuilder<>& learned) {
996 // Reset the interrupt flag
997 d_interrupted = false;
998
999 // Definition of the statement that is to be run by every theory
1000 #ifdef CVC4_FOR_EACH_THEORY_STATEMENT
1001 #undef CVC4_FOR_EACH_THEORY_STATEMENT
1002 #endif
1003 #define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
1004 if (theory::TheoryTraits<THEORY>::hasPpStaticLearn) { \
1005 theoryOf(THEORY)->ppStaticLearn(in, learned); \
1006 }
1007
1008 // static learning for each theory using the statement above
1009 CVC4_FOR_EACH_THEORY;
1010 }
1011
1012 void TheoryEngine::shutdown() {
1013 // Set this first; if a Theory shutdown() throws an exception,
1014 // at least the destruction of the TheoryEngine won't confound
1015 // matters.
1016 d_hasShutDown = true;
1017
1018 // Shutdown all the theories
1019 for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
1020 if(d_theoryTable[theoryId]) {
1021 theoryOf(theoryId)->shutdown();
1022 }
1023 }
1024
1025 d_ppCache.clear();
1026 }
1027
1028 theory::Theory::PPAssertStatus TheoryEngine::solve(TNode literal, SubstitutionMap& substitutionOut) {
1029 // Reset the interrupt flag
1030 d_interrupted = false;
1031
1032 TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal;
1033 Trace("theory::solve") << "TheoryEngine::solve(" << literal << "): solving with " << theoryOf(atom)->getId() << endl;
1034
1035 if(! d_logicInfo.isTheoryEnabled(Theory::theoryOf(atom)) &&
1036 Theory::theoryOf(atom) != THEORY_SAT_SOLVER) {
1037 stringstream ss;
1038 ss << "The logic was specified as " << d_logicInfo.getLogicString()
1039 << ", which doesn't include " << Theory::theoryOf(atom)
1040 << ", but got a preprocessing-time fact for that theory." << endl
1041 << "The fact:" << endl
1042 << literal;
1043 throw LogicException(ss.str());
1044 }
1045
1046 Theory::PPAssertStatus solveStatus = theoryOf(atom)->ppAssert(literal, substitutionOut);
1047 Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl;
1048 return solveStatus;
1049 }
1050
1051 // Recursively traverse a term and call the theory rewriter on its sub-terms
1052 Node TheoryEngine::ppTheoryRewrite(TNode term) {
1053 NodeMap::iterator find = d_ppCache.find(term);
1054 if (find != d_ppCache.end()) {
1055 return (*find).second;
1056 }
1057 unsigned nc = term.getNumChildren();
1058 if (nc == 0) {
1059 return theoryOf(term)->ppRewrite(term);
1060 }
1061 Trace("theory-pp") << "ppTheoryRewrite { " << term << endl;
1062
1063 Node newTerm;
1064 // do not rewrite inside quantifiers
1065 if (term.getKind() == kind::FORALL || term.getKind() == kind::EXISTS
1066 || term.getKind() == kind::CHOICE
1067 || term.getKind() == kind::LAMBDA)
1068 {
1069 newTerm = Rewriter::rewrite(term);
1070 }
1071 else
1072 {
1073 NodeBuilder<> newNode(term.getKind());
1074 if (term.getMetaKind() == kind::metakind::PARAMETERIZED) {
1075 newNode << term.getOperator();
1076 }
1077 unsigned i;
1078 for (i = 0; i < nc; ++i) {
1079 newNode << ppTheoryRewrite(term[i]);
1080 }
1081 newTerm = Rewriter::rewrite(Node(newNode));
1082 }
1083 Node newTerm2 = theoryOf(newTerm)->ppRewrite(newTerm);
1084 if (newTerm != newTerm2) {
1085 newTerm = ppTheoryRewrite(Rewriter::rewrite(newTerm2));
1086 }
1087 d_ppCache[term] = newTerm;
1088 Trace("theory-pp")<< "ppTheoryRewrite returning " << newTerm << "}" << endl;
1089 return newTerm;
1090 }
1091
1092
1093 void TheoryEngine::preprocessStart()
1094 {
1095 d_ppCache.clear();
1096 }
1097
1098
1099 struct preprocess_stack_element {
1100 TNode node;
1101 bool children_added;
1102 preprocess_stack_element(TNode node)
1103 : node(node), children_added(false) {}
1104 };/* struct preprocess_stack_element */
1105
1106
1107 Node TheoryEngine::preprocess(TNode assertion) {
1108
1109 Trace("theory::preprocess") << "TheoryEngine::preprocess(" << assertion << ")" << endl;
1110 // spendResource();
1111
1112 // Do a topological sort of the subexpressions and substitute them
1113 vector<preprocess_stack_element> toVisit;
1114 toVisit.push_back(assertion);
1115
1116 while (!toVisit.empty())
1117 {
1118 // The current node we are processing
1119 preprocess_stack_element& stackHead = toVisit.back();
1120 TNode current = stackHead.node;
1121
1122 Debug("theory::internal") << "TheoryEngine::preprocess(" << assertion << "): processing " << current << endl;
1123
1124 // If node already in the cache we're done, pop from the stack
1125 NodeMap::iterator find = d_ppCache.find(current);
1126 if (find != d_ppCache.end()) {
1127 toVisit.pop_back();
1128 continue;
1129 }
1130
1131 if(! d_logicInfo.isTheoryEnabled(Theory::theoryOf(current)) &&
1132 Theory::theoryOf(current) != THEORY_SAT_SOLVER) {
1133 stringstream ss;
1134 ss << "The logic was specified as " << d_logicInfo.getLogicString()
1135 << ", which doesn't include " << Theory::theoryOf(current)
1136 << ", but got a preprocessing-time fact for that theory." << endl
1137 << "The fact:" << endl
1138 << current;
1139 throw LogicException(ss.str());
1140 }
1141
1142 // If this is an atom, we preprocess its terms with the theory ppRewriter
1143 if (Theory::theoryOf(current) != THEORY_BOOL) {
1144 Node ppRewritten = ppTheoryRewrite(current);
1145 d_ppCache[current] = ppRewritten;
1146 Assert(Rewriter::rewrite(d_ppCache[current]) == d_ppCache[current]);
1147 continue;
1148 }
1149
1150 // Not yet substituted, so process
1151 if (stackHead.children_added) {
1152 // Children have been processed, so substitute
1153 NodeBuilder<> builder(current.getKind());
1154 if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
1155 builder << current.getOperator();
1156 }
1157 for (unsigned i = 0; i < current.getNumChildren(); ++ i) {
1158 Assert(d_ppCache.find(current[i]) != d_ppCache.end());
1159 builder << d_ppCache[current[i]];
1160 }
1161 // Mark the substitution and continue
1162 Node result = builder;
1163 if (result != current) {
1164 result = Rewriter::rewrite(result);
1165 }
1166 Debug("theory::internal") << "TheoryEngine::preprocess(" << assertion << "): setting " << current << " -> " << result << endl;
1167 d_ppCache[current] = result;
1168 toVisit.pop_back();
1169 } else {
1170 // Mark that we have added the children if any
1171 if (current.getNumChildren() > 0) {
1172 stackHead.children_added = true;
1173 // We need to add the children
1174 for(TNode::iterator child_it = current.begin(); child_it != current.end(); ++ child_it) {
1175 TNode childNode = *child_it;
1176 NodeMap::iterator childFind = d_ppCache.find(childNode);
1177 if (childFind == d_ppCache.end()) {
1178 toVisit.push_back(childNode);
1179 }
1180 }
1181 } else {
1182 // No children, so we're done
1183 Debug("substitution::internal") << "SubstitutionMap::internalSubstitute(" << assertion << "): setting " << current << " -> " << current << endl;
1184 d_ppCache[current] = current;
1185 toVisit.pop_back();
1186 }
1187 }
1188 }
1189
1190 // Return the substituted version
1191 return d_ppCache[assertion];
1192 }
1193
1194 void TheoryEngine::notifyPreprocessedAssertions(
1195 const std::vector<Node>& assertions) {
1196 // call all the theories
1197 for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST;
1198 ++theoryId) {
1199 if (d_theoryTable[theoryId]) {
1200 theoryOf(theoryId)->ppNotifyAssertions(assertions);
1201 }
1202 }
1203 }
1204
1205 bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
1206
1207 // What and where we are asserting
1208 NodeTheoryPair toAssert(assertion, toTheoryId, d_propagationMapTimestamp);
1209 // What and where it came from
1210 NodeTheoryPair toExplain(originalAssertion, fromTheoryId, d_propagationMapTimestamp);
1211
1212 // See if the theory already got this literal
1213 PropagationMap::const_iterator find = d_propagationMap.find(toAssert);
1214 if (find != d_propagationMap.end()) {
1215 // The theory already knows this
1216 Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): already there" << endl;
1217 return false;
1218 }
1219
1220 Trace("theory::assertToTheory") << "TheoryEngine::markPropagation(): marking [" << d_propagationMapTimestamp << "] " << assertion << ", " << toTheoryId << " from " << originalAssertion << ", " << fromTheoryId << endl;
1221
1222 // Mark the propagation
1223 d_propagationMap[toAssert] = toExplain;
1224 d_propagationMapTimestamp = d_propagationMapTimestamp + 1;
1225
1226 return true;
1227 }
1228
1229
1230 void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
1231
1232 Trace("theory::assertToTheory") << "TheoryEngine::assertToTheory(" << assertion << ", " << originalAssertion << "," << toTheoryId << ", " << fromTheoryId << ")" << endl;
1233
1234 Assert(toTheoryId != fromTheoryId);
1235 if(toTheoryId != THEORY_SAT_SOLVER &&
1236 ! d_logicInfo.isTheoryEnabled(toTheoryId)) {
1237 stringstream ss;
1238 ss << "The logic was specified as " << d_logicInfo.getLogicString()
1239 << ", which doesn't include " << toTheoryId
1240 << ", but got an asserted fact to that theory." << endl
1241 << "The fact:" << endl
1242 << assertion;
1243 throw LogicException(ss.str());
1244 }
1245
1246 if (d_inConflict) {
1247 return;
1248 }
1249
1250 // If sharing is disabled, things are easy
1251 if (!d_logicInfo.isSharingEnabled()) {
1252 Assert(assertion == originalAssertion);
1253 if (fromTheoryId == THEORY_SAT_SOLVER) {
1254 // Send to the apropriate theory
1255 theory::Theory* toTheory = theoryOf(toTheoryId);
1256 // We assert it, and we know it's preregistereed
1257 toTheory->assertFact(assertion, true);
1258 // Mark that we have more information
1259 d_factsAsserted = true;
1260 } else {
1261 Assert(toTheoryId == THEORY_SAT_SOLVER);
1262 // Check for propositional conflict
1263 bool value;
1264 if (d_propEngine->hasValue(assertion, value)) {
1265 if (!value) {
1266 Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict (no sharing)" << endl;
1267 d_inConflict = true;
1268 } else {
1269 return;
1270 }
1271 }
1272 d_propagatedLiterals.push_back(assertion);
1273 }
1274 return;
1275 }
1276
1277 // Polarity of the assertion
1278 bool polarity = assertion.getKind() != kind::NOT;
1279
1280 // Atom of the assertion
1281 TNode atom = polarity ? assertion : assertion[0];
1282
1283 // If sending to the shared terms database, it's also simple
1284 if (toTheoryId == THEORY_BUILTIN) {
1285 Assert(atom.getKind() == kind::EQUAL, "atom should be an EQUALity, not `%s'", atom.toString().c_str());
1286 if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
1287 d_sharedTerms.assertEquality(atom, polarity, assertion);
1288 }
1289 return;
1290 }
1291
1292 // Things from the SAT solver are already normalized, so they go
1293 // directly to the apropriate theory
1294 if (fromTheoryId == THEORY_SAT_SOLVER) {
1295 // We know that this is normalized, so just send it off to the theory
1296 if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
1297 // Is it preregistered
1298 bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
1299 // We assert it
1300 theoryOf(toTheoryId)->assertFact(assertion, preregistered);
1301 // Mark that we have more information
1302 d_factsAsserted = true;
1303 }
1304 return;
1305 }
1306
1307 // Propagations to the SAT solver are just enqueued for pickup by
1308 // the SAT solver later
1309 if (toTheoryId == THEORY_SAT_SOLVER) {
1310 if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
1311 // Enqueue for propagation to the SAT solver
1312 d_propagatedLiterals.push_back(assertion);
1313 // Check for propositional conflicts
1314 bool value;
1315 if (d_propEngine->hasValue(assertion, value) && !value) {
1316 Trace("theory::propagate") << "TheoryEngine::assertToTheory(" << assertion << ", " << toTheoryId << ", " << fromTheoryId << "): conflict (sharing)" << endl;
1317 d_inConflict = true;
1318 }
1319 }
1320 return;
1321 }
1322
1323 Assert(atom.getKind() == kind::EQUAL);
1324
1325 // Normalize
1326 Node normalizedLiteral = Rewriter::rewrite(assertion);
1327
1328 // See if it rewrites false directly -> conflict
1329 if (normalizedLiteral.isConst()) {
1330 if (!normalizedLiteral.getConst<bool>()) {
1331 // Mark the propagation for explanations
1332 if (markPropagation(normalizedLiteral, originalAssertion, toTheoryId, fromTheoryId)) {
1333 // Get the explanation (conflict will figure out where it came from)
1334 conflict(normalizedLiteral, toTheoryId);
1335 } else {
1336 Unreachable();
1337 }
1338 return;
1339 }
1340 }
1341
1342 // Try and assert (note that we assert the non-normalized one)
1343 if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
1344 // Check if has been pre-registered with the theory
1345 bool preregistered = d_propEngine->isSatLiteral(assertion) && Theory::theoryOf(assertion) == toTheoryId;
1346 // Assert away
1347 theoryOf(toTheoryId)->assertFact(assertion, preregistered);
1348 d_factsAsserted = true;
1349 }
1350
1351 return;
1352 }
1353
1354 void TheoryEngine::assertFact(TNode literal)
1355 {
1356 Trace("theory") << "TheoryEngine::assertFact(" << literal << ")" << endl;
1357
1358 // spendResource();
1359
1360 // If we're in conflict, nothing to do
1361 if (d_inConflict) {
1362 return;
1363 }
1364
1365 // Get the atom
1366 bool polarity = literal.getKind() != kind::NOT;
1367 TNode atom = polarity ? literal : literal[0];
1368
1369 if (d_logicInfo.isSharingEnabled()) {
1370
1371 // If any shared terms, it's time to do sharing work
1372 if (d_sharedTerms.hasSharedTerms(atom)) {
1373 // Notify the theories the shared terms
1374 SharedTermsDatabase::shared_terms_iterator it = d_sharedTerms.begin(atom);
1375 SharedTermsDatabase::shared_terms_iterator it_end = d_sharedTerms.end(atom);
1376 for (; it != it_end; ++ it) {
1377 TNode term = *it;
1378 Theory::Set theories = d_sharedTerms.getTheoriesToNotify(atom, term);
1379 for (TheoryId id = THEORY_FIRST; id != THEORY_LAST; ++ id) {
1380 if (Theory::setContains(id, theories)) {
1381 theoryOf(id)->addSharedTermInternal(term);
1382 }
1383 }
1384 d_sharedTerms.markNotified(term, theories);
1385 }
1386 }
1387
1388 // If it's an equality, assert it to the shared term manager, even though the terms are not
1389 // yet shared. As the terms become shared later, the shared terms manager will then add them
1390 // to the assert the equality to the interested theories
1391 if (atom.getKind() == kind::EQUAL) {
1392 // Assert it to the the owning theory
1393 assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
1394 // Shared terms manager will assert to interested theories directly, as the terms become shared
1395 assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
1396
1397 // Now, let's check for any atom triggers from lemmas
1398 AtomRequests::atom_iterator it = d_atomRequests.getAtomIterator(atom);
1399 while (!it.done()) {
1400 const AtomRequests::Request& request = it.get();
1401 Node toAssert = polarity ? (Node) request.atom : request.atom.notNode();
1402 Debug("theory::atoms") << "TheoryEngine::assertFact(" << literal << "): sending requested " << toAssert << endl;
1403 assertToTheory(toAssert, literal, request.toTheory, THEORY_SAT_SOLVER);
1404 it.next();
1405 }
1406
1407 } else {
1408 // Not an equality, just assert to the appropriate theory
1409 assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
1410 }
1411 } else {
1412 // Assert the fact to the appropriate theory directly
1413 assertToTheory(literal, literal, /* to */ Theory::theoryOf(atom), /* from */ THEORY_SAT_SOLVER);
1414 }
1415 }
1416
1417 bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
1418
1419 Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl;
1420
1421 // spendResource();
1422
1423 if(Dump.isOn("t-propagations")) {
1424 Dump("t-propagations") << CommentCommand("negation of theory propagation: expect valid")
1425 << QueryCommand(literal.toExpr());
1426 }
1427 if(Dump.isOn("missed-t-propagations")) {
1428 d_hasPropagated.insert(literal);
1429 }
1430
1431 // Get the atom
1432 bool polarity = literal.getKind() != kind::NOT;
1433 TNode atom = polarity ? literal : literal[0];
1434
1435 if (d_logicInfo.isSharingEnabled() && atom.getKind() == kind::EQUAL) {
1436 if (d_propEngine->isSatLiteral(literal)) {
1437 // We propagate SAT literals to SAT
1438 assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
1439 }
1440 if (theory != THEORY_BUILTIN) {
1441 // Assert to the shared terms database
1442 assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
1443 }
1444 } else {
1445 // We could be propagating a unit-clause lemma. In this case, we need to provide a
1446 // recipe.
1447 // TODO: Consider putting this someplace else? This is the only refence to the proof
1448 // manager in this class.
1449
1450 PROOF({
1451 LemmaProofRecipe proofRecipe;
1452 proofRecipe.addBaseAssertion(literal);
1453
1454 Node emptyNode;
1455 LemmaProofRecipe::ProofStep proofStep(theory, emptyNode);
1456 proofStep.addAssertion(literal);
1457 proofRecipe.addStep(proofStep);
1458
1459 ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
1460 });
1461
1462 // Just send off to the SAT solver
1463 Assert(d_propEngine->isSatLiteral(literal));
1464 assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
1465 }
1466
1467 return !d_inConflict;
1468 }
1469
1470 const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; }
1471
1472 theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) {
1473 Assert(a.getType().isComparableTo(b.getType()));
1474 if (d_sharedTerms.isShared(a) && d_sharedTerms.isShared(b)) {
1475 if (d_sharedTerms.areEqual(a,b)) {
1476 return EQUALITY_TRUE_AND_PROPAGATED;
1477 }
1478 else if (d_sharedTerms.areDisequal(a,b)) {
1479 return EQUALITY_FALSE_AND_PROPAGATED;
1480 }
1481 }
1482 return theoryOf(Theory::theoryOf(a.getType()))->getEqualityStatus(a, b);
1483 }
1484
1485 Node TheoryEngine::getModelValue(TNode var) {
1486 if (var.isConst()) return var; // FIXME: HACK!!!
1487 Assert(d_sharedTerms.isShared(var));
1488 return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var);
1489 }
1490
1491
1492 Node TheoryEngine::ensureLiteral(TNode n) {
1493 Debug("ensureLiteral") << "rewriting: " << n << std::endl;
1494 Node rewritten = Rewriter::rewrite(n);
1495 Debug("ensureLiteral") << " got: " << rewritten << std::endl;
1496 Node preprocessed = preprocess(rewritten);
1497 Debug("ensureLiteral") << "preprocessed: " << preprocessed << std::endl;
1498 d_propEngine->ensureLiteral(preprocessed);
1499 return preprocessed;
1500 }
1501
1502
1503 void TheoryEngine::printInstantiations( std::ostream& out ) {
1504 if( d_quantEngine ){
1505 d_quantEngine->printInstantiations( out );
1506 }else{
1507 out << "Internal error : instantiations not available when quantifiers are not present." << std::endl;
1508 Assert(false);
1509 }
1510 }
1511
1512 void TheoryEngine::printSynthSolution( std::ostream& out ) {
1513 if( d_quantEngine ){
1514 d_quantEngine->printSynthSolution( out );
1515 }else{
1516 out << "Internal error : synth solution not available when quantifiers are not present." << std::endl;
1517 Assert(false);
1518 }
1519 }
1520
1521 void TheoryEngine::getInstantiatedQuantifiedFormulas( std::vector< Node >& qs ) {
1522 if( d_quantEngine ){
1523 d_quantEngine->getInstantiatedQuantifiedFormulas( qs );
1524 }else{
1525 Assert( false );
1526 }
1527 }
1528
1529 void TheoryEngine::getInstantiations( Node q, std::vector< Node >& insts ) {
1530 if( d_quantEngine ){
1531 d_quantEngine->getInstantiations( q, insts );
1532 }else{
1533 Assert( false );
1534 }
1535 }
1536
1537 void TheoryEngine::getInstantiationTermVectors( Node q, std::vector< std::vector< Node > >& tvecs ) {
1538 if( d_quantEngine ){
1539 d_quantEngine->getInstantiationTermVectors( q, tvecs );
1540 }else{
1541 Assert( false );
1542 }
1543 }
1544
1545 void TheoryEngine::getInstantiations( std::map< Node, std::vector< Node > >& insts ) {
1546 if( d_quantEngine ){
1547 d_quantEngine->getInstantiations( insts );
1548 }else{
1549 Assert( false );
1550 }
1551 }
1552
1553 void TheoryEngine::getInstantiationTermVectors( std::map< Node, std::vector< std::vector< Node > > >& insts ) {
1554 if( d_quantEngine ){
1555 d_quantEngine->getInstantiationTermVectors( insts );
1556 }else{
1557 Assert( false );
1558 }
1559 }
1560
1561 Node TheoryEngine::getInstantiatedConjunction( Node q ) {
1562 if( d_quantEngine ){
1563 return d_quantEngine->getInstantiatedConjunction( q );
1564 }else{
1565 Assert( false );
1566 return Node::null();
1567 }
1568 }
1569
1570
1571 static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
1572
1573 std::set<TNode> all;
1574 for (unsigned i = 0; i < explanation.size(); ++ i) {
1575 Assert(explanation[i].theory == THEORY_SAT_SOLVER);
1576 all.insert(explanation[i].node);
1577 }
1578
1579 if (all.size() == 0) {
1580 // Normalize to true
1581 return NodeManager::currentNM()->mkConst<bool>(true);
1582 }
1583
1584 if (all.size() == 1) {
1585 // All the same, or just one
1586 return explanation[0].node;
1587 }
1588
1589 NodeBuilder<> conjunction(kind::AND);
1590 std::set<TNode>::const_iterator it = all.begin();
1591 std::set<TNode>::const_iterator it_end = all.end();
1592 while (it != it_end) {
1593 conjunction << *it;
1594 ++ it;
1595 }
1596
1597 return conjunction;
1598 }
1599
1600 Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe) {
1601 Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
1602
1603 bool polarity = node.getKind() != kind::NOT;
1604 TNode atom = polarity ? node : node[0];
1605
1606 // If we're not in shared mode, explanations are simple
1607 if (!d_logicInfo.isSharingEnabled()) {
1608 Debug("theory::explain") << "TheoryEngine::getExplanation: sharing is NOT enabled. "
1609 << " Responsible theory is: "
1610 << theoryOf(atom)->getId() << std::endl;
1611
1612 Node explanation = theoryOf(atom)->explain(node);
1613 Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
1614 PROOF({
1615 if(proofRecipe) {
1616 Node emptyNode;
1617 LemmaProofRecipe::ProofStep proofStep(theoryOf(atom)->getId(), emptyNode);
1618 proofStep.addAssertion(node);
1619 proofRecipe->addBaseAssertion(node);
1620
1621 if (explanation.getKind() == kind::AND) {
1622 // If the explanation is a conjunction, the recipe for the corresponding lemma is
1623 // the negation of its conjuncts.
1624 Node flat = flattenAnd(explanation);
1625 for (unsigned i = 0; i < flat.getNumChildren(); ++i) {
1626 if (flat[i].isConst() && flat[i].getConst<bool>()) {
1627 ++ i;
1628 continue;
1629 }
1630 if (flat[i].getKind() == kind::NOT &&
1631 flat[i][0].isConst() && !flat[i][0].getConst<bool>()) {
1632 ++ i;
1633 continue;
1634 }
1635 Debug("theory::explain") << "TheoryEngine::getExplanationAndRecipe: adding recipe assertion: "
1636 << flat[i].negate() << std::endl;
1637 proofStep.addAssertion(flat[i].negate());
1638 proofRecipe->addBaseAssertion(flat[i].negate());
1639 }
1640 } else {
1641 // The recipe for proving it is by negating it. "True" is not an acceptable reason.
1642 if (!((explanation.isConst() && explanation.getConst<bool>()) ||
1643 (explanation.getKind() == kind::NOT &&
1644 explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
1645 proofStep.addAssertion(explanation.negate());
1646 proofRecipe->addBaseAssertion(explanation.negate());
1647 }
1648 }
1649
1650 proofRecipe->addStep(proofStep);
1651 }
1652 });
1653
1654 return explanation;
1655 }
1656
1657 Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl;
1658
1659 // Initial thing to explain
1660 NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp);
1661 Assert(d_propagationMap.find(toExplain) != d_propagationMap.end());
1662
1663 NodeTheoryPair nodeExplainerPair = d_propagationMap[toExplain];
1664 Debug("theory::explain") << "TheoryEngine::getExplanation: explainer for node "
1665 << nodeExplainerPair.node
1666 << " is theory: " << nodeExplainerPair.theory << std::endl;
1667 TheoryId explainer = nodeExplainerPair.theory;
1668
1669 // Create the workplace for explanations
1670 std::vector<NodeTheoryPair> explanationVector;
1671 explanationVector.push_back(d_propagationMap[toExplain]);
1672 // Process the explanation
1673 if (proofRecipe) {
1674 Node emptyNode;
1675 LemmaProofRecipe::ProofStep proofStep(explainer, emptyNode);
1676 proofStep.addAssertion(node);
1677 proofRecipe->addStep(proofStep);
1678 proofRecipe->addBaseAssertion(node);
1679 }
1680
1681 getExplanation(explanationVector, proofRecipe);
1682 Node explanation = mkExplanation(explanationVector);
1683
1684 Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
1685
1686 return explanation;
1687 }
1688
1689 Node TheoryEngine::getExplanation(TNode node) {
1690 LemmaProofRecipe *dontCareRecipe = NULL;
1691 return getExplanationAndRecipe(node, dontCareRecipe);
1692 }
1693
1694 struct AtomsCollect {
1695
1696 std::vector<TNode> d_atoms;
1697 std::unordered_set<TNode, TNodeHashFunction> d_visited;
1698
1699 public:
1700
1701 typedef void return_type;
1702
1703 bool alreadyVisited(TNode current, TNode parent) {
1704 // Check if already visited
1705 if (d_visited.find(current) != d_visited.end()) return true;
1706 // Don't visit non-boolean
1707 if (!current.getType().isBoolean()) return true;
1708 // New node
1709 return false;
1710 }
1711
1712 void visit(TNode current, TNode parent) {
1713 if (Theory::theoryOf(current) != theory::THEORY_BOOL) {
1714 d_atoms.push_back(current);
1715 }
1716 d_visited.insert(current);
1717 }
1718
1719 void start(TNode node) {}
1720 void done(TNode node) {}
1721
1722 std::vector<TNode> getAtoms() const {
1723 return d_atoms;
1724 }
1725 };
1726
1727 void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId atomsTo) {
1728 for (unsigned i = 0; i < atoms.size(); ++ i) {
1729
1730 // Non-equality atoms are either owned by theory or they don't make sense
1731 if (atoms[i].getKind() != kind::EQUAL) {
1732 continue;
1733 }
1734
1735 // The equality
1736 Node eq = atoms[i];
1737 // Simple normalization to not repeat stuff
1738 if (eq[0] > eq[1]) {
1739 eq = eq[1].eqNode(eq[0]);
1740 }
1741
1742 // Rewrite the equality
1743 Node eqNormalized = Rewriter::rewrite(atoms[i]);
1744
1745 Debug("theory::atoms") << "TheoryEngine::ensureLemmaAtoms(): " << eq << " with nf " << eqNormalized << endl;
1746
1747 // If the equality is a boolean constant, we send immediately
1748 if (eqNormalized.isConst()) {
1749 if (eqNormalized.getConst<bool>()) {
1750 assertToTheory(eq, eqNormalized, /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
1751 } else {
1752 assertToTheory(eq.notNode(), eqNormalized.notNode(), /** to */ atomsTo, /** Sat solver */ theory::THEORY_SAT_SOLVER);
1753 }
1754 continue;
1755 }else if( eqNormalized.getKind() != kind::EQUAL){
1756 Assert( eqNormalized.getKind()==kind::BOOLEAN_TERM_VARIABLE ||
1757 ( eqNormalized.getKind()==kind::NOT && eqNormalized[0].getKind()==kind::BOOLEAN_TERM_VARIABLE ) );
1758 // this happens for Boolean term equalities V = true that are rewritten to V, we should skip
1759 // TODO : revisit this
1760 continue;
1761 }
1762
1763 // If the normalization did the just flips, keep the flip
1764 if (eqNormalized[0] == eq[1] && eqNormalized[1] == eq[0]) {
1765 eq = eqNormalized;
1766 }
1767
1768 // Check if the equality is already known by the sat solver
1769 if (d_propEngine->isSatLiteral(eqNormalized)) {
1770 bool value;
1771 if (d_propEngine->hasValue(eqNormalized, value)) {
1772 if (value) {
1773 assertToTheory(eq, eqNormalized, atomsTo, theory::THEORY_SAT_SOLVER);
1774 continue;
1775 } else {
1776 assertToTheory(eq.notNode(), eqNormalized.notNode(), atomsTo, theory::THEORY_SAT_SOLVER);
1777 continue;
1778 }
1779 }
1780 }
1781
1782 // If the theory is asking about a different form, or the form is ok but if will go to a different theory
1783 // then we must figure it out
1784 if (eqNormalized != eq || Theory::theoryOf(eq) != atomsTo) {
1785 // If you get eqNormalized, send atoms[i] to atomsTo
1786 d_atomRequests.add(eqNormalized, eq, atomsTo);
1787 }
1788 }
1789 }
1790
1791 theory::LemmaStatus TheoryEngine::lemma(TNode node,
1792 ProofRule rule,
1793 bool negated,
1794 bool removable,
1795 bool preprocess,
1796 theory::TheoryId atomsTo) {
1797 // For resource-limiting (also does a time check).
1798 // spendResource();
1799
1800 // Do we need to check atoms
1801 if (atomsTo != theory::THEORY_LAST) {
1802 Debug("theory::atoms") << "TheoryEngine::lemma(" << node << ", " << atomsTo << ")" << endl;
1803 AtomsCollect collectAtoms;
1804 NodeVisitor<AtomsCollect>::run(collectAtoms, node);
1805 ensureLemmaAtoms(collectAtoms.getAtoms(), atomsTo);
1806 }
1807
1808 if(Dump.isOn("t-lemmas")) {
1809 Node n = node;
1810 if (negated) {
1811 n = node.negate();
1812 }
1813 Dump("t-lemmas") << CommentCommand("theory lemma: expect valid")
1814 << QueryCommand(n.toExpr());
1815 }
1816
1817 // Share with other portfolio threads
1818 if(d_channels->getLemmaOutputChannel() != NULL) {
1819 d_channels->getLemmaOutputChannel()->notifyNewLemma(node.toExpr());
1820 }
1821
1822 std::vector<Node> additionalLemmas;
1823 IteSkolemMap iteSkolemMap;
1824
1825 // Run theory preprocessing, maybe
1826 Node ppNode = preprocess ? this->preprocess(node) : Node(node);
1827
1828 // Remove the ITEs
1829 Debug("ite") << "Remove ITE from " << ppNode << std::endl;
1830 additionalLemmas.push_back(ppNode);
1831 d_tform_remover.run(additionalLemmas, iteSkolemMap);
1832 Debug("ite") << "..done " << additionalLemmas[0] << std::endl;
1833 additionalLemmas[0] = theory::Rewriter::rewrite(additionalLemmas[0]);
1834
1835 if(Debug.isOn("lemma-ites")) {
1836 Debug("lemma-ites") << "removed ITEs from lemma: " << ppNode << endl;
1837 Debug("lemma-ites") << " + now have the following "
1838 << additionalLemmas.size() << " lemma(s):" << endl;
1839 for(std::vector<Node>::const_iterator i = additionalLemmas.begin();
1840 i != additionalLemmas.end();
1841 ++i) {
1842 Debug("lemma-ites") << " + " << *i << endl;
1843 }
1844 Debug("lemma-ites") << endl;
1845 }
1846
1847 // assert to prop engine
1848 d_propEngine->assertLemma(additionalLemmas[0], negated, removable, rule, node);
1849 for (unsigned i = 1; i < additionalLemmas.size(); ++ i) {
1850 additionalLemmas[i] = theory::Rewriter::rewrite(additionalLemmas[i]);
1851 d_propEngine->assertLemma(additionalLemmas[i], false, removable, rule, node);
1852 }
1853
1854 // WARNING: Below this point don't assume additionalLemmas[0] to be not negated.
1855 if(negated) {
1856 additionalLemmas[0] = additionalLemmas[0].notNode();
1857 negated = false;
1858 }
1859
1860 // assert to decision engine
1861 if(!removable) {
1862 d_decisionEngine->addAssertions(additionalLemmas, 1, iteSkolemMap);
1863 }
1864
1865 // Mark that we added some lemmas
1866 d_lemmasAdded = true;
1867
1868 // Lemma analysis isn't online yet; this lemma may only live for this
1869 // user level.
1870 return theory::LemmaStatus(additionalLemmas[0], d_userContext->getLevel());
1871 }
1872
1873 void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
1874
1875 Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << endl;
1876
1877 // Mark that we are in conflict
1878 d_inConflict = true;
1879
1880 if(Dump.isOn("t-conflicts")) {
1881 Dump("t-conflicts") << CommentCommand("theory conflict: expect unsat")
1882 << CheckSatCommand(conflict.toExpr());
1883 }
1884
1885 LemmaProofRecipe* proofRecipe = NULL;
1886 PROOF({
1887 proofRecipe = new LemmaProofRecipe;
1888 Node emptyNode;
1889 LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
1890
1891 if (conflict.getKind() == kind::AND) {
1892 for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
1893 proofStep.addAssertion(conflict[i].negate());
1894 }
1895 } else {
1896 proofStep.addAssertion(conflict.negate());
1897 }
1898
1899 proofRecipe->addStep(proofStep);
1900 });
1901
1902 // In the multiple-theories case, we need to reconstruct the conflict
1903 if (d_logicInfo.isSharingEnabled()) {
1904 // Create the workplace for explanations
1905 std::vector<NodeTheoryPair> explanationVector;
1906 explanationVector.push_back(NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
1907
1908 // Process the explanation
1909 getExplanation(explanationVector, proofRecipe);
1910 PROOF(ProofManager::getCnfProof()->setProofRecipe(proofRecipe));
1911 Node fullConflict = mkExplanation(explanationVector);
1912 Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
1913 Assert(properConflict(fullConflict));
1914 lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
1915
1916 } else {
1917 // When only one theory, the conflict should need no processing
1918 Assert(properConflict(conflict));
1919 PROOF({
1920 if (conflict.getKind() == kind::AND) {
1921 // If the conflict is a conjunction, the corresponding lemma is derived by negating
1922 // its conjuncts.
1923 for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
1924 if (conflict[i].isConst() && conflict[i].getConst<bool>()) {
1925 ++ i;
1926 continue;
1927 }
1928 if (conflict[i].getKind() == kind::NOT &&
1929 conflict[i][0].isConst() && !conflict[i][0].getConst<bool>()) {
1930 ++ i;
1931 continue;
1932 }
1933 proofRecipe->getStep(0)->addAssertion(conflict[i].negate());
1934 proofRecipe->addBaseAssertion(conflict[i].negate());
1935 }
1936 } else {
1937 proofRecipe->getStep(0)->addAssertion(conflict.negate());
1938 proofRecipe->addBaseAssertion(conflict.negate());
1939 }
1940
1941 ProofManager::getCnfProof()->setProofRecipe(proofRecipe);
1942 });
1943
1944 lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
1945 }
1946
1947 PROOF({
1948 delete proofRecipe;
1949 proofRecipe = NULL;
1950 });
1951 }
1952
1953 void TheoryEngine::staticInitializeBVOptions(
1954 const std::vector<Node>& assertions)
1955 {
1956 bool useSlicer = true;
1957 if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_ON)
1958 {
1959 if (!d_logicInfo.isPure(theory::THEORY_BV) || d_logicInfo.isQuantified())
1960 throw ModalException(
1961 "Slicer currently only supports pure QF_BV formulas. Use "
1962 "--bv-eq-slicer=off");
1963 if (options::incrementalSolving())
1964 throw ModalException(
1965 "Slicer does not currently support incremental mode. Use "
1966 "--bv-eq-slicer=off");
1967 if (options::produceModels())
1968 throw ModalException(
1969 "Slicer does not currently support model generation. Use "
1970 "--bv-eq-slicer=off");
1971 }
1972 else if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_OFF)
1973 {
1974 return;
1975 }
1976 else if (options::bitvectorEqualitySlicer() == bv::BITVECTOR_SLICER_AUTO)
1977 {
1978 if ((!d_logicInfo.isPure(theory::THEORY_BV) || d_logicInfo.isQuantified())
1979 || options::incrementalSolving()
1980 || options::produceModels())
1981 return;
1982
1983 bv::utils::TNodeBoolMap cache;
1984 for (unsigned i = 0; i < assertions.size(); ++i)
1985 {
1986 useSlicer = useSlicer && bv::utils::isCoreTerm(assertions[i], cache);
1987 }
1988 }
1989
1990 if (useSlicer)
1991 {
1992 bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
1993 bv_theory->enableCoreTheorySlicer();
1994 }
1995 }
1996
1997 Node TheoryEngine::ppSimpITE(TNode assertion)
1998 {
1999 if (!d_iteUtilities->containsTermITE(assertion))
2000 {
2001 return assertion;
2002 } else {
2003 Node result = d_iteUtilities->simpITE(assertion);
2004 Node res_rewritten = Rewriter::rewrite(result);
2005
2006 if(options::simplifyWithCareEnabled()){
2007 Chat() << "starting simplifyWithCare()" << endl;
2008 Node postSimpWithCare = d_iteUtilities->simplifyWithCare(res_rewritten);
2009 Chat() << "ending simplifyWithCare()"
2010 << " post simplifyWithCare()" << postSimpWithCare.getId() << endl;
2011 result = Rewriter::rewrite(postSimpWithCare);
2012 } else {
2013 result = res_rewritten;
2014 }
2015 return result;
2016 }
2017 }
2018
2019 bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
2020 // This pass does not support dependency tracking yet
2021 // (learns substitutions from all assertions so just
2022 // adding addDependence is not enough)
2023 if (options::unsatCores() || options::fewerPreprocessingHoles()) {
2024 return true;
2025 }
2026 bool result = true;
2027 bool simpDidALotOfWork = d_iteUtilities->simpIteDidALotOfWorkHeuristic();
2028 if(simpDidALotOfWork){
2029 if(options::compressItes()){
2030 result = d_iteUtilities->compress(assertions);
2031 }
2032
2033 if(result){
2034 // if false, don't bother to reclaim memory here.
2035 NodeManager* nm = NodeManager::currentNM();
2036 if(nm->poolSize() >= options::zombieHuntThreshold()){
2037 Chat() << "..ite simplifier did quite a bit of work.. " << nm->poolSize() << endl;
2038 Chat() << "....node manager contains " << nm->poolSize() << " nodes before cleanup" << endl;
2039 d_iteUtilities->clear();
2040 Rewriter::clearCaches();
2041 nm->reclaimZombiesUntil(options::zombieHuntThreshold());
2042 Chat() << "....node manager contains " << nm->poolSize() << " nodes after cleanup" << endl;
2043 }
2044 }
2045 }
2046
2047 // Do theory specific preprocessing passes
2048 if(d_logicInfo.isTheoryEnabled(theory::THEORY_ARITH)
2049 && !options::incrementalSolving() ){
2050 if(!simpDidALotOfWork){
2051 ContainsTermITEVisitor& contains =
2052 *(d_iteUtilities->getContainsVisitor());
2053 arith::ArithIteUtils aiteu(contains, d_userContext, getModel());
2054 bool anyItes = false;
2055 for(size_t i = 0; i < assertions.size(); ++i){
2056 Node curr = assertions[i];
2057 if(contains.containsTermITE(curr)){
2058 anyItes = true;
2059 Node res = aiteu.reduceVariablesInItes(curr);
2060 Debug("arith::ite::red") << "@ " << i << " ... " << curr << endl << " ->" << res << endl;
2061 if(curr != res){
2062 Node more = aiteu.reduceConstantIteByGCD(res);
2063 Debug("arith::ite::red") << " gcd->" << more << endl;
2064 assertions[i] = Rewriter::rewrite(more);
2065 }
2066 }
2067 }
2068 if(!anyItes){
2069 unsigned prevSubCount = aiteu.getSubCount();
2070 aiteu.learnSubstitutions(assertions);
2071 if(prevSubCount < aiteu.getSubCount()){
2072 d_arithSubstitutionsAdded += aiteu.getSubCount() - prevSubCount;
2073 bool anySuccess = false;
2074 for(size_t i = 0, N = assertions.size(); i < N; ++i){
2075 Node curr = assertions[i];
2076 Node next = Rewriter::rewrite(aiteu.applySubstitutions(curr));
2077 Node res = aiteu.reduceVariablesInItes(next);
2078 Debug("arith::ite::red") << "@ " << i << " ... " << next << endl << " ->" << res << endl;
2079 Node more = aiteu.reduceConstantIteByGCD(res);
2080 Debug("arith::ite::red") << " gcd->" << more << endl;
2081 if(more != next){
2082 anySuccess = true;
2083 break;
2084 }
2085 }
2086 for(size_t i = 0, N = assertions.size(); anySuccess && i < N; ++i){
2087 Node curr = assertions[i];
2088 Node next = Rewriter::rewrite(aiteu.applySubstitutions(curr));
2089 Node res = aiteu.reduceVariablesInItes(next);
2090 Debug("arith::ite::red") << "@ " << i << " ... " << next << endl << " ->" << res << endl;
2091 Node more = aiteu.reduceConstantIteByGCD(res);
2092 Debug("arith::ite::red") << " gcd->" << more << endl;
2093 assertions[i] = Rewriter::rewrite(more);
2094 }
2095 }
2096 }
2097 }
2098 }
2099 return result;
2100 }
2101
2102 void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* proofRecipe) {
2103 Assert(explanationVector.size() > 0);
2104
2105 unsigned i = 0; // Index of the current literal we are processing
2106 unsigned j = 0; // Index of the last literal we are keeping
2107
2108 std::set<Node> inputAssertions;
2109 PROOF(inputAssertions = proofRecipe->getStep(0)->getAssertions(););
2110
2111 while (i < explanationVector.size()) {
2112 // Get the current literal to explain
2113 NodeTheoryPair toExplain = explanationVector[i];
2114
2115 Debug("theory::explain") << "[i=" << i << "] TheoryEngine::explain(): processing [" << toExplain.timestamp << "] " << toExplain.node << " sent from " << toExplain.theory << endl;
2116
2117
2118 // If a true constant or a negation of a false constant we can ignore it
2119 if (toExplain.node.isConst() && toExplain.node.getConst<bool>()) {
2120 ++ i;
2121 continue;
2122 }
2123 if (toExplain.node.getKind() == kind::NOT && toExplain.node[0].isConst() && !toExplain.node[0].getConst<bool>()) {
2124 ++ i;
2125 continue;
2126 }
2127
2128 // If from the SAT solver, keep it
2129 if (toExplain.theory == THEORY_SAT_SOLVER) {
2130 Debug("theory::explain") << "\tLiteral came from THEORY_SAT_SOLVER. Kepping it." << endl;
2131 explanationVector[j++] = explanationVector[i++];
2132 continue;
2133 }
2134
2135 // If an and, expand it
2136 if (toExplain.node.getKind() == kind::AND) {
2137 Debug("theory::explain") << "TheoryEngine::explain(): expanding " << toExplain.node << " got from " << toExplain.theory << endl;
2138 for (unsigned k = 0; k < toExplain.node.getNumChildren(); ++ k) {
2139 NodeTheoryPair newExplain(toExplain.node[k], toExplain.theory, toExplain.timestamp);
2140 explanationVector.push_back(newExplain);
2141 }
2142 ++ i;
2143 continue;
2144 }
2145
2146 // See if it was sent to the theory by another theory
2147 PropagationMap::const_iterator find = d_propagationMap.find(toExplain);
2148 if (find != d_propagationMap.end()) {
2149 Debug("theory::explain") << "\tTerm was propagated by another theory (theory = "
2150 << theoryOf((*find).second.theory)->getId() << ")" << std::endl;
2151 // There is some propagation, check if its a timely one
2152 if ((*find).second.timestamp < toExplain.timestamp) {
2153 Debug("theory::explain") << "\tRelevant timetsamp, pushing "
2154 << (*find).second.node << "to index = " << explanationVector.size() << std::endl;
2155 explanationVector.push_back((*find).second);
2156 ++i;
2157
2158 PROOF({
2159 if (toExplain.node != (*find).second.node) {
2160 Debug("pf::explain") << "TheoryEngine::getExplanation: Rewrite alert! toAssert = " << toExplain.node
2161 << ", toExplain = " << (*find).second.node << std::endl;
2162
2163 if (proofRecipe) {
2164 proofRecipe->addRewriteRule(toExplain.node, (*find).second.node);
2165 }
2166 }
2167 })
2168
2169 continue;
2170 }
2171 }
2172
2173 // It was produced by the theory, so ask for an explanation
2174 Node explanation;
2175 if (toExplain.theory == THEORY_BUILTIN) {
2176 explanation = d_sharedTerms.explain(toExplain.node);
2177 Debug("theory::explain") << "\tTerm was propagated by THEORY_BUILTIN. Explanation: " << explanation << std::endl;
2178 } else {
2179 explanation = theoryOf(toExplain.theory)->explain(toExplain.node);
2180 Debug("theory::explain") << "\tTerm was propagated by owner theory: "
2181 << theoryOf(toExplain.theory)->getId()
2182 << ". Explanation: " << explanation << std::endl;
2183 }
2184
2185 Debug("theory::explain") << "TheoryEngine::explain(): got explanation " << explanation << " got from " << toExplain.theory << endl;
2186 Assert( explanation != toExplain.node, "wasn't sent to you, so why are you explaining it trivially");
2187 // Mark the explanation
2188 NodeTheoryPair newExplain(explanation, toExplain.theory, toExplain.timestamp);
2189 explanationVector.push_back(newExplain);
2190
2191 ++ i;
2192
2193 PROOF({
2194 if (proofRecipe) {
2195 // If we're expanding the target node of the explanation (this is the first expansion...),
2196 // we don't want to add it as a separate proof step. It is already part of the assertions.
2197 if (inputAssertions.find(toExplain.node) == inputAssertions.end()) {
2198 LemmaProofRecipe::ProofStep proofStep(toExplain.theory, toExplain.node);
2199 if (explanation.getKind() == kind::AND) {
2200 Node flat = flattenAnd(explanation);
2201 for (unsigned k = 0; k < flat.getNumChildren(); ++ k) {
2202 // If a true constant or a negation of a false constant we can ignore it
2203 if (! ((flat[k].isConst() && flat[k].getConst<bool>()) ||
2204 (flat[k].getKind() == kind::NOT && flat[k][0].isConst() && !flat[k][0].getConst<bool>()))) {
2205 proofStep.addAssertion(flat[k].negate());
2206 }
2207 }
2208 } else {
2209 if (! ((explanation.isConst() && explanation.getConst<bool>()) ||
2210 (explanation.getKind() == kind::NOT && explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
2211 proofStep.addAssertion(explanation.negate());
2212 }
2213 }
2214 proofRecipe->addStep(proofStep);
2215 }
2216 }
2217 });
2218 }
2219
2220 // Keep only the relevant literals
2221 explanationVector.resize(j);
2222
2223 PROOF({
2224 if (proofRecipe) {
2225 // The remaining literals are the base of the proof
2226 for (unsigned k = 0; k < explanationVector.size(); ++k) {
2227 proofRecipe->addBaseAssertion(explanationVector[k].node.negate());
2228 }
2229 }
2230 });
2231 }
2232
2233 void TheoryEngine::ppUnconstrainedSimp(vector<Node>& assertions)
2234 {
2235 d_unconstrainedSimp->processAssertions(assertions);
2236 }
2237
2238 void TheoryEngine::setUserAttribute(const std::string& attr,
2239 Node n,
2240 const std::vector<Node>& node_values,
2241 const std::string& str_value)
2242 {
2243 Trace("te-attr") << "set user attribute " << attr << " " << n << endl;
2244 if( d_attr_handle.find( attr )!=d_attr_handle.end() ){
2245 for( size_t i=0; i<d_attr_handle[attr].size(); i++ ){
2246 d_attr_handle[attr][i]->setUserAttribute(attr, n, node_values, str_value);
2247 }
2248 } else {
2249 //unhandled exception?
2250 }
2251 }
2252
2253 void TheoryEngine::handleUserAttribute(const char* attr, Theory* t) {
2254 Trace("te-attr") << "Handle user attribute " << attr << " " << t << endl;
2255 std::string str( attr );
2256 d_attr_handle[ str ].push_back( t );
2257 }
2258
2259 void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure) {
2260 for(TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
2261 Theory* theory = d_theoryTable[theoryId];
2262 if(theory && d_logicInfo.isTheoryEnabled(theoryId)) {
2263 for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(),
2264 it_end = theory->facts_end();
2265 it != it_end;
2266 ++it) {
2267 Node assertion = (*it).assertion;
2268 Node val = getModel()->getValue(assertion);
2269 if(val != d_true) {
2270 stringstream ss;
2271 ss << theoryId << " has an asserted fact that the model doesn't satisfy." << endl
2272 << "The fact: " << assertion << endl
2273 << "Model value: " << val << endl;
2274 if(hardFailure) {
2275 InternalError(ss.str());
2276 }
2277 }
2278 }
2279 }
2280 }
2281 }
2282
2283 std::pair<bool, Node> TheoryEngine::entailmentCheck(theory::TheoryOfMode mode, TNode lit, const EntailmentCheckParameters* params, EntailmentCheckSideEffects* seffects) {
2284 TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit;
2285 if( atom.getKind()==kind::AND || atom.getKind()==kind::OR || atom.getKind()==kind::IMPLIES ){
2286 //Boolean connective, recurse
2287 std::vector< Node > children;
2288 bool pol = (lit.getKind()!=kind::NOT);
2289 bool is_conjunction = pol==(lit.getKind()==kind::AND);
2290 for( unsigned i=0; i<atom.getNumChildren(); i++ ){
2291 Node ch = atom[i];
2292 if( pol==( lit.getKind()==kind::IMPLIES && i==0 ) ){
2293 ch = atom[i].negate();
2294 }
2295 std::pair<bool, Node> chres = entailmentCheck( mode, ch, params, seffects );
2296 if( chres.first ){
2297 if( !is_conjunction ){
2298 return chres;
2299 }else{
2300 children.push_back( chres.second );
2301 }
2302 }else if( !chres.first && is_conjunction ){
2303 return std::pair<bool, Node>(false, Node::null());
2304 }
2305 }
2306 if( is_conjunction ){
2307 return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, children));
2308 }else{
2309 return std::pair<bool, Node>(false, Node::null());
2310 }
2311 }else if( atom.getKind()==kind::ITE || ( atom.getKind()==kind::EQUAL && atom[0].getType().isBoolean() ) ){
2312 bool pol = (lit.getKind()!=kind::NOT);
2313 for( unsigned r=0; r<2; r++ ){
2314 Node ch = atom[0];
2315 if( r==1 ){
2316 ch = ch.negate();
2317 }
2318 std::pair<bool, Node> chres = entailmentCheck( mode, ch, params, seffects );
2319 if( chres.first ){
2320 Node ch2 = atom[ atom.getKind()==kind::ITE ? r+1 : 1 ];
2321 if( pol==( atom.getKind()==kind::ITE ? true : r==1 ) ){
2322 ch2 = ch2.negate();
2323 }
2324 std::pair<bool, Node> chres2 = entailmentCheck( mode, ch2, params, seffects );
2325 if( chres2.first ){
2326 return std::pair<bool, Node>(true, NodeManager::currentNM()->mkNode(kind::AND, chres.second, chres2.second));
2327 }else{
2328 break;
2329 }
2330 }
2331 }
2332 return std::pair<bool, Node>(false, Node::null());
2333 }else{
2334 //it is a theory atom
2335 theory::TheoryId tid = theory::Theory::theoryOf(mode, atom);
2336 theory::Theory* th = theoryOf(tid);
2337
2338 Assert(th != NULL);
2339 Assert(params == NULL || tid == params->getTheoryId());
2340 Assert(seffects == NULL || tid == seffects->getTheoryId());
2341 Trace("theory-engine-entc") << "Entailment check : " << lit << std::endl;
2342
2343 std::pair<bool, Node> chres = th->entailmentCheck(lit, params, seffects);
2344 return chres;
2345 }
2346 }
2347
2348 void TheoryEngine::spendResource(unsigned amount)
2349 {
2350 d_resourceManager->spendResource(amount);
2351 }
2352
2353 void TheoryEngine::enableTheoryAlternative(const std::string& name){
2354 Debug("TheoryEngine::enableTheoryAlternative")
2355 << "TheoryEngine::enableTheoryAlternative(" << name << ")" << std::endl;
2356
2357 d_theoryAlternatives.insert(name);
2358 }
2359
2360 bool TheoryEngine::useTheoryAlternative(const std::string& name) {
2361 return d_theoryAlternatives.find(name) != d_theoryAlternatives.end();
2362 }
2363
2364
2365 TheoryEngine::Statistics::Statistics(theory::TheoryId theory):
2366 conflicts(getStatsPrefix(theory) + "::conflicts", 0),
2367 propagations(getStatsPrefix(theory) + "::propagations", 0),
2368 lemmas(getStatsPrefix(theory) + "::lemmas", 0),
2369 requirePhase(getStatsPrefix(theory) + "::requirePhase", 0),
2370 flipDecision(getStatsPrefix(theory) + "::flipDecision", 0),
2371 restartDemands(getStatsPrefix(theory) + "::restartDemands", 0)
2372 {
2373 smtStatisticsRegistry()->registerStat(&conflicts);
2374 smtStatisticsRegistry()->registerStat(&propagations);
2375 smtStatisticsRegistry()->registerStat(&lemmas);
2376 smtStatisticsRegistry()->registerStat(&requirePhase);
2377 smtStatisticsRegistry()->registerStat(&flipDecision);
2378 smtStatisticsRegistry()->registerStat(&restartDemands);
2379 }
2380
2381 TheoryEngine::Statistics::~Statistics() {
2382 smtStatisticsRegistry()->unregisterStat(&conflicts);
2383 smtStatisticsRegistry()->unregisterStat(&propagations);
2384 smtStatisticsRegistry()->unregisterStat(&lemmas);
2385 smtStatisticsRegistry()->unregisterStat(&requirePhase);
2386 smtStatisticsRegistry()->unregisterStat(&flipDecision);
2387 smtStatisticsRegistry()->unregisterStat(&restartDemands);
2388 }
2389
2390 }/* CVC4 namespace */