1 /********************* */ 2 /*! \file shared_terms_database.h 3 ** \verbatim 4 ** Top contributors (to current version): 5 ** Dejan Jovanovic, Mathias Preiner, Morgan Deters 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 11 ** 12 ** [[ Add lengthier description here ]] 13 ** \todo document this file 14 **/ 15 16 #include "cvc4_private.h" 17 18 #pragma once 19 20 #include <unordered_map> 21 22 #include "context/cdhashset.h" 23 #include "expr/node.h" 24 #include "theory/theory.h" 25 #include "theory/uf/equality_engine.h" 26 #include "util/statistics_registry.h" 27 28 namespace CVC4 { 29 30 class TheoryEngine; 31 32 class SharedTermsDatabase : public context::ContextNotifyObj { 33 34 public: 35 36 /** A container for a list of shared terms */ 37 typedef std::vector<TNode> shared_terms_list; 38 39 /** The iterator to go through the shared terms list */ 40 typedef shared_terms_list::const_iterator shared_terms_iterator; 41 42 private: 43 44 /** Some statistics */ 45 IntStat d_statSharedTerms; 46 47 // Needs to be a map from Nodes as after a backtrack they might not exist 48 typedef std::unordered_map<Node, shared_terms_list, TNodeHashFunction> SharedTermsMap; 49 50 /** A map from atoms to a list of shared terms */ 51 SharedTermsMap d_atomsToTerms; 52 53 /** Each time we add a shared term, we add it's parent to this list */ 54 std::vector<TNode> d_addedSharedTerms; 55 56 /** Context-dependent size of the d_addedSharedTerms list */ 57 context::CDO<unsigned> d_addedSharedTermsSize; 58 59 /** A map from atoms and subterms to the theories that use it */ 60 typedef context::CDHashMap<std::pair<Node, TNode>, theory::Theory::Set, TNodePairHashFunction> SharedTermsTheoriesMap; 61 SharedTermsTheoriesMap d_termsToTheories; 62 63 /** Map from term to theories that have already been notified about the shared term */ 64 typedef context::CDHashMap<TNode, theory::Theory::Set, TNodeHashFunction> AlreadyNotifiedMap; 65 AlreadyNotifiedMap d_alreadyNotifiedMap; 66 67 /** The registered equalities for propagation */ 68 typedef context::CDHashSet<Node, NodeHashFunction> RegisteredEqualitiesSet; 69 RegisteredEqualitiesSet d_registeredEqualities; 70 71 private: 72 73 /** This method removes all the un-necessary stuff from the maps */ 74 void backtrack(); 75 76 // EENotifyClass: template helper class for d_equalityEngine - handles call-backs 77 class EENotifyClass : public theory::eq::EqualityEngineNotify { 78 SharedTermsDatabase& d_sharedTerms; 79 public: EENotifyClass(SharedTermsDatabase & shared)80 EENotifyClass(SharedTermsDatabase& shared): d_sharedTerms(shared) {} eqNotifyTriggerEquality(TNode equality,bool value)81 bool eqNotifyTriggerEquality(TNode equality, bool value) override 82 { 83 d_sharedTerms.propagateEquality(equality, value); 84 return true; 85 } 86 eqNotifyTriggerPredicate(TNode predicate,bool value)87 bool eqNotifyTriggerPredicate(TNode predicate, bool value) override 88 { 89 Unreachable(); 90 return true; 91 } 92 eqNotifyTriggerTermEquality(theory::TheoryId tag,TNode t1,TNode t2,bool value)93 bool eqNotifyTriggerTermEquality(theory::TheoryId tag, 94 TNode t1, 95 TNode t2, 96 bool value) override 97 { 98 return d_sharedTerms.propagateSharedEquality(tag, t1, t2, value); 99 } 100 eqNotifyConstantTermMerge(TNode t1,TNode t2)101 void eqNotifyConstantTermMerge(TNode t1, TNode t2) override 102 { 103 d_sharedTerms.conflict(t1, t2, true); 104 } 105 eqNotifyNewClass(TNode t)106 void eqNotifyNewClass(TNode t) override {} eqNotifyPreMerge(TNode t1,TNode t2)107 void eqNotifyPreMerge(TNode t1, TNode t2) override {} eqNotifyPostMerge(TNode t1,TNode t2)108 void eqNotifyPostMerge(TNode t1, TNode t2) override {} eqNotifyDisequal(TNode t1,TNode t2,TNode reason)109 void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {} 110 }; 111 112 /** The notify class for d_equalityEngine */ 113 EENotifyClass d_EENotify; 114 115 /** Equality engine */ 116 theory::eq::EqualityEngine d_equalityEngine; 117 118 /** 119 * Method called by equalityEngine when a becomes (dis-)equal to b and a and b are shared with 120 * the theory. Returns false if there is a direct conflict (via rewrite for example). 121 */ 122 bool propagateSharedEquality(theory::TheoryId theory, TNode a, TNode b, bool value); 123 124 /** 125 * Called from the equality engine when a trigger equality is deduced. 126 */ 127 bool propagateEquality(TNode equality, bool polarity); 128 129 /** Theory engine */ 130 TheoryEngine* d_theoryEngine; 131 132 /** Are we in conflict */ 133 context::CDO<bool> d_inConflict; 134 135 /** Conflicting terms, if any */ 136 Node d_conflictLHS, d_conflictRHS; 137 138 /** Polarity of the conflict */ 139 bool d_conflictPolarity; 140 141 /** Called by the equality engine notify to mark the conflict */ conflict(TNode lhs,TNode rhs,bool polarity)142 void conflict(TNode lhs, TNode rhs, bool polarity) { 143 if (!d_inConflict) { 144 // Only remember it if we're not already in conflict 145 d_inConflict = true; 146 d_conflictLHS = lhs; 147 d_conflictRHS = rhs; 148 d_conflictPolarity = polarity; 149 } 150 } 151 152 /** 153 * Should be called before any public non-const method in order to 154 * enqueue the conflict to the theory engine. 155 */ 156 void checkForConflict(); 157 158 public: 159 160 SharedTermsDatabase(TheoryEngine* theoryEngine, context::Context* context); 161 ~SharedTermsDatabase(); 162 163 /** 164 * Asserts the equality to the shared terms database, 165 */ 166 void assertEquality(TNode equality, bool polarity, TNode reason); 167 168 /** 169 * Return whether the equality is alreday known to the engine 170 */ 171 bool isKnown(TNode literal) const; 172 173 /** 174 * Returns an explanation of the propagation that came from the database. 175 */ 176 Node explain(TNode literal) const; 177 178 /** 179 * Add an equality to propagate. 180 */ 181 void addEqualityToPropagate(TNode equality); 182 183 /** 184 * Add a shared term to the database. The shared term is a subterm of the atom and 185 * should be associated with the given theory. 186 */ 187 void addSharedTerm(TNode atom, TNode term, theory::Theory::Set theories); 188 189 /** 190 * Mark that the given theories have been notified of the given shared term. 191 */ 192 void markNotified(TNode term, theory::Theory::Set theories); 193 194 /** 195 * Returns true if the atom contains any shared terms, false otherwise. 196 */ 197 bool hasSharedTerms(TNode atom) const; 198 199 /** 200 * Iterator pointing to the first shared term belonging to the given atom. 201 */ 202 shared_terms_iterator begin(TNode atom) const; 203 204 /** 205 * Iterator pointing to the end of the list of shared terms belonging to the given atom. 206 */ 207 shared_terms_iterator end(TNode atom) const; 208 209 /** 210 * Get the theories that share the term in a given atom (and have not yet been notified). 211 */ 212 theory::Theory::Set getTheoriesToNotify(TNode atom, TNode term) const; 213 214 /** 215 * Get the theories that share the term and have been notified already. 216 */ 217 theory::Theory::Set getNotifiedTheories(TNode term) const; 218 219 /** 220 * Returns true if the term is currently registered as shared with some theory. 221 */ isShared(TNode term)222 bool isShared(TNode term) const { 223 return d_alreadyNotifiedMap.find(term) != d_alreadyNotifiedMap.end(); 224 } 225 226 /** 227 * Returns true if the literal is an (dis-)equality with both sides registered as shared with 228 * some theory. 229 */ isSharedEquality(TNode literal)230 bool isSharedEquality(TNode literal) const { 231 TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal; 232 return atom.getKind() == kind::EQUAL && isShared(atom[0]) && isShared(atom[1]); 233 } 234 235 /** 236 * Returns true if the shared terms a and b are known to be equal. 237 */ 238 bool areEqual(TNode a, TNode b) const; 239 240 /** 241 * Retursn true if the shared terms a and b are known to be dis-equal. 242 */ 243 bool areDisequal(TNode a, TNode b) const; 244 245 /** 246 * get equality engine 247 */ getEqualityEngine()248 theory::eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; } 249 250 protected: 251 252 /** 253 * This method gets called on backtracks from the context manager. 254 */ contextNotifyPop()255 void contextNotifyPop() override { backtrack(); } 256 }; 257 258 } 259