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