1 /********************* */
2 /*! \file theory_inference_manager.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Mathias Preiner, Gereon Kremer
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 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 An inference manager for Theory
15 #include "theory/theory_inference_manager.h"
17 #include "theory/theory.h"
18 #include "theory/uf/equality_engine.h"
20 using namespace CVC4::kind
;
25 TheoryInferenceManager::TheoryInferenceManager(Theory
& t
,
27 ProofNodeManager
* pnm
)
30 d_out(t
.getOutputChannel()),
33 d_keep(t
.getSatContext()),
34 d_lemmasSent(t
.getUserContext()),
36 d_numCurrentLemmas(0),
41 void TheoryInferenceManager::setEqualityEngine(eq::EqualityEngine
* ee
)
44 // if proofs are enabled, also make a proof equality engine to wrap ee
47 d_pfee
.reset(new eq::ProofEqEngine(d_theoryState
.getSatContext(),
48 d_theoryState
.getUserContext(),
54 bool TheoryInferenceManager::isProofEnabled() const { return d_pnm
!= nullptr; }
56 void TheoryInferenceManager::reset()
59 d_numCurrentLemmas
= 0;
60 d_numCurrentFacts
= 0;
63 bool TheoryInferenceManager::hasSent() const
65 return d_theoryState
.isInConflict() || d_numCurrentLemmas
> 0
66 || d_numCurrentFacts
> 0;
69 eq::ProofEqEngine
* TheoryInferenceManager::getProofEqEngine()
74 void TheoryInferenceManager::conflictEqConstantMerge(TNode a
, TNode b
)
76 if (!d_theoryState
.isInConflict())
78 TrustNode tconf
= explainConflictEqConstantMerge(a
, b
);
79 d_theoryState
.notifyInConflict();
80 d_out
.trustedConflict(tconf
);
84 void TheoryInferenceManager::conflict(TNode conf
)
86 if (!d_theoryState
.isInConflict())
88 d_theoryState
.notifyInConflict();
94 void TheoryInferenceManager::trustedConflict(TrustNode tconf
)
96 if (!d_theoryState
.isInConflict())
98 d_theoryState
.notifyInConflict();
99 d_out
.trustedConflict(tconf
);
103 void TheoryInferenceManager::conflictExp(PfRule id
,
104 const std::vector
<Node
>& exp
,
105 const std::vector
<Node
>& args
)
107 if (!d_theoryState
.isInConflict())
109 // make the trust node
110 TrustNode tconf
= mkConflictExp(id
, exp
, args
);
111 // send it on the output channel
112 trustedConflict(tconf
);
116 TrustNode
TheoryInferenceManager::mkConflictExp(PfRule id
,
117 const std::vector
<Node
>& exp
,
118 const std::vector
<Node
>& args
)
120 if (d_pfee
!= nullptr)
122 // use proof equality engine to construct the trust node
123 return d_pfee
->assertConflict(id
, exp
, args
);
125 // version without proofs
126 Node conf
= mkExplainPartial(exp
, {});
127 return TrustNode::mkTrustConflict(conf
, nullptr);
130 void TheoryInferenceManager::conflictExp(const std::vector
<Node
>& exp
,
133 if (!d_theoryState
.isInConflict())
135 // make the trust node
136 TrustNode tconf
= mkConflictExp(exp
, pg
);
137 // send it on the output channel
138 trustedConflict(tconf
);
142 TrustNode
TheoryInferenceManager::mkConflictExp(const std::vector
<Node
>& exp
,
145 if (d_pfee
!= nullptr)
147 Assert(pg
!= nullptr);
148 // use proof equality engine to construct the trust node
149 return d_pfee
->assertConflict(exp
, pg
);
151 // version without proofs
152 Node conf
= mkExplainPartial(exp
, {});
153 return TrustNode::mkTrustConflict(conf
, nullptr);
156 bool TheoryInferenceManager::propagateLit(TNode lit
)
158 // If already in conflict, no more propagation
159 if (d_theoryState
.isInConflict())
164 bool ok
= d_out
.propagate(lit
);
167 d_theoryState
.notifyInConflict();
172 TrustNode
TheoryInferenceManager::explainLit(TNode lit
)
174 if (d_pfee
!= nullptr)
176 return d_pfee
->explain(lit
);
180 Node exp
= d_ee
->mkExplainLit(lit
);
181 return TrustNode::mkTrustPropExp(lit
, exp
, nullptr);
183 Unimplemented() << "Inference manager for " << d_theory
.getId()
184 << " was asked to explain a propagation but doesn't have an "
185 "equality engine or implement the "
186 "TheoryInferenceManager::explainLit interface!";
189 TrustNode
TheoryInferenceManager::explainConflictEqConstantMerge(TNode a
,
192 Node lit
= a
.eqNode(b
);
193 if (d_pfee
!= nullptr)
195 return d_pfee
->assertConflict(lit
);
199 Node conf
= d_ee
->mkExplainLit(lit
);
200 return TrustNode::mkTrustConflict(conf
, nullptr);
202 Unimplemented() << "Inference manager for " << d_theory
.getId()
203 << " mkTrustedConflictEqConstantMerge";
206 bool TheoryInferenceManager::lemma(TNode lem
, LemmaProperty p
, bool doCache
)
208 TrustNode tlem
= TrustNode::mkTrustLemma(lem
, nullptr);
209 return trustedLemma(tlem
, p
, doCache
);
212 bool TheoryInferenceManager::trustedLemma(const TrustNode
& tlem
,
218 if (!cacheLemma(tlem
.getNode(), p
))
223 d_numCurrentLemmas
++;
224 d_out
.trustedLemma(tlem
, p
);
228 bool TheoryInferenceManager::lemmaExp(Node conc
,
230 const std::vector
<Node
>& exp
,
231 const std::vector
<Node
>& noExplain
,
232 const std::vector
<Node
>& args
,
236 // make the trust node
237 TrustNode trn
= mkLemmaExp(conc
, id
, exp
, noExplain
, args
);
238 // send it on the output channel
239 return trustedLemma(trn
, p
, doCache
);
242 TrustNode
TheoryInferenceManager::mkLemmaExp(Node conc
,
244 const std::vector
<Node
>& exp
,
245 const std::vector
<Node
>& noExplain
,
246 const std::vector
<Node
>& args
)
248 if (d_pfee
!= nullptr)
250 // make the trust node from the proof equality engine
251 return d_pfee
->assertLemma(conc
, id
, exp
, noExplain
, args
);
253 // otherwise, not using proofs, explain and make trust node
254 Node ant
= mkExplainPartial(exp
, noExplain
);
255 Node lem
= NodeManager::currentNM()->mkNode(kind::IMPLIES
, ant
, conc
);
256 return TrustNode::mkTrustLemma(lem
, nullptr);
259 bool TheoryInferenceManager::lemmaExp(Node conc
,
260 const std::vector
<Node
>& exp
,
261 const std::vector
<Node
>& noExplain
,
266 // make the trust node
267 TrustNode trn
= mkLemmaExp(conc
, exp
, noExplain
, pg
);
268 // send it on the output channel
269 return trustedLemma(trn
, p
, doCache
);
272 TrustNode
TheoryInferenceManager::mkLemmaExp(Node conc
,
273 const std::vector
<Node
>& exp
,
274 const std::vector
<Node
>& noExplain
,
277 if (d_pfee
!= nullptr)
279 // make the trust node from the proof equality engine
280 return d_pfee
->assertLemma(conc
, exp
, noExplain
, pg
);
282 // otherwise, not using proofs, explain and make trust node
283 Node ant
= mkExplainPartial(exp
, noExplain
);
284 Node lem
= NodeManager::currentNM()->mkNode(kind::IMPLIES
, ant
, conc
);
285 return TrustNode::mkTrustLemma(lem
, nullptr);
288 bool TheoryInferenceManager::hasCachedLemma(TNode lem
, LemmaProperty p
)
290 return d_lemmasSent
.find(lem
) != d_lemmasSent
.end();
293 uint32_t TheoryInferenceManager::numSentLemmas() const
295 return d_numCurrentLemmas
;
298 bool TheoryInferenceManager::hasSentLemma() const
300 return d_numCurrentLemmas
!= 0;
303 bool TheoryInferenceManager::assertInternalFact(TNode atom
, bool pol
, TNode exp
)
305 return processInternalFact(atom
, pol
, PfRule::UNKNOWN
, {exp
}, {}, nullptr);
308 bool TheoryInferenceManager::assertInternalFact(TNode atom
,
311 const std::vector
<Node
>& exp
,
312 const std::vector
<Node
>& args
)
314 Assert(id
!= PfRule::UNKNOWN
);
315 return processInternalFact(atom
, pol
, id
, exp
, args
, nullptr);
318 bool TheoryInferenceManager::assertInternalFact(TNode atom
,
320 const std::vector
<Node
>& exp
,
323 Assert(pg
!= nullptr);
324 return processInternalFact(atom
, pol
, PfRule::ASSUME
, exp
, {}, pg
);
327 bool TheoryInferenceManager::processInternalFact(TNode atom
,
330 const std::vector
<Node
>& exp
,
331 const std::vector
<Node
>& args
,
334 // make the node corresponding to the explanation
335 Node expn
= NodeManager::currentNM()->mkAnd(exp
);
336 // call the pre-notify fact method with preReg = false, isInternal = true
337 if (d_theory
.preNotifyFact(atom
, pol
, expn
, false, true))
339 // Handled in a theory-specific way that doesn't require equality engine,
340 // notice we return true, indicating that the fact was processed.
343 Assert(d_ee
!= nullptr);
344 Trace("infer-manager") << "TheoryInferenceManager::assertInternalFact: "
345 << expn
<< std::endl
;
347 // Now, assert the fact. How to do so depends on whether proofs are enabled.
348 // If no proof production, or no proof rule was given
350 if (d_pfee
== nullptr || id
== PfRule::UNKNOWN
)
352 if (atom
.getKind() == kind::EQUAL
)
354 ret
= d_ee
->assertEquality(atom
, pol
, expn
);
358 ret
= d_ee
->assertPredicate(atom
, pol
, expn
);
360 // Must reference count the equality and its explanation, which is not done
361 // by the equality engine. Notice that we do *not* need to do this for
362 // external assertions, which enter as facts in theory check. This is also
363 // not done if we are asserting to the proof equality engine, which does
364 // this caching itself within ProofEqEngine::assertFact.
370 // Note that we reconstruct the original literal lit here, since both the
371 // original literal is needed for bookkeeping proofs. It is possible to
372 // optimize this so that a few less nodes are created, but at the cost
373 // of a more verbose interface to proof equality engine.
374 Node lit
= pol
? Node(atom
) : atom
.notNode();
377 // use the proof generator interface
378 ret
= d_pfee
->assertFact(lit
, expn
, pg
);
382 // use the explict proof step interface
383 ret
= d_pfee
->assertFact(lit
, id
, expn
, args
);
386 // call the notify fact method with isInternal = true
387 d_theory
.notifyFact(atom
, pol
, expn
, true);
388 Trace("infer-manager")
389 << "TheoryInferenceManager::finished assertInternalFact" << std::endl
;
393 void TheoryInferenceManager::explain(TNode n
, std::vector
<TNode
>& assumptions
)
395 if (n
.getKind() == kind::AND
)
397 for (const Node
& nc
: n
)
399 d_ee
->explainLit(nc
, assumptions
);
404 d_ee
->explainLit(n
, assumptions
);
408 Node
TheoryInferenceManager::mkExplain(TNode n
)
410 std::vector
<TNode
> assumptions
;
411 explain(n
, assumptions
);
412 return NodeManager::currentNM()->mkAnd(assumptions
);
415 Node
TheoryInferenceManager::mkExplainPartial(
416 const std::vector
<Node
>& exp
, const std::vector
<Node
>& noExplain
)
418 std::vector
<TNode
> assumps
;
419 for (const Node
& e
: exp
)
421 if (std::find(noExplain
.begin(), noExplain
.end(), e
) != noExplain
.end())
423 if (std::find(assumps
.begin(), assumps
.end(), e
) == assumps
.end())
425 // a non-explained literal
426 assumps
.push_back(e
);
430 // otherwise, explain it
433 return NodeManager::currentNM()->mkAnd(assumps
);
436 uint32_t TheoryInferenceManager::numSentFacts() const
438 return d_numCurrentFacts
;
441 bool TheoryInferenceManager::hasSentFact() const
443 return d_numCurrentFacts
!= 0;
446 bool TheoryInferenceManager::cacheLemma(TNode lem
, LemmaProperty p
)
448 if (d_lemmasSent
.find(lem
) != d_lemmasSent
.end())
452 d_lemmasSent
.insert(lem
);
456 void TheoryInferenceManager::requirePhase(TNode n
, bool pol
)
458 return d_out
.requirePhase(n
, pol
);
461 void TheoryInferenceManager::spendResource(ResourceManager::Resource r
)
463 d_out
.spendResource(r
);
466 void TheoryInferenceManager::safePoint(ResourceManager::Resource r
)
471 void TheoryInferenceManager::setIncomplete() { d_out
.setIncomplete(); }
473 } // namespace theory