1 /********************* */
2 /*! \file shared_terms_database.h
4 ** Top contributors (to current version):
5 ** Dejan Jovanovic, Andrew Reynolds, Mathias Preiner
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 ** [[ Add lengthier description here ]]
13 ** \todo document this file
16 #include "cvc4_private.h"
20 #include <unordered_map>
22 #include "context/cdhashset.h"
23 #include "expr/node.h"
24 #include "expr/proof_node_manager.h"
25 #include "theory/ee_setup_info.h"
26 #include "theory/theory_id.h"
27 #include "theory/trust_node.h"
28 #include "theory/uf/equality_engine.h"
29 #include "theory/uf/proof_equality_engine.h"
30 #include "util/statistics_registry.h"
36 class SharedTermsDatabase
: public context::ContextNotifyObj
{
38 /** A container for a list of shared terms */
39 typedef std::vector
<TNode
> shared_terms_list
;
41 /** The iterator to go through the shared terms list */
42 typedef shared_terms_list::const_iterator shared_terms_iterator
;
45 /** Some statistics */
46 IntStat d_statSharedTerms
;
48 // Needs to be a map from Nodes as after a backtrack they might not exist
49 typedef std::unordered_map
<Node
, shared_terms_list
, TNodeHashFunction
> SharedTermsMap
;
51 /** A map from atoms to a list of shared terms */
52 SharedTermsMap d_atomsToTerms
;
54 /** Each time we add a shared term, we add it's parent to this list */
55 std::vector
<TNode
> d_addedSharedTerms
;
57 /** Context-dependent size of the d_addedSharedTerms list */
58 context::CDO
<unsigned> d_addedSharedTermsSize
;
60 /** A map from atoms and subterms to the theories that use it */
61 typedef context::CDHashMap
<std::pair
<Node
, TNode
>,
63 TNodePairHashFunction
>
64 SharedTermsTheoriesMap
;
65 SharedTermsTheoriesMap d_termsToTheories
;
67 /** Map from term to theories that have already been notified about the shared term */
68 typedef context::CDHashMap
<TNode
, theory::TheoryIdSet
, TNodeHashFunction
>
70 AlreadyNotifiedMap d_alreadyNotifiedMap
;
72 /** The registered equalities for propagation */
73 typedef context::CDHashSet
<Node
, NodeHashFunction
> RegisteredEqualitiesSet
;
74 RegisteredEqualitiesSet d_registeredEqualities
;
77 /** This method removes all the un-necessary stuff from the maps */
80 // EENotifyClass: template helper class for d_equalityEngine - handles call-backs
81 class EENotifyClass
: public theory::eq::EqualityEngineNotify
{
82 SharedTermsDatabase
& d_sharedTerms
;
84 EENotifyClass(SharedTermsDatabase
& shared
): d_sharedTerms(shared
) {}
85 bool eqNotifyTriggerPredicate(TNode predicate
, bool value
) override
87 Assert(predicate
.getKind() == kind::EQUAL
);
88 d_sharedTerms
.propagateEquality(predicate
, value
);
92 bool eqNotifyTriggerTermEquality(theory::TheoryId tag
,
97 return d_sharedTerms
.propagateSharedEquality(tag
, t1
, t2
, value
);
100 void eqNotifyConstantTermMerge(TNode t1
, TNode t2
) override
102 d_sharedTerms
.conflict(t1
, t2
, true);
105 void eqNotifyNewClass(TNode t
) override
{}
106 void eqNotifyMerge(TNode t1
, TNode t2
) override
{}
107 void eqNotifyDisequal(TNode t1
, TNode t2
, TNode reason
) override
{}
110 /** The notify class for d_equalityEngine */
111 EENotifyClass d_EENotify
;
114 * Method called by equalityEngine when a becomes (dis-)equal to b and a and b are shared with
115 * the theory. Returns false if there is a direct conflict (via rewrite for example).
117 bool propagateSharedEquality(theory::TheoryId theory
, TNode a
, TNode b
, bool value
);
120 * Called from the equality engine when a trigger equality is deduced.
122 bool propagateEquality(TNode equality
, bool polarity
);
125 TheoryEngine
* d_theoryEngine
;
127 /** Are we in conflict */
128 context::CDO
<bool> d_inConflict
;
130 /** Conflicting terms, if any */
131 Node d_conflictLHS
, d_conflictRHS
;
133 /** Polarity of the conflict */
134 bool d_conflictPolarity
;
136 /** Called by the equality engine notify to mark the conflict */
137 void conflict(TNode lhs
, TNode rhs
, bool polarity
) {
139 // Only remember it if we're not already in conflict
143 d_conflictPolarity
= polarity
;
148 * Should be called before any public non-const method in order to
149 * enqueue the conflict to the theory engine.
151 void checkForConflict();
155 * @param theoryEngine The parent theory engine
156 * @param context The SAT context
157 * @param userContext The user context
158 * @param pnm The proof node manager to use, which is non-null if proofs
161 SharedTermsDatabase(TheoryEngine
* theoryEngine
,
162 context::Context
* context
,
163 context::UserContext
* userContext
,
164 ProofNodeManager
* pnm
);
165 ~SharedTermsDatabase();
167 //-------------------------------------------- initialization
168 /** Called to set the equality engine. */
169 void setEqualityEngine(theory::eq::EqualityEngine
* ee
);
171 * Returns true if we need an equality engine, this has the same contract
172 * as Theory::needsEqualityEngine.
174 bool needsEqualityEngine(theory::EeSetupInfo
& esi
);
175 //-------------------------------------------- end initialization
178 * Asserts the equality to the shared terms database,
180 void assertEquality(TNode equality
, bool polarity
, TNode reason
);
183 * Return whether the equality is alreday known to the engine
185 bool isKnown(TNode literal
) const;
188 * Returns an explanation of the propagation that came from the database.
190 theory::TrustNode
explain(TNode literal
) const;
193 * Add an equality to propagate.
195 void addEqualityToPropagate(TNode equality
);
198 * Add a shared term to the database. The shared term is a subterm of the atom and
199 * should be associated with the given theory.
201 void addSharedTerm(TNode atom
, TNode term
, theory::TheoryIdSet theories
);
204 * Mark that the given theories have been notified of the given shared term.
206 void markNotified(TNode term
, theory::TheoryIdSet theories
);
209 * Returns true if the atom contains any shared terms, false otherwise.
211 bool hasSharedTerms(TNode atom
) const;
214 * Iterator pointing to the first shared term belonging to the given atom.
216 shared_terms_iterator
begin(TNode atom
) const;
219 * Iterator pointing to the end of the list of shared terms belonging to the given atom.
221 shared_terms_iterator
end(TNode atom
) const;
224 * Get the theories that share the term in a given atom (and have not yet been notified).
226 theory::TheoryIdSet
getTheoriesToNotify(TNode atom
, TNode term
) const;
229 * Get the theories that share the term and have been notified already.
231 theory::TheoryIdSet
getNotifiedTheories(TNode term
) const;
234 * Returns true if the term is currently registered as shared with some theory.
236 bool isShared(TNode term
) const {
237 return d_alreadyNotifiedMap
.find(term
) != d_alreadyNotifiedMap
.end();
241 * Returns true if the literal is an (dis-)equality with both sides registered as shared with
244 bool isSharedEquality(TNode literal
) const {
245 TNode atom
= literal
.getKind() == kind::NOT
? literal
[0] : literal
;
246 return atom
.getKind() == kind::EQUAL
&& isShared(atom
[0]) && isShared(atom
[1]);
250 * Returns true if the shared terms a and b are known to be equal.
252 bool areEqual(TNode a
, TNode b
) const;
255 * Retursn true if the shared terms a and b are known to be dis-equal.
257 bool areDisequal(TNode a
, TNode b
) const;
260 * get equality engine
262 theory::eq::EqualityEngine
* getEqualityEngine();
266 * This method gets called on backtracks from the context manager.
268 void contextNotifyPop() override
{ backtrack(); }
269 /** The SAT search context. */
270 context::Context
* d_satContext
;
271 /** The user level assertion context. */
272 context::UserContext
* d_userContext
;
273 /** Equality engine */
274 theory::eq::EqualityEngine
* d_equalityEngine
;
275 /** Proof equality engine */
276 std::unique_ptr
<theory::eq::ProofEqEngine
> d_pfee
;
277 /** The proof node manager */
278 ProofNodeManager
* d_pnm
;