1 /********************* */
2 /*! \file engine_output_channel.cpp
4 ** Top contributors (to current version):
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief The theory engine output channel.
15 #include "theory/engine_output_channel.h"
17 #include "proof/cnf_proof.h"
18 #include "proof/lemma_proof.h"
19 #include "proof/proof_manager.h"
20 #include "proof/theory_proof.h"
21 #include "prop/prop_engine.h"
22 #include "smt/smt_statistics_registry.h"
23 #include "theory/theory_engine.h"
25 using namespace CVC4::kind
;
30 EngineOutputChannel::Statistics::Statistics(theory::TheoryId theory
)
31 : conflicts(getStatsPrefix(theory
) + "::conflicts", 0),
32 propagations(getStatsPrefix(theory
) + "::propagations", 0),
33 lemmas(getStatsPrefix(theory
) + "::lemmas", 0),
34 requirePhase(getStatsPrefix(theory
) + "::requirePhase", 0),
35 restartDemands(getStatsPrefix(theory
) + "::restartDemands", 0),
36 trustedConflicts(getStatsPrefix(theory
) + "::trustedConflicts", 0),
37 trustedLemmas(getStatsPrefix(theory
) + "::trustedLemmas", 0)
39 smtStatisticsRegistry()->registerStat(&conflicts
);
40 smtStatisticsRegistry()->registerStat(&propagations
);
41 smtStatisticsRegistry()->registerStat(&lemmas
);
42 smtStatisticsRegistry()->registerStat(&requirePhase
);
43 smtStatisticsRegistry()->registerStat(&restartDemands
);
44 smtStatisticsRegistry()->registerStat(&trustedConflicts
);
45 smtStatisticsRegistry()->registerStat(&trustedLemmas
);
48 EngineOutputChannel::Statistics::~Statistics()
50 smtStatisticsRegistry()->unregisterStat(&conflicts
);
51 smtStatisticsRegistry()->unregisterStat(&propagations
);
52 smtStatisticsRegistry()->unregisterStat(&lemmas
);
53 smtStatisticsRegistry()->unregisterStat(&requirePhase
);
54 smtStatisticsRegistry()->unregisterStat(&restartDemands
);
55 smtStatisticsRegistry()->unregisterStat(&trustedConflicts
);
56 smtStatisticsRegistry()->unregisterStat(&trustedLemmas
);
59 EngineOutputChannel::EngineOutputChannel(TheoryEngine
* engine
,
60 theory::TheoryId theory
)
61 : d_engine(engine
), d_statistics(theory
), d_theory(theory
)
65 void EngineOutputChannel::safePoint(ResourceManager::Resource r
)
68 if (d_engine
->d_interrupted
)
70 throw theory::Interrupted();
74 theory::LemmaStatus
EngineOutputChannel::lemma(TNode lemma
,
80 Debug("theory::lemma") << "EngineOutputChannel<" << d_theory
<< ">::lemma("
82 << ", preprocess = " << preprocess
<< std::endl
;
83 ++d_statistics
.lemmas
;
84 d_engine
->d_outputChannelUsed
= true;
86 PROOF({ registerLemmaRecipe(lemma
, lemma
, preprocess
, d_theory
); });
88 theory::LemmaStatus result
=
89 d_engine
->lemma(lemma
,
94 sendAtoms
? d_theory
: theory::THEORY_LAST
);
98 void EngineOutputChannel::registerLemmaRecipe(Node lemma
,
101 theory::TheoryId theoryId
)
103 // During CNF conversion, conjunctions will be broken down into
104 // multiple lemmas. In order for the recipes to match, we have to do
106 NodeManager
* nm
= NodeManager::currentNM();
108 if (preprocess
) lemma
= d_engine
->preprocess(lemma
);
110 bool negated
= (lemma
.getKind() == NOT
);
111 Node nnLemma
= negated
? lemma
[0] : lemma
;
113 switch (nnLemma
.getKind())
118 for (unsigned i
= 0; i
< nnLemma
.getNumChildren(); ++i
)
119 registerLemmaRecipe(nnLemma
[i
], originalLemma
, false, theoryId
);
123 NodeBuilder
<> builder(OR
);
124 for (unsigned i
= 0; i
< nnLemma
.getNumChildren(); ++i
)
125 builder
<< nnLemma
[i
].negate();
128 (builder
.getNumChildren() == 1) ? builder
[0] : builder
;
129 registerLemmaRecipe(disjunction
, originalLemma
, false, theoryId
);
134 if (nnLemma
[0].getType().isBoolean())
138 registerLemmaRecipe(nm
->mkNode(OR
, nnLemma
[0], nnLemma
[1].negate()),
142 registerLemmaRecipe(nm
->mkNode(OR
, nnLemma
[0].negate(), nnLemma
[1]),
149 registerLemmaRecipe(nm
->mkNode(OR
, nnLemma
[0], nnLemma
[1]),
154 nm
->mkNode(OR
, nnLemma
[0].negate(), nnLemma
[1].negate()),
165 registerLemmaRecipe(nm
->mkNode(OR
, nnLemma
[0].negate(), nnLemma
[1]),
169 registerLemmaRecipe(nm
->mkNode(OR
, nnLemma
[0], nnLemma
[2]),
177 nm
->mkNode(OR
, nnLemma
[0].negate(), nnLemma
[1].negate()),
181 registerLemmaRecipe(nm
->mkNode(OR
, nnLemma
[0], nnLemma
[2].negate()),
191 // Theory lemmas have one step that proves the empty clause
192 LemmaProofRecipe proofRecipe
;
194 LemmaProofRecipe::ProofStep
proofStep(theoryId
, emptyNode
);
196 // Remember the original lemma, so we can report this later when asked to
197 proofRecipe
.setOriginalLemma(originalLemma
);
199 // Record the assertions and rewrites
201 if (lemma
.getKind() == OR
)
203 for (unsigned i
= 0; i
< lemma
.getNumChildren(); ++i
)
205 rewritten
= theory::Rewriter::rewrite(lemma
[i
]);
206 if (rewritten
!= lemma
[i
])
208 proofRecipe
.addRewriteRule(lemma
[i
].negate(), rewritten
.negate());
210 proofStep
.addAssertion(lemma
[i
]);
211 proofRecipe
.addBaseAssertion(rewritten
);
216 rewritten
= theory::Rewriter::rewrite(lemma
);
217 if (rewritten
!= lemma
)
219 proofRecipe
.addRewriteRule(lemma
.negate(), rewritten
.negate());
221 proofStep
.addAssertion(lemma
);
222 proofRecipe
.addBaseAssertion(rewritten
);
224 proofRecipe
.addStep(proofStep
);
225 ProofManager::getCnfProof()->setProofRecipe(&proofRecipe
);
228 theory::LemmaStatus
EngineOutputChannel::splitLemma(TNode lemma
, bool removable
)
230 Debug("theory::lemma") << "EngineOutputChannel<" << d_theory
<< ">::lemma("
231 << lemma
<< ")" << std::endl
;
232 ++d_statistics
.lemmas
;
233 d_engine
->d_outputChannelUsed
= true;
235 Debug("pf::explain") << "EngineOutputChannel::splitLemma( " << lemma
<< " )"
237 theory::LemmaStatus result
=
238 d_engine
->lemma(lemma
, RULE_SPLIT
, false, removable
, false, d_theory
);
242 bool EngineOutputChannel::propagate(TNode literal
)
244 Debug("theory::propagate") << "EngineOutputChannel<" << d_theory
245 << ">::propagate(" << literal
<< ")" << std::endl
;
246 ++d_statistics
.propagations
;
247 d_engine
->d_outputChannelUsed
= true;
248 return d_engine
->propagate(literal
, d_theory
);
251 void EngineOutputChannel::conflict(TNode conflictNode
,
252 std::unique_ptr
<Proof
> proof
)
254 Trace("theory::conflict")
255 << "EngineOutputChannel<" << d_theory
<< ">::conflict(" << conflictNode
257 Assert(!proof
); // Theory shouldn't be producing proofs yet
258 ++d_statistics
.conflicts
;
259 d_engine
->d_outputChannelUsed
= true;
260 d_engine
->conflict(conflictNode
, d_theory
);
263 void EngineOutputChannel::demandRestart()
265 NodeManager
* curr
= NodeManager::currentNM();
266 Node restartVar
= curr
->mkSkolem(
269 "A boolean variable asserted to be true to force a restart");
270 Trace("theory::restart") << "EngineOutputChannel<" << d_theory
271 << ">::restart(" << restartVar
<< ")" << std::endl
;
272 ++d_statistics
.restartDemands
;
273 lemma(restartVar
, RULE_INVALID
, true);
276 void EngineOutputChannel::requirePhase(TNode n
, bool phase
)
278 Debug("theory") << "EngineOutputChannel::requirePhase(" << n
<< ", " << phase
280 ++d_statistics
.requirePhase
;
281 d_engine
->getPropEngine()->requirePhase(n
, phase
);
284 void EngineOutputChannel::setIncomplete()
286 Trace("theory") << "setIncomplete()" << std::endl
;
287 d_engine
->setIncomplete(d_theory
);
290 void EngineOutputChannel::spendResource(ResourceManager::Resource r
)
292 d_engine
->spendResource(r
);
295 void EngineOutputChannel::handleUserAttribute(const char* attr
,
298 d_engine
->handleUserAttribute(attr
, t
);
301 } // namespace theory