1 /*********************                                                        */
2 /*! \file equality_engine.cpp
3  ** \verbatim
4  ** Top contributors (to current version):
5  **   Dejan Jovanovic, Guy Katz, Andrew Reynolds
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 "theory/uf/equality_engine.h"
19 
20 #include "smt/smt_statistics_registry.h"
21 
22 namespace CVC4 {
23 namespace theory {
24 namespace eq {
25 
Statistics(std::string name)26 EqualityEngine::Statistics::Statistics(std::string name)
27     : mergesCount(name + "::mergesCount", 0),
28       termsCount(name + "::termsCount", 0),
29       functionTermsCount(name + "::functionTermsCount", 0),
30       constantTermsCount(name + "::constantTermsCount", 0)
31 {
32   smtStatisticsRegistry()->registerStat(&mergesCount);
33   smtStatisticsRegistry()->registerStat(&termsCount);
34   smtStatisticsRegistry()->registerStat(&functionTermsCount);
35   smtStatisticsRegistry()->registerStat(&constantTermsCount);
36 }
37 
~Statistics()38 EqualityEngine::Statistics::~Statistics() {
39   smtStatisticsRegistry()->unregisterStat(&mergesCount);
40   smtStatisticsRegistry()->unregisterStat(&termsCount);
41   smtStatisticsRegistry()->unregisterStat(&functionTermsCount);
42   smtStatisticsRegistry()->unregisterStat(&constantTermsCount);
43 }
44 
45 /**
46  * Data used in the BFS search through the equality graph.
47  */
48 struct BfsData {
49   // The current node
50   EqualityNodeId nodeId;
51   // The index of the edge we traversed
52   EqualityEdgeId edgeId;
53   // Index in the queue of the previous node. Shouldn't be too much of them, at most the size
54   // of the biggest equivalence class
55   size_t previousIndex;
56 
BfsDataCVC4::theory::eq::BfsData57   BfsData(EqualityNodeId nodeId = null_id, EqualityEdgeId edgeId = null_edge, size_t prev = 0)
58   : nodeId(nodeId), edgeId(edgeId), previousIndex(prev) {}
59 };
60 
61 class ScopedBool {
62   bool& watch;
63   bool oldValue;
64 public:
ScopedBool(bool & watch,bool newValue)65   ScopedBool(bool& watch, bool newValue)
66   : watch(watch), oldValue(watch) {
67     watch = newValue;
68   }
~ScopedBool()69   ~ScopedBool() {
70     watch = oldValue;
71   }
72 };
73 
74 EqualityEngineNotifyNone EqualityEngine::s_notifyNone;
75 
init()76 void EqualityEngine::init() {
77   Debug("equality") << "EqualityEdge::EqualityEngine(): id_null = " << +null_id << std::endl;
78   Debug("equality") << "EqualityEdge::EqualityEngine(): edge_null = " << +null_edge << std::endl;
79   Debug("equality") << "EqualityEdge::EqualityEngine(): trigger_null = " << +null_trigger << std::endl;
80 
81   d_true = NodeManager::currentNM()->mkConst<bool>(true);
82   d_false = NodeManager::currentNM()->mkConst<bool>(false);
83 
84   d_triggerDatabaseAllocatedSize = 100000;
85   d_triggerDatabase = (char*) malloc(d_triggerDatabaseAllocatedSize);
86 
87   //We can't notify during the initialization because it notifies
88   // QuantifiersEngine.AddTermToDatabase that try to access to the uf
89   // instantiator that currently doesn't exist.
90   ScopedBool sb(d_performNotify, false);
91   addTermInternal(d_true);
92   addTermInternal(d_false);
93 
94   d_trueId = getNodeId(d_true);
95   d_falseId = getNodeId(d_false);
96 
97   d_freshMergeReasonType = eq::NUMBER_OF_MERGE_REASONS;
98 }
99 
~EqualityEngine()100 EqualityEngine::~EqualityEngine() {
101   free(d_triggerDatabase);
102 }
103 
104 
EqualityEngine(context::Context * context,std::string name,bool constantsAreTriggers)105 EqualityEngine::EqualityEngine(context::Context* context, std::string name, bool constantsAreTriggers)
106 : ContextNotifyObj(context)
107 , d_masterEqualityEngine(0)
108 , d_context(context)
109 , d_done(context, false)
110 , d_performNotify(true)
111 , d_notify(s_notifyNone)
112 , d_applicationLookupsCount(context, 0)
113 , d_nodesCount(context, 0)
114 , d_assertedEqualitiesCount(context, 0)
115 , d_equalityTriggersCount(context, 0)
116 , d_subtermEvaluatesSize(context, 0)
117 , d_stats(name)
118 , d_inPropagate(false)
119 , d_constantsAreTriggers(constantsAreTriggers)
120 , d_triggerDatabaseSize(context, 0)
121 , d_triggerTermSetUpdatesSize(context, 0)
122 , d_deducedDisequalitiesSize(context, 0)
123 , d_deducedDisequalityReasonsSize(context, 0)
124 , d_propagatedDisequalities(context)
125 , d_name(name)
126 {
127   init();
128 }
129 
EqualityEngine(EqualityEngineNotify & notify,context::Context * context,std::string name,bool constantsAreTriggers)130 EqualityEngine::EqualityEngine(EqualityEngineNotify& notify, context::Context* context, std::string name, bool constantsAreTriggers)
131 : ContextNotifyObj(context)
132 , d_masterEqualityEngine(0)
133 , d_context(context)
134 , d_done(context, false)
135 , d_performNotify(true)
136 , d_notify(notify)
137 , d_applicationLookupsCount(context, 0)
138 , d_nodesCount(context, 0)
139 , d_assertedEqualitiesCount(context, 0)
140 , d_equalityTriggersCount(context, 0)
141 , d_subtermEvaluatesSize(context, 0)
142 , d_stats(name)
143 , d_inPropagate(false)
144 , d_constantsAreTriggers(constantsAreTriggers)
145 , d_triggerDatabaseSize(context, 0)
146 , d_triggerTermSetUpdatesSize(context, 0)
147 , d_deducedDisequalitiesSize(context, 0)
148 , d_deducedDisequalityReasonsSize(context, 0)
149 , d_propagatedDisequalities(context)
150 , d_name(name)
151 {
152   init();
153 }
154 
setMasterEqualityEngine(EqualityEngine * master)155 void EqualityEngine::setMasterEqualityEngine(EqualityEngine* master) {
156   Assert(d_masterEqualityEngine == 0);
157   d_masterEqualityEngine = master;
158 }
159 
enqueue(const MergeCandidate & candidate,bool back)160 void EqualityEngine::enqueue(const MergeCandidate& candidate, bool back) {
161   Debug("equality") << d_name << "::eq::enqueue(" << d_nodes[candidate.t1Id] << ", " << d_nodes[candidate.t2Id] << ", " << candidate.type << "). reason: " << candidate.reason << std::endl;
162   if (back) {
163     d_propagationQueue.push_back(candidate);
164   } else {
165     d_propagationQueue.push_front(candidate);
166   }
167 }
168 
newApplicationNode(TNode original,EqualityNodeId t1,EqualityNodeId t2,FunctionApplicationType type)169 EqualityNodeId EqualityEngine::newApplicationNode(TNode original, EqualityNodeId t1, EqualityNodeId t2, FunctionApplicationType type) {
170   Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << ")" << std::endl;
171 
172   ++ d_stats.functionTermsCount;
173 
174   // Get another id for this
175   EqualityNodeId funId = newNode(original);
176   FunctionApplication funOriginal(type, t1, t2);
177   // The function application we're creating
178   EqualityNodeId t1ClassId = getEqualityNode(t1).getFind();
179   EqualityNodeId t2ClassId = getEqualityNode(t2).getFind();
180   FunctionApplication funNormalized(type, t1ClassId, t2ClassId);
181 
182   // We add the original version
183   d_applications[funId] = FunctionApplicationPair(funOriginal, funNormalized);
184 
185   // Add the lookup data, if it's not already there
186   ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
187   if (find == d_applicationLookup.end()) {
188     Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): no lookup, setting up" << std::endl;
189     // Mark the normalization to the lookup
190     storeApplicationLookup(funNormalized, funId);
191   } else {
192     // If it's there, we need to merge these two
193     Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): lookup exists, adding to queue" << std::endl;
194     Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): lookup = " << d_nodes[find->second] << std::endl;
195     enqueue(MergeCandidate(funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null()));
196   }
197 
198   // Add to the use lists
199   Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): adding " << original << " to the uselist of " << d_nodes[t1] << std::endl;
200   d_equalityNodes[t1].usedIn(funId, d_useListNodes);
201   Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): adding " << original << " to the uselist of " << d_nodes[t2] << std::endl;
202   d_equalityNodes[t2].usedIn(funId, d_useListNodes);
203 
204   // Return the new id
205   Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << ") => " << funId << std::endl;
206 
207   return funId;
208 }
209 
newNode(TNode node)210 EqualityNodeId EqualityEngine::newNode(TNode node) {
211 
212   Debug("equality") << d_name << "::eq::newNode(" << node << ")" << std::endl;
213 
214   ++ d_stats.termsCount;
215 
216   // Register the new id of the term
217   EqualityNodeId newId = d_nodes.size();
218   d_nodeIds[node] = newId;
219   // Add the node to it's position
220   d_nodes.push_back(node);
221   // Note if this is an application or not
222   d_applications.push_back(FunctionApplicationPair());
223   // Add the trigger list for this node
224   d_nodeTriggers.push_back(+null_trigger);
225   // Add it to the equality graph
226   d_equalityGraph.push_back(+null_edge);
227   // Mark the no-individual trigger
228   d_nodeIndividualTrigger.push_back(+null_set_id);
229   // Mark non-constant by default
230   d_isConstant.push_back(false);
231   // No terms to evaluate by defaul
232   d_subtermsToEvaluate.push_back(0);
233   // Mark equality nodes
234   d_isEquality.push_back(false);
235   // Mark the node as internal by default
236   d_isInternal.push_back(true);
237   // Add the equality node to the nodes
238   d_equalityNodes.push_back(EqualityNode(newId));
239 
240   // Increase the counters
241   d_nodesCount = d_nodesCount + 1;
242 
243   Debug("equality") << d_name << "::eq::newNode(" << node << ") => " << newId << std::endl;
244 
245   // notify e.g. the UF theory strong solver
246   if (d_performNotify) {
247     d_notify.eqNotifyNewClass(node);
248   }
249 
250   return newId;
251 }
252 
addFunctionKind(Kind fun,bool interpreted,bool extOperator)253 void EqualityEngine::addFunctionKind(Kind fun, bool interpreted, bool extOperator) {
254   d_congruenceKinds |= fun;
255   if (fun != kind::EQUAL) {
256     if (interpreted) {
257       Debug("equality::evaluation") << d_name << "::eq::addFunctionKind(): " << fun << " is interpreted " << std::endl;
258       d_congruenceKindsInterpreted |= fun;
259     }
260     if (extOperator) {
261       Debug("equality::extoperator") << d_name << "::eq::addFunctionKind(): " << fun << " is an external operator kind " << std::endl;
262       d_congruenceKindsExtOperators |= fun;
263     }
264   }
265 }
266 
subtermEvaluates(EqualityNodeId id)267 void EqualityEngine::subtermEvaluates(EqualityNodeId id)  {
268   Debug("equality::evaluation") << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): " << d_subtermsToEvaluate[id] << std::endl;
269   Assert(!d_isInternal[id]);
270   Assert(d_subtermsToEvaluate[id] > 0);
271   if ((-- d_subtermsToEvaluate[id]) == 0) {
272     d_evaluationQueue.push(id);
273   }
274   d_subtermEvaluates.push_back(id);
275   d_subtermEvaluatesSize = d_subtermEvaluates.size();
276   Debug("equality::evaluation") << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): new " << d_subtermsToEvaluate[id] << std::endl;
277 }
278 
addTermInternal(TNode t,bool isOperator)279 void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
280 
281   Debug("equality") << d_name << "::eq::addTermInternal(" << t << ")" << std::endl;
282 
283   // If there already, we're done
284   if (hasTerm(t)) {
285     Debug("equality") << d_name << "::eq::addTermInternal(" << t << "): already there" << std::endl;
286     return;
287   }
288 
289   if (d_done) {
290     return;
291   }
292 
293   EqualityNodeId result;
294 
295   if (t.getKind() == kind::EQUAL) {
296     addTermInternal(t[0]);
297     addTermInternal(t[1]);
298     EqualityNodeId t0id = getNodeId(t[0]);
299     EqualityNodeId t1id = getNodeId(t[1]);
300     result = newApplicationNode(t, t0id, t1id, APP_EQUALITY);
301     d_isInternal[result] = false;
302     d_isConstant[result] = false;
303   } else if (t.getNumChildren() > 0 && d_congruenceKinds[t.getKind()]) {
304     TNode tOp = t.getOperator();
305     // Add the operator
306     addTermInternal(tOp, !isExternalOperatorKind(t.getKind()));
307     result = getNodeId(tOp);
308     // Add all the children and Curryfy
309     bool isInterpreted = isInterpretedFunctionKind(t.getKind());
310     for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
311       // Add the child
312       addTermInternal(t[i]);
313       EqualityNodeId tiId = getNodeId(t[i]);
314       // Add the application
315       result = newApplicationNode(t, result, tiId, isInterpreted ? APP_INTERPRETED : APP_UNINTERPRETED);
316     }
317     d_isInternal[result] = false;
318     d_isConstant[result] = t.isConst();
319     // If interpreted, set the number of non-interpreted children
320     if (isInterpreted) {
321       // How many children are not constants yet
322       d_subtermsToEvaluate[result] = t.getNumChildren();
323       for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
324         if (isConstant(getNodeId(t[i]))) {
325           Debug("equality::evaluation") << d_name << "::eq::addTermInternal(" << t << "): evaluates " << t[i] << std::endl;
326           subtermEvaluates(result);
327         }
328       }
329     }
330   } else {
331     // Otherwise we just create the new id
332     result = newNode(t);
333     // Is this an operator
334     d_isInternal[result] = isOperator;
335     d_isConstant[result] = !isOperator && t.isConst();
336   }
337 
338   if (t.getKind() == kind::EQUAL) {
339     // We set this here as this only applies to actual terms, not the
340     // intermediate application terms
341     d_isEquality[result] = true;
342   } else if (d_constantsAreTriggers && d_isConstant[result]) {
343     // Non-Boolean constants are trigger terms for all tags
344     EqualityNodeId tId = getNodeId(t);
345     // Setup the new set
346     Theory::Set newSetTags = 0;
347     EqualityNodeId newSetTriggers[THEORY_LAST];
348     unsigned newSetTriggersSize = THEORY_LAST;
349     for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST; ++ currentTheory) {
350       newSetTags = Theory::setInsert(currentTheory, newSetTags);
351       newSetTriggers[currentTheory] = tId;
352     }
353     // Add it to the list for backtracking
354     d_triggerTermSetUpdates.push_back(TriggerSetUpdate(tId, null_set_id));
355     d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
356     // Mark the the new set as a trigger
357     d_nodeIndividualTrigger[tId] = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
358   }
359 
360   // If this is not an internal node, add it to the master
361   if (d_masterEqualityEngine && !d_isInternal[result]) {
362     d_masterEqualityEngine->addTermInternal(t);
363   }
364 
365   // Empty the queue
366   propagate();
367 
368   Assert(hasTerm(t));
369 
370   Debug("equality") << d_name << "::eq::addTermInternal(" << t << ") => " << result << std::endl;
371 }
372 
hasTerm(TNode t) const373 bool EqualityEngine::hasTerm(TNode t) const {
374   return d_nodeIds.find(t) != d_nodeIds.end();
375 }
376 
getNodeId(TNode node) const377 EqualityNodeId EqualityEngine::getNodeId(TNode node) const {
378   Assert(hasTerm(node), node.toString().c_str());
379   return (*d_nodeIds.find(node)).second;
380 }
381 
getEqualityNode(TNode t)382 EqualityNode& EqualityEngine::getEqualityNode(TNode t) {
383   return getEqualityNode(getNodeId(t));
384 }
385 
getEqualityNode(EqualityNodeId nodeId)386 EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) {
387   Assert(nodeId < d_equalityNodes.size());
388   return d_equalityNodes[nodeId];
389 }
390 
getEqualityNode(TNode t) const391 const EqualityNode& EqualityEngine::getEqualityNode(TNode t) const {
392   return getEqualityNode(getNodeId(t));
393 }
394 
getEqualityNode(EqualityNodeId nodeId) const395 const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const {
396   Assert(nodeId < d_equalityNodes.size());
397   return d_equalityNodes[nodeId];
398 }
399 
assertEqualityInternal(TNode t1,TNode t2,TNode reason,unsigned pid)400 void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid) {
401 
402   Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 << "), reason = " << reason << ", pid = " << pid << std::endl;
403 
404   if (d_done) {
405     return;
406   }
407 
408   // Add the terms if they are not already in the database
409   addTermInternal(t1);
410   addTermInternal(t2);
411 
412   // Add to the queue and propagate
413   EqualityNodeId t1Id = getNodeId(t1);
414   EqualityNodeId t2Id = getNodeId(t2);
415   enqueue(MergeCandidate(t1Id, t2Id, pid, reason));
416 }
417 
assertPredicate(TNode t,bool polarity,TNode reason,unsigned pid)418 void EqualityEngine::assertPredicate(TNode t, bool polarity, TNode reason, unsigned pid) {
419   Debug("equality") << d_name << "::eq::addPredicate(" << t << "," << (polarity ? "true" : "false") << ")" << std::endl;
420   Assert(t.getKind() != kind::EQUAL, "Use assertEquality instead");
421   assertEqualityInternal(t, polarity ? d_true : d_false, reason, pid);
422   propagate();
423 }
424 
mergePredicates(TNode p,TNode q,TNode reason)425 void EqualityEngine::mergePredicates(TNode p, TNode q, TNode reason) {
426   Debug("equality") << d_name << "::eq::mergePredicates(" << p << "," << q << ")" << std::endl;
427   assertEqualityInternal(p, q, reason);
428   propagate();
429 }
430 
assertEquality(TNode eq,bool polarity,TNode reason,unsigned pid)431 void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsigned pid) {
432   Debug("equality") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
433   if (polarity) {
434     // If two terms are already equal, don't assert anything
435     if (hasTerm(eq[0]) && hasTerm(eq[1]) && areEqual(eq[0], eq[1])) {
436       return;
437     }
438     // Add equality between terms
439     assertEqualityInternal(eq[0], eq[1], reason, pid);
440     propagate();
441   } else {
442     // If two terms are already dis-equal, don't assert anything
443     if (hasTerm(eq[0]) && hasTerm(eq[1]) && areDisequal(eq[0], eq[1], false)) {
444       return;
445     }
446 
447     // notify the theory
448     if (d_performNotify) {
449       d_notify.eqNotifyDisequal(eq[0], eq[1], reason);
450     }
451 
452     Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
453 
454     assertEqualityInternal(eq, d_false, reason, pid);
455     propagate();
456 
457     if (d_done) {
458       return;
459     }
460 
461     // If both have constant representatives, we don't notify anyone
462     EqualityNodeId a = getNodeId(eq[0]);
463     EqualityNodeId b = getNodeId(eq[1]);
464     EqualityNodeId aClassId = getEqualityNode(a).getFind();
465     EqualityNodeId bClassId = getEqualityNode(b).getFind();
466     if (d_isConstant[aClassId] && d_isConstant[bClassId]) {
467       return;
468     }
469 
470     // If we are adding a disequality, notify of the shared term representatives
471     EqualityNodeId eqId = getNodeId(eq);
472     TriggerTermSetRef aTriggerRef = d_nodeIndividualTrigger[aClassId];
473     TriggerTermSetRef bTriggerRef = d_nodeIndividualTrigger[bClassId];
474     if (aTriggerRef != +null_set_id && bTriggerRef != +null_set_id) {
475       Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ": have triggers" << std::endl;
476       // The sets of trigger terms
477       TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef);
478       TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef);
479       // Go through and notify the shared dis-equalities
480       Theory::Set aTags = aTriggerTerms.tags;
481       Theory::Set bTags = bTriggerTerms.tags;
482       TheoryId aTag = Theory::setPop(aTags);
483       TheoryId bTag = Theory::setPop(bTags);
484       int a_i = 0, b_i = 0;
485       while (aTag != THEORY_LAST && bTag != THEORY_LAST) {
486         if (aTag < bTag) {
487           aTag = Theory::setPop(aTags);
488           ++ a_i;
489         } else if (aTag > bTag) {
490           bTag = Theory::setPop(bTags);
491           ++ b_i;
492         } else {
493           // Same tags, notify
494           EqualityNodeId aSharedId = aTriggerTerms.triggers[a_i++];
495           EqualityNodeId bSharedId = bTriggerTerms.triggers[b_i++];
496           // Propagate
497           if (!hasPropagatedDisequality(aTag, aSharedId, bSharedId)) {
498             // Store a proof if not there already
499             if (!hasPropagatedDisequality(aSharedId, bSharedId)) {
500               d_deducedDisequalityReasons.push_back(EqualityPair(aSharedId, a));
501               d_deducedDisequalityReasons.push_back(EqualityPair(bSharedId, b));
502               d_deducedDisequalityReasons.push_back(EqualityPair(eqId, d_falseId));
503             }
504             // Store the propagation
505             storePropagatedDisequality(aTag, aSharedId, bSharedId);
506             // Notify
507             Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ": notifying " << aTag << " for " << d_nodes[aSharedId] << " != " << d_nodes[bSharedId] << std::endl;
508             if (!d_notify.eqNotifyTriggerTermEquality(aTag, d_nodes[aSharedId], d_nodes[bSharedId], false)) {
509               break;
510             }
511           }
512           // Pop the next tags
513           aTag = Theory::setPop(aTags);
514           bTag = Theory::setPop(bTags);
515         }
516       }
517     }
518   }
519 }
520 
getRepresentative(TNode t) const521 TNode EqualityEngine::getRepresentative(TNode t) const {
522   Debug("equality::internal") << d_name << "::eq::getRepresentative(" << t << ")" << std::endl;
523   Assert(hasTerm(t));
524   EqualityNodeId representativeId = getEqualityNode(t).getFind();
525   Assert(!d_isInternal[representativeId]);
526   Debug("equality::internal") << d_name << "::eq::getRepresentative(" << t << ") => " << d_nodes[representativeId] << std::endl;
527   return d_nodes[representativeId];
528 }
529 
merge(EqualityNode & class1,EqualityNode & class2,std::vector<TriggerId> & triggersFired)530 bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vector<TriggerId>& triggersFired) {
531 
532   Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << ")" << std::endl;
533 
534   Assert(triggersFired.empty());
535 
536   ++ d_stats.mergesCount;
537 
538   EqualityNodeId class1Id = class1.getFind();
539   EqualityNodeId class2Id = class2.getFind();
540 
541   Node n1 = d_nodes[class1Id];
542   Node n2 = d_nodes[class2Id];
543   EqualityNode cc1 = getEqualityNode(n1);
544   EqualityNode cc2 = getEqualityNode(n2);
545   bool doNotify = false;
546   // notify the theory
547   // the second part of this check is needed due to the internal implementation of this class.
548   // It ensures that we are merging terms and not operators.
549   if (d_performNotify && class1Id==cc1.getFind() && class2Id==cc2.getFind()) {
550     doNotify = true;
551   }
552   if (doNotify) {
553     d_notify.eqNotifyPreMerge(n1, n2);
554   }
555 
556   // Check for constant merges
557   bool class1isConstant = d_isConstant[class1Id];
558   bool class2isConstant = d_isConstant[class2Id];
559   Assert(class1isConstant || !class2isConstant, "Should always merge into constants");
560   Assert(!class1isConstant || !class2isConstant, "Don't merge constants");
561 
562   // Trigger set of class 1
563   TriggerTermSetRef class1triggerRef = d_nodeIndividualTrigger[class1Id];
564   Theory::Set class1Tags = class1triggerRef == null_set_id ? 0 : getTriggerTermSet(class1triggerRef).tags;
565   // Trigger set of class 2
566   TriggerTermSetRef class2triggerRef = d_nodeIndividualTrigger[class2Id];
567   Theory::Set class2Tags = class2triggerRef == null_set_id ? 0 : getTriggerTermSet(class2triggerRef).tags;
568 
569   // Disequalities coming from class2
570   TaggedEqualitiesSet class2disequalitiesToNotify;
571   // Disequalities coming from class1
572   TaggedEqualitiesSet class1disequalitiesToNotify;
573 
574   // Individual tags
575   Theory::Set class1OnlyTags = Theory::setDifference(class1Tags, class2Tags);
576   Theory::Set class2OnlyTags = Theory::setDifference(class2Tags, class1Tags);
577 
578   // Only get disequalities if they are not both constant
579   if (!class1isConstant || !class2isConstant) {
580     getDisequalities(!class1isConstant, class2Id, class1OnlyTags, class2disequalitiesToNotify);
581     getDisequalities(!class2isConstant, class1Id, class2OnlyTags, class1disequalitiesToNotify);
582   }
583 
584   // Update class2 representative information
585   Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating class " << class2Id << std::endl;
586   EqualityNodeId currentId = class2Id;
587   do {
588     // Get the current node
589     EqualityNode& currentNode = getEqualityNode(currentId);
590 
591     // Update it's find to class1 id
592     Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << currentId << "->" << class1Id << std::endl;
593     currentNode.setFind(class1Id);
594 
595     // Go through the triggers and inform if necessary
596     TriggerId currentTrigger = d_nodeTriggers[currentId];
597     while (currentTrigger != null_trigger) {
598       Trigger& trigger = d_equalityTriggers[currentTrigger];
599       Trigger& otherTrigger = d_equalityTriggers[currentTrigger ^ 1];
600 
601       // If the two are not already in the same class
602       if (otherTrigger.classId != trigger.classId) {
603         trigger.classId = class1Id;
604         // If they became the same, call the trigger
605         if (otherTrigger.classId == class1Id) {
606           // Id of the real trigger is half the internal one
607           triggersFired.push_back(currentTrigger);
608         }
609       }
610 
611       // Go to the next trigger
612       currentTrigger = trigger.nextTrigger;
613     }
614 
615     // Move to the next node
616     currentId = currentNode.getNext();
617 
618   } while (currentId != class2Id);
619 
620   // Update class2 table lookup and information if not a boolean
621   // since booleans can't be in an application
622   if (!d_isEquality[class2Id]) {
623     Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of " << class2Id << std::endl;
624     do {
625       // Get the current node
626       EqualityNode& currentNode = getEqualityNode(currentId);
627       Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of node " << currentId << std::endl;
628 
629       // Go through the uselist and check for congruences
630       UseListNodeId currentUseId = currentNode.getUseList();
631       while (currentUseId != null_uselist_id) {
632         // Get the node of the use list
633         UseListNode& useNode = d_useListNodes[currentUseId];
634         // Get the function application
635         EqualityNodeId funId = useNode.getApplicationId();
636         Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << d_nodes[currentId] << " in " << d_nodes[funId] << std::endl;
637         const FunctionApplication& fun = d_applications[useNode.getApplicationId()].normalized;
638         // If it's interpreted and we can interpret
639   if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId]) {
640     // Get the actual term id
641     TNode term = d_nodes[funId];
642     subtermEvaluates(getNodeId(term));
643   }
644   // Check if there is an application with find arguments
645         EqualityNodeId aNormalized = getEqualityNode(fun.a).getFind();
646         EqualityNodeId bNormalized = getEqualityNode(fun.b).getFind();
647         FunctionApplication funNormalized(fun.type, aNormalized, bNormalized);
648         ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
649         if (find != d_applicationLookup.end()) {
650           // Applications fun and the funNormalized can be merged due to congruence
651           if (getEqualityNode(funId).getFind() != getEqualityNode(find->second).getFind()) {
652             enqueue(MergeCandidate(funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null()));
653           }
654         } else {
655           // There is no representative, so we can add one, we remove this when backtracking
656           storeApplicationLookup(funNormalized, funId);
657         }
658 
659         // Go to the next one in the use list
660         currentUseId = useNode.getNext();
661       }
662 
663       // Move to the next node
664       currentId = currentNode.getNext();
665     } while (currentId != class2Id);
666   }
667 
668   // Now merge the lists
669   class1.merge<true>(class2);
670 
671   // notify the theory
672   if (doNotify) {
673     d_notify.eqNotifyPostMerge(n1, n2);
674   }
675 
676   // Go through the trigger term disequalities and propagate
677   if (!propagateTriggerTermDisequalities(class1OnlyTags, class1triggerRef, class2disequalitiesToNotify)) {
678     return false;
679   }
680   if (!propagateTriggerTermDisequalities(class2OnlyTags, class2triggerRef, class1disequalitiesToNotify)) {
681     return false;
682   }
683 
684   // Notify the trigger term merges
685   if (class2triggerRef != +null_set_id) {
686     if (class1triggerRef == +null_set_id) {
687       // If class1 doesn't have individual triggers, but class2 does, mark it
688       d_nodeIndividualTrigger[class1Id] = class2triggerRef;
689       // Add it to the list for backtracking
690       d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, +null_set_id));
691       d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
692     } else {
693       // Get the triggers
694       TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef);
695       TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
696 
697       // Initialize the merged set
698       Theory::Set newSetTags = Theory::setUnion(class1triggers.tags, class2triggers.tags);
699       EqualityNodeId newSetTriggers[THEORY_LAST];
700       unsigned newSetTriggersSize = 0;
701 
702       int i1 = 0;
703       int i2 = 0;
704       Theory::Set tags1 = class1triggers.tags;
705       Theory::Set tags2 = class2triggers.tags;
706       TheoryId tag1 = Theory::setPop(tags1);
707       TheoryId tag2 = Theory::setPop(tags2);
708 
709       // Comparing the THEORY_LAST is OK because all other theories are
710       // smaller, and will therefore be preferred
711       while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
712       {
713         if (tag1 < tag2) {
714           // copy tag1
715           newSetTriggers[newSetTriggersSize++] = class1triggers.triggers[i1++];
716           tag1 = Theory::setPop(tags1);
717         } else if (tag1 > tag2) {
718           // copy tag2
719           newSetTriggers[newSetTriggersSize++] = class2triggers.triggers[i2++];
720           tag2 = Theory::setPop(tags2);
721         } else {
722           // copy tag1
723           EqualityNodeId tag1id = newSetTriggers[newSetTriggersSize++] = class1triggers.triggers[i1++];
724           // since they are both tagged notify of merge
725           if (d_performNotify) {
726             EqualityNodeId tag2id = class2triggers.triggers[i2++];
727             if (!d_notify.eqNotifyTriggerTermEquality(tag1, d_nodes[tag1id], d_nodes[tag2id], true)) {
728               return false;
729             }
730           }
731           // Next tags
732           tag1 = Theory::setPop(tags1);
733           tag2 = Theory::setPop(tags2);
734         }
735       }
736 
737       // Add the new trigger set, if different from previous one
738       if (class1triggers.tags != class2triggers.tags) {
739         // Add it to the list for backtracking
740         d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, class1triggerRef));
741         d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
742         // Mark the the new set as a trigger
743         d_nodeIndividualTrigger[class1Id] = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
744       }
745     }
746   }
747 
748   // Everything fine
749   return true;
750 }
751 
undoMerge(EqualityNode & class1,EqualityNode & class2,EqualityNodeId class2Id)752 void EqualityEngine::undoMerge(EqualityNode& class1, EqualityNode& class2, EqualityNodeId class2Id) {
753 
754   Debug("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << "," << class2Id << ")" << std::endl;
755 
756   // Now unmerge the lists (same as merge)
757   class1.merge<false>(class2);
758 
759   // Update class2 representative information
760   EqualityNodeId currentId = class2Id;
761   Debug("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << "," << class2Id << "): undoing representative info" << std::endl;
762   do {
763     // Get the current node
764     EqualityNode& currentNode = getEqualityNode(currentId);
765 
766     // Update it's find to class1 id
767     currentNode.setFind(class2Id);
768 
769     // Go through the trigger list (if any) and undo the class
770     TriggerId currentTrigger = d_nodeTriggers[currentId];
771     while (currentTrigger != null_trigger) {
772       Trigger& trigger = d_equalityTriggers[currentTrigger];
773       trigger.classId = class2Id;
774       currentTrigger = trigger.nextTrigger;
775     }
776 
777     // Move to the next node
778     currentId = currentNode.getNext();
779 
780   } while (currentId != class2Id);
781 
782 }
783 
backtrack()784 void EqualityEngine::backtrack() {
785 
786   Debug("equality::backtrack") << "backtracking" << std::endl;
787 
788   // If we need to backtrack then do it
789   if (d_assertedEqualitiesCount < d_assertedEqualities.size()) {
790 
791     // Clear the propagation queue
792     while (!d_propagationQueue.empty()) {
793       d_propagationQueue.pop_front();
794     }
795 
796     Debug("equality") << d_name << "::eq::backtrack(): nodes" << std::endl;
797 
798     for (int i = (int)d_assertedEqualities.size() - 1, i_end = (int)d_assertedEqualitiesCount; i >= i_end; --i) {
799       // Get the ids of the merged classes
800       Equality& eq = d_assertedEqualities[i];
801       // Undo the merge
802       if (eq.lhs != null_id) {
803         undoMerge(d_equalityNodes[eq.lhs], d_equalityNodes[eq.rhs], eq.rhs);
804       }
805     }
806 
807     d_assertedEqualities.resize(d_assertedEqualitiesCount);
808 
809     Debug("equality") << d_name << "::eq::backtrack(): edges" << std::endl;
810 
811     for (int i = (int)d_equalityEdges.size() - 2, i_end = (int)(2*d_assertedEqualitiesCount); i >= i_end; i -= 2) {
812       EqualityEdge& edge1 = d_equalityEdges[i];
813       EqualityEdge& edge2 = d_equalityEdges[i | 1];
814       d_equalityGraph[edge2.getNodeId()] = edge1.getNext();
815       d_equalityGraph[edge1.getNodeId()] = edge2.getNext();
816     }
817 
818     d_equalityEdges.resize(2 * d_assertedEqualitiesCount);
819   }
820 
821   if (d_triggerTermSetUpdates.size() > d_triggerTermSetUpdatesSize) {
822     // Unset the individual triggers
823     for (int i = d_triggerTermSetUpdates.size() - 1, i_end = d_triggerTermSetUpdatesSize; i >= i_end; -- i) {
824       const TriggerSetUpdate& update = d_triggerTermSetUpdates[i];
825       d_nodeIndividualTrigger[update.classId] = update.oldValue;
826     }
827     d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize);
828   }
829 
830   if (d_equalityTriggers.size() > d_equalityTriggersCount) {
831     // Unlink the triggers from the lists
832     for (int i = d_equalityTriggers.size() - 1, i_end = d_equalityTriggersCount; i >= i_end; -- i) {
833       const Trigger& trigger = d_equalityTriggers[i];
834       d_nodeTriggers[trigger.classId] = trigger.nextTrigger;
835     }
836     // Get rid of the triggers
837     d_equalityTriggers.resize(d_equalityTriggersCount);
838     d_equalityTriggersOriginal.resize(d_equalityTriggersCount);
839   }
840 
841   if (d_applicationLookups.size() > d_applicationLookupsCount) {
842     for (int i = d_applicationLookups.size() - 1, i_end = (int) d_applicationLookupsCount; i >= i_end; -- i) {
843       d_applicationLookup.erase(d_applicationLookups[i]);
844     }
845     d_applicationLookups.resize(d_applicationLookupsCount);
846   }
847 
848   if (d_subtermEvaluates.size() > d_subtermEvaluatesSize) {
849     for(int i = d_subtermEvaluates.size() - 1, i_end = (int)d_subtermEvaluatesSize; i >= i_end; --i) {
850       d_subtermsToEvaluate[d_subtermEvaluates[i]] ++;
851     }
852     d_subtermEvaluates.resize(d_subtermEvaluatesSize);
853   }
854 
855   if (d_nodes.size() > d_nodesCount) {
856     // Go down the nodes, check the application nodes and remove them from use-lists
857     for(int i = d_nodes.size() - 1, i_end = (int)d_nodesCount; i >= i_end; -- i) {
858       // Remove from the node -> id map
859       Debug("equality") << d_name << "::eq::backtrack(): removing node " << d_nodes[i] << std::endl;
860       d_nodeIds.erase(d_nodes[i]);
861 
862       const FunctionApplication& app = d_applications[i].original;
863       if (!app.isNull()) {
864         // Remove b from use-list
865         getEqualityNode(app.b).removeTopFromUseList(d_useListNodes);
866         // Remove a from use-list
867         getEqualityNode(app.a).removeTopFromUseList(d_useListNodes);
868       }
869     }
870 
871     // Now get rid of the nodes and the rest
872     d_nodes.resize(d_nodesCount);
873     d_applications.resize(d_nodesCount);
874     d_nodeTriggers.resize(d_nodesCount);
875     d_nodeIndividualTrigger.resize(d_nodesCount);
876     d_isConstant.resize(d_nodesCount);
877     d_subtermsToEvaluate.resize(d_nodesCount);
878     d_isEquality.resize(d_nodesCount);
879     d_isInternal.resize(d_nodesCount);
880     d_equalityGraph.resize(d_nodesCount);
881     d_equalityNodes.resize(d_nodesCount);
882   }
883 
884   if (d_deducedDisequalities.size() > d_deducedDisequalitiesSize) {
885     for(int i = d_deducedDisequalities.size() - 1, i_end = (int)d_deducedDisequalitiesSize; i >= i_end; -- i) {
886       EqualityPair pair = d_deducedDisequalities[i];
887       Assert(d_disequalityReasonsMap.find(pair) != d_disequalityReasonsMap.end());
888       // Remove from the map
889       d_disequalityReasonsMap.erase(pair);
890       std::swap(pair.first, pair.second);
891       d_disequalityReasonsMap.erase(pair);
892     }
893     d_deducedDisequalityReasons.resize(d_deducedDisequalityReasonsSize);
894     d_deducedDisequalities.resize(d_deducedDisequalitiesSize);
895   }
896 
897 }
898 
addGraphEdge(EqualityNodeId t1,EqualityNodeId t2,unsigned type,TNode reason)899 void EqualityEngine::addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, unsigned type, TNode reason) {
900   Debug("equality") << d_name << "::eq::addGraphEdge(" << d_nodes[t1] << "," << d_nodes[t2] << "," << reason << ")" << std::endl;
901   EqualityEdgeId edge = d_equalityEdges.size();
902   d_equalityEdges.push_back(EqualityEdge(t2, d_equalityGraph[t1], type, reason));
903   d_equalityEdges.push_back(EqualityEdge(t1, d_equalityGraph[t2], type, reason));
904   d_equalityGraph[t1] = edge;
905   d_equalityGraph[t2] = edge | 1;
906 
907   if (Debug.isOn("equality::internal")) {
908     debugPrintGraph();
909   }
910 }
911 
edgesToString(EqualityEdgeId edgeId) const912 std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const {
913   std::stringstream out;
914   bool first = true;
915   if (edgeId == null_edge) {
916     out << "null";
917   } else {
918     while (edgeId != null_edge) {
919       const EqualityEdge& edge = d_equalityEdges[edgeId];
920       if (!first) out << ",";
921       out << d_nodes[edge.getNodeId()];
922       edgeId = edge.getNext();
923       first = false;
924     }
925   }
926   return out.str();
927 }
928 
explainEquality(TNode t1,TNode t2,bool polarity,std::vector<TNode> & equalities,EqProof * eqp) const929 void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
930                                      std::vector<TNode>& equalities,
931                                      EqProof* eqp) const {
932   Debug("equality") << d_name << "::eq::explainEquality(" << t1 << ", " << t2
933                     << ", " << (polarity ? "true" : "false") << ")"
934                     << ", proof = " << (eqp ? "ON" : "OFF") << std::endl;
935 
936   // The terms must be there already
937   Assert(hasTerm(t1) && hasTerm(t2));;
938 
939   // Get the ids
940   EqualityNodeId t1Id = getNodeId(t1);
941   EqualityNodeId t2Id = getNodeId(t2);
942 
943   if (polarity) {
944     // Get the explanation
945     getExplanation(t1Id, t2Id, equalities, eqp);
946   } else {
947     if (eqp) {
948       eqp->d_id = eq::MERGED_THROUGH_TRANS;
949       eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t2Id]).notNode();
950     }
951 
952     // Get the reason for this disequality
953     EqualityPair pair(t1Id, t2Id);
954     Assert(d_disequalityReasonsMap.find(pair) != d_disequalityReasonsMap.end(), "Don't ask for stuff I didn't notify you about");
955     DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second;
956 
957     for (unsigned i = reasonRef.mergesStart; i < reasonRef.mergesEnd; ++ i) {
958 
959       EqualityPair toExplain = d_deducedDisequalityReasons[i];
960       std::shared_ptr<EqProof> eqpc;
961 
962       // If we're constructing a (transitivity) proof, we don't need to include an explanation for x=x.
963       if (eqp && toExplain.first != toExplain.second) {
964         eqpc = std::make_shared<EqProof>();
965       }
966 
967       getExplanation(toExplain.first, toExplain.second, equalities, eqpc.get());
968 
969       if (eqpc) {
970         Debug("pf::ee") << "Child proof is:" << std::endl;
971         eqpc->debug_print("pf::ee", 1);
972 
973         if (eqpc->d_id == eq::MERGED_THROUGH_TRANS) {
974           std::vector<std::shared_ptr<EqProof>> orderedChildren;
975           bool nullCongruenceFound = false;
976           for (unsigned i = 0; i < eqpc->d_children.size(); ++i) {
977             if (eqpc->d_children[i]->d_id==eq::MERGED_THROUGH_CONGRUENCE &&
978                 eqpc->d_children[i]->d_node.isNull()) {
979               nullCongruenceFound = true;
980               Debug("pf::ee") << "Have congruence with empty d_node. Splitting..." << std::endl;
981               orderedChildren.insert(orderedChildren.begin(), eqpc->d_children[i]->d_children[0]);
982               orderedChildren.push_back(eqpc->d_children[i]->d_children[1]);
983             } else {
984               orderedChildren.push_back(eqpc->d_children[i]);
985             }
986           }
987 
988           if (nullCongruenceFound) {
989             eqpc->d_children = orderedChildren;
990             Debug("pf::ee") << "Child proof's children have been reordered. It is now:" << std::endl;
991             eqpc->debug_print("pf::ee", 1);
992           }
993         }
994 
995         eqp->d_children.push_back(eqpc);
996       }
997     }
998 
999     if (eqp) {
1000       if (eqp->d_children.size() == 0) {
1001         // Corner case where this is actually a disequality between two constants
1002         Debug("pf::ee") << "Encountered a constant disequality (not a transitivity proof): "
1003                         << eqp->d_node << std::endl;
1004         Assert(eqp->d_node[0][0].isConst());
1005         Assert(eqp->d_node[0][1].isConst());
1006         eqp->d_id = MERGED_THROUGH_CONSTANTS;
1007       } else if (eqp->d_children.size() == 1) {
1008         // The transitivity proof has just one child. Simplify.
1009         std::shared_ptr<EqProof> temp = eqp->d_children[0];
1010         eqp->d_children.clear();
1011         *eqp = *temp;
1012       }
1013 
1014       Debug("pf::ee") << "Disequality explanation final proof: " << std::endl;
1015       eqp->debug_print("pf::ee", 1);
1016     }
1017   }
1018 }
1019 
explainPredicate(TNode p,bool polarity,std::vector<TNode> & assertions,EqProof * eqp) const1020 void EqualityEngine::explainPredicate(TNode p, bool polarity,
1021                                       std::vector<TNode>& assertions,
1022                                       EqProof* eqp) const {
1023   Debug("equality") << d_name << "::eq::explainPredicate(" << p << ")"
1024                     << std::endl;
1025   // Must have the term
1026   Assert(hasTerm(p));
1027   // Get the explanation
1028   getExplanation(getNodeId(p), polarity ? d_trueId : d_falseId, assertions,
1029                  eqp);
1030 }
1031 
getExplanation(EqualityNodeId t1Id,EqualityNodeId t2Id,std::vector<TNode> & equalities,EqProof * eqp) const1032 void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id,
1033                                     std::vector<TNode>& equalities,
1034                                     EqProof* eqp) const {
1035   Debug("equality") << d_name << "::eq::getExplanation(" << d_nodes[t1Id] << "," << d_nodes[t2Id] << ")" << std::endl;
1036 
1037   // We can only explain the nodes that got merged
1038 #ifdef CVC4_ASSERTIONS
1039   bool canExplain = getEqualityNode(t1Id).getFind() == getEqualityNode(t2Id).getFind()
1040                   || (d_done && isConstant(t1Id) && isConstant(t2Id));
1041 
1042   if (!canExplain) {
1043     Warning() << "Can't explain equality:" << std::endl;
1044     Warning() << d_nodes[t1Id] << " with find " << d_nodes[getEqualityNode(t1Id).getFind()] << std::endl;
1045     Warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
1046   }
1047   Assert(canExplain);
1048 #endif
1049 
1050   // If the nodes are the same, we're done
1051   if (t1Id == t2Id){
1052     if( eqp ) {
1053       if ((d_nodes[t1Id].getKind() == kind::BUILTIN) && (d_nodes[t1Id].getConst<Kind>() == kind::SELECT)) {
1054         std::vector<Node> no_children;
1055         eqp->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_SELECT_0, no_children);
1056       } else {
1057         eqp->d_node = ProofManager::currentPM()->mkOp(d_nodes[t1Id]);
1058       }
1059     }
1060     return;
1061   }
1062 
1063 
1064   if (Debug.isOn("equality::internal")) {
1065     debugPrintGraph();
1066   }
1067 
1068   // Queue for the BFS containing nodes
1069   std::vector<BfsData> bfsQueue;
1070 
1071   // Find a path from t1 to t2 in the graph (BFS)
1072   bfsQueue.push_back(BfsData(t1Id, null_id, 0));
1073   size_t currentIndex = 0;
1074   while (true) {
1075     // There should always be a path, and every node can be visited only once (tree)
1076     Assert(currentIndex < bfsQueue.size());
1077 
1078     // The next node to visit
1079     BfsData current = bfsQueue[currentIndex];
1080     EqualityNodeId currentNode = current.nodeId;
1081 
1082     Debug("equality") << d_name << "::eq::getExplanation(): currentNode =  " << d_nodes[currentNode] << std::endl;
1083 
1084     // Go through the equality edges of this node
1085     EqualityEdgeId currentEdge = d_equalityGraph[currentNode];
1086     if (Debug.isOn("equality")) {
1087       Debug("equality") << d_name << "::eq::getExplanation(): edgesId =  " << currentEdge << std::endl;
1088       Debug("equality") << d_name << "::eq::getExplanation(): edges =  " << edgesToString(currentEdge) << std::endl;
1089     }
1090 
1091     while (currentEdge != null_edge) {
1092       // Get the edge
1093       const EqualityEdge& edge = d_equalityEdges[currentEdge];
1094 
1095       // If not just the backwards edge
1096       if ((currentEdge | 1u) != (current.edgeId | 1u)) {
1097 
1098         Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = (" << d_nodes[currentNode] << "," << d_nodes[edge.getNodeId()] << ")" << std::endl;
1099 
1100         // Did we find the path
1101         if (edge.getNodeId() == t2Id) {
1102 
1103           Debug("equality") << d_name << "::eq::getExplanation(): path found: " << std::endl;
1104 
1105           std::vector<std::shared_ptr<EqProof>> eqp_trans;
1106 
1107           // Reconstruct the path
1108           do {
1109             // The current node
1110             currentNode = bfsQueue[currentIndex].nodeId;
1111             EqualityNodeId edgeNode = d_equalityEdges[currentEdge].getNodeId();
1112             unsigned reasonType = d_equalityEdges[currentEdge].getReasonType();
1113             Node reason = d_equalityEdges[currentEdge].getReason();
1114 
1115             Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = " << currentEdge << ", currentNode = " << currentNode << std::endl;
1116             Debug("equality") << d_name << "                     targetNode = " << d_nodes[edgeNode] << std::endl;
1117             Debug("equality") << d_name << "                     in currentEdge = (" << d_nodes[currentNode] << "," << d_nodes[edge.getNodeId()] << ")" << std::endl;
1118             Debug("equality") << d_name << "                     reason type = " << reasonType << std::endl;
1119 
1120             std::shared_ptr<EqProof> eqpc;;
1121             // Make child proof if a proof is being constructed
1122             if (eqp) {
1123               eqpc = std::make_shared<EqProof>();
1124               eqpc->d_id = reasonType;
1125             }
1126 
1127             // Add the actual equality to the vector
1128             switch (reasonType) {
1129             case MERGED_THROUGH_CONGRUENCE: {
1130               // f(x1, x2) == f(y1, y2) because x1 = y1 and x2 = y2
1131               Debug("equality") << d_name << "::eq::getExplanation(): due to congruence, going deeper" << std::endl;
1132               const FunctionApplication& f1 = d_applications[currentNode].original;
1133               const FunctionApplication& f2 = d_applications[edgeNode].original;
1134 
1135               Debug("equality") << push;
1136               Debug("equality") << "Explaining left hand side equalities" << std::endl;
1137               std::shared_ptr<EqProof> eqpc1 =
1138                   eqpc ? std::make_shared<EqProof>() : nullptr;
1139               getExplanation(f1.a, f2.a, equalities, eqpc1.get());
1140               Debug("equality") << "Explaining right hand side equalities" << std::endl;
1141               std::shared_ptr<EqProof> eqpc2 =
1142                   eqpc ? std::make_shared<EqProof>() : nullptr;
1143               getExplanation(f1.b, f2.b, equalities, eqpc2.get());
1144               if( eqpc ){
1145                 eqpc->d_children.push_back( eqpc1 );
1146                 eqpc->d_children.push_back( eqpc2 );
1147                 if( d_nodes[currentNode].getKind()==kind::EQUAL ){
1148                   //leave node null for now
1149                   eqpc->d_node = Node::null();
1150                 } else {
1151                   if(d_nodes[f1.a].getKind() == kind::APPLY_UF ||
1152                      d_nodes[f1.a].getKind() == kind::SELECT ||
1153                      d_nodes[f1.a].getKind() == kind::STORE) {
1154                     eqpc->d_node = d_nodes[f1.a];
1155                   } else {
1156                     if (d_nodes[f1.a].getKind() == kind::BUILTIN && d_nodes[f1.a].getConst<Kind>() == kind::SELECT) {
1157                       eqpc->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_SELECT_1, d_nodes[f1.b]);
1158                       // The first child is a PARTIAL_SELECT_0.
1159                       // Give it a child so that we know what kind of (read) it is, when we dump to LFSC.
1160                       Assert(eqpc->d_children[0]->d_node.getKind() == kind::PARTIAL_SELECT_0);
1161                       Assert(eqpc->d_children[0]->d_children.size() == 0);
1162 
1163                       eqpc->d_children[0]->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_SELECT_0,
1164                                                                                      d_nodes[f1.b]);
1165                     } else {
1166                       eqpc->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_APPLY_UF,
1167                                                                       ProofManager::currentPM()->mkOp(d_nodes[f1.a]),
1168                                                                       d_nodes[f1.b]);
1169                     }
1170                   }
1171                 }
1172               }
1173               Debug("equality") << pop;
1174               break;
1175             }
1176 
1177             case MERGED_THROUGH_REFLEXIVITY: {
1178               // x1 == x1
1179               Debug("equality") << d_name << "::eq::getExplanation(): due to reflexivity, going deeper" << std::endl;
1180               EqualityNodeId eqId = currentNode == d_trueId ? edgeNode : currentNode;
1181               const FunctionApplication& eq = d_applications[eqId].original;
1182               Assert(eq.isEquality(), "Must be an equality");
1183 
1184               // Explain why a = b constant
1185               Debug("equality") << push;
1186               std::shared_ptr<EqProof> eqpc1 =
1187                   eqpc ? std::make_shared<EqProof>() : nullptr;
1188               getExplanation(eq.a, eq.b, equalities, eqpc1.get());
1189               if( eqpc ){
1190                 eqpc->d_children.push_back( eqpc1 );
1191               }
1192               Debug("equality") << pop;
1193 
1194               break;
1195             }
1196 
1197             case MERGED_THROUGH_CONSTANTS: {
1198               // f(c1, ..., cn) = c semantically, we can just ignore it
1199               Debug("equality") << d_name << "::eq::getExplanation(): due to constants, explain the constants" << std::endl;
1200               Debug("equality") << push;
1201 
1202               // Get the node we interpreted
1203               TNode interpreted = d_nodes[currentNode];
1204               if (interpreted.isConst()) {
1205                 interpreted = d_nodes[edgeNode];
1206               }
1207 
1208               // Explain why a is a constant by explaining each argument
1209               for (unsigned i = 0; i < interpreted.getNumChildren(); ++ i) {
1210                 EqualityNodeId childId = getNodeId(interpreted[i]);
1211                 Assert(isConstant(childId));
1212                 std::shared_ptr<EqProof> eqpcc =
1213                     eqpc ? std::make_shared<EqProof>() : nullptr;
1214                 getExplanation(childId, getEqualityNode(childId).getFind(),
1215                                equalities, eqpcc.get());
1216                 if( eqpc ) {
1217                   eqpc->d_children.push_back( eqpcc );
1218 
1219                   Debug("pf::ee") << "MERGED_THROUGH_CONSTANTS. Dumping the child proof" << std::endl;
1220                   eqpc->debug_print("pf::ee", 1);
1221                 }
1222               }
1223 
1224               Debug("equality") << pop;
1225               break;
1226             }
1227 
1228             default: {
1229               // Construct the equality
1230               Debug("equality") << d_name << "::eq::getExplanation(): adding: "
1231                                 << reason << std::endl;
1232               Debug("equality") << d_name << "::eq::getExplanation(): reason type = " << reasonType << std::endl;
1233               Node a = d_nodes[currentNode];
1234               Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()];
1235 
1236               if (eqpc) {
1237                 //apply proof reconstruction processing (when eqpc is non-null)
1238                 if (d_pathReconstructionTriggers.find(reasonType) != d_pathReconstructionTriggers.end()) {
1239                   d_pathReconstructionTriggers.find(reasonType)
1240                       ->second->notify(reasonType, reason, a, b, equalities,
1241                                        eqpc.get());
1242                 }
1243                 if (reasonType == MERGED_THROUGH_EQUALITY) {
1244                   eqpc->d_node = reason;
1245                 } else {
1246                   // The LFSC translator prefers (not (= a b)) over (= (= a b) false)
1247 
1248                   if (a == NodeManager::currentNM()->mkConst(false)) {
1249                     eqpc->d_node = b.notNode();
1250                   } else if (b == NodeManager::currentNM()->mkConst(false)) {
1251                     eqpc->d_node = a.notNode();
1252                   } else {
1253                     eqpc->d_node = b.eqNode(a);
1254                   }
1255                 }
1256                 eqpc->d_id = reasonType;
1257               }
1258 
1259               equalities.push_back(reason);
1260               break;
1261             }
1262             }
1263 
1264             // Go to the previous
1265             currentEdge = bfsQueue[currentIndex].edgeId;
1266             currentIndex = bfsQueue[currentIndex].previousIndex;
1267 
1268             //---from Morgan---
1269             if (eqpc != NULL && eqpc->d_id == MERGED_THROUGH_REFLEXIVITY) {
1270               if(eqpc->d_node.isNull()) {
1271                 Assert(eqpc->d_children.size() == 1);
1272                 std::shared_ptr<EqProof> p = eqpc;
1273                 eqpc = p->d_children[0];
1274               } else {
1275                 Assert(eqpc->d_children.empty());
1276               }
1277             }
1278             //---end from Morgan---
1279 
1280             eqp_trans.push_back(eqpc);
1281           } while (currentEdge != null_id);
1282 
1283           if (eqp) {
1284             if(eqp_trans.size() == 1) {
1285               *eqp = *eqp_trans[0];
1286             } else {
1287               eqp->d_id = MERGED_THROUGH_TRANS;
1288               eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
1289               eqp->d_node = NodeManager::currentNM()->mkNode(kind::EQUAL, d_nodes[t1Id], d_nodes[t2Id]);
1290             }
1291 
1292             eqp->debug_print("pf::ee", 1);
1293           }
1294 
1295           // Done
1296           return;
1297         }
1298 
1299         // Push to the visitation queue if it's not the backward edge
1300         bfsQueue.push_back(BfsData(edge.getNodeId(), currentEdge, currentIndex));
1301       }
1302 
1303       // Go to the next edge
1304       currentEdge = edge.getNext();
1305     }
1306 
1307     // Go to the next node to visit
1308     ++ currentIndex;
1309   }
1310 }
1311 
addTriggerEquality(TNode eq)1312 void EqualityEngine::addTriggerEquality(TNode eq) {
1313   Assert(eq.getKind() == kind::EQUAL);
1314 
1315   if (d_done) {
1316     return;
1317   }
1318 
1319   // Add the terms
1320   addTermInternal(eq[0]);
1321   addTermInternal(eq[1]);
1322 
1323   bool skipTrigger = false;
1324 
1325   // If they are equal or disequal already, no need for the trigger
1326   if (areEqual(eq[0], eq[1])) {
1327     d_notify.eqNotifyTriggerEquality(eq, true);
1328     skipTrigger = true;
1329   }
1330   if (areDisequal(eq[0], eq[1], true)) {
1331     d_notify.eqNotifyTriggerEquality(eq, false);
1332     skipTrigger = true;
1333   }
1334 
1335   if (skipTrigger) {
1336     return;
1337   }
1338 
1339   // Add the equality
1340   addTermInternal(eq);
1341 
1342   // Positive trigger
1343   addTriggerEqualityInternal(eq[0], eq[1], eq, true);
1344   // Negative trigger
1345   addTriggerEqualityInternal(eq, d_false, eq, false);
1346 }
1347 
addTriggerPredicate(TNode predicate)1348 void EqualityEngine::addTriggerPredicate(TNode predicate) {
1349   Assert(predicate.getKind() != kind::NOT && predicate.getKind() != kind::EQUAL);
1350   Assert(d_congruenceKinds.tst(predicate.getKind()), "No point in adding non-congruence predicates");
1351 
1352   if (d_done) {
1353     return;
1354   }
1355 
1356   // Add the term
1357   addTermInternal(predicate);
1358 
1359   bool skipTrigger = false;
1360 
1361   // If it's know already, no need for the trigger
1362   if (areEqual(predicate, d_true)) {
1363     d_notify.eqNotifyTriggerPredicate(predicate, true);
1364     skipTrigger = true;
1365   }
1366   if (areEqual(predicate, d_false)) {
1367     d_notify.eqNotifyTriggerPredicate(predicate, false);
1368     skipTrigger = true;
1369   }
1370 
1371   if (skipTrigger) {
1372     return;
1373   }
1374 
1375   // Positive trigger
1376   addTriggerEqualityInternal(predicate, d_true, predicate, true);
1377   // Negative trigger
1378   addTriggerEqualityInternal(predicate, d_false, predicate, false);
1379 }
1380 
addTriggerEqualityInternal(TNode t1,TNode t2,TNode trigger,bool polarity)1381 void EqualityEngine::addTriggerEqualityInternal(TNode t1, TNode t2, TNode trigger, bool polarity) {
1382 
1383   Debug("equality") << d_name << "::eq::addTrigger(" << t1 << ", " << t2 << ", " << trigger << ")" << std::endl;
1384 
1385   Assert(hasTerm(t1));
1386   Assert(hasTerm(t2));
1387 
1388   if (d_done) {
1389     return;
1390   }
1391 
1392   // Get the information about t1
1393   EqualityNodeId t1Id = getNodeId(t1);
1394   EqualityNodeId t1classId = getEqualityNode(t1Id).getFind();
1395   // We will attach it to the class representative, since then we know how to backtrack it
1396   TriggerId t1TriggerId = d_nodeTriggers[t1classId];
1397 
1398   // Get the information about t2
1399   EqualityNodeId t2Id = getNodeId(t2);
1400   EqualityNodeId t2classId = getEqualityNode(t2Id).getFind();
1401   // We will attach it to the class representative, since then we know how to backtrack it
1402   TriggerId t2TriggerId = d_nodeTriggers[t2classId];
1403 
1404   Debug("equality") << d_name << "::eq::addTrigger(" << trigger << "): " << t1Id << " (" << t1classId << ") = " << t2Id << " (" << t2classId << ")" << std::endl;
1405 
1406   // Create the triggers
1407   TriggerId t1NewTriggerId = d_equalityTriggers.size();
1408   d_equalityTriggers.push_back(Trigger(t1classId, t1TriggerId));
1409   d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity));
1410   TriggerId t2NewTriggerId = d_equalityTriggers.size();
1411   d_equalityTriggers.push_back(Trigger(t2classId, t2TriggerId));
1412   d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity));
1413 
1414   // Update the counters
1415   d_equalityTriggersCount = d_equalityTriggers.size();
1416   Assert(d_equalityTriggers.size() == d_equalityTriggersOriginal.size());
1417   Assert(d_equalityTriggers.size() % 2 == 0);
1418 
1419   // Add the trigger to the trigger graph
1420   d_nodeTriggers[t1classId] = t1NewTriggerId;
1421   d_nodeTriggers[t2classId] = t2NewTriggerId;
1422 
1423   if (Debug.isOn("equality::internal")) {
1424     debugPrintGraph();
1425   }
1426 
1427   Debug("equality") << d_name << "::eq::addTrigger(" << t1 << "," << t2 << ") => (" << t1NewTriggerId << ", " << t2NewTriggerId << ")" << std::endl;
1428 }
1429 
evaluateTerm(TNode node)1430 Node EqualityEngine::evaluateTerm(TNode node) {
1431   Debug("equality::evaluation") << d_name << "::eq::evaluateTerm(" << node << ")" << std::endl;
1432   NodeBuilder<> builder;
1433   builder << node.getKind();
1434   if (node.getMetaKind() == kind::metakind::PARAMETERIZED) {
1435     builder << node.getOperator();
1436   }
1437   for (unsigned i = 0; i < node.getNumChildren(); ++ i) {
1438     TNode child = node[i];
1439     TNode childRep = getRepresentative(child);
1440     Debug("equality::evaluation") << d_name << "::eq::evaluateTerm: " << child << " -> " << childRep << std::endl;
1441     Assert(childRep.isConst());
1442     builder << childRep;
1443   }
1444   Node newNode = builder;
1445   return Rewriter::rewrite(newNode);
1446 }
1447 
processEvaluationQueue()1448 void EqualityEngine::processEvaluationQueue() {
1449 
1450   Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): start" << std::endl;
1451 
1452   while (!d_evaluationQueue.empty()) {
1453     // Get the node
1454     EqualityNodeId id = d_evaluationQueue.front();
1455     d_evaluationQueue.pop();
1456 
1457     // Replace the children with their representatives (must be constants)
1458     Node nodeEvaluated = evaluateTerm(d_nodes[id]);
1459     Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): " << d_nodes[id] << " evaluates to " << nodeEvaluated << std::endl;
1460     Assert(nodeEvaluated.isConst());
1461     addTermInternal(nodeEvaluated);
1462     EqualityNodeId nodeEvaluatedId = getNodeId(nodeEvaluated);
1463 
1464     // Enqueue the semantic equality
1465     enqueue(MergeCandidate(id, nodeEvaluatedId, MERGED_THROUGH_CONSTANTS, TNode::null()));
1466   }
1467 
1468   Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): done" << std::endl;
1469 }
1470 
propagate()1471 void EqualityEngine::propagate() {
1472 
1473   if (d_inPropagate) {
1474     // We're already in propagate, go back
1475     return;
1476   }
1477 
1478   // Make sure we don't get in again
1479   ScopedBool inPropagate(d_inPropagate, true);
1480 
1481   Debug("equality") << d_name << "::eq::propagate()" << std::endl;
1482 
1483   while (!d_propagationQueue.empty() || !d_evaluationQueue.empty()) {
1484 
1485     if (d_done) {
1486       // If we're done, just empty the queue
1487       while (!d_propagationQueue.empty()) d_propagationQueue.pop_front();
1488       while (!d_evaluationQueue.empty()) d_evaluationQueue.pop();
1489       continue;
1490     }
1491 
1492     // Process any evaluation requests
1493     if (!d_evaluationQueue.empty()) {
1494       processEvaluationQueue();
1495       continue;
1496     }
1497 
1498     // The current merge candidate
1499     const MergeCandidate current = d_propagationQueue.front();
1500     d_propagationQueue.pop_front();
1501 
1502     // Get the representatives
1503     EqualityNodeId t1classId = getEqualityNode(current.t1Id).getFind();
1504     EqualityNodeId t2classId = getEqualityNode(current.t2Id).getFind();
1505 
1506     // If already the same, we're done
1507     if (t1classId == t2classId) {
1508       continue;
1509     }
1510 
1511     Debug("equality::internal") << d_name << "::eq::propagate(): t1: " << (d_isInternal[t1classId] ? "internal" : "proper") << std::endl;
1512     Debug("equality::internal") << d_name << "::eq::propagate(): t2: " << (d_isInternal[t2classId] ? "internal" : "proper") << std::endl;
1513 
1514     // Get the nodes of the representatives
1515     EqualityNode& node1 = getEqualityNode(t1classId);
1516     EqualityNode& node2 = getEqualityNode(t2classId);
1517 
1518     Assert(node1.getFind() == t1classId);
1519     Assert(node2.getFind() == t2classId);
1520 
1521     // Add the actual equality to the equality graph
1522     addGraphEdge(current.t1Id, current.t2Id, current.type, current.reason);
1523 
1524     // If constants are being merged we're done
1525     if (d_isConstant[t1classId] && d_isConstant[t2classId]) {
1526       // When merging constants we are inconsistent, hence done
1527       d_done = true;
1528       // But in order to keep invariants (edges = 2*equalities) we put an equalities in
1529       // Note that we can explain this merge as we have a graph edge
1530       d_assertedEqualities.push_back(Equality(null_id, null_id));
1531       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
1532       // Notify
1533       if (d_performNotify) {
1534         d_notify.eqNotifyConstantTermMerge(d_nodes[t1classId], d_nodes[t2classId]);
1535       }
1536       // Empty the queue and exit
1537       continue;
1538     }
1539 
1540     // Vector to collect the triggered events
1541     std::vector<TriggerId> triggers;
1542 
1543     // Figure out the merge preference
1544     EqualityNodeId mergeInto = t1classId;
1545     if (d_isInternal[t2classId] != d_isInternal[t1classId]) {
1546       // We always keep non-internal nodes as representatives: if any node in
1547       // the class is non-internal, then the representative will be non-internal
1548       if (d_isInternal[t1classId]) {
1549         mergeInto = t2classId;
1550       } else {
1551         mergeInto = t1classId;
1552       }
1553     } else if (d_isConstant[t2classId] != d_isConstant[t1classId]) {
1554       // We always keep constants as representatives: if any (at most one) node
1555       // in the class in a constant, then the representative will be a constant
1556       if (d_isConstant[t2classId]) {
1557         mergeInto = t2classId;
1558       } else {
1559         mergeInto = t1classId;
1560       }
1561     } else if (node2.getSize() > node1.getSize()) {
1562       // We always merge into the bigger class to reduce the amount of traversing
1563       // we need to do
1564       mergeInto = t2classId;
1565     }
1566 
1567     if (mergeInto == t2classId) {
1568       Debug("equality") << d_name << "::eq::propagate(): merging " << d_nodes[current.t1Id]<< " into " << d_nodes[current.t2Id] << std::endl;
1569       d_assertedEqualities.push_back(Equality(t2classId, t1classId));
1570       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
1571       if (!merge(node2, node1, triggers)) {
1572         d_done = true;
1573       }
1574     } else {
1575       Debug("equality") << d_name << "::eq::propagate(): merging " << d_nodes[current.t2Id] << " into " << d_nodes[current.t1Id] << std::endl;
1576       d_assertedEqualities.push_back(Equality(t1classId, t2classId));
1577       d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1;
1578     if (!merge(node1, node2, triggers)) {
1579         d_done = true;
1580       }
1581     }
1582 
1583     // If not merging internal nodes, notify the master
1584     if (d_masterEqualityEngine && !d_isInternal[t1classId] && !d_isInternal[t2classId]) {
1585       d_masterEqualityEngine->assertEqualityInternal(d_nodes[t1classId], d_nodes[t2classId], TNode::null());
1586       d_masterEqualityEngine->propagate();
1587     }
1588 
1589     // Notify the triggers
1590     if (d_performNotify && !d_done) {
1591       for (size_t trigger_i = 0, trigger_end = triggers.size(); trigger_i < trigger_end && !d_done; ++ trigger_i) {
1592         const TriggerInfo& triggerInfo = d_equalityTriggersOriginal[triggers[trigger_i]];
1593         if (triggerInfo.trigger.getKind() == kind::EQUAL) {
1594           // Special treatment for disequalities
1595           if (!triggerInfo.polarity) {
1596             // Store that we are propagating a diseauality
1597             TNode equality = triggerInfo.trigger;
1598             EqualityNodeId original = getNodeId(equality);
1599             TNode lhs = equality[0];
1600             TNode rhs = equality[1];
1601             EqualityNodeId lhsId = getNodeId(lhs);
1602             EqualityNodeId rhsId = getNodeId(rhs);
1603             // We use the THEORY_LAST as a marker for "marked as propagated, reasons stored".
1604             // This tag is added to an internal theories set that is only inserted in, so this is
1605             // safe. Had we iterated over, or done other set operations this might be dangerous.
1606             if (!hasPropagatedDisequality(THEORY_LAST, lhsId, rhsId)) {
1607               if (!hasPropagatedDisequality(lhsId, rhsId)) {
1608                 d_deducedDisequalityReasons.push_back(EqualityPair(original, d_falseId));
1609               }
1610               storePropagatedDisequality(THEORY_LAST, lhsId, rhsId);
1611               if (!d_notify.eqNotifyTriggerEquality(triggerInfo.trigger, triggerInfo.polarity)) {
1612                 d_done = true;
1613               }
1614             }
1615           } else {
1616             // Equalities are simple
1617             if (!d_notify.eqNotifyTriggerEquality(triggerInfo.trigger, triggerInfo.polarity)) {
1618               d_done = true;
1619             }
1620           }
1621         } else {
1622           if (!d_notify.eqNotifyTriggerPredicate(triggerInfo.trigger, triggerInfo.polarity)) {
1623             d_done = true;
1624           }
1625         }
1626       }
1627     }
1628   }
1629 }
1630 
debugPrintGraph() const1631 void EqualityEngine::debugPrintGraph() const {
1632   Debug("equality::graph") << std::endl << "Dumping graph" << std::endl;
1633   for (EqualityNodeId nodeId = 0; nodeId < d_nodes.size(); ++ nodeId) {
1634 
1635     Debug("equality::graph") << d_nodes[nodeId] << " " << nodeId << "(" << getEqualityNode(nodeId).getFind() << "):";
1636 
1637     EqualityEdgeId edgeId = d_equalityGraph[nodeId];
1638     while (edgeId != null_edge) {
1639       const EqualityEdge& edge = d_equalityEdges[edgeId];
1640       Debug("equality::graph") << " [" << edge.getNodeId() << "] " << d_nodes[edge.getNodeId()] << ":" << edge.getReason();
1641       edgeId = edge.getNext();
1642     }
1643 
1644     Debug("equality::graph") << std::endl;
1645   }
1646   Debug("equality::graph") << std::endl;
1647 }
1648 
areEqual(TNode t1,TNode t2) const1649 bool EqualityEngine::areEqual(TNode t1, TNode t2) const {
1650   Debug("equality") << d_name << "::eq::areEqual(" << t1 << "," << t2 << ")";
1651 
1652   Assert(hasTerm(t1));
1653   Assert(hasTerm(t2));
1654 
1655   bool result = getEqualityNode(t1).getFind() == getEqualityNode(t2).getFind();
1656   Debug("equality") << (result ? "\t(YES)" : "\t(NO)") << std::endl;
1657   return result;
1658 }
1659 
areDisequal(TNode t1,TNode t2,bool ensureProof) const1660 bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
1661 {
1662   Debug("equality") << d_name << "::eq::areDisequal(" << t1 << "," << t2 << ")";
1663 
1664   // Add the terms
1665   Assert(hasTerm(t1));
1666   Assert(hasTerm(t2));
1667 
1668   // Get ids
1669   EqualityNodeId t1Id = getNodeId(t1);
1670   EqualityNodeId t2Id = getNodeId(t2);
1671 
1672   // If we propagated this disequality we're true
1673   if (hasPropagatedDisequality(t1Id, t2Id)) {
1674     Debug("equality") << "\t(YES)" << std::endl;
1675     return true;
1676   }
1677 
1678   // Get equivalence classes
1679   EqualityNodeId t1ClassId = getEqualityNode(t1Id).getFind();
1680   EqualityNodeId t2ClassId = getEqualityNode(t2Id).getFind();
1681 
1682   // We are semantically const, for remembering stuff
1683   EqualityEngine* nonConst = const_cast<EqualityEngine*>(this);
1684 
1685   // Check for constants
1686   if (d_isConstant[t1ClassId] && d_isConstant[t2ClassId] && t1ClassId != t2ClassId) {
1687     if (ensureProof) {
1688       nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t1Id, t1ClassId));
1689       nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t2Id, t2ClassId));
1690       nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
1691     }
1692     Debug("equality") << "\t(YES)" << std::endl;
1693     return true;
1694   }
1695 
1696   // Create the equality
1697   FunctionApplication eqNormalized(APP_EQUALITY, t1ClassId, t2ClassId);
1698   ApplicationIdsMap::const_iterator find = d_applicationLookup.find(eqNormalized);
1699   if (find != d_applicationLookup.end()) {
1700     if (getEqualityNode(find->second).getFind() == getEqualityNode(d_falseId).getFind()) {
1701       if (ensureProof) {
1702         const FunctionApplication original = d_applications[find->second].original;
1703         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t1Id, original.a));
1704         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(find->second, d_falseId));
1705         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t2Id, original.b));
1706         nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
1707       }
1708       Debug("equality") << "\t(YES)" << std::endl;
1709       return true;
1710     }
1711   }
1712 
1713   // Check the symmetric disequality
1714   std::swap(eqNormalized.a, eqNormalized.b);
1715   find = d_applicationLookup.find(eqNormalized);
1716   if (find != d_applicationLookup.end()) {
1717     if (getEqualityNode(find->second).getFind() == getEqualityNode(d_falseId).getFind()) {
1718       if (ensureProof) {
1719         const FunctionApplication original = d_applications[find->second].original;
1720         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t2Id, original.a));
1721         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(find->second, d_falseId));
1722         nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t1Id, original.b));
1723         nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id);
1724       }
1725       Debug("equality") << "\t(YES)" << std::endl;
1726       return true;
1727     }
1728   }
1729 
1730   // Couldn't deduce dis-equalityReturn whether the terms are disequal
1731   Debug("equality") << "\t(NO)" << std::endl;
1732   return false;
1733 }
1734 
getSize(TNode t)1735 size_t EqualityEngine::getSize(TNode t) {
1736   // Add the term
1737   addTermInternal(t);
1738   return getEqualityNode(getEqualityNode(t).getFind()).getSize();
1739 }
1740 
1741 
addPathReconstructionTrigger(unsigned trigger,const PathReconstructionNotify * notify)1742 void EqualityEngine::addPathReconstructionTrigger(unsigned trigger, const PathReconstructionNotify* notify) {
1743   // Currently we can only inform one callback per trigger
1744   Assert(d_pathReconstructionTriggers.find(trigger) == d_pathReconstructionTriggers.end());
1745   d_pathReconstructionTriggers[trigger] = notify;
1746 }
1747 
getFreshMergeReasonType()1748 unsigned EqualityEngine::getFreshMergeReasonType() {
1749   return d_freshMergeReasonType++;
1750 }
1751 
addTriggerTerm(TNode t,TheoryId tag)1752 void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
1753 {
1754   Debug("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << ")" << std::endl;
1755 
1756   Assert(tag != THEORY_LAST);
1757 
1758   if (d_done) {
1759     return;
1760   }
1761 
1762   // Add the term if it's not already there
1763   addTermInternal(t);
1764 
1765   // Get the node id
1766   EqualityNodeId eqNodeId = getNodeId(t);
1767   EqualityNode& eqNode = getEqualityNode(eqNodeId);
1768   EqualityNodeId classId = eqNode.getFind();
1769 
1770   // Possibly existing set of triggers
1771   TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
1772   if (triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag)) {
1773     // If the term already is in the equivalence class that a tagged representative, just notify
1774     if (d_performNotify) {
1775       EqualityNodeId triggerId = getTriggerTermSet(triggerSetRef).getTrigger(tag);
1776       Debug("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << "): already have this trigger in class with " << d_nodes[triggerId] << std::endl;
1777       if (eqNodeId != triggerId && !d_notify.eqNotifyTriggerTermEquality(tag, t, d_nodes[triggerId], true)) {
1778         d_done = true;
1779       }
1780     }
1781   } else {
1782 
1783     // Check for disequalities by going through the equivalence class looking for equalities in the
1784     // uselists that have been asserted to false. All the representatives appearing on the other
1785     // side of such disequalities, that have the tag on, are put in a set.
1786     TaggedEqualitiesSet disequalitiesToNotify;
1787     Theory::Set tags = Theory::setInsert(tag);
1788     getDisequalities(!d_isConstant[classId], classId, tags, disequalitiesToNotify);
1789 
1790     // Trigger data
1791     Theory::Set newSetTags;
1792     EqualityNodeId newSetTriggers[THEORY_LAST];
1793     unsigned newSetTriggersSize;
1794 
1795     // Setup the data for the new set
1796     if (triggerSetRef != null_set_id) {
1797       // Get the existing set
1798       TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
1799       // Initialize the new set for copy/insert
1800       newSetTags = Theory::setInsert(tag, triggerSet.tags);
1801       newSetTriggersSize = 0;
1802       // Copy into to new one, and insert the new tag/id
1803       unsigned i = 0;
1804       Theory::Set tags = newSetTags;
1805       TheoryId current;
1806       while ((current = Theory::setPop(tags)) != THEORY_LAST) {
1807         // Remove from the tags
1808         tags = Theory::setRemove(current, tags);
1809         // Insert the id into the triggers
1810         newSetTriggers[newSetTriggersSize++] =
1811           current == tag ? eqNodeId : triggerSet.triggers[i++];
1812       }
1813     } else {
1814       // Setup a singleton
1815       newSetTags = Theory::setInsert(tag);
1816       newSetTriggers[0] = eqNodeId;
1817       newSetTriggersSize = 1;
1818     }
1819 
1820     // Add it to the list for backtracking
1821     d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef));
1822     d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
1823     // Mark the the new set as a trigger
1824     d_nodeIndividualTrigger[classId] = triggerSetRef = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize);
1825 
1826     // Propagate trigger term disequalities we remembered
1827     Debug("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << "): propagating " << disequalitiesToNotify.size() << " disequalities " << std::endl;
1828     propagateTriggerTermDisequalities(tags, triggerSetRef, disequalitiesToNotify);
1829   }
1830 }
1831 
isTriggerTerm(TNode t,TheoryId tag) const1832 bool EqualityEngine::isTriggerTerm(TNode t, TheoryId tag) const {
1833   if (!hasTerm(t)) return false;
1834   EqualityNodeId classId = getEqualityNode(t).getFind();
1835   TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId];
1836   return triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag);
1837 }
1838 
1839 
getTriggerTermRepresentative(TNode t,TheoryId tag) const1840 TNode EqualityEngine::getTriggerTermRepresentative(TNode t, TheoryId tag) const {
1841   Assert(isTriggerTerm(t, tag));
1842   EqualityNodeId classId = getEqualityNode(t).getFind();
1843   const TriggerTermSet& triggerSet = getTriggerTermSet(d_nodeIndividualTrigger[classId]);
1844   unsigned i = 0;
1845   Theory::Set tags = triggerSet.tags;
1846   while (Theory::setPop(tags) != tag) {
1847     ++ i;
1848   }
1849   return d_nodes[triggerSet.triggers[i]];
1850 }
1851 
storeApplicationLookup(FunctionApplication & funNormalized,EqualityNodeId funId)1852 void EqualityEngine::storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId) {
1853   Assert(d_applicationLookup.find(funNormalized) == d_applicationLookup.end());
1854   d_applicationLookup[funNormalized] = funId;
1855   d_applicationLookups.push_back(funNormalized);
1856   d_applicationLookupsCount = d_applicationLookupsCount + 1;
1857   Debug("equality::backtrack") << "d_applicationLookupsCount = " << d_applicationLookupsCount << std::endl;
1858   Debug("equality::backtrack") << "d_applicationLookups.size() = " << d_applicationLookups.size() << std::endl;
1859   Assert(d_applicationLookupsCount == d_applicationLookups.size());
1860 
1861   // If an equality over constants we merge to false
1862   if (funNormalized.isEquality()) {
1863     if (funNormalized.a == funNormalized.b) {
1864       enqueue(MergeCandidate(funId, d_trueId, MERGED_THROUGH_REFLEXIVITY, TNode::null()));
1865     } else if (d_isConstant[funNormalized.a] && d_isConstant[funNormalized.b]) {
1866       enqueue(MergeCandidate(funId, d_falseId, MERGED_THROUGH_CONSTANTS, TNode::null()));
1867     }
1868   }
1869 }
1870 
getUseListTerms(TNode t,std::set<TNode> & output)1871 void EqualityEngine::getUseListTerms(TNode t, std::set<TNode>& output) {
1872   if (hasTerm(t)) {
1873     // Get the equivalence class
1874     EqualityNodeId classId = getEqualityNode(t).getFind();
1875     // Go through the equivalence class and get where t is used in
1876     EqualityNodeId currentId = classId;
1877     do {
1878       // Get the current node
1879       EqualityNode& currentNode = getEqualityNode(currentId);
1880       // Go through the use-list
1881       UseListNodeId currentUseId = currentNode.getUseList();
1882       while (currentUseId != null_uselist_id) {
1883         // Get the node of the use list
1884         UseListNode& useNode = d_useListNodes[currentUseId];
1885         // Get the function application
1886         EqualityNodeId funId = useNode.getApplicationId();
1887         output.insert(d_nodes[funId]);
1888         // Go to the next one in the use list
1889         currentUseId = useNode.getNext();
1890       }
1891       // Move to the next node
1892       currentId = currentNode.getNext();
1893     } while (currentId != classId);
1894   }
1895 }
1896 
newTriggerTermSet(Theory::Set newSetTags,EqualityNodeId * newSetTriggers,unsigned newSetTriggersSize)1897 EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet(Theory::Set newSetTags, EqualityNodeId* newSetTriggers, unsigned newSetTriggersSize) {
1898   // Size of the required set
1899   size_t size = sizeof(TriggerTermSet) + newSetTriggersSize*sizeof(EqualityNodeId);
1900   // Align the size
1901   size = (size + 7) & ~((size_t)7);
1902   // Reallocate if necessary
1903   if (d_triggerDatabaseSize + size > d_triggerDatabaseAllocatedSize) {
1904     d_triggerDatabaseAllocatedSize *= 2;
1905     d_triggerDatabase = (char*) realloc(d_triggerDatabase, d_triggerDatabaseAllocatedSize);
1906   }
1907   // New reference
1908   TriggerTermSetRef newTriggerSetRef = d_triggerDatabaseSize;
1909   // Update the size
1910   d_triggerDatabaseSize = d_triggerDatabaseSize + size;
1911   // Copy the information
1912   TriggerTermSet& newSet = getTriggerTermSet(newTriggerSetRef);
1913   newSet.tags = newSetTags;
1914   for (unsigned i = 0; i < newSetTriggersSize; ++i) {
1915     newSet.triggers[i] = newSetTriggers[i];
1916   }
1917   // Return the new reference
1918   return newTriggerSetRef;
1919 }
1920 
hasPropagatedDisequality(EqualityNodeId lhsId,EqualityNodeId rhsId) const1921 bool EqualityEngine::hasPropagatedDisequality(EqualityNodeId lhsId, EqualityNodeId rhsId) const {
1922   EqualityPair eq(lhsId, rhsId);
1923   bool propagated = d_propagatedDisequalities.find(eq) != d_propagatedDisequalities.end();
1924 #ifdef CVC4_ASSERTIONS
1925   bool stored = d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end();
1926   Assert(propagated == stored, "These two should be in sync");
1927 #endif
1928   Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (propagated ? "true" : "false") << std::endl;
1929   return propagated;
1930 }
1931 
hasPropagatedDisequality(TheoryId tag,EqualityNodeId lhsId,EqualityNodeId rhsId) const1932 bool EqualityEngine::hasPropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) const {
1933 
1934   EqualityPair eq(lhsId, rhsId);
1935 
1936   PropagatedDisequalitiesMap::const_iterator it = d_propagatedDisequalities.find(eq);
1937   if (it == d_propagatedDisequalities.end()) {
1938     Assert(d_disequalityReasonsMap.find(eq) == d_disequalityReasonsMap.end(), "Why do we have a proof if not propagated");
1939     Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => false" << std::endl;
1940     return false;
1941   }
1942   Assert(d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end(), "We propagated but there is no proof");
1943   bool result = Theory::setContains(tag, (*it).second);
1944   Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (result ? "true" : "false") << std::endl;
1945   return result;
1946 }
1947 
1948 
storePropagatedDisequality(TheoryId tag,EqualityNodeId lhsId,EqualityNodeId rhsId)1949 void EqualityEngine::storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) {
1950 
1951   Assert(!hasPropagatedDisequality(tag, lhsId, rhsId), "Check before you store it");
1952   Assert(lhsId != rhsId, "Wow, wtf!");
1953 
1954   Debug("equality::disequality") << d_name << "::eq::storePropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ")" << std::endl;
1955 
1956   EqualityPair pair1(lhsId, rhsId);
1957   EqualityPair pair2(rhsId, lhsId);
1958 
1959   // Store the fact that we've propagated this already
1960   Theory::Set notified = 0;
1961   PropagatedDisequalitiesMap::const_iterator find = d_propagatedDisequalities.find(pair1);
1962   if (find == d_propagatedDisequalities.end()) {
1963     notified = Theory::setInsert(tag);
1964   } else {
1965     notified = Theory::setInsert(tag, (*find).second);
1966   }
1967   d_propagatedDisequalities[pair1] = notified;
1968   d_propagatedDisequalities[pair2] = notified;
1969 
1970   // Store the proof if provided
1971   if (d_deducedDisequalityReasons.size() > d_deducedDisequalityReasonsSize) {
1972     Debug("equality::disequality") << d_name << "::eq::storePropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << "): storing proof" << std::endl;
1973     Assert(d_disequalityReasonsMap.find(pair1) == d_disequalityReasonsMap.end(), "There can't be a proof if you're adding a new one");
1974     DisequalityReasonRef ref(d_deducedDisequalityReasonsSize, d_deducedDisequalityReasons.size());
1975 #ifdef CVC4_ASSERTIONS
1976     // Check that the reasons are valid
1977     for (unsigned i = ref.mergesStart; i < ref.mergesEnd; ++ i) {
1978       Assert(getEqualityNode(d_deducedDisequalityReasons[i].first).getFind() == getEqualityNode(d_deducedDisequalityReasons[i].second).getFind());
1979     }
1980 #endif
1981     if (Debug.isOn("equality::disequality")) {
1982       for (unsigned i = ref.mergesStart; i < ref.mergesEnd; ++ i) {
1983         TNode lhs = d_nodes[d_deducedDisequalityReasons[i].first];
1984         TNode rhs = d_nodes[d_deducedDisequalityReasons[i].second];
1985         Debug("equality::disequality") << d_name << "::eq::storePropagatedDisequality(): because " << lhs << " == " << rhs << std::endl;
1986       }
1987 
1988     }
1989 
1990     // Store for backtracking
1991     d_deducedDisequalities.push_back(pair1);
1992     d_deducedDisequalitiesSize = d_deducedDisequalities.size();
1993     d_deducedDisequalityReasonsSize = d_deducedDisequalityReasons.size();
1994     // Store the proof reference
1995     d_disequalityReasonsMap[pair1] = ref;
1996     d_disequalityReasonsMap[pair2] = ref;
1997   } else {
1998     Assert(d_disequalityReasonsMap.find(pair1) != d_disequalityReasonsMap.end(), "You must provide a proof initially");
1999   }
2000 }
2001 
getDisequalities(bool allowConstants,EqualityNodeId classId,Theory::Set inputTags,TaggedEqualitiesSet & out)2002 void EqualityEngine::getDisequalities(bool allowConstants, EqualityNodeId classId, Theory::Set inputTags, TaggedEqualitiesSet& out) {
2003   // Must be empty on input
2004   Assert(out.size() == 0);
2005   // The class we are looking for, shouldn't have any of the tags we are looking for already set
2006   Assert(d_nodeIndividualTrigger[classId] == null_set_id || Theory::setIntersection(getTriggerTermSet(d_nodeIndividualTrigger[classId]).tags, inputTags) == 0);
2007 
2008   if (inputTags == 0) {
2009     return;
2010   }
2011 
2012   // Set of already (through disequalities) visited equivalence classes
2013   std::set<EqualityNodeId> alreadyVisited;
2014 
2015   // Go through the equivalence class
2016   EqualityNodeId currentId = classId;
2017   do {
2018 
2019     Debug("equality::trigger") << d_name << "::getDisequalities() : going through uselist of " << d_nodes[currentId] << std::endl;
2020 
2021     // Current node in the equivalence class
2022     EqualityNode& currentNode = getEqualityNode(currentId);
2023 
2024     // Go through the uselist and look for disequalities
2025     UseListNodeId currentUseId = currentNode.getUseList();
2026     while (currentUseId != null_uselist_id) {
2027       UseListNode& useListNode = d_useListNodes[currentUseId];
2028       EqualityNodeId funId = useListNode.getApplicationId();
2029 
2030       Debug("equality::trigger") << d_name << "::getDisequalities() : checking " << d_nodes[funId] << std::endl;
2031 
2032       const FunctionApplication& fun = d_applications[useListNode.getApplicationId()].original;
2033       // If it's an equality asserted to false, we do the work
2034       if (fun.isEquality() && getEqualityNode(funId).getFind() == getEqualityNode(d_false).getFind()) {
2035         // Get the other equality member
2036         bool lhs = false;
2037         EqualityNodeId toCompare = fun.b;
2038         if (toCompare == currentId) {
2039           toCompare = fun.a;
2040           lhs = true;
2041         }
2042         // Representative of the other member
2043         EqualityNodeId toCompareRep = getEqualityNode(toCompare).getFind();
2044         if (toCompareRep == classId) {
2045           // We're in conflict, so we will send it out from merge
2046           out.clear();
2047           return;
2048         }
2049         // Check if we already have this one
2050         if (alreadyVisited.count(toCompareRep) == 0) {
2051           // Mark as visited
2052           alreadyVisited.insert(toCompareRep);
2053           // Get the trigger set
2054           TriggerTermSetRef toCompareTriggerSetRef = d_nodeIndividualTrigger[toCompareRep];
2055           // We only care if we're not both constants and there are trigger terms in the other class
2056           if ((allowConstants || !d_isConstant[toCompareRep]) && toCompareTriggerSetRef != null_set_id) {
2057             // Tags of the other gey
2058             TriggerTermSet& toCompareTriggerSet = getTriggerTermSet(toCompareTriggerSetRef);
2059             // We only care if there are things in inputTags that is also in toCompareTags
2060             Theory::Set commonTags = Theory::setIntersection(inputTags, toCompareTriggerSet.tags);
2061             if (commonTags) {
2062               out.push_back(TaggedEquality(funId, toCompareTriggerSetRef, lhs));
2063             }
2064           }
2065         }
2066       }
2067       // Go to the next one in the use list
2068       currentUseId = useListNode.getNext();
2069     }
2070     // Next in equivalence class
2071     currentId = currentNode.getNext();
2072   } while (!d_done && currentId != classId);
2073 
2074 }
2075 
propagateTriggerTermDisequalities(Theory::Set tags,TriggerTermSetRef triggerSetRef,const TaggedEqualitiesSet & disequalitiesToNotify)2076 bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify) {
2077 
2078   // No tags, no food
2079   if (!tags) {
2080     return !d_done;
2081   }
2082 
2083   Assert(triggerSetRef != null_set_id);
2084 
2085   // This is the class trigger set
2086   const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
2087   // Go through the disequalities and notify
2088   TaggedEqualitiesSet::const_iterator it = disequalitiesToNotify.begin();
2089   TaggedEqualitiesSet::const_iterator it_end = disequalitiesToNotify.end();
2090   for (; !d_done && it != it_end; ++ it) {
2091     // The information about the equality that is asserted to false
2092     const TaggedEquality& disequalityInfo = *it;
2093     const TriggerTermSet& disequalityTriggerSet = getTriggerTermSet(disequalityInfo.triggerSetRef);
2094     Theory::Set commonTags = Theory::setIntersection(disequalityTriggerSet.tags, tags);
2095     Assert(commonTags);
2096     // This is the actual function
2097     const FunctionApplication& fun = d_applications[disequalityInfo.equalityId].original;
2098     // Figure out who we are comparing to in the original equality
2099     EqualityNodeId toCompare = disequalityInfo.lhs ? fun.a : fun.b;
2100     EqualityNodeId myCompare = disequalityInfo.lhs ? fun.b : fun.a;
2101     if (getEqualityNode(toCompare).getFind() == getEqualityNode(myCompare).getFind()) {
2102       // We're propagating a != a, which means we're inconsistent, just bail and let it go into
2103       // a regular conflict
2104       return !d_done;
2105     }
2106     // Go through the tags, and add the disequalities
2107     TheoryId currentTag;
2108     while (!d_done && ((currentTag = Theory::setPop(commonTags)) != THEORY_LAST)) {
2109       // Get the tag representative
2110       EqualityNodeId tagRep = disequalityTriggerSet.getTrigger(currentTag);
2111       EqualityNodeId myRep = triggerSet.getTrigger(currentTag);
2112       // Propagate
2113       if (!hasPropagatedDisequality(currentTag, myRep, tagRep)) {
2114         // Construct the proof if not there already
2115         if (!hasPropagatedDisequality(myRep, tagRep)) {
2116           d_deducedDisequalityReasons.push_back(EqualityPair(myCompare, myRep));
2117           d_deducedDisequalityReasons.push_back(EqualityPair(toCompare, tagRep));
2118           d_deducedDisequalityReasons.push_back(EqualityPair(disequalityInfo.equalityId, d_falseId));
2119         }
2120         // Store the propagation
2121         storePropagatedDisequality(currentTag, myRep, tagRep);
2122         // Notify
2123         if (d_performNotify) {
2124           if (!d_notify.eqNotifyTriggerTermEquality(currentTag, d_nodes[myRep], d_nodes[tagRep], false)) {
2125             d_done = true;
2126           }
2127         }
2128       }
2129     }
2130   }
2131 
2132   return !d_done;
2133 }
2134 
EqClassesIterator()2135 EqClassesIterator::EqClassesIterator() :
2136     d_ee(NULL), d_it(0) {
2137 }
2138 
EqClassesIterator(const eq::EqualityEngine * ee)2139 EqClassesIterator::EqClassesIterator(const eq::EqualityEngine* ee)
2140 : d_ee(ee)
2141 {
2142   Assert(d_ee->consistent());
2143   d_it = 0;
2144   // Go to the first non-internal node that is it's own representative
2145   if(d_it < d_ee->d_nodesCount && (d_ee->d_isInternal[d_it] || d_ee->getEqualityNode(d_it).getFind() != d_it)) {
2146     ++d_it;
2147   }
2148 }
2149 
operator *() const2150 Node EqClassesIterator::operator*() const {
2151   return d_ee->d_nodes[d_it];
2152 }
2153 
operator ==(const EqClassesIterator & i) const2154 bool EqClassesIterator::operator==(const EqClassesIterator& i) const {
2155   return d_ee == i.d_ee && d_it == i.d_it;
2156 }
2157 
operator !=(const EqClassesIterator & i) const2158 bool EqClassesIterator::operator!=(const EqClassesIterator& i) const {
2159   return !(*this == i);
2160 }
2161 
operator ++()2162 EqClassesIterator& EqClassesIterator::operator++() {
2163   ++d_it;
2164   while(d_it < d_ee->d_nodesCount && (d_ee->d_isInternal[d_it] || d_ee->getEqualityNode(d_it).getFind() != d_it)) {
2165     ++d_it;
2166   }
2167   return *this;
2168 }
2169 
operator ++(int)2170 EqClassesIterator EqClassesIterator::operator++(int) {
2171   EqClassesIterator i = *this;
2172   ++*this;
2173   return i;
2174 }
2175 
isFinished() const2176 bool EqClassesIterator::isFinished() const {
2177   return d_it >= d_ee->d_nodesCount;
2178 }
2179 
EqClassIterator()2180 EqClassIterator::EqClassIterator()
2181 : d_ee(NULL)
2182 , d_start(null_id)
2183 , d_current(null_id)
2184 {}
2185 
EqClassIterator(Node eqc,const eq::EqualityEngine * ee)2186 EqClassIterator::EqClassIterator(Node eqc, const eq::EqualityEngine* ee)
2187 : d_ee(ee)
2188 {
2189   Assert(d_ee->consistent());
2190   d_current = d_start = d_ee->getNodeId(eqc);
2191   Assert(d_start == d_ee->getEqualityNode(d_start).getFind());
2192   Assert (!d_ee->d_isInternal[d_start]);
2193 }
2194 
operator *() const2195 Node EqClassIterator::operator*() const {
2196   return d_ee->d_nodes[d_current];
2197 }
2198 
operator ==(const EqClassIterator & i) const2199 bool EqClassIterator::operator==(const EqClassIterator& i) const {
2200   return d_ee == i.d_ee && d_current == i.d_current;
2201 }
2202 
operator !=(const EqClassIterator & i) const2203 bool EqClassIterator::operator!=(const EqClassIterator& i) const {
2204   return !(*this == i);
2205 }
2206 
operator ++()2207 EqClassIterator& EqClassIterator::operator++() {
2208   Assert(!isFinished());
2209 
2210   Assert(d_start == d_ee->getEqualityNode(d_current).getFind());
2211   Assert(!d_ee->d_isInternal[d_current]);
2212 
2213   // Find the next one
2214   do {
2215     d_current = d_ee->getEqualityNode(d_current).getNext();
2216   } while(d_ee->d_isInternal[d_current]);
2217 
2218   Assert(d_start == d_ee->getEqualityNode(d_current).getFind());
2219   Assert(!d_ee->d_isInternal[d_current]);
2220 
2221   if(d_current == d_start) {
2222     // we end when we have cycled back to the original representative
2223     d_current = null_id;
2224   }
2225   return *this;
2226 }
2227 
operator ++(int)2228 EqClassIterator EqClassIterator::operator++(int) {
2229   EqClassIterator i = *this;
2230   ++*this;
2231   return i;
2232 }
2233 
isFinished() const2234 bool EqClassIterator::isFinished() const {
2235   return d_current == null_id;
2236 }
2237 
debug_print(const char * c,unsigned tb,PrettyPrinter * prettyPrinter) const2238 void EqProof::debug_print(const char* c, unsigned tb, PrettyPrinter* prettyPrinter) const {
2239   for(unsigned i=0; i<tb; i++) { Debug( c ) << "  "; }
2240 
2241   if (prettyPrinter)
2242     Debug( c ) << prettyPrinter->printTag(d_id);
2243   else
2244     Debug( c ) << d_id;
2245 
2246   Debug( c ) << "(";
2247   if( !d_children.empty() || !d_node.isNull() ){
2248     if( !d_node.isNull() ){
2249       Debug( c ) << std::endl;
2250       for( unsigned i=0; i<tb+1; i++ ) { Debug( c ) << "  "; }
2251       Debug( c ) << d_node;
2252     }
2253     for( unsigned i=0; i<d_children.size(); i++ ){
2254       if( i>0 || !d_node.isNull() ) Debug( c ) << ",";
2255       Debug( c ) << std::endl;
2256       d_children[i]->debug_print( c, tb+1, prettyPrinter );
2257     }
2258   }
2259   Debug( c ) << ")" << std::endl;
2260 }
2261 
2262 } // Namespace uf
2263 } // Namespace theory
2264 } // Namespace CVC4
2265