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