1 /********************* */ 2 /*! \file equality_engine_types.h 3 ** \verbatim 4 ** Top contributors (to current version): 5 ** Dejan Jovanovic, Andrew Reynolds, Andres Noetzli 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 ** \brief [[ Add one-line brief description here ]] 13 ** 14 ** [[ Add lengthier description here ]] 15 ** \todo document this file 16 **/ 17 18 #include "cvc4_private.h" 19 20 #ifndef __CVC4__THEORY__UF__EQUALITY_ENGINE_TYPES_H 21 #define __CVC4__THEORY__UF__EQUALITY_ENGINE_TYPES_H 22 23 #include <string> 24 #include <iostream> 25 #include <sstream> 26 27 #include "util/hash.h" 28 29 namespace CVC4 { 30 namespace theory { 31 namespace eq { 32 33 /** Default type for the size of the sizes (size_t replacement) */ 34 typedef uint32_t DefaultSizeType; 35 36 /** Id of the node */ 37 typedef DefaultSizeType EqualityNodeId; 38 39 /** Id of the use list */ 40 typedef DefaultSizeType UseListNodeId; 41 42 /** The trigger ids */ 43 typedef DefaultSizeType TriggerId; 44 45 /** The equality edge ids */ 46 typedef DefaultSizeType EqualityEdgeId; 47 48 /** The null node */ 49 static const EqualityNodeId null_id = (EqualityNodeId)(-1); 50 51 /** The null use list node */ 52 static const EqualityNodeId null_uselist_id = (EqualityNodeId)(-1); 53 54 /** The null trigger */ 55 static const TriggerId null_trigger = (TriggerId)(-1); 56 57 /** The null edge id */ 58 static const EqualityEdgeId null_edge = (EqualityEdgeId)(-1); 59 60 /** 61 * A reason for a merge. Either an equality x = y, a merge of two 62 * function applications f(x1, x2), f(y1, y2) due to congruence, 63 * or a merge of an equality to false due to both sides being 64 * (different) constants. 65 */ 66 enum MergeReasonType { 67 /** Terms were merged due to application of congruence closure */ 68 MERGED_THROUGH_CONGRUENCE, 69 /** Terms were merged due to application of pure equality */ 70 MERGED_THROUGH_EQUALITY, 71 /** Equality was merged to true, due to both sides of equality being in the same class */ 72 MERGED_THROUGH_REFLEXIVITY, 73 /** Equality was merged to false, due to both sides of equality being a constant */ 74 MERGED_THROUGH_CONSTANTS, 75 /** (for proofs only) Equality was merged due to transitivity */ 76 MERGED_THROUGH_TRANS, 77 78 /** Reason types beyond this constant are theory specific reasons */ 79 NUMBER_OF_MERGE_REASONS 80 }; 81 82 inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) { 83 switch (reason) { 84 case MERGED_THROUGH_CONGRUENCE: 85 out << "congruence"; 86 break; 87 case MERGED_THROUGH_EQUALITY: 88 out << "pure equality"; 89 break; 90 case MERGED_THROUGH_REFLEXIVITY: 91 out << "reflexivity"; 92 break; 93 case MERGED_THROUGH_CONSTANTS: 94 out << "constants disequal"; 95 break; 96 case MERGED_THROUGH_TRANS: 97 out << "transitivity"; 98 break; 99 100 default: 101 out << "[theory]"; 102 break; 103 } 104 return out; 105 } 106 107 /** 108 * A candidate for merging two equivalence classes, with the necessary 109 * additional information. 110 */ 111 struct MergeCandidate { 112 EqualityNodeId t1Id, t2Id; 113 unsigned type; 114 TNode reason; MergeCandidateMergeCandidate115 MergeCandidate(EqualityNodeId x, EqualityNodeId y, unsigned type, TNode reason) 116 : t1Id(x), t2Id(y), type(type), reason(reason) 117 {} 118 }; 119 120 /** 121 * Just an index into the reasons array, and the number of merges to consume. 122 */ 123 struct DisequalityReasonRef { 124 DefaultSizeType mergesStart; 125 DefaultSizeType mergesEnd; 126 DisequalityReasonRef(DefaultSizeType mergesStart = 0, DefaultSizeType mergesEnd = 0) mergesStartDisequalityReasonRef127 : mergesStart(mergesStart), mergesEnd(mergesEnd) {} 128 }; 129 130 /** 131 * We maintain uselist where a node appears in, and this is the node 132 * of such a list. 133 */ 134 class UseListNode { 135 136 private: 137 138 /** The id of the application node where this representative is at */ 139 EqualityNodeId d_applicationId; 140 141 /** The next one in the class */ 142 UseListNodeId d_nextUseListNodeId; 143 144 public: 145 146 /** 147 * Creates a new node, which is in a list of it's own. 148 */ 149 UseListNode(EqualityNodeId nodeId = null_id, UseListNodeId nextId = null_uselist_id) d_applicationId(nodeId)150 : d_applicationId(nodeId), d_nextUseListNodeId(nextId) {} 151 152 /** 153 * Returns the next node in the circular list. 154 */ getNext()155 UseListNodeId getNext() const { 156 return d_nextUseListNodeId; 157 } 158 159 /** 160 * Returns the id of the function application. 161 */ getApplicationId()162 EqualityNodeId getApplicationId() const { 163 return d_applicationId; 164 } 165 }; 166 167 /** 168 * Main class for representing nodes in the equivalence class. The 169 * nodes are a circular list, with the representative carrying the 170 * size. Each individual node carries with itself the uselist of 171 * function applications it appears in and the list of asserted 172 * disequalities it belongs to. In order to get these lists one must 173 * traverse the entire class and pick up all the individual lists. 174 */ 175 class EqualityNode { 176 177 private: 178 179 /** The size of this equivalence class (if it's a representative) */ 180 DefaultSizeType d_size; 181 182 /** The id (in the eq-manager) of the representative equality node */ 183 EqualityNodeId d_findId; 184 185 /** The next equality node in this class */ 186 EqualityNodeId d_nextId; 187 188 /** The use list of this node */ 189 UseListNodeId d_useList; 190 191 public: 192 193 /** 194 * Creates a new node, which is in a list of it's own. 195 */ 196 EqualityNode(EqualityNodeId nodeId = null_id) 197 : d_size(1) 198 , d_findId(nodeId) 199 , d_nextId(nodeId) 200 , d_useList(null_uselist_id) 201 {} 202 203 /** 204 * Returns the requested uselist. 205 */ getUseList()206 UseListNodeId getUseList() const { 207 return d_useList; 208 } 209 210 /** 211 * Returns the next node in the class circular list. 212 */ getNext()213 EqualityNodeId getNext() const { 214 return d_nextId; 215 } 216 217 /** 218 * Returns the size of this equivalence class (only valid if this is the representative). 219 */ getSize()220 DefaultSizeType getSize() const { 221 return d_size; 222 } 223 224 /** 225 * Merges the two lists. If add size is true the size of this node is increased by the size of 226 * the other node, otherwise the size is decreased by the size of the other node. 227 */ 228 template<bool addSize> merge(EqualityNode & other)229 void merge(EqualityNode& other) { 230 EqualityNodeId tmp = d_nextId; d_nextId = other.d_nextId; other.d_nextId = tmp; 231 if (addSize) { 232 d_size += other.d_size; 233 } else { 234 d_size -= other.d_size; 235 } 236 } 237 238 /** 239 * Returns the class representative. 240 */ getFind()241 EqualityNodeId getFind() const { return d_findId; } 242 243 /** 244 * Set the class representative. 245 */ setFind(EqualityNodeId findId)246 void setFind(EqualityNodeId findId) { d_findId = findId; } 247 248 /** 249 * Note that this node is used in a function application funId, or 250 * a negatively asserted equality (dis-equality) with funId. 251 */ 252 template<typename memory_class> usedIn(EqualityNodeId funId,memory_class & memory)253 void usedIn(EqualityNodeId funId, memory_class& memory) { 254 UseListNodeId newUseId = memory.size(); 255 memory.push_back(UseListNode(funId, d_useList)); 256 d_useList = newUseId; 257 } 258 259 /** 260 * For backtracking: remove the first element from the uselist and pop the memory. 261 */ 262 template<typename memory_class> removeTopFromUseList(memory_class & memory)263 void removeTopFromUseList(memory_class& memory) { 264 Assert ((int) d_useList == (int)memory.size() - 1); 265 d_useList = memory.back().getNext(); 266 memory.pop_back(); 267 } 268 }; 269 270 /** A pair of ids */ 271 typedef std::pair<EqualityNodeId, EqualityNodeId> EqualityPair; 272 using EqualityPairHashFunction = 273 PairHashFunction<EqualityNodeId, EqualityNodeId>; 274 275 enum FunctionApplicationType { 276 /** This application is an equality a = b */ 277 APP_EQUALITY, 278 /** This is a part of an uninterpreted application f(t1, ...., tn) */ 279 APP_UNINTERPRETED, 280 /** This is a part of an interpreted application f(t1, ..., tn) */ 281 APP_INTERPRETED 282 }; 283 284 /** 285 * Represents the function APPLY a b. If isEquality is true then it 286 * represents the predicate (a = b). Note that since one can not 287 * construct the equality over function terms, the equality and hash 288 * function below are still well defined. 289 */ 290 struct FunctionApplication { 291 /** Type of application */ 292 FunctionApplicationType type; 293 /** The actual application elements */ 294 EqualityNodeId a, b; 295 296 /** Construct an application */ 297 FunctionApplication(FunctionApplicationType type = APP_EQUALITY, EqualityNodeId a = null_id, EqualityNodeId b = null_id) typeFunctionApplication298 : type(type), a(a), b(b) {} 299 300 /** Equality of two applications */ 301 bool operator == (const FunctionApplication& other) const { 302 return type == other.type && a == other.a && b == other.b; 303 } 304 305 /** Is this a null application */ isNullFunctionApplication306 bool isNull() const { 307 return a == null_id || b == null_id; 308 } 309 310 /** Is this an equality */ isEqualityFunctionApplication311 bool isEquality() const { 312 return type == APP_EQUALITY; 313 } 314 315 /** Is this an interpreted application (equality is special, i.e. not interpreted) */ isInterpretedFunctionApplication316 bool isInterpreted() const { 317 return type == APP_INTERPRETED; 318 } 319 320 }; 321 322 struct FunctionApplicationHashFunction { operatorFunctionApplicationHashFunction323 size_t operator () (const FunctionApplication& app) const { 324 size_t hash = 0; 325 hash = 0x9e3779b9 + app.a; 326 hash ^= 0x9e3779b9 + app.b + (hash << 6) + (hash >> 2); 327 return hash; 328 } 329 }; 330 331 /** 332 * At time of addition a function application can already normalize to something, so 333 * we keep both the original, and the normalized version. 334 */ 335 struct FunctionApplicationPair { 336 FunctionApplication original; 337 FunctionApplication normalized; FunctionApplicationPairFunctionApplicationPair338 FunctionApplicationPair() {} FunctionApplicationPairFunctionApplicationPair339 FunctionApplicationPair(const FunctionApplication& original, const FunctionApplication& normalized) 340 : original(original), normalized(normalized) {} isNullFunctionApplicationPair341 bool isNull() const { 342 return original.isNull(); 343 } 344 }; 345 346 /** 347 * Information about the added triggers. 348 */ 349 struct TriggerInfo { 350 /** The trigger itself */ 351 Node trigger; 352 /** Polarity of the trigger */ 353 bool polarity; TriggerInfoTriggerInfo354 TriggerInfo() : polarity(false) {} TriggerInfoTriggerInfo355 TriggerInfo(Node trigger, bool polarity) 356 : trigger(trigger), polarity(polarity) {} 357 }; 358 359 } // namespace eq 360 } // namespace theory 361 } // namespace CVC4 362 363 #endif /* __CVC4__THEORY__UF__EQUALITY_ENGINE_TYPES_H */ 364