GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/theory_uf.cpp Lines: 274 313 87.5 %
Date: 2021-03-22 Branches: 623 1288 48.4 %

Line Exec Source
1
/*********************                                                        */
2
/*! \file theory_uf.cpp
3
 ** \verbatim
4
 ** Top contributors (to current version):
5
 **   Andrew Reynolds, Morgan Deters, Dejan Jovanovic
6
 ** This file is part of the CVC4 project.
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.\endverbatim
11
 **
12
 ** \brief This is the interface to TheoryUF implementations
13
 **
14
 ** This is the interface to TheoryUF implementations.  All
15
 ** implementations of TheoryUF should inherit from this class.
16
 **/
17
18
#include "theory/uf/theory_uf.h"
19
20
#include <memory>
21
#include <sstream>
22
23
#include "expr/node_algorithm.h"
24
#include "expr/proof_node_manager.h"
25
#include "options/quantifiers_options.h"
26
#include "options/smt_options.h"
27
#include "options/theory_options.h"
28
#include "options/uf_options.h"
29
#include "smt/logic_exception.h"
30
#include "theory/theory_model.h"
31
#include "theory/type_enumerator.h"
32
#include "theory/uf/cardinality_extension.h"
33
#include "theory/uf/ho_extension.h"
34
#include "theory/uf/theory_uf_rewriter.h"
35
36
using namespace std;
37
38
namespace CVC4 {
39
namespace theory {
40
namespace uf {
41
42
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
43
8995
TheoryUF::TheoryUF(context::Context* c,
44
                   context::UserContext* u,
45
                   OutputChannel& out,
46
                   Valuation valuation,
47
                   const LogicInfo& logicInfo,
48
                   ProofNodeManager* pnm,
49
8995
                   std::string instanceName)
50
    : Theory(THEORY_UF, c, u, out, valuation, logicInfo, pnm, instanceName),
51
      d_thss(nullptr),
52
      d_ho(nullptr),
53
      d_functionsTerms(c),
54
      d_symb(u, instanceName),
55
      d_state(c, u, valuation),
56
      d_im(*this, d_state, pnm, "theory::uf", false),
57
8995
      d_notify(d_im, *this)
58
{
59
8995
  d_true = NodeManager::currentNM()->mkConst( true );
60
61
8995
  ProofChecker* pc = pnm != nullptr ? pnm->getChecker() : nullptr;
62
8995
  if (pc != nullptr)
63
  {
64
962
    d_ufProofChecker.registerTo(pc);
65
  }
66
  // indicate we are using the default theory state and inference managers
67
8995
  d_theoryState = &d_state;
68
8995
  d_inferManager = &d_im;
69
8995
}
70
71
17984
TheoryUF::~TheoryUF() {
72
17984
}
73
74
8995
TheoryRewriter* TheoryUF::getTheoryRewriter() { return &d_rewriter; }
75
76
8995
bool TheoryUF::needsEqualityEngine(EeSetupInfo& esi)
77
{
78
8995
  esi.d_notify = &d_notify;
79
8995
  esi.d_name = d_instanceName + "theory::uf::ee";
80
8995
  return true;
81
}
82
83
8995
void TheoryUF::finishInit() {
84
8995
  Assert(d_equalityEngine != nullptr);
85
  // combined cardinality constraints are not evaluated in getModelValue
86
8995
  d_valuation.setUnevaluatedKind(kind::COMBINED_CARDINALITY_CONSTRAINT);
87
  // Initialize the cardinality constraints solver if the logic includes UF,
88
  // finite model finding is enabled, and it is not disabled by
89
  // options::ufssMode().
90
17990
  if (options::finiteModelFind()
91
8995
      && options::ufssMode() != options::UfssMode::NONE)
92
  {
93
250
    d_thss.reset(new CardinalityExtension(d_state, d_im, this));
94
  }
95
  // The kinds we are treating as function application in congruence
96
8995
  d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, options::ufHo());
97
8995
  if (options::ufHo())
98
  {
99
216
    d_equalityEngine->addFunctionKind(kind::HO_APPLY);
100
216
    d_ho.reset(new HoExtension(d_state, d_im));
101
  }
102
8995
}
103
104
static Node mkAnd(const std::vector<TNode>& conjunctions) {
105
  Assert(conjunctions.size() > 0);
106
107
  std::set<TNode> all;
108
  all.insert(conjunctions.begin(), conjunctions.end());
109
110
  if (all.size() == 1) {
111
    // All the same, or just one
112
    return conjunctions[0];
113
  }
114
115
  NodeBuilder<> conjunction(kind::AND);
116
  std::set<TNode>::const_iterator it = all.begin();
117
  std::set<TNode>::const_iterator it_end = all.end();
118
  while (it != it_end) {
119
    conjunction << *it;
120
    ++ it;
121
  }
122
123
  return conjunction;
124
}/* mkAnd() */
125
126
//--------------------------------- standard check
127
128
17907
bool TheoryUF::needsCheckLastEffort()
129
{
130
  // last call effort needed if using finite model finding
131
17907
  return d_thss != nullptr;
132
}
133
134
1556676
void TheoryUF::postCheck(Effort level)
135
{
136
1556676
  if (d_state.isInConflict())
137
  {
138
65684
    return;
139
  }
140
  // check with the cardinality constraints extension
141
1490992
  if (d_thss != nullptr)
142
  {
143
127301
    d_thss->check(level);
144
  }
145
  // check with the higher-order extension at full effort
146
1490992
  if (!d_state.isInConflict() && fullEffort(level))
147
  {
148
67830
    if (options::ufHo())
149
    {
150
1074
      d_ho->check();
151
    }
152
  }
153
}
154
155
4205818
bool TheoryUF::preNotifyFact(
156
    TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
157
{
158
4205818
  if (d_thss != nullptr)
159
  {
160
    bool isDecision =
161
274692
        d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
162
274692
    d_thss->assertNode(fact, isDecision);
163
274692
    if (d_state.isInConflict())
164
    {
165
771
      return true;
166
    }
167
  }
168
8410094
  if (atom.getKind() == kind::CARDINALITY_CONSTRAINT
169
4205047
      || atom.getKind() == kind::COMBINED_CARDINALITY_CONSTRAINT)
170
  {
171
11254
    if (d_thss == nullptr)
172
    {
173
      if (!getLogicInfo().hasCardinalityConstraints())
174
      {
175
        std::stringstream ss;
176
        ss << "Cardinality constraint " << atom
177
           << " was asserted, but the logic does not allow it." << std::endl;
178
        ss << "Try using a logic containing \"UFC\"." << std::endl;
179
        throw Exception(ss.str());
180
      }
181
      else
182
      {
183
        // support for cardinality constraints is not enabled, set incomplete
184
        d_im.setIncomplete();
185
      }
186
    }
187
    // don't need to assert cardinality constraints if not producing models
188
11254
    return !options::produceModels();
189
  }
190
4193793
  return false;
191
}
192
193
4196837
void TheoryUF::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
194
{
195
4196837
  if (!d_state.isInConflict() && atom.getKind() == kind::EQUAL)
196
  {
197
3932759
    if (options::ufHo() && options::ufHoExt())
198
    {
199
69234
      if (!pol && !d_state.isInConflict() && atom[0].getType().isFunction())
200
      {
201
        // apply extensionality eagerly using the ho extension
202
295
        d_ho->applyExtensionality(fact);
203
      }
204
    }
205
  }
206
4196837
}
207
//--------------------------------- end standard check
208
209
469150
TrustNode TheoryUF::ppRewrite(TNode node, std::vector<SkolemLemma>& lems)
210
{
211
938300
  Trace("uf-exp-def") << "TheoryUF::ppRewrite: expanding definition : " << node
212
469150
                      << std::endl;
213
469150
  if( node.getKind()==kind::HO_APPLY ){
214
256
    if( !options::ufHo() ){
215
      std::stringstream ss;
216
      ss << "Partial function applications are not supported in default mode, try --uf-ho.";
217
      throw LogicException(ss.str());
218
    }
219
392
    Node ret = d_ho->ppRewrite(node);
220
256
    if (ret != node)
221
    {
222
240
      Trace("uf-exp-def") << "TheoryUF::ppRewrite: higher-order: " << node
223
120
                          << " to " << ret << std::endl;
224
120
      return TrustNode::mkTrustRewrite(node, ret, nullptr);
225
    }
226
  }
227
469030
  return TrustNode::null();
228
}
229
230
345154
void TheoryUF::preRegisterTerm(TNode node)
231
{
232
345154
  Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
233
234
345154
  if (d_thss != NULL) {
235
38904
    d_thss->preRegisterTerm(node);
236
  }
237
238
  // we always use APPLY_UF if not higher-order, HO_APPLY if higher-order
239
  //Assert( node.getKind()!=kind::APPLY_UF || !options::ufHo() );
240
345154
  Assert(node.getKind() != kind::HO_APPLY || options::ufHo());
241
242
345154
  switch (node.getKind()) {
243
160016
  case kind::EQUAL:
244
    // Add the trigger for equality
245
160016
    d_equalityEngine->addTriggerPredicate(node);
246
160016
    break;
247
114006
  case kind::APPLY_UF:
248
  case kind::HO_APPLY:
249
    // Maybe it's a predicate
250
114006
    if (node.getType().isBoolean()) {
251
      // Get triggered for both equal and dis-equal
252
26935
      d_equalityEngine->addTriggerPredicate(node);
253
    } else {
254
      // Function applications/predicates
255
87071
      d_equalityEngine->addTerm(node);
256
    }
257
    // Remember the function and predicate terms
258
114006
    d_functionsTerms.push_back(node);
259
114006
    break;
260
3014
  case kind::CARDINALITY_CONSTRAINT:
261
  case kind::COMBINED_CARDINALITY_CONSTRAINT:
262
    //do nothing
263
3014
    break;
264
68118
  default:
265
    // Variables etc
266
68118
    d_equalityEngine->addTerm(node);
267
68118
    break;
268
  }
269
345154
}
270
271
void TheoryUF::explain(TNode literal, Node& exp)
272
{
273
  Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
274
  std::vector<TNode> assumptions;
275
  // Do the work
276
  bool polarity = literal.getKind() != kind::NOT;
277
  TNode atom = polarity ? literal : literal[0];
278
  if (atom.getKind() == kind::EQUAL)
279
  {
280
    d_equalityEngine->explainEquality(
281
        atom[0], atom[1], polarity, assumptions, nullptr);
282
  }
283
  else
284
  {
285
    d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr);
286
  }
287
  exp = mkAnd(assumptions);
288
}
289
290
128927
TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); }
291
292
16242
bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
293
{
294
16242
  if( options::ufHo() ){
295
    // must add extensionality disequalities for all pairs of (non-disequal)
296
    // function equivalence classes.
297
504
    if (!d_ho->collectModelInfoHo(m, termSet))
298
    {
299
      Trace("uf") << "Collect model info fail HO" << std::endl;
300
      return false;
301
    }
302
  }
303
304
16242
  Debug("uf") << "UF : finish collectModelInfo " << std::endl;
305
16242
  return true;
306
}
307
308
12420
void TheoryUF::presolve() {
309
  // TimerStat::CodeTimer codeTimer(d_presolveTimer);
310
311
12420
  Debug("uf") << "uf: begin presolve()" << endl;
312
12420
  if(options::ufSymmetryBreaker()) {
313
298
    vector<Node> newClauses;
314
149
    d_symb.apply(newClauses);
315
151
    for(vector<Node>::const_iterator i = newClauses.begin();
316
151
        i != newClauses.end();
317
        ++i) {
318
2
      Debug("uf") << "uf: generating a lemma: " << *i << std::endl;
319
      // no proof generator provided
320
2
      d_im.lemma(*i, InferenceId::UF_BREAK_SYMMETRY);
321
    }
322
  }
323
12420
  if( d_thss ){
324
300
    d_thss->presolve();
325
  }
326
12420
  Debug("uf") << "uf: end presolve()" << endl;
327
12420
}
328
329
91998
void TheoryUF::ppStaticLearn(TNode n, NodeBuilder<>& learned) {
330
  //TimerStat::CodeTimer codeTimer(d_staticLearningTimer);
331
332
183996
  vector<TNode> workList;
333
91998
  workList.push_back(n);
334
183996
  std::unordered_set<TNode, TNodeHashFunction> processed;
335
336
4557194
  while(!workList.empty()) {
337
2232598
    n = workList.back();
338
339
2255773
    if (n.isClosure())
340
    {
341
      // unsafe to go under quantifiers; we might pull bound vars out of scope!
342
23175
      processed.insert(n);
343
23175
      workList.pop_back();
344
23175
      continue;
345
    }
346
347
2209423
    bool unprocessedChildren = false;
348
7220620
    for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ++i) {
349
5011197
      if(processed.find(*i) == processed.end()) {
350
        // unprocessed child
351
1450295
        workList.push_back(*i);
352
1450295
        unprocessedChildren = true;
353
      }
354
    }
355
356
2209423
    if(unprocessedChildren) {
357
690305
      continue;
358
    }
359
360
1519118
    workList.pop_back();
361
    // has node n been processed in the meantime ?
362
1519118
    if(processed.find(n) != processed.end()) {
363
18647
      continue;
364
    }
365
1500471
    processed.insert(n);
366
367
    // == DIAMONDS ==
368
369
3000942
    Debug("diamonds") << "===================== looking at" << endl
370
1500471
                      << n << endl;
371
372
    // binary OR of binary ANDs of EQUALities
373
3769456
    if(n.getKind() == kind::OR && n.getNumChildren() == 2 &&
374
1917920
       n[0].getKind() == kind::AND && n[0].getNumChildren() == 2 &&
375
1515369
       n[1].getKind() == kind::AND && n[1].getNumChildren() == 2 &&
376
1505573
       (n[0][0].getKind() == kind::EQUAL) &&
377
1503111
       (n[0][1].getKind() == kind::EQUAL) &&
378
4503985
       (n[1][0].getKind() == kind::EQUAL) &&
379
1501757
       (n[1][1].getKind() == kind::EQUAL)) {
380
      // now we have (a = b && c = d) || (e = f && g = h)
381
382
631
      Debug("diamonds") << "has form of a diamond!" << endl;
383
384
      TNode
385
1244
        a = n[0][0][0], b = n[0][0][1],
386
1244
        c = n[0][1][0], d = n[0][1][1],
387
1244
        e = n[1][0][0], f = n[1][0][1],
388
1244
        g = n[1][1][0], h = n[1][1][1];
389
390
      // test that one of {a, b} = one of {c, d}, and make "b" the
391
      // shared node (i.e. put in the form (a = b && b = d))
392
      // note we don't actually care about the shared ones, so the
393
      // "swaps" below are one-sided, ignoring b and c
394
631
      if(a == c) {
395
16
        a = b;
396
615
      } else if(a == d) {
397
442
        a = b;
398
442
        d = c;
399
173
      } else if(b == c) {
400
        // nothing to do
401
49
      } else if(b == d) {
402
17
        d = c;
403
      } else {
404
        // condition not satisfied
405
16
        Debug("diamonds") << "+ A fails" << endl;
406
16
        continue;
407
      }
408
409
615
      Debug("diamonds") << "+ A holds" << endl;
410
411
      // same: one of {e, f} = one of {g, h}, and make "f" the
412
      // shared node (i.e. put in the form (e = f && f = h))
413
615
      if(e == g) {
414
16
        e = f;
415
599
      } else if(e == h) {
416
454
        e = f;
417
454
        h = g;
418
145
      } else if(f == g) {
419
        // nothing to do
420
7
      } else if(f == h) {
421
3
        h = g;
422
      } else {
423
        // condition not satisfied
424
2
        Debug("diamonds") << "+ B fails" << endl;
425
2
        continue;
426
      }
427
428
613
      Debug("diamonds") << "+ B holds" << endl;
429
430
      // now we have (a = b && b = d) || (e = f && f = h)
431
      // test that {a, d} == {e, h}
432
1226
      if( (a == e && d == h) ||
433
          (a == h && d == e) ) {
434
        // learn: n implies a == d
435
613
        Debug("diamonds") << "+ C holds" << endl;
436
1226
        Node newEquality = a.eqNode(d);
437
613
        Debug("diamonds") << "  ==> " << newEquality << endl;
438
613
        learned << n.impNode(newEquality);
439
      } else {
440
        Debug("diamonds") << "+ C fails" << endl;
441
      }
442
    }
443
  }
444
445
91998
  if(options::ufSymmetryBreaker()) {
446
24116
    d_symb.assertFormula(n);
447
  }
448
91998
}/* TheoryUF::ppStaticLearn() */
449
450
1763
EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
451
452
  // Check for equality (simplest)
453
1763
  if (d_equalityEngine->areEqual(a, b))
454
  {
455
    // The terms are implied to be equal
456
    return EQUALITY_TRUE;
457
  }
458
459
  // Check for disequality
460
1763
  if (d_equalityEngine->areDisequal(a, b, false))
461
  {
462
    // The terms are implied to be dis-equal
463
    return EQUALITY_FALSE;
464
  }
465
466
  // All other terms we interpret as dis-equal in the model
467
1763
  return EQUALITY_FALSE_IN_MODEL;
468
}
469
470
1669161
bool TheoryUF::areCareDisequal(TNode x, TNode y){
471
1669161
  Assert(d_equalityEngine->hasTerm(x));
472
1669161
  Assert(d_equalityEngine->hasTerm(y));
473
5007483
  if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
474
5007483
      && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
475
  {
476
    TNode x_shared =
477
1673070
        d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
478
    TNode y_shared =
479
1673070
        d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
480
1385112
    EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
481
1385112
    if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
482
1097154
      return true;
483
    }
484
  }
485
572007
  return false;
486
}
487
488
461957
void TheoryUF::addCarePairs(const TNodeTrie* t1,
489
                            const TNodeTrie* t2,
490
                            unsigned arity,
491
                            unsigned depth)
492
{
493
461957
  if( depth==arity ){
494
148316
    if( t2!=NULL ){
495
296632
      Node f1 = t1->getData();
496
296632
      Node f2 = t2->getData();
497
148316
      if (!d_equalityEngine->areEqual(f1, f2))
498
      {
499
137657
        Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
500
275314
        vector< pair<TNode, TNode> > currentPairs;
501
357248
        for (size_t k = 0, nchildren = f1.getNumChildren(); k < nchildren; ++k)
502
        {
503
439182
          TNode x = f1[k];
504
439182
          TNode y = f2[k];
505
219591
          Assert(d_equalityEngine->hasTerm(x));
506
219591
          Assert(d_equalityEngine->hasTerm(y));
507
219591
          Assert(!d_equalityEngine->areDisequal(x, y, false));
508
219591
          Assert(!areCareDisequal(x, y));
509
219591
          if (!d_equalityEngine->areEqual(x, y))
510
          {
511
426216
            if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
512
426216
                && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
513
            {
514
              TNode x_shared =
515
124592
                  d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
516
              TNode y_shared =
517
124592
                  d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
518
62296
              currentPairs.push_back(make_pair(x_shared, y_shared));
519
            }
520
          }
521
        }
522
199953
        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
523
62296
          Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
524
62296
          addCarePair(currentPairs[c].first, currentPairs[c].second);
525
        }
526
      }
527
    }
528
  }else{
529
313641
    if( t2==NULL ){
530
109541
      if( depth<(arity-1) ){
531
        //add care pairs internal to each child
532
111554
        for (const std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
533
        {
534
64963
          addCarePairs(&tt.second, NULL, arity, depth + 1);
535
        }
536
      }
537
      //add care pairs based on each pair of non-disequal arguments
538
644614
      for (std::map<TNode, TNodeTrie>::const_iterator it = t1->d_data.begin();
539
644614
           it != t1->d_data.end();
540
           ++it)
541
      {
542
535073
        std::map<TNode, TNodeTrie>::const_iterator it2 = it;
543
535073
        ++it2;
544
7176561
        for( ; it2 != t1->d_data.end(); ++it2 ){
545
3320744
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
546
          {
547
1139827
            if( !areCareDisequal(it->first, it2->first) ){
548
265161
              addCarePairs( &it->second, &it2->second, arity, depth+1 );
549
            }
550
          }
551
        }
552
      }
553
    }else{
554
      //add care pairs based on product of indices, non-disequal arguments
555
500649
      for (const std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
556
      {
557
624462
        for (const std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
558
        {
559
327913
          if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
560
          {
561
309743
            if (!areCareDisequal(tt1.first, tt2.first))
562
            {
563
87255
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1);
564
            }
565
          }
566
        }
567
      }
568
    }
569
  }
570
461957
}
571
572
29471
void TheoryUF::computeCareGraph() {
573
29471
  if (d_sharedTerms.empty())
574
  {
575
7900
    return;
576
  }
577
  // Use term indexing. We build separate indices for APPLY_UF and HO_APPLY.
578
  // We maintain indices per operator for the former, and indices per
579
  // function type for the latter.
580
43142
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..."
581
21571
                       << std::endl;
582
43142
  std::map<Node, TNodeTrie> index;
583
43142
  std::map<TypeNode, TNodeTrie> hoIndex;
584
43142
  std::map<Node, size_t> arity;
585
589557
  for (TNode app : d_functionsTerms)
586
  {
587
1135972
    std::vector<TNode> reps;
588
567986
    bool has_trigger_arg = false;
589
1267797
    for (const Node& j : app)
590
    {
591
699811
      reps.push_back(d_equalityEngine->getRepresentative(j));
592
699811
      if (d_equalityEngine->isTriggerTerm(j, THEORY_UF))
593
      {
594
608303
        has_trigger_arg = true;
595
      }
596
    }
597
567986
    if (has_trigger_arg)
598
    {
599
514377
      if (app.getKind() == kind::APPLY_UF)
600
      {
601
1028690
        Node op = app.getOperator();
602
514345
        index[op].addTerm(app, reps);
603
514345
        arity[op] = reps.size();
604
      }
605
      else
606
      {
607
32
        Assert(app.getKind() == kind::HO_APPLY);
608
        // add it to the hoIndex for the function type
609
32
        hoIndex[app[0].getType()].addTerm(app, reps);
610
      }
611
    }
612
  }
613
  // for each index
614
66139
  for (std::pair<const Node, TNodeTrie>& tt : index)
615
  {
616
89136
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
617
44568
                         << tt.first << "..." << std::endl;
618
44568
    Assert(arity.find(tt.first) != arity.end());
619
44568
    addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
620
  }
621
21581
  for (std::pair<const TypeNode, TNodeTrie>& tt : hoIndex)
622
  {
623
20
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process ho index "
624
10
                         << tt.first << "..." << std::endl;
625
    // the arity of HO_APPLY is always two
626
10
    addCarePairs(&tt.second, nullptr, 2, 0);
627
  }
628
43142
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished."
629
21571
                       << std::endl;
630
}/* TheoryUF::computeCareGraph() */
631
632
229806
void TheoryUF::eqNotifyNewClass(TNode t) {
633
229806
  if (d_thss != NULL) {
634
30484
    d_thss->newEqClass(t);
635
  }
636
229806
}
637
638
5533686
void TheoryUF::eqNotifyMerge(TNode t1, TNode t2)
639
{
640
5533686
  if (d_thss != NULL) {
641
394220
    d_thss->merge(t1, t2);
642
  }
643
5533686
}
644
645
996238
void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
646
996238
  if (d_thss != NULL) {
647
24443
    d_thss->assertDisequal(t1, t2, reason);
648
  }
649
996238
}
650
651
} /* namespace CVC4::theory::uf */
652
} /* namespace CVC4::theory */
653
26676
} /* namespace CVC4 */