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