GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/equality_engine.cpp Lines: 1256 1370 91.7 %
Date: 2021-05-24 Branches: 2444 5586 43.8 %

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