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