GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/equality_engine.cpp Lines: 1265 1378 91.8 %
Date: 2021-09-17 Branches: 2431 5570 43.6 %

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