GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/theory_uf.cpp Lines: 294 338 87.0 %
Date: 2021-08-14 Branches: 634 1335 47.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Dejan Jovanovic
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
 *
13
 * This is the interface to TheoryUF implementations
14
 *
15
 * All 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 "options/quantifiers_options.h"
25
#include "options/smt_options.h"
26
#include "options/theory_options.h"
27
#include "options/uf_options.h"
28
#include "proof/proof_node_manager.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 cvc5 {
39
namespace theory {
40
namespace uf {
41
42
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
43
9853
TheoryUF::TheoryUF(context::Context* c,
44
                   context::UserContext* u,
45
                   OutputChannel& out,
46
                   Valuation valuation,
47
                   const LogicInfo& logicInfo,
48
                   ProofNodeManager* pnm,
49
9853
                   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
19706
      d_im(*this, d_state, pnm, "theory::uf::" + instanceName, false),
57
29559
      d_notify(d_im, *this)
58
{
59
9853
  d_true = NodeManager::currentNM()->mkConst( true );
60
  // indicate we are using the default theory state and inference managers
61
9853
  d_theoryState = &d_state;
62
9853
  d_inferManager = &d_im;
63
9853
}
64
65
19706
TheoryUF::~TheoryUF() {
66
19706
}
67
68
9853
TheoryRewriter* TheoryUF::getTheoryRewriter() { return &d_rewriter; }
69
70
3768
ProofRuleChecker* TheoryUF::getProofChecker() { return &d_checker; }
71
72
9853
bool TheoryUF::needsEqualityEngine(EeSetupInfo& esi)
73
{
74
9853
  esi.d_notify = &d_notify;
75
9853
  esi.d_name = d_instanceName + "theory::uf::ee";
76
19706
  if (options::finiteModelFind()
77
9853
      && options::ufssMode() != options::UfssMode::NONE)
78
  {
79
    // need notifications about sorts
80
286
    esi.d_notifyNewClass = true;
81
286
    esi.d_notifyMerge = true;
82
286
    esi.d_notifyDisequal = true;
83
  }
84
9853
  return true;
85
}
86
87
9853
void TheoryUF::finishInit() {
88
9853
  Assert(d_equalityEngine != nullptr);
89
  // combined cardinality constraints are not evaluated in getModelValue
90
9853
  d_valuation.setUnevaluatedKind(kind::COMBINED_CARDINALITY_CONSTRAINT);
91
  // Initialize the cardinality constraints solver if the logic includes UF,
92
  // finite model finding is enabled, and it is not disabled by
93
  // options::ufssMode().
94
19706
  if (options::finiteModelFind()
95
9853
      && options::ufssMode() != options::UfssMode::NONE)
96
  {
97
286
    d_thss.reset(new CardinalityExtension(d_state, d_im, this));
98
  }
99
  // The kinds we are treating as function application in congruence
100
9853
  d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, options::ufHo());
101
9853
  if (options::ufHo())
102
  {
103
187
    d_equalityEngine->addFunctionKind(kind::HO_APPLY);
104
187
    d_ho.reset(new HoExtension(d_state, d_im));
105
  }
106
9853
}
107
108
static Node mkAnd(const std::vector<TNode>& conjunctions) {
109
  Assert(conjunctions.size() > 0);
110
111
  std::set<TNode> all;
112
  all.insert(conjunctions.begin(), conjunctions.end());
113
114
  if (all.size() == 1) {
115
    // All the same, or just one
116
    return conjunctions[0];
117
  }
118
119
  NodeBuilder conjunction(kind::AND);
120
  std::set<TNode>::const_iterator it = all.begin();
121
  std::set<TNode>::const_iterator it_end = all.end();
122
  while (it != it_end) {
123
    conjunction << *it;
124
    ++ it;
125
  }
126
127
  return conjunction;
128
}/* mkAnd() */
129
130
//--------------------------------- standard check
131
132
15392
bool TheoryUF::needsCheckLastEffort()
133
{
134
  // last call effort needed if using finite model finding
135
15392
  return d_thss != nullptr;
136
}
137
138
1236066
void TheoryUF::postCheck(Effort level)
139
{
140
1236066
  if (d_state.isInConflict())
141
  {
142
58055
    return;
143
  }
144
  // check with the cardinality constraints extension
145
1178011
  if (d_thss != nullptr)
146
  {
147
88871
    d_thss->check(level);
148
  }
149
  // check with the higher-order extension at full effort
150
1178011
  if (!d_state.isInConflict() && fullEffort(level))
151
  {
152
75069
    if (options::ufHo())
153
    {
154
1047
      d_ho->check();
155
    }
156
  }
157
}
158
159
3373223
void TheoryUF::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
160
{
161
3373223
  if (d_state.isInConflict())
162
  {
163
57081
    return;
164
  }
165
3316142
  if (d_thss != nullptr)
166
  {
167
    bool isDecision =
168
218462
        d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
169
218462
    d_thss->assertNode(fact, isDecision);
170
  }
171
3316142
  switch (atom.getKind())
172
  {
173
3097874
    case kind::EQUAL:
174
    {
175
3097874
      if (options::ufHo() && options::ufHoExt())
176
      {
177
33184
        if (!pol && !d_state.isInConflict() && atom[0].getType().isFunction())
178
        {
179
          // apply extensionality eagerly using the ho extension
180
3725
          d_ho->applyExtensionality(fact);
181
        }
182
      }
183
    }
184
3097874
    break;
185
13655
    case kind::CARDINALITY_CONSTRAINT:
186
    case kind::COMBINED_CARDINALITY_CONSTRAINT:
187
    {
188
13655
      if (d_thss == nullptr)
189
      {
190
        if (!getLogicInfo().hasCardinalityConstraints())
191
        {
192
          std::stringstream ss;
193
          ss << "Cardinality constraint " << atom
194
             << " was asserted, but the logic does not allow it." << std::endl;
195
          ss << "Try using a logic containing \"UFC\"." << std::endl;
196
          throw Exception(ss.str());
197
        }
198
        else
199
        {
200
          // support for cardinality constraints is not enabled, set incomplete
201
          d_im.setIncomplete(IncompleteId::UF_CARD_DISABLED);
202
        }
203
      }
204
    }
205
13655
    break;
206
204613
    default: break;
207
  }
208
}
209
//--------------------------------- end standard check
210
211
463319
TrustNode TheoryUF::ppRewrite(TNode node, std::vector<SkolemLemma>& lems)
212
{
213
926638
  Trace("uf-exp-def") << "TheoryUF::ppRewrite: expanding definition : " << node
214
463319
                      << std::endl;
215
463319
  Kind k = node.getKind();
216
463319
  if (k == kind::HO_APPLY)
217
  {
218
284
    if( !options::ufHo() ){
219
      std::stringstream ss;
220
      ss << "Partial function applications are only supported with "
221
            "higher-order logic. Try adding the logic prefix HO_.";
222
      throw LogicException(ss.str());
223
    }
224
455
    Node ret = d_ho->ppRewrite(node);
225
284
    if (ret != node)
226
    {
227
226
      Trace("uf-exp-def") << "TheoryUF::ppRewrite: higher-order: " << node
228
113
                          << " to " << ret << std::endl;
229
113
      return TrustNode::mkTrustRewrite(node, ret, nullptr);
230
    }
231
  }
232
463035
  else if (k == kind::APPLY_UF)
233
  {
234
    // check for higher-order
235
    // logic exception if higher-order is not enabled
236
85417
    if (isHigherOrderType(node.getOperator().getType()) && !options::ufHo())
237
    {
238
      std::stringstream ss;
239
      ss << "UF received an application whose operator has higher-order type "
240
         << node
241
         << ", which is only supported with higher-order logic. Try adding the "
242
            "logic prefix HO_.";
243
      throw LogicException(ss.str());
244
    }
245
  }
246
463206
  return TrustNode::null();
247
}
248
249
374962
void TheoryUF::preRegisterTerm(TNode node)
250
{
251
374962
  Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
252
253
374962
  if (d_thss != NULL) {
254
45022
    d_thss->preRegisterTerm(node);
255
  }
256
257
  // we always use APPLY_UF if not higher-order, HO_APPLY if higher-order
258
  //Assert( node.getKind()!=kind::APPLY_UF || !options::ufHo() );
259
374962
  Assert(node.getKind() != kind::HO_APPLY || options::ufHo());
260
261
374962
  Kind k = node.getKind();
262
374962
  switch (k)
263
  {
264
165312
    case kind::EQUAL:
265
      // Add the trigger for equality
266
165312
      d_equalityEngine->addTriggerPredicate(node);
267
165312
      break;
268
134442
    case kind::APPLY_UF:
269
    case kind::HO_APPLY:
270
    {
271
      // Maybe it's a predicate
272
134442
      if (node.getType().isBoolean())
273
      {
274
        // Get triggered for both equal and dis-equal
275
29481
        d_equalityEngine->addTriggerPredicate(node);
276
      }
277
      else
278
      {
279
        // Function applications/predicates
280
104961
        d_equalityEngine->addTerm(node);
281
      }
282
      // Remember the function and predicate terms
283
134442
      d_functionsTerms.push_back(node);
284
    }
285
134442
    break;
286
3755
  case kind::CARDINALITY_CONSTRAINT:
287
  case kind::COMBINED_CARDINALITY_CONSTRAINT:
288
    //do nothing
289
3755
    break;
290
71453
  default:
291
    // Variables etc
292
71453
    d_equalityEngine->addTerm(node);
293
71453
    break;
294
  }
295
374962
}
296
297
void TheoryUF::explain(TNode literal, Node& exp)
298
{
299
  Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
300
  std::vector<TNode> assumptions;
301
  // Do the work
302
  bool polarity = literal.getKind() != kind::NOT;
303
  TNode atom = polarity ? literal : literal[0];
304
  if (atom.getKind() == kind::EQUAL)
305
  {
306
    d_equalityEngine->explainEquality(
307
        atom[0], atom[1], polarity, assumptions, nullptr);
308
  }
309
  else
310
  {
311
    d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr);
312
  }
313
  exp = mkAnd(assumptions);
314
}
315
316
103239
TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); }
317
318
13323
bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
319
{
320
13323
  if( options::ufHo() ){
321
    // must add extensionality disequalities for all pairs of (non-disequal)
322
    // function equivalence classes.
323
398
    if (!d_ho->collectModelInfoHo(m, termSet))
324
    {
325
      Trace("uf") << "Collect model info fail HO" << std::endl;
326
      return false;
327
    }
328
  }
329
330
13323
  Debug("uf") << "UF : finish collectModelInfo " << std::endl;
331
13323
  return true;
332
}
333
334
15204
void TheoryUF::presolve() {
335
  // TimerStat::CodeTimer codeTimer(d_presolveTimer);
336
337
15204
  Debug("uf") << "uf: begin presolve()" << endl;
338
15204
  if(options::ufSymmetryBreaker()) {
339
306
    vector<Node> newClauses;
340
153
    d_symb.apply(newClauses);
341
155
    for(vector<Node>::const_iterator i = newClauses.begin();
342
155
        i != newClauses.end();
343
        ++i) {
344
2
      Debug("uf") << "uf: generating a lemma: " << *i << std::endl;
345
      // no proof generator provided
346
2
      d_im.lemma(*i, InferenceId::UF_BREAK_SYMMETRY);
347
    }
348
  }
349
15204
  if( d_thss ){
350
336
    d_thss->presolve();
351
  }
352
15204
  Debug("uf") << "uf: end presolve()" << endl;
353
15204
}
354
355
105238
void TheoryUF::ppStaticLearn(TNode n, NodeBuilder& learned)
356
{
357
  //TimerStat::CodeTimer codeTimer(d_staticLearningTimer);
358
359
210476
  vector<TNode> workList;
360
105238
  workList.push_back(n);
361
210476
  std::unordered_set<TNode> processed;
362
363
4939846
  while(!workList.empty()) {
364
2417304
    n = workList.back();
365
366
2440662
    if (n.isClosure())
367
    {
368
      // unsafe to go under quantifiers; we might pull bound vars out of scope!
369
23358
      processed.insert(n);
370
23358
      workList.pop_back();
371
23358
      continue;
372
    }
373
374
2393946
    bool unprocessedChildren = false;
375
7835545
    for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ++i) {
376
5441599
      if(processed.find(*i) == processed.end()) {
377
        // unprocessed child
378
1556025
        workList.push_back(*i);
379
1556025
        unprocessedChildren = true;
380
      }
381
    }
382
383
2393946
    if(unprocessedChildren) {
384
756041
      continue;
385
    }
386
387
1637905
    workList.pop_back();
388
    // has node n been processed in the meantime ?
389
1637905
    if(processed.find(n) != processed.end()) {
390
19674
      continue;
391
    }
392
1618231
    processed.insert(n);
393
394
    // == DIAMONDS ==
395
396
3236462
    Debug("diamonds") << "===================== looking at" << endl
397
1618231
                      << n << endl;
398
399
    // binary OR of binary ANDs of EQUALities
400
4057491
    if(n.getKind() == kind::OR && n.getNumChildren() == 2 &&
401
2072789
       n[0].getKind() == kind::AND && n[0].getNumChildren() == 2 &&
402
1638525
       n[1].getKind() == kind::AND && n[1].getNumChildren() == 2 &&
403
1624421
       (n[0][0].getKind() == kind::EQUAL) &&
404
1620883
       (n[0][1].getKind() == kind::EQUAL) &&
405
4857277
       (n[1][0].getKind() == kind::EQUAL) &&
406
1619523
       (n[1][1].getKind() == kind::EQUAL)) {
407
      // now we have (a = b && c = d) || (e = f && g = h)
408
409
634
      Debug("diamonds") << "has form of a diamond!" << endl;
410
411
      TNode
412
1250
        a = n[0][0][0], b = n[0][0][1],
413
1250
        c = n[0][1][0], d = n[0][1][1],
414
1250
        e = n[1][0][0], f = n[1][0][1],
415
1250
        g = n[1][1][0], h = n[1][1][1];
416
417
      // test that one of {a, b} = one of {c, d}, and make "b" the
418
      // shared node (i.e. put in the form (a = b && b = d))
419
      // note we don't actually care about the shared ones, so the
420
      // "swaps" below are one-sided, ignoring b and c
421
634
      if(a == c) {
422
16
        a = b;
423
618
      } else if(a == d) {
424
442
        a = b;
425
442
        d = c;
426
176
      } else if(b == c) {
427
        // nothing to do
428
52
      } else if(b == d) {
429
20
        d = c;
430
      } else {
431
        // condition not satisfied
432
16
        Debug("diamonds") << "+ A fails" << endl;
433
16
        continue;
434
      }
435
436
618
      Debug("diamonds") << "+ A holds" << endl;
437
438
      // same: one of {e, f} = one of {g, h}, and make "f" the
439
      // shared node (i.e. put in the form (e = f && f = h))
440
618
      if(e == g) {
441
16
        e = f;
442
602
      } else if(e == h) {
443
454
        e = f;
444
454
        h = g;
445
148
      } else if(f == g) {
446
        // nothing to do
447
10
      } else if(f == h) {
448
6
        h = g;
449
      } else {
450
        // condition not satisfied
451
2
        Debug("diamonds") << "+ B fails" << endl;
452
2
        continue;
453
      }
454
455
616
      Debug("diamonds") << "+ B holds" << endl;
456
457
      // now we have (a = b && b = d) || (e = f && f = h)
458
      // test that {a, d} == {e, h}
459
1232
      if( (a == e && d == h) ||
460
          (a == h && d == e) ) {
461
        // learn: n implies a == d
462
616
        Debug("diamonds") << "+ C holds" << endl;
463
1232
        Node newEquality = a.eqNode(d);
464
616
        Debug("diamonds") << "  ==> " << newEquality << endl;
465
616
        learned << n.impNode(newEquality);
466
      } else {
467
        Debug("diamonds") << "+ C fails" << endl;
468
      }
469
    }
470
  }
471
472
105238
  if(options::ufSymmetryBreaker()) {
473
24124
    d_symb.assertFormula(n);
474
  }
475
105238
} /* TheoryUF::ppStaticLearn() */
476
477
4525
EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
478
479
  // Check for equality (simplest)
480
4525
  if (d_equalityEngine->areEqual(a, b))
481
  {
482
    // The terms are implied to be equal
483
    return EQUALITY_TRUE;
484
  }
485
486
  // Check for disequality
487
4525
  if (d_equalityEngine->areDisequal(a, b, false))
488
  {
489
    // The terms are implied to be dis-equal
490
    return EQUALITY_FALSE;
491
  }
492
493
  // All other terms we interpret as dis-equal in the model
494
4525
  return EQUALITY_FALSE_IN_MODEL;
495
}
496
497
1453986
bool TheoryUF::areCareDisequal(TNode x, TNode y){
498
1453986
  Assert(d_equalityEngine->hasTerm(x));
499
1453986
  Assert(d_equalityEngine->hasTerm(y));
500
4361958
  if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
501
4361958
      && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
502
  {
503
    TNode x_shared =
504
1421645
        d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
505
    TNode y_shared =
506
1421645
        d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
507
1167539
    EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
508
1167539
    if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
509
913433
      return true;
510
    }
511
  }
512
540553
  return false;
513
}
514
515
444190
void TheoryUF::addCarePairs(const TNodeTrie* t1,
516
                            const TNodeTrie* t2,
517
                            unsigned arity,
518
                            unsigned depth)
519
{
520
444190
  if( depth==arity ){
521
130911
    if( t2!=NULL ){
522
261822
      Node f1 = t1->getData();
523
261822
      Node f2 = t2->getData();
524
130911
      if (!d_equalityEngine->areEqual(f1, f2))
525
      {
526
120807
        Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
527
241614
        vector< pair<TNode, TNode> > currentPairs;
528
328937
        for (size_t k = 0, nchildren = f1.getNumChildren(); k < nchildren; ++k)
529
        {
530
416260
          TNode x = f1[k];
531
416260
          TNode y = f2[k];
532
208130
          Assert(d_equalityEngine->hasTerm(x));
533
208130
          Assert(d_equalityEngine->hasTerm(y));
534
208130
          Assert(!d_equalityEngine->areDisequal(x, y, false));
535
208130
          Assert(!areCareDisequal(x, y));
536
208130
          if (!d_equalityEngine->areEqual(x, y))
537
          {
538
385644
            if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
539
385644
                && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
540
            {
541
              TNode x_shared =
542
86912
                  d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
543
              TNode y_shared =
544
86912
                  d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
545
43456
              currentPairs.push_back(make_pair(x_shared, y_shared));
546
            }
547
          }
548
        }
549
164263
        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
550
43456
          Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
551
43456
          addCarePair(currentPairs[c].first, currentPairs[c].second);
552
        }
553
      }
554
    }
555
  }else{
556
313279
    if( t2==NULL ){
557
111767
      if( depth<(arity-1) ){
558
        //add care pairs internal to each child
559
132135
        for (const std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
560
        {
561
76123
          addCarePairs(&tt.second, NULL, arity, depth + 1);
562
        }
563
      }
564
      //add care pairs based on each pair of non-disequal arguments
565
542527
      for (std::map<TNode, TNodeTrie>::const_iterator it = t1->d_data.begin();
566
542527
           it != t1->d_data.end();
567
           ++it)
568
      {
569
430760
        std::map<TNode, TNodeTrie>::const_iterator it2 = it;
570
430760
        ++it2;
571
5632258
        for( ; it2 != t1->d_data.end(); ++it2 ){
572
2600749
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
573
          {
574
942456
            if( !areCareDisequal(it->first, it2->first) ){
575
241745
              addCarePairs( &it->second, &it2->second, arity, depth+1 );
576
            }
577
          }
578
        }
579
      }
580
    }else{
581
      //add care pairs based on product of indices, non-disequal arguments
582
498054
      for (const std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
583
      {
584
612706
        for (const std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
585
        {
586
316164
          if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
587
          {
588
303400
            if (!areCareDisequal(tt1.first, tt2.first))
589
            {
590
90678
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1);
591
            }
592
          }
593
        }
594
      }
595
    }
596
  }
597
444190
}
598
599
24043
void TheoryUF::computeCareGraph() {
600
24043
  if (d_sharedTerms.empty())
601
  {
602
8239
    return;
603
  }
604
  // Use term indexing. We build separate indices for APPLY_UF and HO_APPLY.
605
  // We maintain indices per operator for the former, and indices per
606
  // function type for the latter.
607
31608
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..."
608
15804
                       << std::endl;
609
31608
  std::map<Node, TNodeTrie> index;
610
31608
  std::map<TypeNode, TNodeTrie> hoIndex;
611
31608
  std::map<Node, size_t> arity;
612
445734
  for (TNode app : d_functionsTerms)
613
  {
614
859860
    std::vector<TNode> reps;
615
429930
    bool has_trigger_arg = false;
616
1008772
    for (const Node& j : app)
617
    {
618
578842
      reps.push_back(d_equalityEngine->getRepresentative(j));
619
578842
      if (d_equalityEngine->isTriggerTerm(j, THEORY_UF))
620
      {
621
505994
        has_trigger_arg = true;
622
      }
623
    }
624
429930
    if (has_trigger_arg)
625
    {
626
388387
      if (app.getKind() == kind::APPLY_UF)
627
      {
628
776710
        Node op = app.getOperator();
629
388355
        index[op].addTerm(app, reps);
630
388355
        arity[op] = reps.size();
631
      }
632
      else
633
      {
634
32
        Assert(app.getKind() == kind::HO_APPLY);
635
        // add it to the hoIndex for the function type
636
32
        hoIndex[app[0].getType()].addTerm(app, reps);
637
      }
638
    }
639
  }
640
  // for each index
641
51438
  for (std::pair<const Node, TNodeTrie>& tt : index)
642
  {
643
71268
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
644
35634
                         << tt.first << "..." << std::endl;
645
35634
    Assert(arity.find(tt.first) != arity.end());
646
35634
    addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
647
  }
648
15814
  for (std::pair<const TypeNode, TNodeTrie>& tt : hoIndex)
649
  {
650
20
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process ho index "
651
10
                         << tt.first << "..." << std::endl;
652
    // the arity of HO_APPLY is always two
653
10
    addCarePairs(&tt.second, nullptr, 2, 0);
654
  }
655
31608
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished."
656
15804
                       << std::endl;
657
}/* TheoryUF::computeCareGraph() */
658
659
267855
void TheoryUF::eqNotifyNewClass(TNode t) {
660
267855
  if (d_thss != NULL) {
661
52824
    d_thss->newEqClass(t);
662
  }
663
267855
}
664
665
4571472
void TheoryUF::eqNotifyMerge(TNode t1, TNode t2)
666
{
667
4571472
  if (d_thss != NULL) {
668
282277
    d_thss->merge(t1, t2);
669
  }
670
4571472
}
671
672
892745
void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
673
892745
  if (d_thss != NULL) {
674
21042
    d_thss->assertDisequal(t1, t2, reason);
675
  }
676
892745
}
677
678
85417
bool TheoryUF::isHigherOrderType(TypeNode tn)
679
{
680
85417
  Assert(tn.isFunction());
681
85417
  std::map<TypeNode, bool>::iterator it = d_isHoType.find(tn);
682
85417
  if (it != d_isHoType.end())
683
  {
684
80481
    return it->second;
685
  }
686
4936
  bool ret = false;
687
9872
  const std::vector<TypeNode>& argTypes = tn.getArgTypes();
688
14140
  for (const TypeNode& tnc : argTypes)
689
  {
690
9272
    if (tnc.isFunction())
691
    {
692
68
      ret = true;
693
68
      break;
694
    }
695
  }
696
4936
  d_isHoType[tn] = ret;
697
4936
  return ret;
698
}
699
700
}  // namespace uf
701
}  // namespace theory
702
29340
}  // namespace cvc5