1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Dejan Jovanovic, Andrew Reynolds, Haniel Barbosa |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* [[ Add one-line brief description here ]] |
13 |
|
* |
14 |
|
* |
15 |
|
* [[ Add lengthier description here ]] |
16 |
|
* \todo document this file |
17 |
|
*/ |
18 |
|
|
19 |
|
#include "theory/uf/equality_engine.h" |
20 |
|
|
21 |
|
#include "base/output.h" |
22 |
|
#include "options/smt_options.h" |
23 |
|
#include "smt/smt_statistics_registry.h" |
24 |
|
#include "theory/rewriter.h" |
25 |
|
#include "theory/uf/eq_proof.h" |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
namespace theory { |
29 |
|
namespace eq { |
30 |
|
|
31 |
131617 |
EqualityEngine::Statistics::Statistics(const std::string& name) |
32 |
263234 |
: d_mergesCount(smtStatisticsRegistry().registerInt(name + "mergesCount")), |
33 |
263234 |
d_termsCount(smtStatisticsRegistry().registerInt(name + "termsCount")), |
34 |
|
d_functionTermsCount( |
35 |
263234 |
smtStatisticsRegistry().registerInt(name + "functionTermsCount")), |
36 |
|
d_constantTermsCount( |
37 |
526468 |
smtStatisticsRegistry().registerInt(name + "constantTermsCount")) |
38 |
|
{ |
39 |
131617 |
} |
40 |
|
|
41 |
|
/** |
42 |
|
* Data used in the BFS search through the equality graph. |
43 |
|
*/ |
44 |
|
struct BfsData { |
45 |
|
// The current node |
46 |
|
EqualityNodeId d_nodeId; |
47 |
|
// The index of the edge we traversed |
48 |
|
EqualityEdgeId d_edgeId; |
49 |
|
// Index in the queue of the previous node. Shouldn't be too much of them, at most the size |
50 |
|
// of the biggest equivalence class |
51 |
|
size_t d_previousIndex; |
52 |
|
|
53 |
21273067 |
BfsData(EqualityNodeId nodeId = null_id, |
54 |
|
EqualityEdgeId edgeId = null_edge, |
55 |
|
size_t prev = 0) |
56 |
21273067 |
: d_nodeId(nodeId), d_edgeId(edgeId), d_previousIndex(prev) |
57 |
|
{ |
58 |
21273067 |
} |
59 |
|
}; |
60 |
|
|
61 |
|
class ScopedBool { |
62 |
|
bool& d_watch; |
63 |
|
bool d_oldValue; |
64 |
|
|
65 |
|
public: |
66 |
19203833 |
ScopedBool(bool& watch, bool newValue) : d_watch(watch), d_oldValue(watch) |
67 |
|
{ |
68 |
19203833 |
d_watch = newValue; |
69 |
19203833 |
} |
70 |
19203833 |
~ScopedBool() { d_watch = d_oldValue; } |
71 |
|
}; |
72 |
|
|
73 |
9245 |
EqualityEngineNotifyNone EqualityEngine::s_notifyNone; |
74 |
|
|
75 |
131617 |
void EqualityEngine::init() { |
76 |
131617 |
Debug("equality") << "EqualityEdge::EqualityEngine(): id_null = " << +null_id << std::endl; |
77 |
131617 |
Debug("equality") << "EqualityEdge::EqualityEngine(): edge_null = " << +null_edge << std::endl; |
78 |
131617 |
Debug("equality") << "EqualityEdge::EqualityEngine(): trigger_null = " << +null_trigger << std::endl; |
79 |
|
|
80 |
|
// If we are not at level zero when we initialize this equality engine, we |
81 |
|
// may remove true/false from the equality engine when we pop to level zero, |
82 |
|
// which leads to issues. |
83 |
131617 |
Assert(d_context->getLevel() == 0); |
84 |
|
|
85 |
131617 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
86 |
131617 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
87 |
|
|
88 |
131617 |
d_triggerDatabaseAllocatedSize = 100000; |
89 |
131617 |
d_triggerDatabase = (char*) malloc(d_triggerDatabaseAllocatedSize); |
90 |
|
|
91 |
|
//We can't notify during the initialization because it notifies |
92 |
|
// QuantifiersEngine.AddTermToDatabase that try to access to the uf |
93 |
|
// instantiator that currently doesn't exist. |
94 |
263234 |
ScopedBool sb(d_performNotify, false); |
95 |
131617 |
addTermInternal(d_true); |
96 |
131617 |
addTermInternal(d_false); |
97 |
|
|
98 |
131617 |
d_trueId = getNodeId(d_true); |
99 |
131617 |
d_falseId = getNodeId(d_false); |
100 |
131617 |
} |
101 |
|
|
102 |
376924 |
EqualityEngine::~EqualityEngine() { |
103 |
131617 |
free(d_triggerDatabase); |
104 |
245307 |
} |
105 |
|
|
106 |
26869 |
EqualityEngine::EqualityEngine(context::Context* context, |
107 |
|
std::string name, |
108 |
|
bool constantsAreTriggers, |
109 |
26869 |
bool anyTermTriggers) |
110 |
|
: ContextNotifyObj(context), |
111 |
|
d_masterEqualityEngine(0), |
112 |
|
d_context(context), |
113 |
|
d_done(context, false), |
114 |
|
d_performNotify(true), |
115 |
|
d_notify(s_notifyNone), |
116 |
|
d_applicationLookupsCount(context, 0), |
117 |
|
d_nodesCount(context, 0), |
118 |
|
d_assertedEqualitiesCount(context, 0), |
119 |
|
d_equalityTriggersCount(context, 0), |
120 |
|
d_subtermEvaluatesSize(context, 0), |
121 |
53738 |
d_stats(name + "::"), |
122 |
|
d_inPropagate(false), |
123 |
|
d_constantsAreTriggers(constantsAreTriggers), |
124 |
|
d_anyTermsAreTriggers(anyTermTriggers), |
125 |
|
d_triggerDatabaseSize(context, 0), |
126 |
|
d_triggerTermSetUpdatesSize(context, 0), |
127 |
|
d_deducedDisequalitiesSize(context, 0), |
128 |
|
d_deducedDisequalityReasonsSize(context, 0), |
129 |
|
d_propagatedDisequalities(context), |
130 |
80607 |
d_name(name) |
131 |
|
{ |
132 |
26869 |
init(); |
133 |
26869 |
} |
134 |
|
|
135 |
104748 |
EqualityEngine::EqualityEngine(EqualityEngineNotify& notify, |
136 |
|
context::Context* context, |
137 |
|
std::string name, |
138 |
|
bool constantsAreTriggers, |
139 |
104748 |
bool anyTermTriggers) |
140 |
|
: ContextNotifyObj(context), |
141 |
|
d_masterEqualityEngine(0), |
142 |
|
d_context(context), |
143 |
|
d_done(context, false), |
144 |
|
d_performNotify(true), |
145 |
|
d_notify(notify), |
146 |
|
d_applicationLookupsCount(context, 0), |
147 |
|
d_nodesCount(context, 0), |
148 |
|
d_assertedEqualitiesCount(context, 0), |
149 |
|
d_equalityTriggersCount(context, 0), |
150 |
|
d_subtermEvaluatesSize(context, 0), |
151 |
209496 |
d_stats(name + "::"), |
152 |
|
d_inPropagate(false), |
153 |
|
d_constantsAreTriggers(constantsAreTriggers), |
154 |
|
d_anyTermsAreTriggers(anyTermTriggers), |
155 |
|
d_triggerDatabaseSize(context, 0), |
156 |
|
d_triggerTermSetUpdatesSize(context, 0), |
157 |
|
d_deducedDisequalitiesSize(context, 0), |
158 |
|
d_deducedDisequalityReasonsSize(context, 0), |
159 |
|
d_propagatedDisequalities(context), |
160 |
314244 |
d_name(name) |
161 |
|
{ |
162 |
104748 |
init(); |
163 |
104748 |
} |
164 |
|
|
165 |
62856 |
void EqualityEngine::setMasterEqualityEngine(EqualityEngine* master) { |
166 |
62856 |
Assert(d_masterEqualityEngine == 0); |
167 |
62856 |
d_masterEqualityEngine = master; |
168 |
62856 |
} |
169 |
|
|
170 |
28713115 |
void EqualityEngine::enqueue(const MergeCandidate& candidate, bool back) { |
171 |
57426230 |
Debug("equality") << d_name << "::eq::enqueue({" << candidate.d_t1Id << "} " |
172 |
28713115 |
<< d_nodes[candidate.d_t1Id] << ", {" << candidate.d_t2Id |
173 |
28713115 |
<< "} " << d_nodes[candidate.d_t2Id] << ", " |
174 |
57426230 |
<< static_cast<MergeReasonType>(candidate.d_type) |
175 |
28713115 |
<< "). reason: " << candidate.d_reason << std::endl; |
176 |
28713115 |
if (back) { |
177 |
28713115 |
d_propagationQueue.push_back(candidate); |
178 |
|
} else { |
179 |
|
d_propagationQueue.push_front(candidate); |
180 |
|
} |
181 |
28713115 |
} |
182 |
|
|
183 |
2822818 |
EqualityNodeId EqualityEngine::newApplicationNode(TNode original, EqualityNodeId t1, EqualityNodeId t2, FunctionApplicationType type) { |
184 |
5645636 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original |
185 |
2822818 |
<< ", {" << t1 << "} " << d_nodes[t1] << ", {" << t2 << "} " |
186 |
2822818 |
<< d_nodes[t2] << ")" << std::endl; |
187 |
|
|
188 |
2822818 |
++d_stats.d_functionTermsCount; |
189 |
|
|
190 |
|
// Get another id for this |
191 |
2822818 |
EqualityNodeId funId = newNode(original); |
192 |
2822818 |
FunctionApplication funOriginal(type, t1, t2); |
193 |
|
// The function application we're creating |
194 |
2822818 |
EqualityNodeId t1ClassId = getEqualityNode(t1).getFind(); |
195 |
2822818 |
EqualityNodeId t2ClassId = getEqualityNode(t2).getFind(); |
196 |
2822818 |
FunctionApplication funNormalized(type, t1ClassId, t2ClassId); |
197 |
|
|
198 |
5645636 |
Debug("equality") << d_name << "::eq::newApplicationNode: funOriginal: (" |
199 |
2822818 |
<< type << " " << d_nodes[t1] << " " << d_nodes[t2] |
200 |
2822818 |
<< "), funNorm: (" << type << " " << d_nodes[t1ClassId] |
201 |
2822818 |
<< " " << d_nodes[t2ClassId] << ")\n"; |
202 |
|
|
203 |
|
// We add the original version |
204 |
2822818 |
d_applications[funId] = FunctionApplicationPair(funOriginal, funNormalized); |
205 |
|
|
206 |
|
// Add the lookup data, if it's not already there |
207 |
2822818 |
ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized); |
208 |
2822818 |
if (find == d_applicationLookup.end()) { |
209 |
5093708 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original |
210 |
2546854 |
<< ", " << t1 << ", " << t2 |
211 |
2546854 |
<< "): no lookup, setting up funNorm: (" << type << " " |
212 |
2546854 |
<< d_nodes[t1ClassId] << " " << d_nodes[t2ClassId] |
213 |
2546854 |
<< ") => " << funId << std::endl; |
214 |
|
// Mark the normalization to the lookup |
215 |
2546854 |
storeApplicationLookup(funNormalized, funId); |
216 |
|
} else { |
217 |
|
// If it's there, we need to merge these two |
218 |
275964 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): lookup exists, adding to queue" << std::endl; |
219 |
275964 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): lookup = " << d_nodes[find->second] << std::endl; |
220 |
275964 |
enqueue(MergeCandidate(funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null())); |
221 |
|
} |
222 |
|
|
223 |
|
// Add to the use lists |
224 |
2822818 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): adding " << original << " to the uselist of " << d_nodes[t1] << std::endl; |
225 |
2822818 |
d_equalityNodes[t1].usedIn(funId, d_useListNodes); |
226 |
2822818 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): adding " << original << " to the uselist of " << d_nodes[t2] << std::endl; |
227 |
2822818 |
d_equalityNodes[t2].usedIn(funId, d_useListNodes); |
228 |
|
|
229 |
|
// Return the new id |
230 |
2822818 |
Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << ") => " << funId << std::endl; |
231 |
|
|
232 |
2822818 |
return funId; |
233 |
|
} |
234 |
|
|
235 |
6864490 |
EqualityNodeId EqualityEngine::newNode(TNode node) { |
236 |
|
|
237 |
6864490 |
Debug("equality") << d_name << "::eq::newNode(" << node << ")" << std::endl; |
238 |
|
|
239 |
6864490 |
++d_stats.d_termsCount; |
240 |
|
|
241 |
|
// Register the new id of the term |
242 |
6864490 |
EqualityNodeId newId = d_nodes.size(); |
243 |
6864490 |
d_nodeIds[node] = newId; |
244 |
|
// Add the node to it's position |
245 |
6864490 |
d_nodes.push_back(node); |
246 |
|
// Note if this is an application or not |
247 |
6864490 |
d_applications.push_back(FunctionApplicationPair()); |
248 |
|
// Add the trigger list for this node |
249 |
6864490 |
d_nodeTriggers.push_back(+null_trigger); |
250 |
|
// Add it to the equality graph |
251 |
6864490 |
d_equalityGraph.push_back(+null_edge); |
252 |
|
// Mark the no-individual trigger |
253 |
6864490 |
d_nodeIndividualTrigger.push_back(+null_set_id); |
254 |
|
// Mark non-constant by default |
255 |
6864490 |
d_isConstant.push_back(false); |
256 |
|
// No terms to evaluate by defaul |
257 |
6864490 |
d_subtermsToEvaluate.push_back(0); |
258 |
|
// Mark equality nodes |
259 |
6864490 |
d_isEquality.push_back(false); |
260 |
|
// Mark the node as internal by default |
261 |
6864490 |
d_isInternal.push_back(true); |
262 |
|
// Add the equality node to the nodes |
263 |
6864490 |
d_equalityNodes.push_back(EqualityNode(newId)); |
264 |
|
|
265 |
|
// Increase the counters |
266 |
6864490 |
d_nodesCount = d_nodesCount + 1; |
267 |
|
|
268 |
6864490 |
Debug("equality") << d_name << "::eq::newNode(" << node << ") => " << newId << std::endl; |
269 |
|
|
270 |
6864490 |
return newId; |
271 |
|
} |
272 |
|
|
273 |
995144 |
void EqualityEngine::addFunctionKind(Kind fun, |
274 |
|
bool interpreted, |
275 |
|
bool extOperator) |
276 |
|
{ |
277 |
995144 |
d_congruenceKinds.set(fun); |
278 |
995144 |
if (fun != kind::EQUAL) |
279 |
|
{ |
280 |
995144 |
if (interpreted) |
281 |
|
{ |
282 |
500720 |
Debug("equality::evaluation") |
283 |
250360 |
<< d_name << "::eq::addFunctionKind(): " << fun << " is interpreted " |
284 |
250360 |
<< std::endl; |
285 |
250360 |
d_congruenceKindsInterpreted.set(fun); |
286 |
|
} |
287 |
995144 |
if (extOperator) |
288 |
|
{ |
289 |
816 |
Debug("equality::extoperator") |
290 |
408 |
<< d_name << "::eq::addFunctionKind(): " << fun |
291 |
408 |
<< " is an external operator kind " << std::endl; |
292 |
408 |
d_congruenceKindsExtOperators.set(fun); |
293 |
|
} |
294 |
|
} |
295 |
995144 |
} |
296 |
|
|
297 |
607218 |
void EqualityEngine::subtermEvaluates(EqualityNodeId id) { |
298 |
607218 |
Debug("equality::evaluation") << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): " << d_subtermsToEvaluate[id] << std::endl; |
299 |
607218 |
Assert(!d_isInternal[id]); |
300 |
607218 |
Assert(d_subtermsToEvaluate[id] > 0); |
301 |
607218 |
if ((-- d_subtermsToEvaluate[id]) == 0) { |
302 |
408886 |
d_evaluationQueue.push(id); |
303 |
|
} |
304 |
607218 |
d_subtermEvaluates.push_back(id); |
305 |
607218 |
d_subtermEvaluatesSize = d_subtermEvaluates.size(); |
306 |
607218 |
Debug("equality::evaluation") << d_name << "::eq::subtermEvaluates(" << d_nodes[id] << "): new " << d_subtermsToEvaluate[id] << std::endl; |
307 |
607218 |
} |
308 |
|
|
309 |
40516218 |
void EqualityEngine::addTermInternal(TNode t, bool isOperator) { |
310 |
|
|
311 |
40516218 |
Debug("equality") << d_name << "::eq::addTermInternal(" << t << ")" << std::endl; |
312 |
|
|
313 |
|
// If there already, we're done |
314 |
40516218 |
if (hasTerm(t)) { |
315 |
34239967 |
Debug("equality") << d_name << "::eq::addTermInternal(" << t << "): already there" << std::endl; |
316 |
68480261 |
return; |
317 |
|
} |
318 |
|
|
319 |
6276251 |
if (d_done) { |
320 |
327 |
return; |
321 |
|
} |
322 |
|
|
323 |
|
EqualityNodeId result; |
324 |
|
|
325 |
6275924 |
Kind tk = t.getKind(); |
326 |
6275924 |
if (tk == kind::EQUAL) |
327 |
|
{ |
328 |
1581207 |
addTermInternal(t[0]); |
329 |
1581207 |
addTermInternal(t[1]); |
330 |
1581207 |
EqualityNodeId t0id = getNodeId(t[0]); |
331 |
1581207 |
EqualityNodeId t1id = getNodeId(t[1]); |
332 |
1581207 |
result = newApplicationNode(t, t0id, t1id, APP_EQUALITY); |
333 |
1581207 |
d_isInternal[result] = false; |
334 |
1581207 |
d_isConstant[result] = false; |
335 |
|
} |
336 |
4694717 |
else if (t.getNumChildren() > 0 && d_congruenceKinds[tk]) |
337 |
|
{ |
338 |
1306090 |
TNode tOp = t.getOperator(); |
339 |
|
// Add the operator |
340 |
653045 |
addTermInternal(tOp, !isExternalOperatorKind(tk)); |
341 |
653045 |
result = getNodeId(tOp); |
342 |
|
// Add all the children and Curryfy |
343 |
653045 |
bool isInterpreted = isInterpretedFunctionKind(tk); |
344 |
1894656 |
for (unsigned i = 0; i < t.getNumChildren(); ++ i) { |
345 |
|
// Add the child |
346 |
1241611 |
addTermInternal(t[i]); |
347 |
1241611 |
EqualityNodeId tiId = getNodeId(t[i]); |
348 |
|
// Add the application |
349 |
1241611 |
result = newApplicationNode(t, result, tiId, isInterpreted ? APP_INTERPRETED : APP_UNINTERPRETED); |
350 |
|
} |
351 |
653045 |
d_isInternal[result] = false; |
352 |
653045 |
d_isConstant[result] = t.isConst(); |
353 |
|
// If interpreted, set the number of non-interpreted children |
354 |
653045 |
if (isInterpreted) { |
355 |
|
// How many children are not constants yet |
356 |
80304 |
d_subtermsToEvaluate[result] = t.getNumChildren(); |
357 |
251855 |
for (unsigned i = 0; i < t.getNumChildren(); ++ i) { |
358 |
171551 |
if (isConstant(getNodeId(t[i]))) { |
359 |
37890 |
Debug("equality::evaluation") << d_name << "::eq::addTermInternal(" << t << "): evaluates " << t[i] << std::endl; |
360 |
37890 |
subtermEvaluates(result); |
361 |
|
} |
362 |
|
} |
363 |
|
} |
364 |
|
} |
365 |
|
else |
366 |
|
{ |
367 |
|
// Otherwise we just create the new id |
368 |
4041672 |
result = newNode(t); |
369 |
|
// Is this an operator |
370 |
4041672 |
d_isInternal[result] = isOperator; |
371 |
4041672 |
d_isConstant[result] = !isOperator && t.isConst(); |
372 |
|
} |
373 |
|
|
374 |
6275924 |
if (tk == kind::EQUAL) |
375 |
|
{ |
376 |
|
// We set this here as this only applies to actual terms, not the |
377 |
|
// intermediate application terms |
378 |
1581207 |
d_isEquality[result] = true; |
379 |
|
} |
380 |
|
else |
381 |
|
{ |
382 |
|
// Notify e.g. the theory that owns this equality engine that there is a |
383 |
|
// new equivalence class. |
384 |
4694717 |
if (d_performNotify) |
385 |
|
{ |
386 |
4431483 |
d_notify.eqNotifyNewClass(t); |
387 |
|
} |
388 |
4694717 |
if (d_constantsAreTriggers && d_isConstant[result]) |
389 |
|
{ |
390 |
|
// Non-Boolean constants are trigger terms for all tags |
391 |
536280 |
EqualityNodeId tId = getNodeId(t); |
392 |
|
// Setup the new set |
393 |
536280 |
TheoryIdSet newSetTags = 0; |
394 |
|
EqualityNodeId newSetTriggers[THEORY_LAST]; |
395 |
536280 |
unsigned newSetTriggersSize = THEORY_LAST; |
396 |
7507920 |
for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST; |
397 |
|
++currentTheory) |
398 |
|
{ |
399 |
6971640 |
newSetTags = TheoryIdSetUtil::setInsert(currentTheory, newSetTags); |
400 |
6971640 |
newSetTriggers[currentTheory] = tId; |
401 |
|
} |
402 |
|
// Add it to the list for backtracking |
403 |
536280 |
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(tId, null_set_id)); |
404 |
536280 |
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1; |
405 |
|
// Mark the the new set as a trigger |
406 |
536280 |
d_nodeIndividualTrigger[tId] = |
407 |
536280 |
newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize); |
408 |
|
} |
409 |
|
} |
410 |
|
|
411 |
|
// If this is not an internal node, add it to the master |
412 |
6275924 |
if (d_masterEqualityEngine && !d_isInternal[result]) { |
413 |
1489917 |
d_masterEqualityEngine->addTermInternal(t); |
414 |
|
} |
415 |
|
|
416 |
|
// Empty the queue |
417 |
6275924 |
propagate(); |
418 |
|
|
419 |
6275924 |
Assert(hasTerm(t)); |
420 |
|
|
421 |
6275924 |
Debug("equality") << d_name << "::eq::addTermInternal(" << t << ") => " << result << std::endl; |
422 |
|
} |
423 |
|
|
424 |
421895972 |
bool EqualityEngine::hasTerm(TNode t) const { |
425 |
421895972 |
return d_nodeIds.find(t) != d_nodeIds.end(); |
426 |
|
} |
427 |
|
|
428 |
205266090 |
EqualityNodeId EqualityEngine::getNodeId(TNode node) const { |
429 |
205266090 |
Assert(hasTerm(node)) << node; |
430 |
205266090 |
return (*d_nodeIds.find(node)).second; |
431 |
|
} |
432 |
|
|
433 |
52504422 |
EqualityNode& EqualityEngine::getEqualityNode(TNode t) { |
434 |
52504422 |
return getEqualityNode(getNodeId(t)); |
435 |
|
} |
436 |
|
|
437 |
390440204 |
EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) { |
438 |
390440204 |
Assert(nodeId < d_equalityNodes.size()); |
439 |
390440204 |
return d_equalityNodes[nodeId]; |
440 |
|
} |
441 |
|
|
442 |
63279754 |
const EqualityNode& EqualityEngine::getEqualityNode(TNode t) const { |
443 |
63279754 |
return getEqualityNode(getNodeId(t)); |
444 |
|
} |
445 |
|
|
446 |
165038707 |
const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const { |
447 |
165038707 |
Assert(nodeId < d_equalityNodes.size()); |
448 |
165038707 |
return d_equalityNodes[nodeId]; |
449 |
|
} |
450 |
|
|
451 |
12860281 |
void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid) { |
452 |
25720562 |
Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 |
453 |
12860281 |
<< "), reason = " << reason |
454 |
25720562 |
<< ", pid = " << static_cast<MergeReasonType>(pid) |
455 |
12860281 |
<< std::endl; |
456 |
|
|
457 |
12860281 |
if (d_done) { |
458 |
63 |
return; |
459 |
|
} |
460 |
|
|
461 |
|
// Add the terms if they are not already in the database |
462 |
12860218 |
addTermInternal(t1); |
463 |
12860218 |
addTermInternal(t2); |
464 |
|
|
465 |
|
// Add to the queue and propagate |
466 |
12860218 |
EqualityNodeId t1Id = getNodeId(t1); |
467 |
12860218 |
EqualityNodeId t2Id = getNodeId(t2); |
468 |
12860218 |
enqueue(MergeCandidate(t1Id, t2Id, pid, reason)); |
469 |
|
} |
470 |
|
|
471 |
1355420 |
bool EqualityEngine::assertPredicate(TNode t, |
472 |
|
bool polarity, |
473 |
|
TNode reason, |
474 |
|
unsigned pid) |
475 |
|
{ |
476 |
1355420 |
Debug("equality") << d_name << "::eq::addPredicate(" << t << "," << (polarity ? "true" : "false") << ")" << std::endl; |
477 |
1355420 |
Assert(t.getKind() != kind::EQUAL) << "Use assertEquality instead"; |
478 |
2710840 |
TNode b = polarity ? d_true : d_false; |
479 |
1355420 |
if (hasTerm(t) && areEqual(t, b)) |
480 |
|
{ |
481 |
581579 |
return false; |
482 |
|
} |
483 |
773841 |
assertEqualityInternal(t, b, reason, pid); |
484 |
773841 |
propagate(); |
485 |
773841 |
return true; |
486 |
|
} |
487 |
|
|
488 |
12012482 |
bool EqualityEngine::assertEquality(TNode eq, |
489 |
|
bool polarity, |
490 |
|
TNode reason, |
491 |
|
unsigned pid) |
492 |
|
{ |
493 |
12012482 |
Debug("equality") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl; |
494 |
12012482 |
if (polarity) { |
495 |
|
// If two terms are already equal, don't assert anything |
496 |
6513078 |
if (hasTerm(eq[0]) && hasTerm(eq[1]) && areEqual(eq[0], eq[1])) { |
497 |
1718030 |
return false; |
498 |
|
} |
499 |
|
// Add equality between terms |
500 |
4795048 |
assertEqualityInternal(eq[0], eq[1], reason, pid); |
501 |
4795048 |
propagate(); |
502 |
|
} else { |
503 |
|
// If two terms are already dis-equal, don't assert anything |
504 |
5499404 |
if (hasTerm(eq[0]) && hasTerm(eq[1]) && areDisequal(eq[0], eq[1], false)) { |
505 |
5626032 |
return false; |
506 |
|
} |
507 |
|
|
508 |
|
// notify the theory |
509 |
2686766 |
if (d_performNotify) { |
510 |
2686766 |
d_notify.eqNotifyDisequal(eq[0], eq[1], reason); |
511 |
|
} |
512 |
|
|
513 |
2686766 |
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl; |
514 |
|
|
515 |
2686766 |
assertEqualityInternal(eq, d_false, reason, pid); |
516 |
2686766 |
propagate(); |
517 |
|
|
518 |
2686766 |
if (d_done) { |
519 |
736 |
return true; |
520 |
|
} |
521 |
|
|
522 |
|
// If both have constant representatives, we don't notify anyone |
523 |
2686030 |
EqualityNodeId a = getNodeId(eq[0]); |
524 |
2686030 |
EqualityNodeId b = getNodeId(eq[1]); |
525 |
2686030 |
EqualityNodeId aClassId = getEqualityNode(a).getFind(); |
526 |
2686030 |
EqualityNodeId bClassId = getEqualityNode(b).getFind(); |
527 |
2686030 |
if (d_isConstant[aClassId] && d_isConstant[bClassId]) { |
528 |
20 |
return true; |
529 |
|
} |
530 |
|
|
531 |
|
// If we are adding a disequality, notify of the shared term representatives |
532 |
2686010 |
EqualityNodeId eqId = getNodeId(eq); |
533 |
2686010 |
TriggerTermSetRef aTriggerRef = d_nodeIndividualTrigger[aClassId]; |
534 |
2686010 |
TriggerTermSetRef bTriggerRef = d_nodeIndividualTrigger[bClassId]; |
535 |
2686010 |
if (aTriggerRef != +null_set_id && bTriggerRef != +null_set_id) { |
536 |
987381 |
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ": have triggers" << std::endl; |
537 |
|
// The sets of trigger terms |
538 |
987381 |
TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef); |
539 |
987381 |
TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef); |
540 |
|
// Go through and notify the shared dis-equalities |
541 |
987381 |
TheoryIdSet aTags = aTriggerTerms.d_tags; |
542 |
987381 |
TheoryIdSet bTags = bTriggerTerms.d_tags; |
543 |
987381 |
TheoryId aTag = TheoryIdSetUtil::setPop(aTags); |
544 |
987381 |
TheoryId bTag = TheoryIdSetUtil::setPop(bTags); |
545 |
987381 |
int a_i = 0, b_i = 0; |
546 |
9740315 |
while (aTag != THEORY_LAST && bTag != THEORY_LAST) { |
547 |
4376478 |
if (aTag < bTag) { |
548 |
981948 |
aTag = TheoryIdSetUtil::setPop(aTags); |
549 |
981948 |
++ a_i; |
550 |
3394530 |
} else if (aTag > bTag) { |
551 |
1981437 |
bTag = TheoryIdSetUtil::setPop(bTags); |
552 |
1981437 |
++ b_i; |
553 |
|
} else { |
554 |
|
// Same tags, notify |
555 |
1413093 |
EqualityNodeId aSharedId = aTriggerTerms.d_triggers[a_i++]; |
556 |
1413093 |
EqualityNodeId bSharedId = bTriggerTerms.d_triggers[b_i++]; |
557 |
|
// Propagate |
558 |
1413093 |
if (!hasPropagatedDisequality(aTag, aSharedId, bSharedId)) { |
559 |
|
// Store a proof if not there already |
560 |
1413093 |
if (!hasPropagatedDisequality(aSharedId, bSharedId)) { |
561 |
664134 |
d_deducedDisequalityReasons.push_back(EqualityPair(aSharedId, a)); |
562 |
664134 |
d_deducedDisequalityReasons.push_back(EqualityPair(bSharedId, b)); |
563 |
664134 |
d_deducedDisequalityReasons.push_back(EqualityPair(eqId, d_falseId)); |
564 |
|
} |
565 |
|
// Store the propagation |
566 |
1413093 |
storePropagatedDisequality(aTag, aSharedId, bSharedId); |
567 |
|
// Notify |
568 |
1413093 |
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ": notifying " << aTag << " for " << d_nodes[aSharedId] << " != " << d_nodes[bSharedId] << std::endl; |
569 |
1413093 |
if (!d_notify.eqNotifyTriggerTermEquality(aTag, d_nodes[aSharedId], d_nodes[bSharedId], false)) { |
570 |
11 |
break; |
571 |
|
} |
572 |
|
} |
573 |
|
// Pop the next tags |
574 |
1413082 |
aTag = TheoryIdSetUtil::setPop(aTags); |
575 |
1413082 |
bTag = TheoryIdSetUtil::setPop(bTags); |
576 |
|
} |
577 |
|
} |
578 |
|
} |
579 |
|
} |
580 |
7481055 |
return true; |
581 |
|
} |
582 |
|
|
583 |
22397947 |
TNode EqualityEngine::getRepresentative(TNode t) const { |
584 |
22397947 |
Debug("equality::internal") << d_name << "::eq::getRepresentative(" << t << ")" << std::endl; |
585 |
22397947 |
Assert(hasTerm(t)); |
586 |
22397947 |
EqualityNodeId representativeId = getEqualityNode(t).getFind(); |
587 |
22397947 |
Assert(!d_isInternal[representativeId]); |
588 |
22397947 |
Debug("equality::internal") << d_name << "::eq::getRepresentative(" << t << ") => " << d_nodes[representativeId] << std::endl; |
589 |
22397947 |
return d_nodes[representativeId]; |
590 |
|
} |
591 |
|
|
592 |
20567304 |
bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vector<TriggerId>& triggersFired) { |
593 |
|
|
594 |
20567304 |
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << ")" << std::endl; |
595 |
|
|
596 |
20567304 |
Assert(triggersFired.empty()); |
597 |
|
|
598 |
20567304 |
++d_stats.d_mergesCount; |
599 |
|
|
600 |
20567304 |
EqualityNodeId class1Id = class1.getFind(); |
601 |
20567304 |
EqualityNodeId class2Id = class2.getFind(); |
602 |
|
|
603 |
41134608 |
Node n1 = d_nodes[class1Id]; |
604 |
41134608 |
Node n2 = d_nodes[class2Id]; |
605 |
20567304 |
EqualityNode cc1 = getEqualityNode(n1); |
606 |
20567304 |
EqualityNode cc2 = getEqualityNode(n2); |
607 |
20567304 |
bool doNotify = false; |
608 |
|
// Determine if we should notify the owner of this class of this merge. |
609 |
|
// The second part of this check is needed due to the internal implementation |
610 |
|
// of this class. It ensures that we are merging terms and not operators. |
611 |
20567304 |
if (d_performNotify && class1Id == cc1.getFind() && class2Id == cc2.getFind()) |
612 |
|
{ |
613 |
19977540 |
doNotify = true; |
614 |
|
} |
615 |
|
|
616 |
|
// Check for constant merges |
617 |
20567304 |
bool class1isConstant = d_isConstant[class1Id]; |
618 |
20567304 |
bool class2isConstant = d_isConstant[class2Id]; |
619 |
20567304 |
Assert(class1isConstant || !class2isConstant) |
620 |
|
<< "Should always merge into constants"; |
621 |
20567304 |
Assert(!class1isConstant || !class2isConstant) << "Don't merge constants"; |
622 |
|
|
623 |
|
// Trigger set of class 1 |
624 |
20567304 |
TriggerTermSetRef class1triggerRef = d_nodeIndividualTrigger[class1Id]; |
625 |
|
TheoryIdSet class1Tags = class1triggerRef == null_set_id |
626 |
32667014 |
? 0 |
627 |
32667014 |
: getTriggerTermSet(class1triggerRef).d_tags; |
628 |
|
// Trigger set of class 2 |
629 |
20567304 |
TriggerTermSetRef class2triggerRef = d_nodeIndividualTrigger[class2Id]; |
630 |
|
TheoryIdSet class2Tags = class2triggerRef == null_set_id |
631 |
22642168 |
? 0 |
632 |
22642168 |
: getTriggerTermSet(class2triggerRef).d_tags; |
633 |
|
|
634 |
|
// Disequalities coming from class2 |
635 |
41134608 |
TaggedEqualitiesSet class2disequalitiesToNotify; |
636 |
|
// Disequalities coming from class1 |
637 |
41134608 |
TaggedEqualitiesSet class1disequalitiesToNotify; |
638 |
|
|
639 |
|
// Individual tags |
640 |
|
TheoryIdSet class1OnlyTags = |
641 |
20567304 |
TheoryIdSetUtil::setDifference(class1Tags, class2Tags); |
642 |
|
TheoryIdSet class2OnlyTags = |
643 |
20567304 |
TheoryIdSetUtil::setDifference(class2Tags, class1Tags); |
644 |
|
|
645 |
|
// Only get disequalities if they are not both constant |
646 |
20567304 |
if (!class1isConstant || !class2isConstant) { |
647 |
20567304 |
getDisequalities(!class1isConstant, class2Id, class1OnlyTags, class2disequalitiesToNotify); |
648 |
20567304 |
getDisequalities(!class2isConstant, class1Id, class2OnlyTags, class1disequalitiesToNotify); |
649 |
|
} |
650 |
|
|
651 |
|
// Update class2 representative information |
652 |
20567304 |
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating class " << class2Id << std::endl; |
653 |
20567304 |
EqualityNodeId currentId = class2Id; |
654 |
6170649 |
do { |
655 |
|
// Get the current node |
656 |
26737953 |
EqualityNode& currentNode = getEqualityNode(currentId); |
657 |
|
|
658 |
|
// Update it's find to class1 id |
659 |
26737953 |
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << currentId << "->" << class1Id << std::endl; |
660 |
26737953 |
currentNode.setFind(class1Id); |
661 |
|
|
662 |
|
// Go through the triggers and inform if necessary |
663 |
26737953 |
TriggerId currentTrigger = d_nodeTriggers[currentId]; |
664 |
91813153 |
while (currentTrigger != null_trigger) { |
665 |
32537600 |
Trigger& trigger = d_equalityTriggers[currentTrigger]; |
666 |
32537600 |
Trigger& otherTrigger = d_equalityTriggers[currentTrigger ^ 1]; |
667 |
|
|
668 |
|
// If the two are not already in the same class |
669 |
32537600 |
if (otherTrigger.d_classId != trigger.d_classId) |
670 |
|
{ |
671 |
28354550 |
trigger.d_classId = class1Id; |
672 |
|
// If they became the same, call the trigger |
673 |
28354550 |
if (otherTrigger.d_classId == class1Id) |
674 |
|
{ |
675 |
|
// Id of the real trigger is half the internal one |
676 |
9986258 |
triggersFired.push_back(currentTrigger); |
677 |
|
} |
678 |
|
} |
679 |
|
|
680 |
|
// Go to the next trigger |
681 |
32537600 |
currentTrigger = trigger.d_nextTrigger; |
682 |
|
} |
683 |
|
|
684 |
|
// Move to the next node |
685 |
26737953 |
currentId = currentNode.getNext(); |
686 |
|
|
687 |
26737953 |
} while (currentId != class2Id); |
688 |
|
|
689 |
|
// Update class2 table lookup and information if not a boolean |
690 |
|
// since booleans can't be in an application |
691 |
20567304 |
if (!d_isEquality[class2Id]) { |
692 |
10968460 |
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of " << class2Id << std::endl; |
693 |
5119832 |
do { |
694 |
|
// Get the current node |
695 |
16088292 |
EqualityNode& currentNode = getEqualityNode(currentId); |
696 |
16088292 |
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of node " << currentId << std::endl; |
697 |
|
|
698 |
|
// Go through the uselist and check for congruences |
699 |
16088292 |
UseListNodeId currentUseId = currentNode.getUseList(); |
700 |
80214542 |
while (currentUseId != null_uselist_id) { |
701 |
|
// Get the node of the use list |
702 |
32063125 |
UseListNode& useNode = d_useListNodes[currentUseId]; |
703 |
|
// Get the function application |
704 |
32063125 |
EqualityNodeId funId = useNode.getApplicationId(); |
705 |
32063125 |
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): " << d_nodes[currentId] << " in " << d_nodes[funId] << std::endl; |
706 |
|
const FunctionApplication& fun = |
707 |
32063125 |
d_applications[useNode.getApplicationId()].d_normalized; |
708 |
|
// If it's interpreted and we can interpret |
709 |
32063125 |
if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId]) |
710 |
|
{ |
711 |
|
// Get the actual term id |
712 |
1138656 |
TNode term = d_nodes[funId]; |
713 |
569328 |
subtermEvaluates(getNodeId(term)); |
714 |
|
} |
715 |
|
// Check if there is an application with find arguments |
716 |
32063125 |
EqualityNodeId aNormalized = getEqualityNode(fun.d_a).getFind(); |
717 |
32063125 |
EqualityNodeId bNormalized = getEqualityNode(fun.d_b).getFind(); |
718 |
32063125 |
FunctionApplication funNormalized(fun.d_type, aNormalized, bNormalized); |
719 |
32063125 |
ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized); |
720 |
32063125 |
if (find != d_applicationLookup.end()) { |
721 |
|
// Applications fun and the funNormalized can be merged due to congruence |
722 |
22313377 |
if (getEqualityNode(funId).getFind() != getEqualityNode(find->second).getFind()) { |
723 |
13503203 |
enqueue(MergeCandidate(funId, find->second, MERGED_THROUGH_CONGRUENCE, TNode::null())); |
724 |
|
} |
725 |
|
} else { |
726 |
|
// There is no representative, so we can add one, we remove this when backtracking |
727 |
9749748 |
storeApplicationLookup(funNormalized, funId); |
728 |
|
} |
729 |
|
|
730 |
|
// Go to the next one in the use list |
731 |
32063125 |
currentUseId = useNode.getNext(); |
732 |
|
} |
733 |
|
|
734 |
|
// Move to the next node |
735 |
16088292 |
currentId = currentNode.getNext(); |
736 |
16088292 |
} while (currentId != class2Id); |
737 |
|
} |
738 |
|
|
739 |
|
// Now merge the lists |
740 |
20567304 |
class1.merge<true>(class2); |
741 |
|
|
742 |
|
// notify the theory |
743 |
20567304 |
if (doNotify) { |
744 |
19977543 |
d_notify.eqNotifyMerge(n1, n2); |
745 |
|
} |
746 |
|
|
747 |
|
// Go through the trigger term disequalities and propagate |
748 |
20567301 |
if (!propagateTriggerTermDisequalities(class1OnlyTags, class1triggerRef, class2disequalitiesToNotify)) { |
749 |
2 |
return false; |
750 |
|
} |
751 |
20567299 |
if (!propagateTriggerTermDisequalities(class2OnlyTags, class2triggerRef, class1disequalitiesToNotify)) { |
752 |
14 |
return false; |
753 |
|
} |
754 |
|
|
755 |
|
// Notify the trigger term merges |
756 |
20567285 |
if (class2triggerRef != +null_set_id) { |
757 |
2074850 |
if (class1triggerRef == +null_set_id) { |
758 |
|
// If class1 doesn't have individual triggers, but class2 does, mark it |
759 |
94011 |
d_nodeIndividualTrigger[class1Id] = class2triggerRef; |
760 |
|
// Add it to the list for backtracking |
761 |
94011 |
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, +null_set_id)); |
762 |
94011 |
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1; |
763 |
|
} else { |
764 |
|
// Get the triggers |
765 |
1980839 |
TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef); |
766 |
1980839 |
TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef); |
767 |
|
|
768 |
|
// Initialize the merged set |
769 |
1980839 |
TheoryIdSet newSetTags = TheoryIdSetUtil::setUnion(class1triggers.d_tags, |
770 |
1980839 |
class2triggers.d_tags); |
771 |
|
EqualityNodeId newSetTriggers[THEORY_LAST]; |
772 |
1980839 |
unsigned newSetTriggersSize = 0; |
773 |
|
|
774 |
1980839 |
int i1 = 0; |
775 |
1980839 |
int i2 = 0; |
776 |
1980839 |
TheoryIdSet tags1 = class1triggers.d_tags; |
777 |
1980839 |
TheoryIdSet tags2 = class2triggers.d_tags; |
778 |
1980839 |
TheoryId tag1 = TheoryIdSetUtil::setPop(tags1); |
779 |
1980839 |
TheoryId tag2 = TheoryIdSetUtil::setPop(tags2); |
780 |
|
|
781 |
|
// Comparing the THEORY_LAST is OK because all other theories are |
782 |
|
// smaller, and will therefore be preferred |
783 |
36201411 |
while (tag1 != THEORY_LAST || tag2 != THEORY_LAST) |
784 |
|
{ |
785 |
17121109 |
if (tag1 < tag2) { |
786 |
|
// copy tag1 |
787 |
14492070 |
newSetTriggers[newSetTriggersSize++] = |
788 |
14492070 |
class1triggers.d_triggers[i1++]; |
789 |
14492070 |
tag1 = TheoryIdSetUtil::setPop(tags1); |
790 |
2629039 |
} else if (tag1 > tag2) { |
791 |
|
// copy tag2 |
792 |
1075 |
newSetTriggers[newSetTriggersSize++] = |
793 |
1075 |
class2triggers.d_triggers[i2++]; |
794 |
1075 |
tag2 = TheoryIdSetUtil::setPop(tags2); |
795 |
|
} else { |
796 |
|
// copy tag1 |
797 |
2627964 |
EqualityNodeId tag1id = newSetTriggers[newSetTriggersSize++] = |
798 |
5255928 |
class1triggers.d_triggers[i1++]; |
799 |
|
// since they are both tagged notify of merge |
800 |
2627964 |
if (d_performNotify) { |
801 |
2627964 |
EqualityNodeId tag2id = class2triggers.d_triggers[i2++]; |
802 |
2627964 |
if (!d_notify.eqNotifyTriggerTermEquality(tag1, d_nodes[tag1id], d_nodes[tag2id], true)) { |
803 |
10823 |
return false; |
804 |
|
} |
805 |
|
} |
806 |
|
// Next tags |
807 |
2617141 |
tag1 = TheoryIdSetUtil::setPop(tags1); |
808 |
2617141 |
tag2 = TheoryIdSetUtil::setPop(tags2); |
809 |
|
} |
810 |
|
} |
811 |
|
|
812 |
|
// Add the new trigger set, if different from previous one |
813 |
1970016 |
if (class1triggers.d_tags != class2triggers.d_tags) |
814 |
|
{ |
815 |
|
// Add it to the list for backtracking |
816 |
1243419 |
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, class1triggerRef)); |
817 |
1243419 |
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1; |
818 |
|
// Mark the the new set as a trigger |
819 |
1243419 |
d_nodeIndividualTrigger[class1Id] = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize); |
820 |
|
} |
821 |
|
} |
822 |
|
} |
823 |
|
|
824 |
|
// Everything fine |
825 |
20556462 |
return true; |
826 |
|
} |
827 |
|
|
828 |
20566051 |
void EqualityEngine::undoMerge(EqualityNode& class1, EqualityNode& class2, EqualityNodeId class2Id) { |
829 |
|
|
830 |
20566051 |
Debug("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << "," << class2Id << ")" << std::endl; |
831 |
|
|
832 |
|
// Now unmerge the lists (same as merge) |
833 |
20566051 |
class1.merge<false>(class2); |
834 |
|
|
835 |
|
// Update class2 representative information |
836 |
20566051 |
EqualityNodeId currentId = class2Id; |
837 |
20566051 |
Debug("equality") << d_name << "::eq::undoMerge(" << class1.getFind() << "," << class2Id << "): undoing representative info" << std::endl; |
838 |
6170435 |
do { |
839 |
|
// Get the current node |
840 |
26736486 |
EqualityNode& currentNode = getEqualityNode(currentId); |
841 |
|
|
842 |
|
// Update it's find to class1 id |
843 |
26736486 |
currentNode.setFind(class2Id); |
844 |
|
|
845 |
|
// Go through the trigger list (if any) and undo the class |
846 |
26736486 |
TriggerId currentTrigger = d_nodeTriggers[currentId]; |
847 |
91811686 |
while (currentTrigger != null_trigger) { |
848 |
32537600 |
Trigger& trigger = d_equalityTriggers[currentTrigger]; |
849 |
32537600 |
trigger.d_classId = class2Id; |
850 |
32537600 |
currentTrigger = trigger.d_nextTrigger; |
851 |
|
} |
852 |
|
|
853 |
|
// Move to the next node |
854 |
26736486 |
currentId = currentNode.getNext(); |
855 |
|
|
856 |
26736486 |
} while (currentId != class2Id); |
857 |
|
|
858 |
20566051 |
} |
859 |
|
|
860 |
27453754 |
void EqualityEngine::backtrack() { |
861 |
|
|
862 |
27453754 |
Debug("equality::backtrack") << "backtracking" << std::endl; |
863 |
|
|
864 |
|
// If we need to backtrack then do it |
865 |
27453754 |
if (d_assertedEqualitiesCount < d_assertedEqualities.size()) { |
866 |
|
|
867 |
|
// Clear the propagation queue |
868 |
3133130 |
while (!d_propagationQueue.empty()) { |
869 |
6 |
d_propagationQueue.pop_front(); |
870 |
|
} |
871 |
|
|
872 |
3133118 |
Debug("equality") << d_name << "::eq::backtrack(): nodes" << std::endl; |
873 |
|
|
874 |
23730219 |
for (int i = (int)d_assertedEqualities.size() - 1, i_end = (int)d_assertedEqualitiesCount; i >= i_end; --i) { |
875 |
|
// Get the ids of the merged classes |
876 |
20597101 |
Equality& eq = d_assertedEqualities[i]; |
877 |
|
// Undo the merge |
878 |
20597101 |
if (eq.d_lhs != null_id) |
879 |
|
{ |
880 |
41132102 |
undoMerge( |
881 |
20566051 |
d_equalityNodes[eq.d_lhs], d_equalityNodes[eq.d_rhs], eq.d_rhs); |
882 |
|
} |
883 |
|
} |
884 |
|
|
885 |
3133118 |
d_assertedEqualities.resize(d_assertedEqualitiesCount); |
886 |
|
|
887 |
3133118 |
Debug("equality") << d_name << "::eq::backtrack(): edges" << std::endl; |
888 |
|
|
889 |
23730219 |
for (int i = (int)d_equalityEdges.size() - 2, i_end = (int)(2*d_assertedEqualitiesCount); i >= i_end; i -= 2) { |
890 |
20597101 |
EqualityEdge& edge1 = d_equalityEdges[i]; |
891 |
20597101 |
EqualityEdge& edge2 = d_equalityEdges[i | 1]; |
892 |
20597101 |
d_equalityGraph[edge2.getNodeId()] = edge1.getNext(); |
893 |
20597101 |
d_equalityGraph[edge1.getNodeId()] = edge2.getNext(); |
894 |
|
} |
895 |
|
|
896 |
3133118 |
d_equalityEdges.resize(2 * d_assertedEqualitiesCount); |
897 |
|
} |
898 |
|
|
899 |
27453754 |
if (d_triggerTermSetUpdates.size() > d_triggerTermSetUpdatesSize) { |
900 |
|
// Unset the individual triggers |
901 |
5015699 |
for (int i = d_triggerTermSetUpdates.size() - 1, i_end = d_triggerTermSetUpdatesSize; i >= i_end; -- i) { |
902 |
3811528 |
const TriggerSetUpdate& update = d_triggerTermSetUpdates[i]; |
903 |
3811528 |
d_nodeIndividualTrigger[update.d_classId] = update.d_oldValue; |
904 |
|
} |
905 |
1204171 |
d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize); |
906 |
|
} |
907 |
|
|
908 |
27453754 |
if (d_equalityTriggers.size() > d_equalityTriggersCount) { |
909 |
|
// Unlink the triggers from the lists |
910 |
3358108 |
for (int i = d_equalityTriggers.size() - 1, i_end = d_equalityTriggersCount; i >= i_end; -- i) { |
911 |
3292888 |
const Trigger& trigger = d_equalityTriggers[i]; |
912 |
3292888 |
d_nodeTriggers[trigger.d_classId] = trigger.d_nextTrigger; |
913 |
|
} |
914 |
|
// Get rid of the triggers |
915 |
65220 |
d_equalityTriggers.resize(d_equalityTriggersCount); |
916 |
65220 |
d_equalityTriggersOriginal.resize(d_equalityTriggersCount); |
917 |
|
} |
918 |
|
|
919 |
27453754 |
if (d_applicationLookups.size() > d_applicationLookupsCount) { |
920 |
13550508 |
for (int i = d_applicationLookups.size() - 1, i_end = (int) d_applicationLookupsCount; i >= i_end; -- i) { |
921 |
12294430 |
d_applicationLookup.erase(d_applicationLookups[i]); |
922 |
|
} |
923 |
1256078 |
d_applicationLookups.resize(d_applicationLookupsCount); |
924 |
|
} |
925 |
|
|
926 |
27453754 |
if (d_subtermEvaluates.size() > d_subtermEvaluatesSize) { |
927 |
682561 |
for(int i = d_subtermEvaluates.size() - 1, i_end = (int)d_subtermEvaluatesSize; i >= i_end; --i) { |
928 |
607218 |
d_subtermsToEvaluate[d_subtermEvaluates[i]] ++; |
929 |
|
} |
930 |
75343 |
d_subtermEvaluates.resize(d_subtermEvaluatesSize); |
931 |
|
} |
932 |
|
|
933 |
27453754 |
if (d_nodes.size() > d_nodesCount) { |
934 |
|
// Go down the nodes, check the application nodes and remove them from use-lists |
935 |
7520641 |
for(int i = d_nodes.size() - 1, i_end = (int)d_nodesCount; i >= i_end; -- i) { |
936 |
|
// Remove from the node -> id map |
937 |
6599304 |
Debug("equality") << d_name << "::eq::backtrack(): removing node " << d_nodes[i] << std::endl; |
938 |
6599304 |
d_nodeIds.erase(d_nodes[i]); |
939 |
|
|
940 |
6599304 |
const FunctionApplication& app = d_applications[i].d_original; |
941 |
6599304 |
if (!app.isNull()) { |
942 |
|
// Remove b from use-list |
943 |
2820911 |
getEqualityNode(app.d_b).removeTopFromUseList(d_useListNodes); |
944 |
|
// Remove a from use-list |
945 |
2820911 |
getEqualityNode(app.d_a).removeTopFromUseList(d_useListNodes); |
946 |
|
} |
947 |
|
} |
948 |
|
|
949 |
|
// Now get rid of the nodes and the rest |
950 |
921337 |
d_nodes.resize(d_nodesCount); |
951 |
921337 |
d_applications.resize(d_nodesCount); |
952 |
921337 |
d_nodeTriggers.resize(d_nodesCount); |
953 |
921337 |
d_nodeIndividualTrigger.resize(d_nodesCount); |
954 |
921337 |
d_isConstant.resize(d_nodesCount); |
955 |
921337 |
d_subtermsToEvaluate.resize(d_nodesCount); |
956 |
921337 |
d_isEquality.resize(d_nodesCount); |
957 |
921337 |
d_isInternal.resize(d_nodesCount); |
958 |
921337 |
d_equalityGraph.resize(d_nodesCount); |
959 |
921337 |
d_equalityNodes.resize(d_nodesCount); |
960 |
|
} |
961 |
|
|
962 |
27453754 |
if (d_deducedDisequalities.size() > d_deducedDisequalitiesSize) { |
963 |
6968548 |
for(int i = d_deducedDisequalities.size() - 1, i_end = (int)d_deducedDisequalitiesSize; i >= i_end; -- i) { |
964 |
5425667 |
EqualityPair pair = d_deducedDisequalities[i]; |
965 |
5425667 |
Assert(d_disequalityReasonsMap.find(pair) |
966 |
|
!= d_disequalityReasonsMap.end()); |
967 |
|
// Remove from the map |
968 |
5425667 |
d_disequalityReasonsMap.erase(pair); |
969 |
5425667 |
std::swap(pair.first, pair.second); |
970 |
5425667 |
d_disequalityReasonsMap.erase(pair); |
971 |
|
} |
972 |
1542881 |
d_deducedDisequalityReasons.resize(d_deducedDisequalityReasonsSize); |
973 |
1542881 |
d_deducedDisequalities.resize(d_deducedDisequalitiesSize); |
974 |
|
} |
975 |
|
|
976 |
27453754 |
} |
977 |
|
|
978 |
20598354 |
void EqualityEngine::addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, unsigned type, TNode reason) { |
979 |
41196708 |
Debug("equality") << d_name << "::eq::addGraphEdge({" << t1 << "} " |
980 |
20598354 |
<< d_nodes[t1] << ", {" << t2 << "} " << d_nodes[t2] << "," |
981 |
20598354 |
<< reason << ")" << std::endl; |
982 |
20598354 |
EqualityEdgeId edge = d_equalityEdges.size(); |
983 |
20598354 |
d_equalityEdges.push_back(EqualityEdge(t2, d_equalityGraph[t1], type, reason)); |
984 |
20598354 |
d_equalityEdges.push_back(EqualityEdge(t1, d_equalityGraph[t2], type, reason)); |
985 |
20598354 |
d_equalityGraph[t1] = edge; |
986 |
20598354 |
d_equalityGraph[t2] = edge | 1; |
987 |
|
|
988 |
20598354 |
if (Debug.isOn("equality::internal")) { |
989 |
|
debugPrintGraph(); |
990 |
|
} |
991 |
20598354 |
} |
992 |
|
|
993 |
|
std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const { |
994 |
|
std::stringstream out; |
995 |
|
bool first = true; |
996 |
|
if (edgeId == null_edge) { |
997 |
|
out << "null"; |
998 |
|
} else { |
999 |
|
while (edgeId != null_edge) { |
1000 |
|
const EqualityEdge& edge = d_equalityEdges[edgeId]; |
1001 |
|
if (!first) out << ","; |
1002 |
|
out << "{" << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()]; |
1003 |
|
edgeId = edge.getNext(); |
1004 |
|
first = false; |
1005 |
|
} |
1006 |
|
} |
1007 |
|
return out.str(); |
1008 |
|
} |
1009 |
|
|
1010 |
949270 |
void EqualityEngine::buildEqConclusion(EqualityNodeId id1, |
1011 |
|
EqualityNodeId id2, |
1012 |
|
EqProof* eqp) const |
1013 |
|
{ |
1014 |
949270 |
Kind k1 = d_nodes[id1].getKind(); |
1015 |
949270 |
Kind k2 = d_nodes[id2].getKind(); |
1016 |
|
// only try to build if ids do not correspond to internal nodes. If they do, |
1017 |
|
// only try to build build if full applications corresponding to the given ids |
1018 |
|
// have the same congruence n-ary non-APPLY_* kind, since the internal nodes |
1019 |
|
// may be full nodes. |
1020 |
2293902 |
if ((d_isInternal[id1] || d_isInternal[id2]) |
1021 |
2056862 |
&& (k1 != k2 || k1 == kind::APPLY_UF || k1 == kind::APPLY_CONSTRUCTOR |
1022 |
7572 |
|| k1 == kind::APPLY_SELECTOR || k1 == kind::APPLY_TESTER |
1023 |
7572 |
|| !NodeManager::isNAryKind(k1))) |
1024 |
|
{ |
1025 |
553684 |
return; |
1026 |
|
} |
1027 |
791172 |
Debug("equality") << "buildEqConclusion: {" << id1 << "} " << d_nodes[id1] |
1028 |
395586 |
<< "\n"; |
1029 |
791172 |
Debug("equality") << "buildEqConclusion: {" << id2 << "} " << d_nodes[id2] |
1030 |
395586 |
<< "\n"; |
1031 |
791172 |
Node eq[2]; |
1032 |
395586 |
NodeManager* nm = NodeManager::currentNM(); |
1033 |
1186758 |
for (unsigned i = 0; i < 2; ++i) |
1034 |
|
{ |
1035 |
791172 |
EqualityNodeId equalityNodeId = i == 0 ? id1 : id2; |
1036 |
791620 |
Node equalityNode = d_nodes[equalityNodeId]; |
1037 |
|
// if not an internal node, just retrieve it |
1038 |
1581896 |
if (!d_isInternal[equalityNodeId]) |
1039 |
|
{ |
1040 |
790724 |
eq[i] = equalityNode; |
1041 |
790724 |
continue; |
1042 |
|
} |
1043 |
|
// build node relative to partial application of this |
1044 |
|
// n-ary kind. We get the full application, then we get |
1045 |
|
// the arguments relative to how partial the internal |
1046 |
|
// node is, and build the application |
1047 |
|
|
1048 |
|
// get number of children of partial app: |
1049 |
|
// #children of full app - (id of full app - id of |
1050 |
|
// partial app) |
1051 |
448 |
EqualityNodeId fullAppId = getNodeId(equalityNode); |
1052 |
448 |
EqualityNodeId curr = fullAppId; |
1053 |
448 |
unsigned separation = 0; |
1054 |
448 |
Assert(fullAppId >= equalityNodeId); |
1055 |
1856 |
while (curr != equalityNodeId) |
1056 |
|
{ |
1057 |
704 |
separation = separation + (d_nodes[curr--] == equalityNode ? 1 : 0); |
1058 |
|
} |
1059 |
|
// compute separation, which is how many ids with the |
1060 |
|
// same fullappnode exist between equalityNodeId and |
1061 |
|
// fullAppId |
1062 |
448 |
unsigned numChildren = equalityNode.getNumChildren() - separation; |
1063 |
896 |
Assert(numChildren < equalityNode.getNumChildren()) |
1064 |
|
<< "broke for numChildren " << numChildren << ", fullAppId " |
1065 |
|
<< fullAppId << ", equalityNodeId " << equalityNodeId << ", node " |
1066 |
448 |
<< equalityNode << ", cong: {" << id1 << "} " << d_nodes[id1] << " = {" |
1067 |
448 |
<< id2 << "} " << d_nodes[id2] << "\n"; |
1068 |
|
// if has at least as many children as the minimal |
1069 |
|
// number of children of the n-ary kind, build the node |
1070 |
448 |
if (numChildren >= kind::metakind::getMinArityForKind(k1)) |
1071 |
|
{ |
1072 |
164 |
std::vector<Node> children; |
1073 |
246 |
for (unsigned j = 0; j < numChildren; ++j) |
1074 |
|
{ |
1075 |
164 |
children.push_back(equalityNode[j]); |
1076 |
|
} |
1077 |
82 |
eq[i] = nm->mkNode(k1, children); |
1078 |
|
} |
1079 |
|
} |
1080 |
|
// if built equality, add it as eqp's conclusion |
1081 |
395586 |
if (!eq[0].isNull() && !eq[1].isNull()) |
1082 |
|
{ |
1083 |
395403 |
eqp->d_node = eq[0].eqNode(eq[1]); |
1084 |
|
} |
1085 |
|
} |
1086 |
|
|
1087 |
386856 |
void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, |
1088 |
|
std::vector<TNode>& equalities, |
1089 |
|
EqProof* eqp) const { |
1090 |
773712 |
Debug("pf::ee") << d_name << "::eq::explainEquality(" << t1 << ", " << t2 |
1091 |
773712 |
<< ", " << (polarity ? "true" : "false") << ")" |
1092 |
386856 |
<< ", proof = " << (eqp ? "ON" : "OFF") << std::endl; |
1093 |
|
|
1094 |
|
// The terms must be there already |
1095 |
386856 |
Assert(hasTerm(t1) && hasTerm(t2)); |
1096 |
|
|
1097 |
386856 |
if (Debug.isOn("equality::internal")) |
1098 |
|
{ |
1099 |
|
debugPrintGraph(); |
1100 |
|
} |
1101 |
|
// Get the ids |
1102 |
386856 |
EqualityNodeId t1Id = getNodeId(t1); |
1103 |
386856 |
EqualityNodeId t2Id = getNodeId(t2); |
1104 |
|
|
1105 |
773712 |
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache; |
1106 |
386856 |
if (polarity) { |
1107 |
|
// Get the explanation |
1108 |
360857 |
getExplanation(t1Id, t2Id, equalities, cache, eqp); |
1109 |
|
} else { |
1110 |
25999 |
if (eqp) { |
1111 |
5014 |
eqp->d_id = MERGED_THROUGH_TRANS; |
1112 |
5014 |
eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t2Id]).notNode(); |
1113 |
|
} |
1114 |
|
|
1115 |
|
// Get the reason for this disequality |
1116 |
25999 |
EqualityPair pair(t1Id, t2Id); |
1117 |
25999 |
Assert(d_disequalityReasonsMap.find(pair) != d_disequalityReasonsMap.end()) |
1118 |
|
<< "Don't ask for stuff I didn't notify you about"; |
1119 |
25999 |
DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second; |
1120 |
25999 |
if (eqp) |
1121 |
|
{ |
1122 |
10028 |
Debug("pf::ee") << "Deq reason for " << eqp->d_node << " " |
1123 |
5014 |
<< reasonRef.d_mergesStart << "..." |
1124 |
5014 |
<< reasonRef.d_mergesEnd << std::endl; |
1125 |
|
} |
1126 |
73115 |
for (unsigned i = reasonRef.d_mergesStart; i < reasonRef.d_mergesEnd; ++i) |
1127 |
|
{ |
1128 |
47116 |
EqualityPair toExplain = d_deducedDisequalityReasons[i]; |
1129 |
94232 |
std::shared_ptr<EqProof> eqpc; |
1130 |
|
|
1131 |
|
// If we're constructing a (transitivity) proof, we don't need to include an explanation for x=x. |
1132 |
47116 |
if (eqp && toExplain.first != toExplain.second) { |
1133 |
6067 |
eqpc = std::make_shared<EqProof>(); |
1134 |
12134 |
Debug("pf::ee") << "Deq getExplanation #" << i << " for " << eqp->d_node |
1135 |
6067 |
<< " : " << toExplain.first << " " << toExplain.second |
1136 |
6067 |
<< std::endl; |
1137 |
|
} |
1138 |
|
|
1139 |
47116 |
getExplanation( |
1140 |
|
toExplain.first, toExplain.second, equalities, cache, eqpc.get()); |
1141 |
|
|
1142 |
47116 |
if (eqpc) { |
1143 |
6067 |
if (Debug.isOn("pf::ee")) |
1144 |
|
{ |
1145 |
|
Debug("pf::ee") << "Child proof is:" << std::endl; |
1146 |
|
eqpc->debug_print("pf::ee", 1); |
1147 |
|
} |
1148 |
6067 |
if (eqpc->d_id == MERGED_THROUGH_TRANS) |
1149 |
|
{ |
1150 |
5494 |
std::vector<std::shared_ptr<EqProof>> orderedChildren; |
1151 |
2747 |
bool nullCongruenceFound = false; |
1152 |
9261 |
for (const auto& child : eqpc->d_children) |
1153 |
|
{ |
1154 |
13028 |
if (child->d_id == MERGED_THROUGH_CONGRUENCE |
1155 |
6514 |
&& child->d_node.isNull()) |
1156 |
|
{ |
1157 |
2538 |
nullCongruenceFound = true; |
1158 |
5076 |
Debug("pf::ee") |
1159 |
2538 |
<< "Have congruence with empty d_node. Splitting..." |
1160 |
2538 |
<< std::endl; |
1161 |
7614 |
orderedChildren.insert(orderedChildren.begin(), |
1162 |
7614 |
child->d_children[0]); |
1163 |
2538 |
orderedChildren.push_back(child->d_children[1]); |
1164 |
|
} |
1165 |
|
else |
1166 |
|
{ |
1167 |
3976 |
orderedChildren.push_back(child); |
1168 |
|
} |
1169 |
|
} |
1170 |
|
|
1171 |
2747 |
if (nullCongruenceFound) { |
1172 |
2001 |
eqpc->d_children = orderedChildren; |
1173 |
2001 |
if (Debug.isOn("pf::ee")) |
1174 |
|
{ |
1175 |
|
Debug("pf::ee") |
1176 |
|
<< "Child proof's children have been reordered. It is now:" |
1177 |
|
<< std::endl; |
1178 |
|
eqpc->debug_print("pf::ee", 1); |
1179 |
|
} |
1180 |
|
} |
1181 |
|
} |
1182 |
|
|
1183 |
6067 |
eqp->d_children.push_back(eqpc); |
1184 |
|
} |
1185 |
|
} |
1186 |
|
|
1187 |
25999 |
if (eqp) { |
1188 |
5014 |
if (eqp->d_children.size() == 0) { |
1189 |
|
// Corner case where this is actually a disequality between two constants |
1190 |
|
Debug("pf::ee") << "Encountered a constant disequality (not a transitivity proof): " |
1191 |
|
<< eqp->d_node << std::endl; |
1192 |
|
Assert(eqp->d_node[0][0].isConst()); |
1193 |
|
Assert(eqp->d_node[0][1].isConst()); |
1194 |
|
eqp->d_id = MERGED_THROUGH_CONSTANTS; |
1195 |
5014 |
} else if (eqp->d_children.size() == 1) { |
1196 |
7968 |
Node cnode = eqp->d_children[0]->d_node; |
1197 |
7968 |
Debug("pf::ee") << "Simplifying " << cnode << " from " << eqp->d_node |
1198 |
3984 |
<< std::endl; |
1199 |
3984 |
bool simpTrans = true; |
1200 |
3984 |
if (cnode.getKind() == kind::EQUAL) |
1201 |
|
{ |
1202 |
|
// It may be the case that we have a proof of x = c2 and we want to |
1203 |
|
// conclude x != c1. If this is the case, below we construct: |
1204 |
|
// |
1205 |
|
// -------- MERGED_THROUGH_EQUALITY |
1206 |
|
// x = c2 c1 != c2 |
1207 |
|
// ----------------- TRANS |
1208 |
|
// x != c1 |
1209 |
7968 |
TNode c1 = t1.isConst() ? t1 : (t2.isConst() ? t2 : TNode::null()); |
1210 |
7968 |
TNode nc = t1.isConst() ? t2 : (t2.isConst() ? t1 : TNode::null()); |
1211 |
7968 |
Node c2; |
1212 |
|
// merge constants transitivity |
1213 |
11910 |
for (unsigned i = 0; i < 2; i++) |
1214 |
|
{ |
1215 |
7950 |
if (cnode[i].isConst() && cnode[1 - i] == nc) |
1216 |
|
{ |
1217 |
24 |
c2 = cnode[i]; |
1218 |
24 |
break; |
1219 |
|
} |
1220 |
|
} |
1221 |
3984 |
if (!c1.isNull() && !c2.isNull()) |
1222 |
|
{ |
1223 |
24 |
simpTrans = false; |
1224 |
24 |
Assert(c1.getType().isComparableTo(c2.getType())); |
1225 |
48 |
std::shared_ptr<EqProof> eqpmc = std::make_shared<EqProof>(); |
1226 |
24 |
eqpmc->d_id = MERGED_THROUGH_CONSTANTS; |
1227 |
24 |
eqpmc->d_node = c1.eqNode(c2).eqNode(d_false); |
1228 |
24 |
eqp->d_children.push_back(eqpmc); |
1229 |
|
} |
1230 |
|
} |
1231 |
3984 |
if (simpTrans) |
1232 |
|
{ |
1233 |
|
// The transitivity proof has just one child. Simplify. |
1234 |
7920 |
std::shared_ptr<EqProof> temp = eqp->d_children[0]; |
1235 |
3960 |
eqp->d_children.clear(); |
1236 |
3960 |
*eqp = *temp; |
1237 |
|
} |
1238 |
|
} |
1239 |
|
|
1240 |
5014 |
if (Debug.isOn("pf::ee")) |
1241 |
|
{ |
1242 |
|
Debug("pf::ee") << "Disequality explanation final proof: " << std::endl; |
1243 |
|
eqp->debug_print("pf::ee", 1); |
1244 |
|
} |
1245 |
|
} |
1246 |
|
} |
1247 |
386856 |
} |
1248 |
|
|
1249 |
19638 |
void EqualityEngine::explainPredicate(TNode p, bool polarity, |
1250 |
|
std::vector<TNode>& assertions, |
1251 |
|
EqProof* eqp) const { |
1252 |
39276 |
Debug("equality") << d_name << "::eq::explainPredicate(" << p << ")" |
1253 |
19638 |
<< std::endl; |
1254 |
|
// Must have the term |
1255 |
19638 |
Assert(hasTerm(p)); |
1256 |
39276 |
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache; |
1257 |
19638 |
if (Debug.isOn("equality::internal")) |
1258 |
|
{ |
1259 |
|
debugPrintGraph(); |
1260 |
|
} |
1261 |
|
// Get the explanation |
1262 |
19638 |
getExplanation( |
1263 |
|
getNodeId(p), polarity ? d_trueId : d_falseId, assertions, cache, eqp); |
1264 |
19638 |
} |
1265 |
|
|
1266 |
315997 |
void EqualityEngine::explainLit(TNode lit, std::vector<TNode>& assumptions) |
1267 |
|
{ |
1268 |
315997 |
Assert(lit.getKind() != kind::AND); |
1269 |
315997 |
bool polarity = lit.getKind() != kind::NOT; |
1270 |
631994 |
TNode atom = polarity ? lit : lit[0]; |
1271 |
631994 |
std::vector<TNode> tassumptions; |
1272 |
315997 |
if (atom.getKind() == kind::EQUAL) |
1273 |
|
{ |
1274 |
299407 |
Assert(hasTerm(atom[0])); |
1275 |
299407 |
Assert(hasTerm(atom[1])); |
1276 |
299407 |
if (!polarity) |
1277 |
|
{ |
1278 |
|
// ensure that we are ready to explain the disequality |
1279 |
20359 |
AlwaysAssert(areDisequal(atom[0], atom[1], true)); |
1280 |
|
} |
1281 |
279048 |
else if (atom[0] == atom[1]) |
1282 |
|
{ |
1283 |
|
// no need to explain reflexivity |
1284 |
|
return; |
1285 |
|
} |
1286 |
299407 |
explainEquality(atom[0], atom[1], polarity, tassumptions); |
1287 |
|
} |
1288 |
|
else |
1289 |
|
{ |
1290 |
16590 |
explainPredicate(atom, polarity, tassumptions); |
1291 |
|
} |
1292 |
|
// ensure that duplicates are removed |
1293 |
1694446 |
for (TNode a : tassumptions) |
1294 |
|
{ |
1295 |
4135347 |
if (std::find(assumptions.begin(), assumptions.end(), a) |
1296 |
4135347 |
== assumptions.end()) |
1297 |
|
{ |
1298 |
1233531 |
Assert(!a.isNull()); |
1299 |
1233531 |
assumptions.push_back(a); |
1300 |
|
} |
1301 |
|
} |
1302 |
|
} |
1303 |
|
|
1304 |
283582 |
Node EqualityEngine::mkExplainLit(TNode lit) |
1305 |
|
{ |
1306 |
283582 |
Assert(lit.getKind() != kind::AND); |
1307 |
567164 |
std::vector<TNode> assumptions; |
1308 |
283582 |
explainLit(lit, assumptions); |
1309 |
283582 |
Node ret; |
1310 |
283582 |
if (assumptions.empty()) |
1311 |
|
{ |
1312 |
|
ret = NodeManager::currentNM()->mkConst(true); |
1313 |
|
} |
1314 |
283582 |
else if (assumptions.size() == 1) |
1315 |
|
{ |
1316 |
58348 |
ret = assumptions[0]; |
1317 |
|
} |
1318 |
|
else |
1319 |
|
{ |
1320 |
225234 |
ret = NodeManager::currentNM()->mkNode(kind::AND, assumptions); |
1321 |
|
} |
1322 |
567164 |
return ret; |
1323 |
|
} |
1324 |
|
|
1325 |
5020686 |
void EqualityEngine::getExplanation( |
1326 |
|
EqualityNodeId t1Id, |
1327 |
|
EqualityNodeId t2Id, |
1328 |
|
std::vector<TNode>& equalities, |
1329 |
|
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>& cache, |
1330 |
|
EqProof* eqp) const |
1331 |
|
{ |
1332 |
10041372 |
Trace("eq-exp") << d_name << "::eq::getExplanation({" << t1Id << "} " |
1333 |
5020686 |
<< d_nodes[t1Id] << ", {" << t2Id << "} " << d_nodes[t2Id] |
1334 |
5020686 |
<< ") size = " << cache.size() << std::endl; |
1335 |
|
|
1336 |
|
// determine if we have already computed the explanation. |
1337 |
5020686 |
std::pair<EqualityNodeId, EqualityNodeId> cacheKey; |
1338 |
5020686 |
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>::iterator it; |
1339 |
5020686 |
if (!eqp) |
1340 |
|
{ |
1341 |
|
// If proofs are disabled, we order the ids, since explaining t1 = t2 is the |
1342 |
|
// same as explaining t2 = t1. |
1343 |
3625081 |
cacheKey = std::minmax(t1Id, t2Id); |
1344 |
3625081 |
it = cache.find(cacheKey); |
1345 |
3625081 |
if (it != cache.end()) |
1346 |
|
{ |
1347 |
1845906 |
return; |
1348 |
|
} |
1349 |
|
} |
1350 |
|
else |
1351 |
|
{ |
1352 |
|
// If proofs are enabled, note that proofs are sensitive to the order of t1 |
1353 |
|
// and t2, so we don't sort the ids in this case. TODO: Depending on how |
1354 |
|
// issue #2965 is resolved, we may be able to revisit this, if it is the |
1355 |
|
// case that proof/uf_proof.h,cpp is robust to equality ordering. |
1356 |
1395605 |
cacheKey = std::pair<EqualityNodeId, EqualityNodeId>(t1Id, t2Id); |
1357 |
1395605 |
it = cache.find(cacheKey); |
1358 |
1395605 |
if (it != cache.end()) |
1359 |
|
{ |
1360 |
832340 |
if (it->second) |
1361 |
|
{ |
1362 |
832338 |
eqp->d_id = it->second->d_id; |
1363 |
2497014 |
eqp->d_children.insert(eqp->d_children.end(), |
1364 |
832338 |
it->second->d_children.begin(), |
1365 |
3329352 |
it->second->d_children.end()); |
1366 |
832338 |
eqp->d_node = it->second->d_node; |
1367 |
|
} |
1368 |
|
else |
1369 |
|
{ |
1370 |
|
// We may have cached null in its place, create the trivial proof now. |
1371 |
2 |
Assert(d_nodes[t1Id] == d_nodes[t2Id]); |
1372 |
2 |
Assert(eqp->d_id == MERGED_THROUGH_REFLEXIVITY); |
1373 |
2 |
eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]); |
1374 |
|
} |
1375 |
832340 |
return; |
1376 |
|
} |
1377 |
|
} |
1378 |
2342440 |
cache[cacheKey] = eqp; |
1379 |
|
|
1380 |
|
// We can only explain the nodes that got merged |
1381 |
|
#ifdef CVC5_ASSERTIONS |
1382 |
2342440 |
bool canExplain = getEqualityNode(t1Id).getFind() == getEqualityNode(t2Id).getFind() |
1383 |
2342440 |
|| (d_done && isConstant(t1Id) && isConstant(t2Id)); |
1384 |
|
|
1385 |
2342440 |
if (!canExplain) { |
1386 |
|
Warning() << "Can't explain equality:" << std::endl; |
1387 |
|
Warning() << d_nodes[t1Id] << " with find " << d_nodes[getEqualityNode(t1Id).getFind()] << std::endl; |
1388 |
|
Warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl; |
1389 |
|
} |
1390 |
2342440 |
Assert(canExplain); |
1391 |
|
#endif |
1392 |
|
|
1393 |
|
// If the nodes are the same, we're done |
1394 |
2342440 |
if (t1Id == t2Id) |
1395 |
|
{ |
1396 |
597723 |
if (eqp) |
1397 |
|
{ |
1398 |
|
// ignore equalities between function symbols, i.e. internal nullary |
1399 |
|
// non-constant nodes. |
1400 |
|
// |
1401 |
|
// Note that this is robust for HOL because in that case function |
1402 |
|
// symbols are not internal nodes |
1403 |
306320 |
if (d_isInternal[t1Id] && d_nodes[t1Id].getNumChildren() == 0 |
1404 |
176191 |
&& !d_isConstant[t1Id]) |
1405 |
|
{ |
1406 |
46211 |
eqp->d_node = Node::null(); |
1407 |
|
} |
1408 |
|
else |
1409 |
|
{ |
1410 |
83769 |
Assert(d_nodes[t1Id].getKind() != kind::BUILTIN); |
1411 |
83769 |
eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]); |
1412 |
|
} |
1413 |
|
} |
1414 |
597723 |
return; |
1415 |
|
} |
1416 |
|
|
1417 |
|
// Queue for the BFS containing nodes |
1418 |
3489434 |
std::vector<BfsData> bfsQueue; |
1419 |
|
|
1420 |
|
// Find a path from t1 to t2 in the graph (BFS) |
1421 |
1744717 |
bfsQueue.push_back(BfsData(t1Id, null_id, 0)); |
1422 |
1744717 |
size_t currentIndex = 0; |
1423 |
|
while (true) { |
1424 |
|
// There should always be a path, and every node can be visited only once (tree) |
1425 |
12111747 |
Assert(currentIndex < bfsQueue.size()); |
1426 |
|
|
1427 |
|
// The next node to visit |
1428 |
12111747 |
BfsData current = bfsQueue[currentIndex]; |
1429 |
12111747 |
EqualityNodeId currentNode = current.d_nodeId; |
1430 |
|
|
1431 |
24223494 |
Debug("equality") << d_name << "::eq::getExplanation(): currentNode = {" |
1432 |
12111747 |
<< currentNode << "} " << d_nodes[currentNode] |
1433 |
12111747 |
<< std::endl; |
1434 |
|
|
1435 |
|
// Go through the equality edges of this node |
1436 |
12111747 |
EqualityEdgeId currentEdge = d_equalityGraph[currentNode]; |
1437 |
12111747 |
if (Debug.isOn("equality")) { |
1438 |
|
Debug("equality") << d_name << "::eq::getExplanation(): edgesId = " << currentEdge << std::endl; |
1439 |
|
Debug("equality") << d_name << "::eq::getExplanation(): edges = " << edgesToString(currentEdge) << std::endl; |
1440 |
|
} |
1441 |
|
|
1442 |
70894825 |
while (currentEdge != null_edge) { |
1443 |
|
// Get the edge |
1444 |
31136256 |
const EqualityEdge& edge = d_equalityEdges[currentEdge]; |
1445 |
|
|
1446 |
|
// If not just the backwards edge |
1447 |
31136256 |
if ((currentEdge | 1u) != (current.d_edgeId | 1u)) |
1448 |
|
{ |
1449 |
42546134 |
Debug("equality") << d_name |
1450 |
21273067 |
<< "::eq::getExplanation(): currentEdge = ({" |
1451 |
21273067 |
<< currentNode << "} " << d_nodes[currentNode] |
1452 |
42546134 |
<< ", {" << edge.getNodeId() << "} " |
1453 |
21273067 |
<< d_nodes[edge.getNodeId()] << ")" << std::endl; |
1454 |
|
|
1455 |
|
// Did we find the path |
1456 |
21273067 |
if (edge.getNodeId() == t2Id) { |
1457 |
|
|
1458 |
1744717 |
Debug("equality") << d_name << "::eq::getExplanation(): path found: " << std::endl; |
1459 |
|
|
1460 |
3489434 |
std::vector<std::shared_ptr<EqProof>> eqp_trans; |
1461 |
|
|
1462 |
|
// Reconstruct the path |
1463 |
2443594 |
do { |
1464 |
|
// The current node |
1465 |
4188311 |
currentNode = bfsQueue[currentIndex].d_nodeId; |
1466 |
4188311 |
EqualityNodeId edgeNode = d_equalityEdges[currentEdge].getNodeId(); |
1467 |
|
MergeReasonType reasonType = static_cast<MergeReasonType>( |
1468 |
4188311 |
d_equalityEdges[currentEdge].getReasonType()); |
1469 |
8376622 |
Node reason = d_equalityEdges[currentEdge].getReason(); |
1470 |
|
|
1471 |
8376622 |
Debug("equality") |
1472 |
4188311 |
<< d_name |
1473 |
4188311 |
<< "::eq::getExplanation(): currentEdge = " << currentEdge |
1474 |
4188311 |
<< ", currentNode = " << currentNode << std::endl; |
1475 |
8376622 |
Debug("equality") |
1476 |
4188311 |
<< d_name << " targetNode = {" << edgeNode |
1477 |
4188311 |
<< "} " << d_nodes[edgeNode] << std::endl; |
1478 |
8376622 |
Debug("equality") |
1479 |
4188311 |
<< d_name << " in currentEdge = ({" |
1480 |
4188311 |
<< currentNode << "} " << d_nodes[currentNode] << ", {" |
1481 |
8376622 |
<< edge.getNodeId() << "} " << d_nodes[edge.getNodeId()] << ")" |
1482 |
4188311 |
<< std::endl; |
1483 |
8376622 |
Debug("equality") |
1484 |
4188311 |
<< d_name |
1485 |
4188311 |
<< " reason type = " << reasonType |
1486 |
4188311 |
<< "\n"; |
1487 |
|
|
1488 |
8376622 |
std::shared_ptr<EqProof> eqpc;; |
1489 |
|
// Make child proof if a proof is being constructed |
1490 |
4188311 |
if (eqp) { |
1491 |
1088087 |
eqpc = std::make_shared<EqProof>(); |
1492 |
1088087 |
eqpc->d_id = reasonType; |
1493 |
|
} |
1494 |
|
|
1495 |
|
// Add the actual equality to the vector |
1496 |
4188311 |
switch (reasonType) { |
1497 |
2273616 |
case MERGED_THROUGH_CONGRUENCE: { |
1498 |
|
// f(x1, x2) == f(y1, y2) because x1 = y1 and x2 = y2 |
1499 |
4547232 |
Debug("equality") |
1500 |
2273616 |
<< d_name |
1501 |
2273616 |
<< "::eq::getExplanation(): due to congruence, going deeper" |
1502 |
2273616 |
<< std::endl; |
1503 |
|
const FunctionApplication& f1 = |
1504 |
2273616 |
d_applications[currentNode].d_original; |
1505 |
|
const FunctionApplication& f2 = |
1506 |
2273616 |
d_applications[edgeNode].d_original; |
1507 |
|
|
1508 |
2273616 |
Debug("equality") << push; |
1509 |
2273616 |
Debug("equality") << "Explaining left hand side equalities" << std::endl; |
1510 |
|
std::shared_ptr<EqProof> eqpc1 = |
1511 |
4547232 |
eqpc ? std::make_shared<EqProof>() : nullptr; |
1512 |
2273616 |
getExplanation(f1.d_a, f2.d_a, equalities, cache, eqpc1.get()); |
1513 |
2273616 |
Debug("equality") << "Explaining right hand side equalities" << std::endl; |
1514 |
|
std::shared_ptr<EqProof> eqpc2 = |
1515 |
4547232 |
eqpc ? std::make_shared<EqProof>() : nullptr; |
1516 |
2273616 |
getExplanation(f1.d_b, f2.d_b, equalities, cache, eqpc2.get()); |
1517 |
2273616 |
if (eqpc) |
1518 |
|
{ |
1519 |
657619 |
eqpc->d_children.push_back(eqpc1); |
1520 |
657619 |
eqpc->d_children.push_back(eqpc2); |
1521 |
|
// build conclusion if ids correspond to non-internal nodes or |
1522 |
|
// if non-internal nodes can be retrieved from them (in the |
1523 |
|
// case of n-ary applications), otherwise leave conclusion as |
1524 |
|
// null. This is only done for congruence kinds, since |
1525 |
|
// congruence is not used otherwise. |
1526 |
657619 |
Kind k = d_nodes[currentNode].getKind(); |
1527 |
657619 |
if (d_congruenceKinds[k]) |
1528 |
|
{ |
1529 |
653395 |
buildEqConclusion(currentNode, edgeNode, eqpc.get()); |
1530 |
|
} |
1531 |
|
else |
1532 |
|
{ |
1533 |
8448 |
Assert(k == kind::EQUAL) |
1534 |
4224 |
<< "not an internal node " << d_nodes[currentNode] |
1535 |
|
<< " with non-congruence with " << k << "\n"; |
1536 |
|
} |
1537 |
|
} |
1538 |
2273616 |
Debug("equality") << pop; |
1539 |
2273616 |
break; |
1540 |
|
} |
1541 |
|
|
1542 |
13176 |
case MERGED_THROUGH_REFLEXIVITY: { |
1543 |
|
// x1 == x1 |
1544 |
13176 |
Debug("equality") << d_name << "::eq::getExplanation(): due to reflexivity, going deeper" << std::endl; |
1545 |
13176 |
EqualityNodeId eqId = currentNode == d_trueId ? edgeNode : currentNode; |
1546 |
13176 |
const FunctionApplication& eq = d_applications[eqId].d_original; |
1547 |
13176 |
Assert(eq.isEquality()) << "Must be an equality"; |
1548 |
|
|
1549 |
|
// Explain why a = b constant |
1550 |
13176 |
Debug("equality") << push; |
1551 |
|
std::shared_ptr<EqProof> eqpc1 = |
1552 |
26352 |
eqpc ? std::make_shared<EqProof>() : nullptr; |
1553 |
13176 |
getExplanation(eq.d_a, eq.d_b, equalities, cache, eqpc1.get()); |
1554 |
13176 |
if( eqpc ){ |
1555 |
1714 |
eqpc->d_children.push_back( eqpc1 ); |
1556 |
|
} |
1557 |
13176 |
Debug("equality") << pop; |
1558 |
|
|
1559 |
13176 |
break; |
1560 |
|
} |
1561 |
|
|
1562 |
17103 |
case MERGED_THROUGH_CONSTANTS: { |
1563 |
|
// f(c1, ..., cn) = c semantically, we can just ignore it |
1564 |
17103 |
Debug("equality") << d_name << "::eq::getExplanation(): due to constants, explain the constants" << std::endl; |
1565 |
17103 |
Debug("equality") << push; |
1566 |
|
|
1567 |
|
// Get the node we interpreted |
1568 |
34206 |
TNode interpreted; |
1569 |
17103 |
if (eqpc) |
1570 |
|
{ |
1571 |
|
// build the conclusion f(c1, ..., cn) = c |
1572 |
1485 |
if (d_nodes[currentNode].isConst()) |
1573 |
|
{ |
1574 |
521 |
interpreted = d_nodes[edgeNode]; |
1575 |
521 |
eqpc->d_node = d_nodes[edgeNode].eqNode(d_nodes[currentNode]); |
1576 |
|
} |
1577 |
|
else |
1578 |
|
{ |
1579 |
964 |
interpreted = d_nodes[currentNode]; |
1580 |
964 |
eqpc->d_node = d_nodes[currentNode].eqNode(d_nodes[edgeNode]); |
1581 |
|
} |
1582 |
|
} |
1583 |
|
else |
1584 |
|
{ |
1585 |
31236 |
interpreted = d_nodes[currentNode].isConst() |
1586 |
5869 |
? d_nodes[edgeNode] |
1587 |
21487 |
: d_nodes[currentNode]; |
1588 |
|
} |
1589 |
|
|
1590 |
|
// Explain why a is a constant by explaining each argument |
1591 |
49770 |
for (unsigned i = 0; i < interpreted.getNumChildren(); ++ i) { |
1592 |
32667 |
EqualityNodeId childId = getNodeId(interpreted[i]); |
1593 |
32667 |
Assert(isConstant(childId)); |
1594 |
|
std::shared_ptr<EqProof> eqpcc = |
1595 |
65334 |
eqpc ? std::make_shared<EqProof>() : nullptr; |
1596 |
65334 |
getExplanation(childId, |
1597 |
32667 |
getEqualityNode(childId).getFind(), |
1598 |
|
equalities, |
1599 |
|
cache, |
1600 |
|
eqpcc.get()); |
1601 |
32667 |
if( eqpc ) { |
1602 |
3213 |
eqpc->d_children.push_back( eqpcc ); |
1603 |
3213 |
if (Debug.isOn("pf::ee")) |
1604 |
|
{ |
1605 |
|
Debug("pf::ee") |
1606 |
|
<< "MERGED_THROUGH_CONSTANTS. Dumping the child proof" |
1607 |
|
<< std::endl; |
1608 |
|
eqpc->debug_print("pf::ee", 1); |
1609 |
|
} |
1610 |
|
} |
1611 |
|
} |
1612 |
|
|
1613 |
17103 |
Debug("equality") << pop; |
1614 |
17103 |
break; |
1615 |
|
} |
1616 |
|
|
1617 |
1884416 |
default: { |
1618 |
|
// Construct the equality |
1619 |
3768832 |
Debug("equality") << d_name << "::eq::getExplanation(): adding: " |
1620 |
1884416 |
<< reason << std::endl; |
1621 |
3768832 |
Debug("equality") |
1622 |
1884416 |
<< d_name |
1623 |
1884416 |
<< "::eq::getExplanation(): reason type = " << reasonType |
1624 |
1884416 |
<< "\n"; |
1625 |
3768832 |
Node a = d_nodes[currentNode]; |
1626 |
3768832 |
Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()]; |
1627 |
|
|
1628 |
1884416 |
if (eqpc) { |
1629 |
427269 |
if (reasonType == MERGED_THROUGH_EQUALITY) { |
1630 |
|
// in the new proof infrastructure we can assume that "theory |
1631 |
|
// assumptions", which are a consequence of theory reasoning |
1632 |
|
// on other assumptions, are externally justified. In this |
1633 |
|
// case we can use (= a b) directly as the conclusion here. |
1634 |
427269 |
eqpc->d_node = b.eqNode(a); |
1635 |
|
} else { |
1636 |
|
// The LFSC translator prefers (not (= a b)) over (= (= a b) false) |
1637 |
|
|
1638 |
|
if (a == NodeManager::currentNM()->mkConst(false)) { |
1639 |
|
eqpc->d_node = b.notNode(); |
1640 |
|
} else if (b == NodeManager::currentNM()->mkConst(false)) { |
1641 |
|
eqpc->d_node = a.notNode(); |
1642 |
|
} else { |
1643 |
|
eqpc->d_node = b.eqNode(a); |
1644 |
|
} |
1645 |
|
} |
1646 |
427269 |
eqpc->d_id = reasonType; |
1647 |
|
} |
1648 |
1884416 |
equalities.push_back(reason); |
1649 |
1884416 |
break; |
1650 |
|
} |
1651 |
|
} |
1652 |
|
|
1653 |
|
// Go to the previous |
1654 |
4188311 |
currentEdge = bfsQueue[currentIndex].d_edgeId; |
1655 |
4188311 |
currentIndex = bfsQueue[currentIndex].d_previousIndex; |
1656 |
|
|
1657 |
|
//---from Morgan--- |
1658 |
4188311 |
if (eqpc != NULL && eqpc->d_id == MERGED_THROUGH_REFLEXIVITY) { |
1659 |
1714 |
if(eqpc->d_node.isNull()) { |
1660 |
1714 |
Assert(eqpc->d_children.size() == 1); |
1661 |
3428 |
std::shared_ptr<EqProof> p = eqpc; |
1662 |
1714 |
eqpc = p->d_children[0]; |
1663 |
|
} else { |
1664 |
|
Assert(eqpc->d_children.empty()); |
1665 |
|
} |
1666 |
|
} |
1667 |
|
//---end from Morgan--- |
1668 |
|
|
1669 |
4188311 |
eqp_trans.push_back(eqpc); |
1670 |
4188311 |
} while (currentEdge != null_id); |
1671 |
|
|
1672 |
1744717 |
if (eqp) { |
1673 |
433285 |
if(eqp_trans.size() == 1) { |
1674 |
137410 |
*eqp = *eqp_trans[0]; |
1675 |
|
} else { |
1676 |
295875 |
eqp->d_id = MERGED_THROUGH_TRANS; |
1677 |
295875 |
eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() ); |
1678 |
|
// build conclusion in case of equality between non-internal |
1679 |
|
// nodes or of n-ary congruence kinds, otherwise leave as |
1680 |
|
// null. The latter is necessary for the overall handling of |
1681 |
|
// congruence proofs involving n-ary kinds, see |
1682 |
|
// EqProof::reduceNestedCongruence for more details. |
1683 |
295875 |
buildEqConclusion(t1Id, t2Id, eqp); |
1684 |
|
} |
1685 |
433285 |
if (Debug.isOn("pf::ee")) |
1686 |
|
{ |
1687 |
|
eqp->debug_print("pf::ee", 1); |
1688 |
|
} |
1689 |
|
} |
1690 |
|
|
1691 |
|
// Done |
1692 |
1744717 |
return; |
1693 |
|
} |
1694 |
|
|
1695 |
|
// Push to the visitation queue if it's not the backward edge |
1696 |
19528350 |
bfsQueue.push_back(BfsData(edge.getNodeId(), currentEdge, currentIndex)); |
1697 |
|
} |
1698 |
|
|
1699 |
|
// Go to the next edge |
1700 |
29391539 |
currentEdge = edge.getNext(); |
1701 |
|
} |
1702 |
|
|
1703 |
|
// Go to the next node to visit |
1704 |
10367030 |
++ currentIndex; |
1705 |
10367030 |
} |
1706 |
|
} |
1707 |
|
|
1708 |
768402 |
void EqualityEngine::addTriggerEquality(TNode eq) { |
1709 |
768402 |
Assert(eq.getKind() == kind::EQUAL); |
1710 |
|
|
1711 |
768402 |
if (d_done) { |
1712 |
29 |
return; |
1713 |
|
} |
1714 |
|
|
1715 |
|
// Add the terms |
1716 |
768373 |
addTermInternal(eq[0]); |
1717 |
768373 |
addTermInternal(eq[1]); |
1718 |
|
|
1719 |
768373 |
bool skipTrigger = false; |
1720 |
|
|
1721 |
|
// If they are equal or disequal already, no need for the trigger |
1722 |
768373 |
if (areEqual(eq[0], eq[1])) { |
1723 |
18802 |
d_notify.eqNotifyTriggerPredicate(eq, true); |
1724 |
18802 |
skipTrigger = true; |
1725 |
|
} |
1726 |
768373 |
if (areDisequal(eq[0], eq[1], true)) { |
1727 |
9152 |
d_notify.eqNotifyTriggerPredicate(eq, false); |
1728 |
9152 |
skipTrigger = true; |
1729 |
|
} |
1730 |
|
|
1731 |
768373 |
if (skipTrigger) { |
1732 |
27954 |
return; |
1733 |
|
} |
1734 |
|
|
1735 |
|
// Add the equality |
1736 |
740419 |
addTermInternal(eq); |
1737 |
|
|
1738 |
|
// Positive trigger |
1739 |
740419 |
addTriggerEqualityInternal(eq[0], eq[1], eq, true); |
1740 |
|
// Negative trigger |
1741 |
740419 |
addTriggerEqualityInternal(eq, d_false, eq, false); |
1742 |
|
} |
1743 |
|
|
1744 |
855343 |
void EqualityEngine::addTriggerPredicate(TNode predicate) { |
1745 |
855343 |
Assert(predicate.getKind() != kind::NOT); |
1746 |
855343 |
if (predicate.getKind() == kind::EQUAL) |
1747 |
|
{ |
1748 |
|
// equality is handled separately |
1749 |
768402 |
return addTriggerEquality(predicate); |
1750 |
|
} |
1751 |
86941 |
Assert(d_congruenceKinds.test(predicate.getKind())) |
1752 |
|
<< "No point in adding non-congruence predicates, kind is " |
1753 |
|
<< predicate.getKind(); |
1754 |
|
|
1755 |
86941 |
if (d_done) { |
1756 |
188 |
return; |
1757 |
|
} |
1758 |
|
|
1759 |
|
// Add the term |
1760 |
86753 |
addTermInternal(predicate); |
1761 |
|
|
1762 |
86753 |
bool skipTrigger = false; |
1763 |
|
|
1764 |
|
// If it's know already, no need for the trigger |
1765 |
86753 |
if (areEqual(predicate, d_true)) { |
1766 |
2303 |
d_notify.eqNotifyTriggerPredicate(predicate, true); |
1767 |
2303 |
skipTrigger = true; |
1768 |
|
} |
1769 |
86753 |
if (areEqual(predicate, d_false)) { |
1770 |
1647 |
d_notify.eqNotifyTriggerPredicate(predicate, false); |
1771 |
1647 |
skipTrigger = true; |
1772 |
|
} |
1773 |
|
|
1774 |
86753 |
if (skipTrigger) { |
1775 |
3950 |
return; |
1776 |
|
} |
1777 |
|
|
1778 |
|
// Positive trigger |
1779 |
82803 |
addTriggerEqualityInternal(predicate, d_true, predicate, true); |
1780 |
|
// Negative trigger |
1781 |
82803 |
addTriggerEqualityInternal(predicate, d_false, predicate, false); |
1782 |
|
} |
1783 |
|
|
1784 |
1646444 |
void EqualityEngine::addTriggerEqualityInternal(TNode t1, TNode t2, TNode trigger, bool polarity) { |
1785 |
|
|
1786 |
1646444 |
Debug("equality") << d_name << "::eq::addTrigger(" << t1 << ", " << t2 << ", " << trigger << ")" << std::endl; |
1787 |
|
|
1788 |
1646444 |
Assert(hasTerm(t1)); |
1789 |
1646444 |
Assert(hasTerm(t2)); |
1790 |
|
|
1791 |
1646444 |
if (d_done) { |
1792 |
|
return; |
1793 |
|
} |
1794 |
|
|
1795 |
|
// Get the information about t1 |
1796 |
1646444 |
EqualityNodeId t1Id = getNodeId(t1); |
1797 |
1646444 |
EqualityNodeId t1classId = getEqualityNode(t1Id).getFind(); |
1798 |
|
// We will attach it to the class representative, since then we know how to backtrack it |
1799 |
1646444 |
TriggerId t1TriggerId = d_nodeTriggers[t1classId]; |
1800 |
|
|
1801 |
|
// Get the information about t2 |
1802 |
1646444 |
EqualityNodeId t2Id = getNodeId(t2); |
1803 |
1646444 |
EqualityNodeId t2classId = getEqualityNode(t2Id).getFind(); |
1804 |
|
// We will attach it to the class representative, since then we know how to backtrack it |
1805 |
1646444 |
TriggerId t2TriggerId = d_nodeTriggers[t2classId]; |
1806 |
|
|
1807 |
1646444 |
Debug("equality") << d_name << "::eq::addTrigger(" << trigger << "): " << t1Id << " (" << t1classId << ") = " << t2Id << " (" << t2classId << ")" << std::endl; |
1808 |
|
|
1809 |
|
// Create the triggers |
1810 |
1646444 |
TriggerId t1NewTriggerId = d_equalityTriggers.size(); |
1811 |
1646444 |
d_equalityTriggers.push_back(Trigger(t1classId, t1TriggerId)); |
1812 |
1646444 |
d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity)); |
1813 |
1646444 |
TriggerId t2NewTriggerId = d_equalityTriggers.size(); |
1814 |
1646444 |
d_equalityTriggers.push_back(Trigger(t2classId, t2TriggerId)); |
1815 |
1646444 |
d_equalityTriggersOriginal.push_back(TriggerInfo(trigger, polarity)); |
1816 |
|
|
1817 |
|
// Update the counters |
1818 |
1646444 |
d_equalityTriggersCount = d_equalityTriggers.size(); |
1819 |
1646444 |
Assert(d_equalityTriggers.size() == d_equalityTriggersOriginal.size()); |
1820 |
1646444 |
Assert(d_equalityTriggers.size() % 2 == 0); |
1821 |
|
|
1822 |
|
// Add the trigger to the trigger graph |
1823 |
1646444 |
d_nodeTriggers[t1classId] = t1NewTriggerId; |
1824 |
1646444 |
d_nodeTriggers[t2classId] = t2NewTriggerId; |
1825 |
|
|
1826 |
1646444 |
if (Debug.isOn("equality::internal")) { |
1827 |
|
debugPrintGraph(); |
1828 |
|
} |
1829 |
|
|
1830 |
1646444 |
Debug("equality") << d_name << "::eq::addTrigger(" << t1 << "," << t2 << ") => (" << t1NewTriggerId << ", " << t2NewTriggerId << ")" << std::endl; |
1831 |
|
} |
1832 |
|
|
1833 |
407071 |
Node EqualityEngine::evaluateTerm(TNode node) { |
1834 |
407071 |
Debug("equality::evaluation") << d_name << "::eq::evaluateTerm(" << node << ")" << std::endl; |
1835 |
814142 |
NodeBuilder builder; |
1836 |
407071 |
builder << node.getKind(); |
1837 |
407071 |
if (node.getMetaKind() == kind::metakind::PARAMETERIZED) { |
1838 |
5859 |
builder << node.getOperator(); |
1839 |
|
} |
1840 |
1177305 |
for (unsigned i = 0; i < node.getNumChildren(); ++ i) { |
1841 |
1540468 |
TNode child = node[i]; |
1842 |
1540468 |
TNode childRep = getRepresentative(child); |
1843 |
770234 |
Debug("equality::evaluation") << d_name << "::eq::evaluateTerm: " << child << " -> " << childRep << std::endl; |
1844 |
770234 |
Assert(childRep.isConst()); |
1845 |
770234 |
builder << childRep; |
1846 |
|
} |
1847 |
814142 |
Node newNode = builder; |
1848 |
814142 |
return Rewriter::rewrite(newNode); |
1849 |
|
} |
1850 |
|
|
1851 |
238928 |
void EqualityEngine::processEvaluationQueue() { |
1852 |
|
|
1853 |
238928 |
Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): start" << std::endl; |
1854 |
|
|
1855 |
1053070 |
while (!d_evaluationQueue.empty()) { |
1856 |
|
// Get the node |
1857 |
407071 |
EqualityNodeId id = d_evaluationQueue.front(); |
1858 |
407071 |
d_evaluationQueue.pop(); |
1859 |
|
|
1860 |
|
// Replace the children with their representatives (must be constants) |
1861 |
814142 |
Node nodeEvaluated = evaluateTerm(d_nodes[id]); |
1862 |
407071 |
Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): " << d_nodes[id] << " evaluates to " << nodeEvaluated << std::endl; |
1863 |
407071 |
Assert(nodeEvaluated.isConst()); |
1864 |
407071 |
addTermInternal(nodeEvaluated); |
1865 |
407071 |
EqualityNodeId nodeEvaluatedId = getNodeId(nodeEvaluated); |
1866 |
|
|
1867 |
|
// Enqueue the semantic equality |
1868 |
407071 |
enqueue(MergeCandidate(id, nodeEvaluatedId, MERGED_THROUGH_CONSTANTS, TNode::null())); |
1869 |
|
} |
1870 |
|
|
1871 |
238928 |
Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): done" << std::endl; |
1872 |
238928 |
} |
1873 |
|
|
1874 |
19136205 |
void EqualityEngine::propagate() { |
1875 |
|
|
1876 |
19136205 |
if (d_inPropagate) { |
1877 |
|
// We're already in propagate, go back |
1878 |
63989 |
return; |
1879 |
|
} |
1880 |
|
|
1881 |
|
// Make sure we don't get in again |
1882 |
38144432 |
ScopedBool inPropagate(d_inPropagate, true); |
1883 |
|
|
1884 |
19072216 |
Debug("equality") << d_name << "::eq::propagate()" << std::endl; |
1885 |
|
|
1886 |
70091840 |
while (!d_propagationQueue.empty() || !d_evaluationQueue.empty()) { |
1887 |
|
|
1888 |
25587610 |
if (d_done) { |
1889 |
|
// If we're done, just empty the queue |
1890 |
3597812 |
while (!d_propagationQueue.empty()) d_propagationQueue.pop_front(); |
1891 |
79610 |
while (!d_evaluationQueue.empty()) d_evaluationQueue.pop(); |
1892 |
5020306 |
continue; |
1893 |
|
} |
1894 |
|
|
1895 |
|
// Process any evaluation requests |
1896 |
25670948 |
if (!d_evaluationQueue.empty()) { |
1897 |
238928 |
processEvaluationQueue(); |
1898 |
238928 |
continue; |
1899 |
|
} |
1900 |
|
|
1901 |
|
// The current merge candidate |
1902 |
45760396 |
const MergeCandidate current = d_propagationQueue.front(); |
1903 |
25193092 |
d_propagationQueue.pop_front(); |
1904 |
|
|
1905 |
|
// Get the representatives |
1906 |
25193092 |
EqualityNodeId t1classId = getEqualityNode(current.d_t1Id).getFind(); |
1907 |
25193092 |
EqualityNodeId t2classId = getEqualityNode(current.d_t2Id).getFind(); |
1908 |
|
|
1909 |
|
// If already the same, we're done |
1910 |
25193092 |
if (t1classId == t2classId) { |
1911 |
4594738 |
continue; |
1912 |
|
} |
1913 |
|
|
1914 |
20598354 |
Debug("equality::internal") << d_name << "::eq::propagate(): t1: " << (d_isInternal[t1classId] ? "internal" : "proper") << std::endl; |
1915 |
20598354 |
Debug("equality::internal") << d_name << "::eq::propagate(): t2: " << (d_isInternal[t2classId] ? "internal" : "proper") << std::endl; |
1916 |
|
|
1917 |
|
// Get the nodes of the representatives |
1918 |
20598354 |
EqualityNode& node1 = getEqualityNode(t1classId); |
1919 |
20598354 |
EqualityNode& node2 = getEqualityNode(t2classId); |
1920 |
|
|
1921 |
20598354 |
Assert(node1.getFind() == t1classId); |
1922 |
20598354 |
Assert(node2.getFind() == t2classId); |
1923 |
|
|
1924 |
|
// Add the actual equality to the equality graph |
1925 |
41196708 |
addGraphEdge( |
1926 |
20598354 |
current.d_t1Id, current.d_t2Id, current.d_type, current.d_reason); |
1927 |
|
|
1928 |
|
// If constants are being merged we're done |
1929 |
20629404 |
if (d_isConstant[t1classId] && d_isConstant[t2classId]) { |
1930 |
|
// When merging constants we are inconsistent, hence done |
1931 |
31050 |
d_done = true; |
1932 |
|
// But in order to keep invariants (edges = 2*equalities) we put an equalities in |
1933 |
|
// Note that we can explain this merge as we have a graph edge |
1934 |
31050 |
d_assertedEqualities.push_back(Equality(null_id, null_id)); |
1935 |
31050 |
d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1; |
1936 |
|
// Notify |
1937 |
31050 |
if (d_performNotify) { |
1938 |
31050 |
d_notify.eqNotifyConstantTermMerge(d_nodes[t1classId], d_nodes[t2classId]); |
1939 |
|
} |
1940 |
|
// Empty the queue and exit |
1941 |
31050 |
continue; |
1942 |
|
} |
1943 |
|
|
1944 |
|
// Vector to collect the triggered events |
1945 |
41134608 |
std::vector<TriggerId> triggers; |
1946 |
|
|
1947 |
|
// Figure out the merge preference |
1948 |
20567304 |
EqualityNodeId mergeInto = t1classId; |
1949 |
20567304 |
if (d_isInternal[t2classId] != d_isInternal[t1classId]) { |
1950 |
|
// We always keep non-internal nodes as representatives: if any node in |
1951 |
|
// the class is non-internal, then the representative will be non-internal |
1952 |
11140 |
if (d_isInternal[t1classId]) { |
1953 |
6819 |
mergeInto = t2classId; |
1954 |
|
} else { |
1955 |
4321 |
mergeInto = t1classId; |
1956 |
|
} |
1957 |
20556164 |
} else if (d_isConstant[t2classId] != d_isConstant[t1classId]) { |
1958 |
|
// We always keep constants as representatives: if any (at most one) node |
1959 |
|
// in the class in a constant, then the representative will be a constant |
1960 |
14581588 |
if (d_isConstant[t2classId]) { |
1961 |
13234047 |
mergeInto = t2classId; |
1962 |
|
} else { |
1963 |
1347541 |
mergeInto = t1classId; |
1964 |
|
} |
1965 |
5974576 |
} else if (node2.getSize() > node1.getSize()) { |
1966 |
|
// We always merge into the bigger class to reduce the amount of traversing |
1967 |
|
// we need to do |
1968 |
2301102 |
mergeInto = t2classId; |
1969 |
|
} |
1970 |
|
|
1971 |
20567304 |
if (mergeInto == t2classId) { |
1972 |
31083936 |
Debug("equality") << d_name << "::eq::propagate(): merging " |
1973 |
15541968 |
<< d_nodes[current.d_t1Id] << " into " |
1974 |
15541968 |
<< d_nodes[current.d_t2Id] << std::endl; |
1975 |
15541968 |
d_assertedEqualities.push_back(Equality(t2classId, t1classId)); |
1976 |
15541968 |
d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1; |
1977 |
15541968 |
if (!merge(node2, node1, triggers)) { |
1978 |
5891 |
d_done = true; |
1979 |
|
} |
1980 |
|
} else { |
1981 |
10050672 |
Debug("equality") << d_name << "::eq::propagate(): merging " |
1982 |
5025336 |
<< d_nodes[current.d_t2Id] << " into " |
1983 |
5025336 |
<< d_nodes[current.d_t1Id] << std::endl; |
1984 |
5025336 |
d_assertedEqualities.push_back(Equality(t1classId, t2classId)); |
1985 |
5025336 |
d_assertedEqualitiesCount = d_assertedEqualitiesCount + 1; |
1986 |
5025336 |
if (!merge(node1, node2, triggers)) { |
1987 |
4948 |
d_done = true; |
1988 |
|
} |
1989 |
|
} |
1990 |
|
|
1991 |
|
// If not merging internal nodes, notify the master |
1992 |
20567301 |
if (d_masterEqualityEngine && !d_isInternal[t1classId] && !d_isInternal[t2classId]) { |
1993 |
4604626 |
d_masterEqualityEngine->assertEqualityInternal(d_nodes[t1classId], d_nodes[t2classId], TNode::null()); |
1994 |
4604626 |
d_masterEqualityEngine->propagate(); |
1995 |
|
} |
1996 |
|
|
1997 |
|
// Notify the triggers |
1998 |
20567301 |
if (d_performNotify && !d_done) { |
1999 |
30360493 |
for (size_t trigger_i = 0, trigger_end = triggers.size(); trigger_i < trigger_end && !d_done; ++ trigger_i) { |
2000 |
9804031 |
const TriggerInfo& triggerInfo = d_equalityTriggersOriginal[triggers[trigger_i]]; |
2001 |
9804031 |
if (triggerInfo.d_trigger.getKind() == kind::EQUAL) |
2002 |
|
{ |
2003 |
|
// Special treatment for disequalities |
2004 |
8567543 |
if (!triggerInfo.d_polarity) |
2005 |
|
{ |
2006 |
|
// Store that we are propagating a diseauality |
2007 |
10300296 |
TNode equality = triggerInfo.d_trigger; |
2008 |
5150148 |
EqualityNodeId original = getNodeId(equality); |
2009 |
10300296 |
TNode lhs = equality[0]; |
2010 |
10300296 |
TNode rhs = equality[1]; |
2011 |
5150148 |
EqualityNodeId lhsId = getNodeId(lhs); |
2012 |
5150148 |
EqualityNodeId rhsId = getNodeId(rhs); |
2013 |
|
// We use the THEORY_LAST as a marker for "marked as propagated, reasons stored". |
2014 |
|
// This tag is added to an internal theories set that is only inserted in, so this is |
2015 |
|
// safe. Had we iterated over, or done other set operations this might be dangerous. |
2016 |
5150148 |
if (!hasPropagatedDisequality(THEORY_LAST, lhsId, rhsId)) { |
2017 |
4742661 |
if (!hasPropagatedDisequality(lhsId, rhsId)) { |
2018 |
4733375 |
d_deducedDisequalityReasons.push_back(EqualityPair(original, d_falseId)); |
2019 |
|
} |
2020 |
4742661 |
storePropagatedDisequality(THEORY_LAST, lhsId, rhsId); |
2021 |
9485322 |
if (!d_notify.eqNotifyTriggerPredicate(triggerInfo.d_trigger, |
2022 |
4742661 |
triggerInfo.d_polarity)) |
2023 |
|
{ |
2024 |
375 |
d_done = true; |
2025 |
|
} |
2026 |
|
} |
2027 |
|
} |
2028 |
|
else |
2029 |
|
{ |
2030 |
|
// Equalities are simple |
2031 |
6834790 |
if (!d_notify.eqNotifyTriggerPredicate(triggerInfo.d_trigger, |
2032 |
3417395 |
triggerInfo.d_polarity)) |
2033 |
|
{ |
2034 |
50148 |
d_done = true; |
2035 |
|
} |
2036 |
|
} |
2037 |
|
} |
2038 |
|
else |
2039 |
|
{ |
2040 |
2472976 |
if (!d_notify.eqNotifyTriggerPredicate(triggerInfo.d_trigger, |
2041 |
1236488 |
triggerInfo.d_polarity)) |
2042 |
|
{ |
2043 |
1992 |
d_done = true; |
2044 |
|
} |
2045 |
|
} |
2046 |
|
} |
2047 |
|
} |
2048 |
|
} |
2049 |
|
} |
2050 |
|
|
2051 |
|
void EqualityEngine::debugPrintGraph() const { |
2052 |
|
Debug("equality::graph") << std::endl << "Dumping graph" << std::endl; |
2053 |
|
for (EqualityNodeId nodeId = 0; nodeId < d_nodes.size(); ++ nodeId) { |
2054 |
|
|
2055 |
|
Debug("equality::graph") << d_nodes[nodeId] << " " << nodeId << "(" << getEqualityNode(nodeId).getFind() << "):"; |
2056 |
|
|
2057 |
|
EqualityEdgeId edgeId = d_equalityGraph[nodeId]; |
2058 |
|
while (edgeId != null_edge) { |
2059 |
|
const EqualityEdge& edge = d_equalityEdges[edgeId]; |
2060 |
|
Debug("equality::graph") << " [" << edge.getNodeId() << "] " << d_nodes[edge.getNodeId()] << ":" << edge.getReason(); |
2061 |
|
edgeId = edge.getNext(); |
2062 |
|
} |
2063 |
|
|
2064 |
|
Debug("equality::graph") << std::endl; |
2065 |
|
} |
2066 |
|
Debug("equality::graph") << std::endl; |
2067 |
|
} |
2068 |
|
|
2069 |
|
std::string EqualityEngine::debugPrintEqc() const |
2070 |
|
{ |
2071 |
|
std::stringstream ss; |
2072 |
|
eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(this); |
2073 |
|
while (!eqcs2_i.isFinished()) |
2074 |
|
{ |
2075 |
|
Node eqc = (*eqcs2_i); |
2076 |
|
eq::EqClassIterator eqc2_i = eq::EqClassIterator(eqc, this); |
2077 |
|
ss << "Eqc( " << eqc << " ) : { "; |
2078 |
|
while (!eqc2_i.isFinished()) |
2079 |
|
{ |
2080 |
|
if ((*eqc2_i) != eqc && (*eqc2_i).getKind() != kind::EQUAL) |
2081 |
|
{ |
2082 |
|
ss << (*eqc2_i) << " "; |
2083 |
|
} |
2084 |
|
++eqc2_i; |
2085 |
|
} |
2086 |
|
ss << " } " << std::endl; |
2087 |
|
++eqcs2_i; |
2088 |
|
} |
2089 |
|
return ss.str(); |
2090 |
|
} |
2091 |
|
|
2092 |
16044009 |
bool EqualityEngine::areEqual(TNode t1, TNode t2) const { |
2093 |
16044009 |
Debug("equality") << d_name << "::eq::areEqual(" << t1 << "," << t2 << ")"; |
2094 |
|
|
2095 |
16044009 |
Assert(hasTerm(t1)); |
2096 |
16044009 |
Assert(hasTerm(t2)); |
2097 |
|
|
2098 |
16044009 |
bool result = getEqualityNode(t1).getFind() == getEqualityNode(t2).getFind(); |
2099 |
16044009 |
Debug("equality") << (result ? "\t(YES)" : "\t(NO)") << std::endl; |
2100 |
16044009 |
return result; |
2101 |
|
} |
2102 |
|
|
2103 |
10636592 |
bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const |
2104 |
|
{ |
2105 |
10636592 |
Debug("equality") << d_name << "::eq::areDisequal(" << t1 << "," << t2 << ")"; |
2106 |
|
|
2107 |
|
// Add the terms |
2108 |
10636592 |
Assert(hasTerm(t1)); |
2109 |
10636592 |
Assert(hasTerm(t2)); |
2110 |
|
|
2111 |
|
// Get ids |
2112 |
10636592 |
EqualityNodeId t1Id = getNodeId(t1); |
2113 |
10636592 |
EqualityNodeId t2Id = getNodeId(t2); |
2114 |
|
|
2115 |
|
// If we propagated this disequality we're true |
2116 |
10636592 |
if (hasPropagatedDisequality(t1Id, t2Id)) { |
2117 |
2448120 |
Debug("equality") << "\t(YES)" << std::endl; |
2118 |
2448120 |
return true; |
2119 |
|
} |
2120 |
|
|
2121 |
|
// Get equivalence classes |
2122 |
8188472 |
EqualityNodeId t1ClassId = getEqualityNode(t1Id).getFind(); |
2123 |
8188472 |
EqualityNodeId t2ClassId = getEqualityNode(t2Id).getFind(); |
2124 |
|
|
2125 |
|
// We are semantically const, for remembering stuff |
2126 |
8188472 |
EqualityEngine* nonConst = const_cast<EqualityEngine*>(this); |
2127 |
|
|
2128 |
|
// Check for constants |
2129 |
8188472 |
if (d_isConstant[t1ClassId] && d_isConstant[t2ClassId] && t1ClassId != t2ClassId) { |
2130 |
1572387 |
if (ensureProof) { |
2131 |
6409 |
nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t1Id, t1ClassId)); |
2132 |
6409 |
nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(t2Id, t2ClassId)); |
2133 |
6409 |
nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id); |
2134 |
|
} |
2135 |
1572387 |
Debug("equality") << "\t(YES)" << std::endl; |
2136 |
1572387 |
return true; |
2137 |
|
} |
2138 |
|
|
2139 |
|
// Create the equality |
2140 |
6616085 |
FunctionApplication eqNormalized(APP_EQUALITY, t1ClassId, t2ClassId); |
2141 |
6616085 |
ApplicationIdsMap::const_iterator find = d_applicationLookup.find(eqNormalized); |
2142 |
6616085 |
if (find != d_applicationLookup.end()) { |
2143 |
2824585 |
if (getEqualityNode(find->second).getFind() == getEqualityNode(d_falseId).getFind()) { |
2144 |
231769 |
if (ensureProof) { |
2145 |
|
const FunctionApplication original = |
2146 |
2006 |
d_applications[find->second].d_original; |
2147 |
4012 |
nonConst->d_deducedDisequalityReasons.push_back( |
2148 |
4012 |
EqualityPair(t1Id, original.d_a)); |
2149 |
2006 |
nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(find->second, d_falseId)); |
2150 |
4012 |
nonConst->d_deducedDisequalityReasons.push_back( |
2151 |
4012 |
EqualityPair(t2Id, original.d_b)); |
2152 |
2006 |
nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id); |
2153 |
|
} |
2154 |
231769 |
Debug("equality") << "\t(YES)" << std::endl; |
2155 |
231769 |
return true; |
2156 |
|
} |
2157 |
|
} |
2158 |
|
|
2159 |
|
// Check the symmetric disequality |
2160 |
6384316 |
std::swap(eqNormalized.d_a, eqNormalized.d_b); |
2161 |
6384316 |
find = d_applicationLookup.find(eqNormalized); |
2162 |
6384316 |
if (find != d_applicationLookup.end()) { |
2163 |
519049 |
if (getEqualityNode(find->second).getFind() == getEqualityNode(d_falseId).getFind()) { |
2164 |
339226 |
if (ensureProof) { |
2165 |
|
const FunctionApplication original = |
2166 |
1192 |
d_applications[find->second].d_original; |
2167 |
2384 |
nonConst->d_deducedDisequalityReasons.push_back( |
2168 |
2384 |
EqualityPair(t2Id, original.d_a)); |
2169 |
1192 |
nonConst->d_deducedDisequalityReasons.push_back(EqualityPair(find->second, d_falseId)); |
2170 |
2384 |
nonConst->d_deducedDisequalityReasons.push_back( |
2171 |
2384 |
EqualityPair(t1Id, original.d_b)); |
2172 |
1192 |
nonConst->storePropagatedDisequality(THEORY_LAST, t1Id, t2Id); |
2173 |
|
} |
2174 |
339226 |
Debug("equality") << "\t(YES)" << std::endl; |
2175 |
339226 |
return true; |
2176 |
|
} |
2177 |
|
} |
2178 |
|
|
2179 |
|
// Couldn't deduce dis-equalityReturn whether the terms are disequal |
2180 |
6045090 |
Debug("equality") << "\t(NO)" << std::endl; |
2181 |
6045090 |
return false; |
2182 |
|
} |
2183 |
|
|
2184 |
|
size_t EqualityEngine::getSize(TNode t) { |
2185 |
|
// Add the term |
2186 |
|
addTermInternal(t); |
2187 |
|
return getEqualityNode(getEqualityNode(t).getFind()).getSize(); |
2188 |
|
} |
2189 |
|
|
2190 |
18450 |
std::string EqualityEngine::identify() const { return d_name; } |
2191 |
|
|
2192 |
3080745 |
void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag) |
2193 |
|
{ |
2194 |
3080745 |
Debug("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << ")" << std::endl; |
2195 |
|
|
2196 |
3080745 |
Assert(tag != THEORY_LAST); |
2197 |
|
|
2198 |
3080745 |
if (d_done) { |
2199 |
|
return; |
2200 |
|
} |
2201 |
|
|
2202 |
|
// Add the term if it's not already there |
2203 |
3080745 |
addTermInternal(t); |
2204 |
|
|
2205 |
3080745 |
if (!d_anyTermsAreTriggers) |
2206 |
|
{ |
2207 |
|
// if we are not using triggers, we only add the term, but not as a trigger |
2208 |
|
return; |
2209 |
|
} |
2210 |
|
|
2211 |
|
// Get the node id |
2212 |
3080745 |
EqualityNodeId eqNodeId = getNodeId(t); |
2213 |
3080745 |
EqualityNode& eqNode = getEqualityNode(eqNodeId); |
2214 |
3080745 |
EqualityNodeId classId = eqNode.getFind(); |
2215 |
|
|
2216 |
|
// Possibly existing set of triggers |
2217 |
3080745 |
TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId]; |
2218 |
3080745 |
if (triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag)) { |
2219 |
|
// If the term already is in the equivalence class that a tagged representative, just notify |
2220 |
910189 |
if (d_performNotify) { |
2221 |
910189 |
EqualityNodeId triggerId = getTriggerTermSet(triggerSetRef).getTrigger(tag); |
2222 |
910189 |
Debug("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << "): already have this trigger in class with " << d_nodes[triggerId] << std::endl; |
2223 |
910189 |
if (eqNodeId != triggerId && !d_notify.eqNotifyTriggerTermEquality(tag, t, d_nodes[triggerId], true)) { |
2224 |
508 |
d_done = true; |
2225 |
|
} |
2226 |
|
} |
2227 |
|
} else { |
2228 |
|
|
2229 |
|
// Check for disequalities by going through the equivalence class looking for equalities in the |
2230 |
|
// uselists that have been asserted to false. All the representatives appearing on the other |
2231 |
|
// side of such disequalities, that have the tag on, are put in a set. |
2232 |
4341112 |
TaggedEqualitiesSet disequalitiesToNotify; |
2233 |
2170556 |
TheoryIdSet tags = TheoryIdSetUtil::setInsert(tag); |
2234 |
2170556 |
getDisequalities(!d_isConstant[classId], classId, tags, disequalitiesToNotify); |
2235 |
|
|
2236 |
|
// Trigger data |
2237 |
|
TheoryIdSet newSetTags; |
2238 |
|
EqualityNodeId newSetTriggers[THEORY_LAST]; |
2239 |
|
unsigned newSetTriggersSize; |
2240 |
|
|
2241 |
|
// Setup the data for the new set |
2242 |
2170556 |
if (triggerSetRef != null_set_id) { |
2243 |
|
// Get the existing set |
2244 |
493634 |
TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef); |
2245 |
|
// Initialize the new set for copy/insert |
2246 |
493634 |
newSetTags = TheoryIdSetUtil::setInsert(tag, triggerSet.d_tags); |
2247 |
493634 |
newSetTriggersSize = 0; |
2248 |
|
// Copy into to new one, and insert the new tag/id |
2249 |
493634 |
unsigned i = 0; |
2250 |
493634 |
TheoryIdSet tags2 = newSetTags; |
2251 |
|
TheoryId current; |
2252 |
2503406 |
while ((current = TheoryIdSetUtil::setPop(tags2)) != THEORY_LAST) |
2253 |
|
{ |
2254 |
|
// Remove from the tags |
2255 |
1004886 |
tags2 = TheoryIdSetUtil::setRemove(current, tags2); |
2256 |
|
// Insert the id into the triggers |
2257 |
1004886 |
newSetTriggers[newSetTriggersSize++] = |
2258 |
1004886 |
current == tag ? eqNodeId : triggerSet.d_triggers[i++]; |
2259 |
|
} |
2260 |
|
} else { |
2261 |
|
// Setup a singleton |
2262 |
1676922 |
newSetTags = TheoryIdSetUtil::setInsert(tag); |
2263 |
1676922 |
newSetTriggers[0] = eqNodeId; |
2264 |
1676922 |
newSetTriggersSize = 1; |
2265 |
|
} |
2266 |
|
|
2267 |
|
// Add it to the list for backtracking |
2268 |
2170556 |
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef)); |
2269 |
2170556 |
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1; |
2270 |
|
// Mark the the new set as a trigger |
2271 |
2170556 |
d_nodeIndividualTrigger[classId] = triggerSetRef = newTriggerTermSet(newSetTags, newSetTriggers, newSetTriggersSize); |
2272 |
|
|
2273 |
|
// Propagate trigger term disequalities we remembered |
2274 |
2170556 |
Debug("equality::trigger") << d_name << "::eq::addTriggerTerm(" << t << ", " << tag << "): propagating " << disequalitiesToNotify.size() << " disequalities " << std::endl; |
2275 |
2170556 |
propagateTriggerTermDisequalities(tags, triggerSetRef, disequalitiesToNotify); |
2276 |
|
} |
2277 |
|
} |
2278 |
|
|
2279 |
6419518 |
bool EqualityEngine::isTriggerTerm(TNode t, TheoryId tag) const { |
2280 |
6419518 |
if (!hasTerm(t)) return false; |
2281 |
6419518 |
EqualityNodeId classId = getEqualityNode(t).getFind(); |
2282 |
6419518 |
TriggerTermSetRef triggerSetRef = d_nodeIndividualTrigger[classId]; |
2283 |
6419518 |
return triggerSetRef != +null_set_id && getTriggerTermSet(triggerSetRef).hasTrigger(tag); |
2284 |
|
} |
2285 |
|
|
2286 |
|
|
2287 |
2374271 |
TNode EqualityEngine::getTriggerTermRepresentative(TNode t, TheoryId tag) const { |
2288 |
2374271 |
Assert(isTriggerTerm(t, tag)); |
2289 |
2374271 |
EqualityNodeId classId = getEqualityNode(t).getFind(); |
2290 |
2374271 |
const TriggerTermSet& triggerSet = getTriggerTermSet(d_nodeIndividualTrigger[classId]); |
2291 |
2374271 |
unsigned i = 0; |
2292 |
2374271 |
TheoryIdSet tags = triggerSet.d_tags; |
2293 |
5385165 |
while (TheoryIdSetUtil::setPop(tags) != tag) |
2294 |
|
{ |
2295 |
1505447 |
++ i; |
2296 |
|
} |
2297 |
2374271 |
return d_nodes[triggerSet.d_triggers[i]]; |
2298 |
|
} |
2299 |
|
|
2300 |
12296602 |
void EqualityEngine::storeApplicationLookup(FunctionApplication& funNormalized, EqualityNodeId funId) { |
2301 |
12296602 |
Assert(d_applicationLookup.find(funNormalized) == d_applicationLookup.end()); |
2302 |
12296602 |
d_applicationLookup[funNormalized] = funId; |
2303 |
12296602 |
d_applicationLookups.push_back(funNormalized); |
2304 |
12296602 |
d_applicationLookupsCount = d_applicationLookupsCount + 1; |
2305 |
12296602 |
Debug("equality::backtrack") << "d_applicationLookupsCount = " << d_applicationLookupsCount << std::endl; |
2306 |
12296602 |
Debug("equality::backtrack") << "d_applicationLookups.size() = " << d_applicationLookups.size() << std::endl; |
2307 |
12296602 |
Assert(d_applicationLookupsCount == d_applicationLookups.size()); |
2308 |
|
|
2309 |
|
// If an equality over constants we merge to false |
2310 |
12296602 |
if (funNormalized.isEquality()) { |
2311 |
8596449 |
if (funNormalized.d_a == funNormalized.d_b) |
2312 |
|
{ |
2313 |
833777 |
enqueue(MergeCandidate(funId, d_trueId, MERGED_THROUGH_REFLEXIVITY, TNode::null())); |
2314 |
|
} |
2315 |
7762672 |
else if (d_isConstant[funNormalized.d_a] && d_isConstant[funNormalized.d_b]) |
2316 |
|
{ |
2317 |
832882 |
enqueue(MergeCandidate(funId, d_falseId, MERGED_THROUGH_CONSTANTS, TNode::null())); |
2318 |
|
} |
2319 |
|
} |
2320 |
12296602 |
} |
2321 |
|
|
2322 |
|
void EqualityEngine::getUseListTerms(TNode t, std::set<TNode>& output) { |
2323 |
|
if (hasTerm(t)) { |
2324 |
|
// Get the equivalence class |
2325 |
|
EqualityNodeId classId = getEqualityNode(t).getFind(); |
2326 |
|
// Go through the equivalence class and get where t is used in |
2327 |
|
EqualityNodeId currentId = classId; |
2328 |
|
do { |
2329 |
|
// Get the current node |
2330 |
|
EqualityNode& currentNode = getEqualityNode(currentId); |
2331 |
|
// Go through the use-list |
2332 |
|
UseListNodeId currentUseId = currentNode.getUseList(); |
2333 |
|
while (currentUseId != null_uselist_id) { |
2334 |
|
// Get the node of the use list |
2335 |
|
UseListNode& useNode = d_useListNodes[currentUseId]; |
2336 |
|
// Get the function application |
2337 |
|
EqualityNodeId funId = useNode.getApplicationId(); |
2338 |
|
output.insert(d_nodes[funId]); |
2339 |
|
// Go to the next one in the use list |
2340 |
|
currentUseId = useNode.getNext(); |
2341 |
|
} |
2342 |
|
// Move to the next node |
2343 |
|
currentId = currentNode.getNext(); |
2344 |
|
} while (currentId != classId); |
2345 |
|
} |
2346 |
|
} |
2347 |
|
|
2348 |
3950255 |
EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet( |
2349 |
|
TheoryIdSet newSetTags, |
2350 |
|
EqualityNodeId* newSetTriggers, |
2351 |
|
unsigned newSetTriggersSize) |
2352 |
|
{ |
2353 |
|
// Size of the required set |
2354 |
3950255 |
size_t size = sizeof(TriggerTermSet) + newSetTriggersSize*sizeof(EqualityNodeId); |
2355 |
|
// Align the size |
2356 |
3950255 |
size = (size + 7) & ~((size_t)7); |
2357 |
|
// Reallocate if necessary |
2358 |
3950255 |
if (d_triggerDatabaseSize + size > d_triggerDatabaseAllocatedSize) { |
2359 |
|
d_triggerDatabaseAllocatedSize *= 2; |
2360 |
|
d_triggerDatabase = (char*) realloc(d_triggerDatabase, d_triggerDatabaseAllocatedSize); |
2361 |
|
} |
2362 |
|
// New reference |
2363 |
3950255 |
TriggerTermSetRef newTriggerSetRef = d_triggerDatabaseSize; |
2364 |
|
// Update the size |
2365 |
3950255 |
d_triggerDatabaseSize = d_triggerDatabaseSize + size; |
2366 |
|
// Copy the information |
2367 |
3950255 |
TriggerTermSet& newSet = getTriggerTermSet(newTriggerSetRef); |
2368 |
3950255 |
newSet.d_tags = newSetTags; |
2369 |
29725080 |
for (unsigned i = 0; i < newSetTriggersSize; ++i) { |
2370 |
25774825 |
newSet.d_triggers[i] = newSetTriggers[i]; |
2371 |
|
} |
2372 |
|
// Return the new reference |
2373 |
3950255 |
return newTriggerSetRef; |
2374 |
|
} |
2375 |
|
|
2376 |
16846501 |
bool EqualityEngine::hasPropagatedDisequality(EqualityNodeId lhsId, EqualityNodeId rhsId) const { |
2377 |
16846501 |
EqualityPair eq(lhsId, rhsId); |
2378 |
16846501 |
bool propagated = d_propagatedDisequalities.find(eq) != d_propagatedDisequalities.end(); |
2379 |
|
#ifdef CVC5_ASSERTIONS |
2380 |
16846501 |
bool stored = d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end(); |
2381 |
16846501 |
Assert(propagated == stored) << "These two should be in sync"; |
2382 |
|
#endif |
2383 |
16846501 |
Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (propagated ? "true" : "false") << std::endl; |
2384 |
16846501 |
return propagated; |
2385 |
|
} |
2386 |
|
|
2387 |
13975846 |
bool EqualityEngine::hasPropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) const { |
2388 |
|
|
2389 |
13975846 |
EqualityPair eq(lhsId, rhsId); |
2390 |
|
|
2391 |
13975846 |
PropagatedDisequalitiesMap::const_iterator it = d_propagatedDisequalities.find(eq); |
2392 |
13975846 |
if (it == d_propagatedDisequalities.end()) { |
2393 |
10841727 |
Assert(d_disequalityReasonsMap.find(eq) == d_disequalityReasonsMap.end()) |
2394 |
|
<< "Why do we have a proof if not propagated"; |
2395 |
10841727 |
Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => false" << std::endl; |
2396 |
10841727 |
return false; |
2397 |
|
} |
2398 |
3134119 |
Assert(d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end()) |
2399 |
|
<< "We propagated but there is no proof"; |
2400 |
3134119 |
bool result = TheoryIdSetUtil::setContains(tag, (*it).second); |
2401 |
3134119 |
Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (result ? "true" : "false") << std::endl; |
2402 |
3134119 |
return result; |
2403 |
|
} |
2404 |
|
|
2405 |
|
|
2406 |
6219516 |
void EqualityEngine::storePropagatedDisequality(TheoryId tag, EqualityNodeId lhsId, EqualityNodeId rhsId) { |
2407 |
6219516 |
Assert(!hasPropagatedDisequality(tag, lhsId, rhsId)) |
2408 |
|
<< "Check before you store it"; |
2409 |
6219516 |
Assert(lhsId != rhsId) << "Wow, wtf!"; |
2410 |
|
|
2411 |
6219516 |
Debug("equality::disequality") << d_name << "::eq::storePropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ")" << std::endl; |
2412 |
|
|
2413 |
6219516 |
EqualityPair pair1(lhsId, rhsId); |
2414 |
6219516 |
EqualityPair pair2(rhsId, lhsId); |
2415 |
|
|
2416 |
|
// Store the fact that we've propagated this already |
2417 |
6219516 |
TheoryIdSet notified = 0; |
2418 |
6219516 |
PropagatedDisequalitiesMap::const_iterator find = d_propagatedDisequalities.find(pair1); |
2419 |
6219516 |
if (find == d_propagatedDisequalities.end()) { |
2420 |
5425667 |
notified = TheoryIdSetUtil::setInsert(tag); |
2421 |
|
} else { |
2422 |
793849 |
notified = TheoryIdSetUtil::setInsert(tag, (*find).second); |
2423 |
|
} |
2424 |
6219516 |
d_propagatedDisequalities[pair1] = notified; |
2425 |
6219516 |
d_propagatedDisequalities[pair2] = notified; |
2426 |
|
|
2427 |
|
// Store the proof if provided |
2428 |
6219516 |
if (d_deducedDisequalityReasons.size() > d_deducedDisequalityReasonsSize) { |
2429 |
5425667 |
Debug("equality::disequality") << d_name << "::eq::storePropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << "): storing proof" << std::endl; |
2430 |
5425667 |
Assert(d_disequalityReasonsMap.find(pair1) == d_disequalityReasonsMap.end()) |
2431 |
|
<< "There can't be a proof if you're adding a new one"; |
2432 |
5425667 |
DisequalityReasonRef ref(d_deducedDisequalityReasonsSize, d_deducedDisequalityReasons.size()); |
2433 |
|
#ifdef CVC5_ASSERTIONS |
2434 |
|
// Check that the reasons are valid |
2435 |
12229509 |
for (unsigned i = ref.d_mergesStart; i < ref.d_mergesEnd; ++i) |
2436 |
|
{ |
2437 |
6803842 |
Assert( |
2438 |
|
getEqualityNode(d_deducedDisequalityReasons[i].first).getFind() |
2439 |
|
== getEqualityNode(d_deducedDisequalityReasons[i].second).getFind()); |
2440 |
|
} |
2441 |
|
#endif |
2442 |
5425667 |
if (Debug.isOn("equality::disequality")) { |
2443 |
|
for (unsigned i = ref.d_mergesStart; i < ref.d_mergesEnd; ++i) |
2444 |
|
{ |
2445 |
|
TNode lhs = d_nodes[d_deducedDisequalityReasons[i].first]; |
2446 |
|
TNode rhs = d_nodes[d_deducedDisequalityReasons[i].second]; |
2447 |
|
Debug("equality::disequality") << d_name << "::eq::storePropagatedDisequality(): because " << lhs << " == " << rhs << std::endl; |
2448 |
|
} |
2449 |
|
} |
2450 |
|
|
2451 |
|
// Store for backtracking |
2452 |
5425667 |
d_deducedDisequalities.push_back(pair1); |
2453 |
5425667 |
d_deducedDisequalitiesSize = d_deducedDisequalities.size(); |
2454 |
5425667 |
d_deducedDisequalityReasonsSize = d_deducedDisequalityReasons.size(); |
2455 |
|
// Store the proof reference |
2456 |
5425667 |
d_disequalityReasonsMap[pair1] = ref; |
2457 |
5425667 |
d_disequalityReasonsMap[pair2] = ref; |
2458 |
|
} else { |
2459 |
793849 |
Assert(d_disequalityReasonsMap.find(pair1) != d_disequalityReasonsMap.end()) |
2460 |
|
<< "You must provide a proof initially"; |
2461 |
|
} |
2462 |
6219516 |
} |
2463 |
|
|
2464 |
43305164 |
void EqualityEngine::getDisequalities(bool allowConstants, |
2465 |
|
EqualityNodeId classId, |
2466 |
|
TheoryIdSet inputTags, |
2467 |
|
TaggedEqualitiesSet& out) |
2468 |
|
{ |
2469 |
|
// Must be empty on input |
2470 |
43305164 |
Assert(out.size() == 0); |
2471 |
|
// The class we are looking for, shouldn't have any of the tags we are looking for already set |
2472 |
43305164 |
Assert(d_nodeIndividualTrigger[classId] == null_set_id |
2473 |
|
|| TheoryIdSetUtil::setIntersection( |
2474 |
|
getTriggerTermSet(d_nodeIndividualTrigger[classId]).d_tags, |
2475 |
|
inputTags) |
2476 |
|
== 0); |
2477 |
|
|
2478 |
43305164 |
if (inputTags == 0) { |
2479 |
59351574 |
return; |
2480 |
|
} |
2481 |
|
|
2482 |
|
// Set of already (through disequalities) visited equivalence classes |
2483 |
27258754 |
std::set<EqualityNodeId> alreadyVisited; |
2484 |
|
|
2485 |
|
// Go through the equivalence class |
2486 |
13629377 |
EqualityNodeId currentId = classId; |
2487 |
2228773 |
do { |
2488 |
|
|
2489 |
15858150 |
Debug("equality::trigger") << d_name << "::getDisequalities() : going through uselist of " << d_nodes[currentId] << std::endl; |
2490 |
|
|
2491 |
|
// Current node in the equivalence class |
2492 |
15858150 |
EqualityNode& currentNode = getEqualityNode(currentId); |
2493 |
|
|
2494 |
|
// Go through the uselist and look for disequalities |
2495 |
15858150 |
UseListNodeId currentUseId = currentNode.getUseList(); |
2496 |
44177198 |
while (currentUseId != null_uselist_id) { |
2497 |
14159524 |
UseListNode& useListNode = d_useListNodes[currentUseId]; |
2498 |
14159524 |
EqualityNodeId funId = useListNode.getApplicationId(); |
2499 |
|
|
2500 |
14159524 |
Debug("equality::trigger") << d_name << "::getDisequalities() : checking " << d_nodes[funId] << std::endl; |
2501 |
|
|
2502 |
|
const FunctionApplication& fun = |
2503 |
14159524 |
d_applications[useListNode.getApplicationId()].d_original; |
2504 |
|
// If it's an equality asserted to false, we do the work |
2505 |
14159524 |
if (fun.isEquality() && getEqualityNode(funId).getFind() == getEqualityNode(d_false).getFind()) { |
2506 |
|
// Get the other equality member |
2507 |
2542486 |
bool lhs = false; |
2508 |
2542486 |
EqualityNodeId toCompare = fun.d_b; |
2509 |
2542486 |
if (toCompare == currentId) { |
2510 |
1447378 |
toCompare = fun.d_a; |
2511 |
1447378 |
lhs = true; |
2512 |
|
} |
2513 |
|
// Representative of the other member |
2514 |
2542486 |
EqualityNodeId toCompareRep = getEqualityNode(toCompare).getFind(); |
2515 |
2542486 |
if (toCompareRep == classId) { |
2516 |
|
// We're in conflict, so we will send it out from merge |
2517 |
|
out.clear(); |
2518 |
|
return; |
2519 |
|
} |
2520 |
|
// Check if we already have this one |
2521 |
2542486 |
if (alreadyVisited.count(toCompareRep) == 0) { |
2522 |
|
// Mark as visited |
2523 |
2104763 |
alreadyVisited.insert(toCompareRep); |
2524 |
|
// Get the trigger set |
2525 |
2104763 |
TriggerTermSetRef toCompareTriggerSetRef = d_nodeIndividualTrigger[toCompareRep]; |
2526 |
|
// We only care if we're not both constants and there are trigger terms in the other class |
2527 |
2104763 |
if ((allowConstants || !d_isConstant[toCompareRep]) && toCompareTriggerSetRef != null_set_id) { |
2528 |
|
// Tags of the other gey |
2529 |
1028683 |
TriggerTermSet& toCompareTriggerSet = getTriggerTermSet(toCompareTriggerSetRef); |
2530 |
|
// We only care if there are things in inputTags that is also in toCompareTags |
2531 |
1028683 |
TheoryIdSet commonTags = TheoryIdSetUtil::setIntersection( |
2532 |
1028683 |
inputTags, toCompareTriggerSet.d_tags); |
2533 |
1028683 |
if (commonTags) { |
2534 |
838691 |
out.push_back(TaggedEquality(funId, toCompareTriggerSetRef, lhs)); |
2535 |
|
} |
2536 |
|
} |
2537 |
|
} |
2538 |
|
} |
2539 |
|
// Go to the next one in the use list |
2540 |
14159524 |
currentUseId = useListNode.getNext(); |
2541 |
|
} |
2542 |
|
// Next in equivalence class |
2543 |
15858150 |
currentId = currentNode.getNext(); |
2544 |
15858150 |
} while (!d_done && currentId != classId); |
2545 |
|
|
2546 |
|
} |
2547 |
|
|
2548 |
43305156 |
bool EqualityEngine::propagateTriggerTermDisequalities( |
2549 |
|
TheoryIdSet tags, |
2550 |
|
TriggerTermSetRef triggerSetRef, |
2551 |
|
const TaggedEqualitiesSet& disequalitiesToNotify) |
2552 |
|
{ |
2553 |
|
// No tags, no food |
2554 |
43305156 |
if (!tags) { |
2555 |
29675780 |
return !d_done; |
2556 |
|
} |
2557 |
|
|
2558 |
13629376 |
Assert(triggerSetRef != null_set_id); |
2559 |
|
|
2560 |
|
// This is the class trigger set |
2561 |
13629376 |
const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef); |
2562 |
|
// Go through the disequalities and notify |
2563 |
13629376 |
TaggedEqualitiesSet::const_iterator it = disequalitiesToNotify.begin(); |
2564 |
13629376 |
TaggedEqualitiesSet::const_iterator it_end = disequalitiesToNotify.end(); |
2565 |
15236264 |
for (; !d_done && it != it_end; ++ it) { |
2566 |
|
// The information about the equality that is asserted to false |
2567 |
812935 |
const TaggedEquality& disequalityInfo = *it; |
2568 |
|
const TriggerTermSet& disequalityTriggerSet = |
2569 |
812935 |
getTriggerTermSet(disequalityInfo.d_triggerSetRef); |
2570 |
|
TheoryIdSet commonTags = |
2571 |
812935 |
TheoryIdSetUtil::setIntersection(disequalityTriggerSet.d_tags, tags); |
2572 |
812935 |
Assert(commonTags); |
2573 |
|
// This is the actual function |
2574 |
|
const FunctionApplication& fun = |
2575 |
812935 |
d_applications[disequalityInfo.d_equalityId].d_original; |
2576 |
|
// Figure out who we are comparing to in the original equality |
2577 |
812935 |
EqualityNodeId toCompare = disequalityInfo.d_lhs ? fun.d_a : fun.d_b; |
2578 |
812935 |
EqualityNodeId myCompare = disequalityInfo.d_lhs ? fun.d_b : fun.d_a; |
2579 |
812935 |
if (getEqualityNode(toCompare).getFind() == getEqualityNode(myCompare).getFind()) { |
2580 |
|
// We're propagating a != a, which means we're inconsistent, just bail and let it go into |
2581 |
|
// a regular conflict |
2582 |
9491 |
return !d_done; |
2583 |
|
} |
2584 |
|
// Go through the tags, and add the disequalities |
2585 |
|
TheoryId currentTag; |
2586 |
1193089 |
while ( |
2587 |
1996533 |
!d_done |
2588 |
1996533 |
&& ((currentTag = TheoryIdSetUtil::setPop(commonTags)) != THEORY_LAST)) |
2589 |
|
{ |
2590 |
|
// Get the tag representative |
2591 |
1193089 |
EqualityNodeId tagRep = disequalityTriggerSet.getTrigger(currentTag); |
2592 |
1193089 |
EqualityNodeId myRep = triggerSet.getTrigger(currentTag); |
2593 |
|
// Propagate |
2594 |
1193089 |
if (!hasPropagatedDisequality(currentTag, myRep, tagRep)) { |
2595 |
|
// Construct the proof if not there already |
2596 |
54155 |
if (!hasPropagatedDisequality(myRep, tagRep)) { |
2597 |
18551 |
d_deducedDisequalityReasons.push_back(EqualityPair(myCompare, myRep)); |
2598 |
18551 |
d_deducedDisequalityReasons.push_back(EqualityPair(toCompare, tagRep)); |
2599 |
37102 |
d_deducedDisequalityReasons.push_back( |
2600 |
37102 |
EqualityPair(disequalityInfo.d_equalityId, d_falseId)); |
2601 |
|
} |
2602 |
|
// Store the propagation |
2603 |
54155 |
storePropagatedDisequality(currentTag, myRep, tagRep); |
2604 |
|
// Notify |
2605 |
54155 |
if (d_performNotify) { |
2606 |
54155 |
if (!d_notify.eqNotifyTriggerTermEquality(currentTag, d_nodes[myRep], d_nodes[tagRep], false)) { |
2607 |
18 |
d_done = true; |
2608 |
|
} |
2609 |
|
} |
2610 |
|
} |
2611 |
|
} |
2612 |
|
} |
2613 |
|
|
2614 |
13619885 |
return !d_done; |
2615 |
|
} |
2616 |
|
|
2617 |
7246475 |
TheoryIdSet EqualityEngine::TriggerTermSet::hasTrigger(TheoryId tag) const |
2618 |
|
{ |
2619 |
7246475 |
return TheoryIdSetUtil::setContains(tag, d_tags); |
2620 |
|
} |
2621 |
|
|
2622 |
3296367 |
EqualityNodeId EqualityEngine::TriggerTermSet::getTrigger(TheoryId tag) const |
2623 |
|
{ |
2624 |
3296367 |
return d_triggers[TheoryIdSetUtil::setIndex(tag, d_tags)]; |
2625 |
|
} |
2626 |
|
|
2627 |
|
} // Namespace uf |
2628 |
|
} // Namespace theory |
2629 |
27735 |
} // namespace cvc5 |