1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Dejan Jovanovic, Andrew Reynolds, Morgan Deters |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 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. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* [[ Add one-line brief description here ]] |
14 |
|
* |
15 |
|
* [[ Add lengthier description here ]] |
16 |
|
* \todo document this file |
17 |
|
*/ |
18 |
|
|
19 |
|
#include "cvc5_private.h" |
20 |
|
|
21 |
|
#ifndef CVC5__THEORY__UF__EQUALITY_ENGINE_H |
22 |
|
#define CVC5__THEORY__UF__EQUALITY_ENGINE_H |
23 |
|
|
24 |
|
#include <deque> |
25 |
|
#include <queue> |
26 |
|
#include <unordered_map> |
27 |
|
#include <vector> |
28 |
|
|
29 |
|
#include "context/cdhashmap.h" |
30 |
|
#include "context/cdo.h" |
31 |
|
#include "expr/kind_map.h" |
32 |
|
#include "expr/node.h" |
33 |
|
#include "smt/env_obj.h" |
34 |
|
#include "theory/theory_id.h" |
35 |
|
#include "theory/uf/equality_engine_iterator.h" |
36 |
|
#include "theory/uf/equality_engine_notify.h" |
37 |
|
#include "theory/uf/equality_engine_types.h" |
38 |
|
#include "util/statistics_stats.h" |
39 |
|
|
40 |
|
namespace cvc5 { |
41 |
|
|
42 |
|
class Env; |
43 |
|
|
44 |
|
namespace theory { |
45 |
|
namespace eq { |
46 |
|
|
47 |
|
class EqClassesIterator; |
48 |
|
class EqClassIterator; |
49 |
|
class EqProof; |
50 |
|
class ProofEqEngine; |
51 |
|
|
52 |
|
/** |
53 |
|
* Class for keeping an incremental congruence closure over a set of terms. It provides |
54 |
|
* notifications via an EqualityEngineNotify object. |
55 |
|
*/ |
56 |
|
class EqualityEngine : public context::ContextNotifyObj, protected EnvObj { |
57 |
|
|
58 |
|
friend class EqClassesIterator; |
59 |
|
friend class EqClassIterator; |
60 |
|
|
61 |
|
/** Default implementation of the notification object */ |
62 |
|
static EqualityEngineNotifyNone s_notifyNone; |
63 |
|
|
64 |
|
/** |
65 |
|
* Master equality engine that gets all the equality information from |
66 |
|
* this one, or null if none. |
67 |
|
*/ |
68 |
|
EqualityEngine* d_masterEqualityEngine; |
69 |
|
|
70 |
|
/** Proof equality engine */ |
71 |
|
ProofEqEngine* d_proofEqualityEngine; |
72 |
|
|
73 |
|
public: |
74 |
|
/** |
75 |
|
* Initialize the equality engine, given the notification class. |
76 |
|
* |
77 |
|
* @param env The environment, which is used for rewriting |
78 |
|
* @param c The context which this equality engine depends, which is typically |
79 |
|
* although not necessarily same as the SAT context of env. |
80 |
|
* @param name The name of this equality engine, for statistics |
81 |
|
* @param constantTriggers Whether we treat constants as trigger terms |
82 |
|
* @param anyTermTriggers Whether we use any terms as triggers |
83 |
|
*/ |
84 |
|
EqualityEngine(Env& env, |
85 |
|
context::Context* c, |
86 |
|
EqualityEngineNotify& notify, |
87 |
|
std::string name, |
88 |
|
bool constantTriggers, |
89 |
|
bool anyTermTriggers = true); |
90 |
|
|
91 |
|
/** |
92 |
|
* Initialize the equality engine with no notification class. |
93 |
|
*/ |
94 |
|
EqualityEngine(Env& env, |
95 |
|
context::Context* c, |
96 |
|
std::string name, |
97 |
|
bool constantsAreTriggers, |
98 |
|
bool anyTermTriggers = true); |
99 |
|
|
100 |
|
/** |
101 |
|
* Just a destructor. |
102 |
|
*/ |
103 |
|
virtual ~EqualityEngine(); |
104 |
|
|
105 |
|
/** |
106 |
|
* Set the master equality engine for this one. Master engine will get copies |
107 |
|
* of all the terms and equalities from this engine. |
108 |
|
*/ |
109 |
|
void setMasterEqualityEngine(EqualityEngine* master); |
110 |
|
/** Set the proof equality engine for this one. */ |
111 |
|
void setProofEqualityEngine(ProofEqEngine* pfee); |
112 |
|
/** Get the proof equality engine */ |
113 |
|
ProofEqEngine* getProofEqualityEngine(); |
114 |
|
|
115 |
|
/** Print the equivalence classes for debugging */ |
116 |
|
std::string debugPrintEqc() const; |
117 |
|
|
118 |
|
/** Statistics about the equality engine instance */ |
119 |
|
struct Statistics |
120 |
|
{ |
121 |
|
/** Total number of merges */ |
122 |
|
IntStat d_mergesCount; |
123 |
|
/** Number of terms managed by the system */ |
124 |
|
IntStat d_termsCount; |
125 |
|
/** Number of function terms managed by the system */ |
126 |
|
IntStat d_functionTermsCount; |
127 |
|
/** Number of constant terms managed by the system */ |
128 |
|
IntStat d_constantTermsCount; |
129 |
|
|
130 |
|
Statistics(const std::string& name); |
131 |
|
};/* struct EqualityEngine::statistics */ |
132 |
|
|
133 |
|
private: |
134 |
|
/** The context we are using */ |
135 |
|
context::Context* d_context; |
136 |
|
|
137 |
|
/** If we are done, we don't except any new assertions */ |
138 |
|
context::CDO<bool> d_done; |
139 |
|
|
140 |
|
/** The class to notify when a representative changes for a term */ |
141 |
|
EqualityEngineNotify* d_notify; |
142 |
|
|
143 |
|
/** The map of kinds to be treated as function applications */ |
144 |
|
KindMap d_congruenceKinds; |
145 |
|
|
146 |
|
/** The map of kinds to be treated as interpreted function applications (for evaluation of constants) */ |
147 |
|
KindMap d_congruenceKindsInterpreted; |
148 |
|
|
149 |
|
/** The map of kinds with operators to be considered external (for higher-order) */ |
150 |
|
KindMap d_congruenceKindsExtOperators; |
151 |
|
|
152 |
|
/** Map from nodes to their ids */ |
153 |
|
std::unordered_map<TNode, EqualityNodeId> d_nodeIds; |
154 |
|
|
155 |
|
/** Map from function applications to their ids */ |
156 |
|
typedef std::unordered_map<FunctionApplication, EqualityNodeId, FunctionApplicationHashFunction> ApplicationIdsMap; |
157 |
|
|
158 |
|
/** |
159 |
|
* A map from a pair (a', b') to a function application f(a, b), where a' and b' are the current representatives |
160 |
|
* of a and b. |
161 |
|
*/ |
162 |
|
ApplicationIdsMap d_applicationLookup; |
163 |
|
|
164 |
|
/** Application lookups in order, so that we can backtrack. */ |
165 |
|
std::vector<FunctionApplication> d_applicationLookups; |
166 |
|
|
167 |
|
/** Number of application lookups, for backtracking. */ |
168 |
|
context::CDO<DefaultSizeType> d_applicationLookupsCount; |
169 |
|
|
170 |
|
/** |
171 |
|
* Store the application lookup, with enough information to backtrack |
172 |
|
*/ |
173 |
|
void storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId); |
174 |
|
|
175 |
|
/** Map from ids to the nodes (these need to be nodes as we pick up the operators) */ |
176 |
|
std::vector<Node> d_nodes; |
177 |
|
|
178 |
|
/** A context-dependents count of nodes */ |
179 |
|
context::CDO<DefaultSizeType> d_nodesCount; |
180 |
|
|
181 |
|
/** Map from ids to the applications */ |
182 |
|
std::vector<FunctionApplicationPair> d_applications; |
183 |
|
|
184 |
|
/** Map from ids to the equality nodes */ |
185 |
|
std::vector<EqualityNode> d_equalityNodes; |
186 |
|
|
187 |
|
/** Number of asserted equalities we have so far */ |
188 |
|
context::CDO<DefaultSizeType> d_assertedEqualitiesCount; |
189 |
|
|
190 |
|
/** Memory for the use-list nodes */ |
191 |
|
std::vector<UseListNode> d_useListNodes; |
192 |
|
|
193 |
|
/** |
194 |
|
* We keep a list of asserted equalities. Not among original terms, but |
195 |
|
* among the class representatives. |
196 |
|
*/ |
197 |
|
struct Equality { |
198 |
|
/** Left hand side of the equality */ |
199 |
|
EqualityNodeId d_lhs; |
200 |
|
/** Right hand side of the equality */ |
201 |
|
EqualityNodeId d_rhs; |
202 |
|
/** Equality constructor */ |
203 |
35900736 |
Equality(EqualityNodeId l = null_id, EqualityNodeId r = null_id) |
204 |
35900736 |
: d_lhs(l), d_rhs(r) |
205 |
|
{ |
206 |
35900736 |
} |
207 |
|
};/* struct EqualityEngine::Equality */ |
208 |
|
|
209 |
|
/** The ids of the classes we have merged */ |
210 |
|
std::vector<Equality> d_assertedEqualities; |
211 |
|
|
212 |
|
/** The reasons for the equalities */ |
213 |
|
|
214 |
|
/** |
215 |
|
* An edge in the equality graph. This graph is an undirected graph (both edges added) |
216 |
|
* containing the actual asserted equalities. |
217 |
|
*/ |
218 |
224957400 |
class EqualityEdge { |
219 |
|
|
220 |
|
// The id of the RHS of this equality |
221 |
|
EqualityNodeId d_nodeId; |
222 |
|
// The next edge |
223 |
|
EqualityEdgeId d_nextId; |
224 |
|
// Type of reason for this equality |
225 |
|
unsigned d_mergeType; |
226 |
|
// Reason of this equality |
227 |
|
TNode d_reason; |
228 |
|
|
229 |
|
public: |
230 |
|
|
231 |
|
EqualityEdge(): |
232 |
|
d_nodeId(null_edge), d_nextId(null_edge), d_mergeType(MERGED_THROUGH_CONGRUENCE) {} |
233 |
|
|
234 |
71801472 |
EqualityEdge(EqualityNodeId nodeId, EqualityNodeId nextId, unsigned type, TNode reason): |
235 |
71801472 |
d_nodeId(nodeId), d_nextId(nextId), d_mergeType(type), d_reason(reason) {} |
236 |
|
|
237 |
|
/** Returns the id of the next edge */ |
238 |
97902224 |
EqualityEdgeId getNext() const { return d_nextId; } |
239 |
|
|
240 |
|
/** Returns the id of the target edge node */ |
241 |
158971961 |
EqualityNodeId getNodeId() const { return d_nodeId; } |
242 |
|
|
243 |
|
/** The reason of this edge */ |
244 |
3819840 |
unsigned getReasonType() const { return d_mergeType; } |
245 |
|
|
246 |
|
/** The reason of this edge */ |
247 |
3819840 |
TNode getReason() const { return d_reason; } |
248 |
|
};/* class EqualityEngine::EqualityEdge */ |
249 |
|
|
250 |
|
/** |
251 |
|
* All the equality edges (twice as many as the number of asserted equalities. If an equality |
252 |
|
* t1 = t2 is asserted, the edges added are -> t2, -> t1 (in this order). Hence, having the index |
253 |
|
* of one of the edges you can reconstruct the original equality. |
254 |
|
*/ |
255 |
|
std::vector<EqualityEdge> d_equalityEdges; |
256 |
|
|
257 |
|
/** |
258 |
|
* Returns the string representation of the edges. |
259 |
|
*/ |
260 |
|
std::string edgesToString(EqualityEdgeId edgeId) const; |
261 |
|
|
262 |
|
/** |
263 |
|
* Map from a node to its first edge in the equality graph. Edges are added to the front of the |
264 |
|
* list which makes the insertion/backtracking easy. |
265 |
|
*/ |
266 |
|
std::vector<EqualityEdgeId> d_equalityGraph; |
267 |
|
|
268 |
|
/** Add an edge to the equality graph */ |
269 |
|
void addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, unsigned type, TNode reason); |
270 |
|
|
271 |
|
/** Returns the equality node of the given node */ |
272 |
|
EqualityNode& getEqualityNode(TNode node); |
273 |
|
|
274 |
|
/** Returns the equality node of the given node */ |
275 |
|
const EqualityNode& getEqualityNode(TNode node) const; |
276 |
|
|
277 |
|
/** Returns the equality node of the given node */ |
278 |
|
EqualityNode& getEqualityNode(EqualityNodeId nodeId); |
279 |
|
|
280 |
|
/** Returns the equality node of the given node */ |
281 |
|
const EqualityNode& getEqualityNode(EqualityNodeId nodeId) const; |
282 |
|
|
283 |
|
/** Returns the id of the node */ |
284 |
|
EqualityNodeId getNodeId(TNode node) const; |
285 |
|
|
286 |
|
/** |
287 |
|
* Merge the class2 into class1 |
288 |
|
* @return true if ok, false if to break out |
289 |
|
*/ |
290 |
|
bool merge(EqualityNode& class1, EqualityNode& class2, std::vector<TriggerId>& triggers); |
291 |
|
|
292 |
|
/** Undo the merge of class2 into class1 */ |
293 |
|
void undoMerge(EqualityNode& class1, EqualityNode& class2, EqualityNodeId class2Id); |
294 |
|
|
295 |
|
/** Backtrack the information if necessary */ |
296 |
|
void backtrack(); |
297 |
|
|
298 |
|
/** |
299 |
|
* Trigger that will be updated |
300 |
|
*/ |
301 |
|
struct Trigger { |
302 |
|
/** The current class id of the LHS of the trigger */ |
303 |
|
EqualityNodeId d_classId; |
304 |
|
/** Next trigger for class */ |
305 |
|
TriggerId d_nextTrigger; |
306 |
|
|
307 |
4026624 |
Trigger(EqualityNodeId classId = null_id, |
308 |
|
TriggerId nextTrigger = null_trigger) |
309 |
4026624 |
: d_classId(classId), d_nextTrigger(nextTrigger) |
310 |
|
{ |
311 |
4026624 |
} |
312 |
|
};/* struct EqualityEngine::Trigger */ |
313 |
|
|
314 |
|
/** |
315 |
|
* Vector of triggers. Triggers come in pairs for an |
316 |
|
* equality trigger (t1, t2): one at position 2k for t1, and one at position 2k + 1 for t2. When |
317 |
|
* updating triggers we always know where the other one is (^1). |
318 |
|
*/ |
319 |
|
std::vector<Trigger> d_equalityTriggers; |
320 |
|
|
321 |
|
/** |
322 |
|
* Vector of original equalities of the triggers. |
323 |
|
*/ |
324 |
|
std::vector<TriggerInfo> d_equalityTriggersOriginal; |
325 |
|
|
326 |
|
/** |
327 |
|
* Context dependent count of triggers |
328 |
|
*/ |
329 |
|
context::CDO<DefaultSizeType> d_equalityTriggersCount; |
330 |
|
|
331 |
|
/** |
332 |
|
* Trigger lists per node. The begin id changes as we merge, but the end always points to |
333 |
|
* the actual end of the triggers for this node. |
334 |
|
*/ |
335 |
|
std::vector<TriggerId> d_nodeTriggers; |
336 |
|
|
337 |
|
/** |
338 |
|
* Map from ids to whether they are constants (constants are always |
339 |
|
* representatives of their class. |
340 |
|
*/ |
341 |
|
std::vector<bool> d_isConstant; |
342 |
|
|
343 |
|
/** |
344 |
|
* Map from ids of proper terms, to the number of non-constant direct subterms. If we update an interpreted |
345 |
|
* application to a constant, we can decrease this value. If we hit 0, we can evaluate the term. |
346 |
|
* |
347 |
|
*/ |
348 |
|
std::vector<unsigned> d_subtermsToEvaluate; |
349 |
|
|
350 |
|
/** |
351 |
|
* For nodes that we need to postpone evaluation. |
352 |
|
*/ |
353 |
|
std::queue<EqualityNodeId> d_evaluationQueue; |
354 |
|
|
355 |
|
/** |
356 |
|
* Evaluate all terms in the evaluation queue. |
357 |
|
*/ |
358 |
|
void processEvaluationQueue(); |
359 |
|
|
360 |
|
/** Vector of nodes that evaluate. */ |
361 |
|
std::vector<EqualityNodeId> d_subtermEvaluates; |
362 |
|
|
363 |
|
/** Size of the nodes that evaluate vector. */ |
364 |
|
context::CDO<unsigned> d_subtermEvaluatesSize; |
365 |
|
|
366 |
|
/** Set the node evaluate flag */ |
367 |
|
void subtermEvaluates(EqualityNodeId id); |
368 |
|
|
369 |
|
/** |
370 |
|
* Returns the evaluation of the term when all (direct) children are replaced with |
371 |
|
* the constant representatives. |
372 |
|
*/ |
373 |
|
Node evaluateTerm(TNode node); |
374 |
|
|
375 |
|
/** |
376 |
|
* Returns true if it's a constant |
377 |
|
*/ |
378 |
323747 |
bool isConstant(EqualityNodeId id) const { |
379 |
323747 |
return d_isConstant[getEqualityNode(id).getFind()]; |
380 |
|
} |
381 |
|
|
382 |
|
/** |
383 |
|
* Map from ids to whether they are Boolean. |
384 |
|
*/ |
385 |
|
std::vector<bool> d_isEquality; |
386 |
|
|
387 |
|
/** |
388 |
|
* Map from ids to whether the nods is internal. An internal node is a node |
389 |
|
* that corresponds to a partially currified node, for example. |
390 |
|
*/ |
391 |
|
std::vector<bool> d_isInternal; |
392 |
|
|
393 |
|
/** |
394 |
|
* Adds the trigger with triggerId to the beginning of the trigger list of the node with id nodeId. |
395 |
|
*/ |
396 |
|
void addTriggerToList(EqualityNodeId nodeId, TriggerId triggerId); |
397 |
|
|
398 |
|
/** Statistics */ |
399 |
|
Statistics d_stats; |
400 |
|
|
401 |
|
/** Add a new function application node to the database, i.e APP t1 t2 */ |
402 |
|
EqualityNodeId newApplicationNode(TNode original, EqualityNodeId t1, EqualityNodeId t2, FunctionApplicationType type); |
403 |
|
|
404 |
|
/** Add a new node to the database */ |
405 |
|
EqualityNodeId newNode(TNode t); |
406 |
|
|
407 |
|
/** Propagation queue */ |
408 |
|
std::deque<MergeCandidate> d_propagationQueue; |
409 |
|
|
410 |
|
/** Enqueue to the propagation queue */ |
411 |
|
void enqueue(const MergeCandidate& candidate, bool back = true); |
412 |
|
|
413 |
|
/** Do the propagation */ |
414 |
|
void propagate(); |
415 |
|
|
416 |
|
/** Are we in propagate */ |
417 |
|
bool d_inPropagate; |
418 |
|
|
419 |
|
/** Proof-new specific construction of equality conclusions for EqProofs |
420 |
|
* |
421 |
|
* Given two equality node ids, build an equality between the nodes they |
422 |
|
* correspond to and add it as a conclusion to the given EqProof. |
423 |
|
* |
424 |
|
* The equality is only built if the nodes the ids correspond to are not |
425 |
|
* internal nodes in the equality engine, i.e., they correspond to full |
426 |
|
* applications of the respective kinds. Since the equality engine also |
427 |
|
* applies congruence over n-ary kinds, internal nodes, i.e., partial |
428 |
|
* applications, may still correspond to "full applications" in the |
429 |
|
* first-order sense. Therefore this method also checks, in the case of n-ary |
430 |
|
* congruence kinds, if an equality between "full applications" can be built. |
431 |
|
*/ |
432 |
|
void buildEqConclusion(EqualityNodeId id1, |
433 |
|
EqualityNodeId id2, |
434 |
|
EqProof* eqp) const; |
435 |
|
|
436 |
|
/** |
437 |
|
* Get an explanation of the equality t1 = t2. Returns the asserted equalities |
438 |
|
* that imply t1 = t2. Returns TNodes as the assertion equalities should be |
439 |
|
* hashed somewhere else. |
440 |
|
* |
441 |
|
* This call refers to terms t1 and t2 by their ids t1Id and t2Id. |
442 |
|
* |
443 |
|
* If eqp is non-null, then this method populates eqp's information and |
444 |
|
* children such that it is a proof of t1 = t2. |
445 |
|
* |
446 |
|
* We cache results of this call in cache, where cache[t1Id][t2Id] stores |
447 |
|
* a proof of t1 = t2. |
448 |
|
*/ |
449 |
|
void getExplanation( |
450 |
|
EqualityEdgeId t1Id, |
451 |
|
EqualityNodeId t2Id, |
452 |
|
std::vector<TNode>& equalities, |
453 |
|
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>& cache, |
454 |
|
EqProof* eqp) const; |
455 |
|
|
456 |
|
/** |
457 |
|
* Print the equality graph. |
458 |
|
*/ |
459 |
|
void debugPrintGraph() const; |
460 |
|
|
461 |
|
/** The true node */ |
462 |
|
Node d_true; |
463 |
|
/** True node id */ |
464 |
|
EqualityNodeId d_trueId; |
465 |
|
|
466 |
|
/** The false node */ |
467 |
|
Node d_false; |
468 |
|
/** False node id */ |
469 |
|
EqualityNodeId d_falseId; |
470 |
|
|
471 |
|
/** |
472 |
|
* Adds an equality of terms t1 and t2 to the database. |
473 |
|
*/ |
474 |
|
void assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid = MERGED_THROUGH_EQUALITY); |
475 |
|
|
476 |
|
/** |
477 |
|
* Adds a trigger equality to the database with the trigger node and polarity for notification. |
478 |
|
*/ |
479 |
|
void addTriggerEqualityInternal(TNode t1, TNode t2, TNode trigger, bool polarity); |
480 |
|
|
481 |
|
/** |
482 |
|
* This method gets called on backtracks from the context manager. |
483 |
|
*/ |
484 |
47762651 |
void contextNotifyPop() override { backtrack(); } |
485 |
|
|
486 |
|
/** |
487 |
|
* Constructor initialization stuff. |
488 |
|
*/ |
489 |
|
void init(); |
490 |
|
|
491 |
|
/** Set of trigger terms */ |
492 |
|
struct TriggerTermSet { |
493 |
|
/** Set of theories in this set */ |
494 |
|
TheoryIdSet d_tags; |
495 |
|
/** The trigger terms */ |
496 |
|
EqualityNodeId d_triggers[0]; |
497 |
|
/** Returns the theory tags */ |
498 |
|
TheoryIdSet hasTrigger(TheoryId tag) const; |
499 |
|
/** Returns a trigger by tag */ |
500 |
|
EqualityNodeId getTrigger(TheoryId tag) const; |
501 |
|
};/* struct EqualityEngine::TriggerTermSet */ |
502 |
|
|
503 |
|
/** Are the constants triggers */ |
504 |
|
bool d_constantsAreTriggers; |
505 |
|
/** |
506 |
|
* Are any terms triggers? If this is false, then all trigger terms are |
507 |
|
* ignored (e.g. this means that addTriggerTerm is equivalent to addTerm). |
508 |
|
*/ |
509 |
|
bool d_anyTermsAreTriggers; |
510 |
|
|
511 |
|
/** The information about trigger terms is stored in this easily maintained memory. */ |
512 |
|
char* d_triggerDatabase; |
513 |
|
|
514 |
|
/** Allocated size of the trigger term database */ |
515 |
|
DefaultSizeType d_triggerDatabaseAllocatedSize; |
516 |
|
|
517 |
|
/** Reference for the trigger terms set */ |
518 |
|
typedef DefaultSizeType TriggerTermSetRef; |
519 |
|
|
520 |
|
/** Null reference */ |
521 |
|
static const TriggerTermSetRef null_set_id = (TriggerTermSetRef)(-1); |
522 |
|
|
523 |
|
/** Create new trigger term set based on the internally set information */ |
524 |
|
TriggerTermSetRef newTriggerTermSet(TheoryIdSet newSetTags, |
525 |
|
EqualityNodeId* newSetTriggers, |
526 |
|
unsigned newSetTriggersSize); |
527 |
|
|
528 |
|
/** Get the trigger set give a reference */ |
529 |
101695724 |
TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) { |
530 |
101695724 |
Assert(ref < d_triggerDatabaseSize); |
531 |
101695724 |
return *(reinterpret_cast<TriggerTermSet*>(d_triggerDatabase + ref)); |
532 |
|
} |
533 |
|
|
534 |
|
/** Get the trigger set give a reference */ |
535 |
9858438 |
const TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) const { |
536 |
9858438 |
Assert(ref < d_triggerDatabaseSize); |
537 |
9858438 |
return *(reinterpret_cast<const TriggerTermSet*>(d_triggerDatabase + ref)); |
538 |
|
} |
539 |
|
|
540 |
|
/** Used part of the trigger term database */ |
541 |
|
context::CDO<DefaultSizeType> d_triggerDatabaseSize; |
542 |
|
|
543 |
|
struct TriggerSetUpdate { |
544 |
|
EqualityNodeId d_classId; |
545 |
|
TriggerTermSetRef d_oldValue; |
546 |
7132941 |
TriggerSetUpdate(EqualityNodeId classId = null_id, |
547 |
|
TriggerTermSetRef oldValue = null_set_id) |
548 |
7132941 |
: d_classId(classId), d_oldValue(oldValue) |
549 |
|
{ |
550 |
7132941 |
} |
551 |
|
};/* struct EqualityEngine::TriggerSetUpdate */ |
552 |
|
|
553 |
|
/** |
554 |
|
* List of trigger updates for backtracking. |
555 |
|
*/ |
556 |
|
std::vector<TriggerSetUpdate> d_triggerTermSetUpdates; |
557 |
|
|
558 |
|
/** |
559 |
|
* Size of the individual triggers list. |
560 |
|
*/ |
561 |
|
context::CDO<unsigned> d_triggerTermSetUpdatesSize; |
562 |
|
|
563 |
|
/** |
564 |
|
* Map from ids to the individual trigger set representatives. |
565 |
|
*/ |
566 |
|
std::vector<TriggerTermSetRef> d_nodeIndividualTrigger; |
567 |
|
|
568 |
|
typedef std::unordered_map<EqualityPair, DisequalityReasonRef, EqualityPairHashFunction> DisequalityReasonsMap; |
569 |
|
|
570 |
|
/** |
571 |
|
* A map from pairs of disequal terms, to the reason why we deduced they are disequal. |
572 |
|
*/ |
573 |
|
DisequalityReasonsMap d_disequalityReasonsMap; |
574 |
|
|
575 |
|
/** |
576 |
|
* A list of all the disequalities we deduced. |
577 |
|
*/ |
578 |
|
std::vector<EqualityPair> d_deducedDisequalities; |
579 |
|
|
580 |
|
/** |
581 |
|
* Context dependent size of the deduced disequalities |
582 |
|
*/ |
583 |
|
context::CDO<size_t> d_deducedDisequalitiesSize; |
584 |
|
|
585 |
|
/** |
586 |
|
* For each disequality deduced, we add the pairs of equivalences needed to explain it. |
587 |
|
*/ |
588 |
|
std::vector<EqualityPair> d_deducedDisequalityReasons; |
589 |
|
|
590 |
|
/** |
591 |
|
* Size of the memory for disequality reasons. |
592 |
|
*/ |
593 |
|
context::CDO<size_t> d_deducedDisequalityReasonsSize; |
594 |
|
|
595 |
|
/** |
596 |
|
* Map from equalities to the tags that have received the notification. |
597 |
|
*/ |
598 |
|
typedef context:: |
599 |
|
CDHashMap<EqualityPair, TheoryIdSet, EqualityPairHashFunction> |
600 |
|
PropagatedDisequalitiesMap; |
601 |
|
PropagatedDisequalitiesMap d_propagatedDisequalities; |
602 |
|
|
603 |
|
/** |
604 |
|
* Has this equality been propagated to anyone. |
605 |
|
*/ |
606 |
|
bool hasPropagatedDisequality(EqualityNodeId lhsId, EqualityNodeId rhsId) const; |
607 |
|
|
608 |
|
/** |
609 |
|
* Has this equality been propagated to the tag owner. |
610 |
|
*/ |
611 |
|
bool hasPropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) const; |
612 |
|
|
613 |
|
/** |
614 |
|
* Stores a propagated disequality for explanation purposes and remembers the reasons. The |
615 |
|
* reasons should be pushed on the reasons vector. |
616 |
|
*/ |
617 |
|
void storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId); |
618 |
|
|
619 |
|
/** |
620 |
|
* An equality tagged with a set of tags. |
621 |
|
*/ |
622 |
|
struct TaggedEquality { |
623 |
|
/** Id of the equality */ |
624 |
|
EqualityNodeId d_equalityId; |
625 |
|
/** TriggerSet reference for the class of one of the sides */ |
626 |
|
TriggerTermSetRef d_triggerSetRef; |
627 |
|
/** Is trigger equivalent to the lhs (rhs otherwise) */ |
628 |
|
bool d_lhs; |
629 |
|
|
630 |
882343 |
TaggedEquality(EqualityNodeId equalityId = null_id, |
631 |
|
TriggerTermSetRef triggerSetRef = null_set_id, |
632 |
|
bool lhs = true) |
633 |
882343 |
: d_equalityId(equalityId), d_triggerSetRef(triggerSetRef), d_lhs(lhs) |
634 |
|
{ |
635 |
882343 |
} |
636 |
|
}; |
637 |
|
|
638 |
|
/** A map from equivalence class id's to tagged equalities */ |
639 |
|
typedef std::vector<TaggedEquality> TaggedEqualitiesSet; |
640 |
|
|
641 |
|
/** |
642 |
|
* Returns a set of equalities that have been asserted false where one side of the equality |
643 |
|
* belongs to the given equivalence class. The equalities are restricted to the ones where |
644 |
|
* one side of the equality is in the tags set, but the other one isn't. Each returned |
645 |
|
* dis-equality is associated with the tags that are the subset of the input tags, such that |
646 |
|
* exactly one side of the equality is not in the set yet. |
647 |
|
* |
648 |
|
* @param classId the equivalence class to search |
649 |
|
* @param inputTags the tags to filter the equalities |
650 |
|
* @param out the output equalities, as described above |
651 |
|
*/ |
652 |
|
void getDisequalities(bool allowConstants, |
653 |
|
EqualityNodeId classId, |
654 |
|
TheoryIdSet inputTags, |
655 |
|
TaggedEqualitiesSet& out); |
656 |
|
|
657 |
|
/** |
658 |
|
* Propagates the remembered disequalities with given tags the original triggers for those tags, |
659 |
|
* and the set of disequalities produced by above. |
660 |
|
*/ |
661 |
|
bool propagateTriggerTermDisequalities( |
662 |
|
TheoryIdSet tags, |
663 |
|
TriggerTermSetRef triggerSetRef, |
664 |
|
const TaggedEqualitiesSet& disequalitiesToNotify); |
665 |
|
|
666 |
|
/** Name of the equality engine */ |
667 |
|
std::string d_name; |
668 |
|
|
669 |
|
/** The internal addTerm */ |
670 |
|
void addTermInternal(TNode t, bool isOperator = false); |
671 |
|
/** |
672 |
|
* Adds a notify trigger for equality. When equality becomes true |
673 |
|
* eqNotifyTriggerPredicate will be called with value = true, and when |
674 |
|
* equality becomes false eqNotifyTriggerPredicate will be called with value = |
675 |
|
* false. |
676 |
|
*/ |
677 |
|
void addTriggerEquality(TNode equality); |
678 |
|
|
679 |
|
public: |
680 |
|
/** |
681 |
|
* Adds a term to the term database. |
682 |
|
*/ |
683 |
3003918 |
void addTerm(TNode t) { |
684 |
3003918 |
addTermInternal(t, false); |
685 |
3003918 |
} |
686 |
|
|
687 |
|
/** |
688 |
|
* Add a kind to treat as function applications. |
689 |
|
* When extOperator is true, this equality engine will treat the operators of this kind |
690 |
|
* as "external" e.g. not internal nodes (see d_isInternal). This means that we will |
691 |
|
* consider equivalence classes containing the operators of such terms, and "hasTerm" will |
692 |
|
* return true. |
693 |
|
*/ |
694 |
|
void addFunctionKind(Kind fun, bool interpreted = false, bool extOperator = false); |
695 |
|
|
696 |
|
/** |
697 |
|
* Returns true if this kind is used for congruence closure. |
698 |
|
*/ |
699 |
63039 |
bool isFunctionKind(Kind fun) const { return d_congruenceKinds.test(fun); } |
700 |
|
|
701 |
|
/** |
702 |
|
* Returns true if this kind is used for congruence closure + evaluation of constants. |
703 |
|
*/ |
704 |
918975 |
bool isInterpretedFunctionKind(Kind fun) const |
705 |
|
{ |
706 |
918975 |
return d_congruenceKindsInterpreted.test(fun); |
707 |
|
} |
708 |
|
|
709 |
|
/** |
710 |
|
* Returns true if this kind has an operator that is considered external (e.g. not internal). |
711 |
|
*/ |
712 |
918975 |
bool isExternalOperatorKind(Kind fun) const |
713 |
|
{ |
714 |
918975 |
return d_congruenceKindsExtOperators.test(fun); |
715 |
|
} |
716 |
|
|
717 |
|
/** |
718 |
|
* Check whether the node is already in the database. |
719 |
|
*/ |
720 |
|
bool hasTerm(TNode t) const; |
721 |
|
|
722 |
|
/** |
723 |
|
* Adds a predicate p with given polarity. The predicate asserted |
724 |
|
* should be in the congruence closure kinds (otherwise it's |
725 |
|
* useless). |
726 |
|
* |
727 |
|
* @param p the (non-negated) predicate |
728 |
|
* @param polarity true if asserting the predicate, false if |
729 |
|
* asserting the negated predicate |
730 |
|
* @param reason the reason to keep for building explanations |
731 |
|
* @return true if a new fact was asserted, false if this call was a no-op. |
732 |
|
*/ |
733 |
|
bool assertPredicate(TNode p, |
734 |
|
bool polarity, |
735 |
|
TNode reason, |
736 |
|
unsigned pid = MERGED_THROUGH_EQUALITY); |
737 |
|
|
738 |
|
/** |
739 |
|
* Adds an equality eq with the given polarity to the database. |
740 |
|
* |
741 |
|
* @param eq the (non-negated) equality |
742 |
|
* @param polarity true if asserting the equality, false if |
743 |
|
* asserting the negated equality |
744 |
|
* @param reason the reason to keep for building explanations |
745 |
|
* @return true if a new fact was asserted, false if this call was a no-op. |
746 |
|
*/ |
747 |
|
bool assertEquality(TNode eq, |
748 |
|
bool polarity, |
749 |
|
TNode reason, |
750 |
|
unsigned pid = MERGED_THROUGH_EQUALITY); |
751 |
|
|
752 |
|
/** |
753 |
|
* Returns the current representative of the term t. |
754 |
|
*/ |
755 |
|
TNode getRepresentative(TNode t) const; |
756 |
|
|
757 |
|
/** |
758 |
|
* Add all the terms where the given term appears as a first child |
759 |
|
* (directly or implicitly). |
760 |
|
*/ |
761 |
|
void getUseListTerms(TNode t, std::set<TNode>& output); |
762 |
|
|
763 |
|
/** |
764 |
|
* Get an explanation of the equality t1 = t2 being true or false. |
765 |
|
* Returns the reasons (added when asserting) that imply it |
766 |
|
* in the assertions vector. |
767 |
|
*/ |
768 |
|
void explainEquality(TNode t1, TNode t2, bool polarity, |
769 |
|
std::vector<TNode>& assertions, |
770 |
|
EqProof* eqp = nullptr) const; |
771 |
|
|
772 |
|
/** |
773 |
|
* Get an explanation of the predicate being true or false. |
774 |
|
* Returns the reasons (added when asserting) that imply imply it |
775 |
|
* in the assertions vector. |
776 |
|
*/ |
777 |
|
void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions, |
778 |
|
EqProof* eqp = nullptr) const; |
779 |
|
|
780 |
|
//--------------------------- standard safe explanation methods |
781 |
|
/** |
782 |
|
* Explain literal, add its explanation to assumptions. This method does not |
783 |
|
* add duplicates to assumptions. It requires that the literal |
784 |
|
* holds in this class. If lit is a disequality, it |
785 |
|
* moreover ensures this class is ready to explain it via areDisequal with |
786 |
|
* ensureProof = true. |
787 |
|
*/ |
788 |
|
void explainLit(TNode lit, std::vector<TNode>& assumptions); |
789 |
|
/** |
790 |
|
* Explain literal, return the explanation as a conjunction. This method |
791 |
|
* relies on the above method. |
792 |
|
*/ |
793 |
|
Node mkExplainLit(TNode lit); |
794 |
|
//--------------------------- end standard safe explanation methods |
795 |
|
|
796 |
|
/** |
797 |
|
* Add term to the set of trigger terms with a corresponding tag. The notify class will get |
798 |
|
* notified when two trigger terms with the same tag become equal or dis-equal. The notification |
799 |
|
* will not happen on all the terms, but only on the ones that are represent the class. Note that |
800 |
|
* a term can be added more than once with different tags, and each tag appearance will merit |
801 |
|
* it's own notification. |
802 |
|
* |
803 |
|
* @param t the trigger term |
804 |
|
* @param theoryTag tag for this trigger (do NOT use THEORY_LAST) |
805 |
|
*/ |
806 |
|
void addTriggerTerm(TNode t, TheoryId theoryTag); |
807 |
|
|
808 |
|
/** |
809 |
|
* Returns true if t is a trigger term or in the same equivalence |
810 |
|
* class as some other trigger term. |
811 |
|
*/ |
812 |
|
bool isTriggerTerm(TNode t, TheoryId theoryTag) const; |
813 |
|
|
814 |
|
/** |
815 |
|
* Returns the representative trigger term of the given term. |
816 |
|
* |
817 |
|
* @param t the term to check where isTriggerTerm(t) should be true |
818 |
|
*/ |
819 |
|
TNode getTriggerTermRepresentative(TNode t, TheoryId theoryTag) const; |
820 |
|
|
821 |
|
/** |
822 |
|
* Adds a notify trigger for the predicate p, where notice that p can be |
823 |
|
* an equality. When the predicate becomes true, eqNotifyTriggerPredicate will |
824 |
|
* be called with value = true, and when predicate becomes false |
825 |
|
* eqNotifyTriggerPredicate will be called with value = false. |
826 |
|
* |
827 |
|
* Notice that if p is an equality, then we use a separate method for |
828 |
|
* determining when to call eqNotifyTriggerPredicate. |
829 |
|
*/ |
830 |
|
void addTriggerPredicate(TNode predicate); |
831 |
|
|
832 |
|
/** |
833 |
|
* Returns true if the two terms are equal. Requires both terms to |
834 |
|
* be in the database. |
835 |
|
*/ |
836 |
|
bool areEqual(TNode t1, TNode t2) const; |
837 |
|
|
838 |
|
/** |
839 |
|
* Check whether the two term are dis-equal. Requires both terms to |
840 |
|
* be in the database. |
841 |
|
*/ |
842 |
|
bool areDisequal(TNode t1, TNode t2, bool ensureProof) const; |
843 |
|
|
844 |
|
/** |
845 |
|
* Return the number of nodes in the equivalence class containing t |
846 |
|
* Adds t if not already there. |
847 |
|
*/ |
848 |
|
size_t getSize(TNode t); |
849 |
|
|
850 |
|
/** |
851 |
|
* Returns true if the engine is in a consistent state. |
852 |
|
*/ |
853 |
11209538 |
bool consistent() const { return !d_done; } |
854 |
|
|
855 |
|
/** Identify this equality engine (for debugging, etc..) */ |
856 |
|
std::string identify() const; |
857 |
|
}; |
858 |
|
|
859 |
|
} // Namespace eq |
860 |
|
} // Namespace theory |
861 |
|
} // namespace cvc5 |
862 |
|
|
863 |
|
#endif |