GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/theory_uf.cpp Lines: 298 342 87.1 %
Date: 2021-09-07 Branches: 642 1351 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
9926
TheoryUF::TheoryUF(Env& env,
44
                   OutputChannel& out,
45
                   Valuation valuation,
46
9926
                   std::string instanceName)
47
    : Theory(THEORY_UF, env, out, valuation, instanceName),
48
      d_thss(nullptr),
49
      d_ho(nullptr),
50
      d_functionsTerms(getSatContext()),
51
9926
      d_symb(userContext(), instanceName),
52
9926
      d_rewriter(logicInfo().isHigherOrder()),
53
      d_state(env, valuation),
54
19852
      d_im(*this, d_state, d_pnm, "theory::uf::" + instanceName, false),
55
49630
      d_notify(d_im, *this)
56
{
57
9926
  d_true = NodeManager::currentNM()->mkConst( true );
58
  // indicate we are using the default theory state and inference managers
59
9926
  d_theoryState = &d_state;
60
9926
  d_inferManager = &d_im;
61
9926
}
62
63
19846
TheoryUF::~TheoryUF() {
64
19846
}
65
66
9926
TheoryRewriter* TheoryUF::getTheoryRewriter() { return &d_rewriter; }
67
68
3786
ProofRuleChecker* TheoryUF::getProofChecker() { return &d_checker; }
69
70
9926
bool TheoryUF::needsEqualityEngine(EeSetupInfo& esi)
71
{
72
9926
  esi.d_notify = &d_notify;
73
9926
  esi.d_name = d_instanceName + "theory::uf::ee";
74
19852
  if (options::finiteModelFind()
75
9926
      && options::ufssMode() != options::UfssMode::NONE)
76
  {
77
    // need notifications about sorts
78
288
    esi.d_notifyNewClass = true;
79
288
    esi.d_notifyMerge = true;
80
288
    esi.d_notifyDisequal = true;
81
  }
82
9926
  return true;
83
}
84
85
9926
void TheoryUF::finishInit() {
86
9926
  Assert(d_equalityEngine != nullptr);
87
  // combined cardinality constraints are not evaluated in getModelValue
88
9926
  d_valuation.setUnevaluatedKind(kind::COMBINED_CARDINALITY_CONSTRAINT);
89
  // Initialize the cardinality constraints solver if the logic includes UF,
90
  // finite model finding is enabled, and it is not disabled by
91
  // options::ufssMode().
92
19852
  if (options::finiteModelFind()
93
9926
      && options::ufssMode() != options::UfssMode::NONE)
94
  {
95
288
    d_thss.reset(new CardinalityExtension(d_state, d_im, this));
96
  }
97
  // The kinds we are treating as function application in congruence
98
9926
  bool isHo = logicInfo().isHigherOrder();
99
9926
  d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, isHo);
100
9926
  if (isHo)
101
  {
102
193
    d_equalityEngine->addFunctionKind(kind::HO_APPLY);
103
193
    d_ho.reset(new HoExtension(d_state, d_im));
104
  }
105
9926
}
106
107
static Node mkAnd(const std::vector<TNode>& conjunctions) {
108
  Assert(conjunctions.size() > 0);
109
110
  std::set<TNode> all;
111
  all.insert(conjunctions.begin(), conjunctions.end());
112
113
  if (all.size() == 1) {
114
    // All the same, or just one
115
    return conjunctions[0];
116
  }
117
118
  NodeBuilder conjunction(kind::AND);
119
  std::set<TNode>::const_iterator it = all.begin();
120
  std::set<TNode>::const_iterator it_end = all.end();
121
  while (it != it_end) {
122
    conjunction << *it;
123
    ++ it;
124
  }
125
126
  return conjunction;
127
}/* mkAnd() */
128
129
//--------------------------------- standard check
130
131
15578
bool TheoryUF::needsCheckLastEffort()
132
{
133
  // last call effort needed if using finite model finding
134
15578
  return d_thss != nullptr;
135
}
136
137
1245480
void TheoryUF::postCheck(Effort level)
138
{
139
1245480
  if (d_state.isInConflict())
140
  {
141
58059
    return;
142
  }
143
  // check with the cardinality constraints extension
144
1187421
  if (d_thss != nullptr)
145
  {
146
88887
    d_thss->check(level);
147
  }
148
  // check with the higher-order extension at full effort
149
1187421
  if (!d_state.isInConflict() && fullEffort(level))
150
  {
151
77303
    if (logicInfo().isHigherOrder())
152
    {
153
1055
      d_ho->check();
154
    }
155
  }
156
}
157
158
3391990
void TheoryUF::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
159
{
160
3391990
  if (d_state.isInConflict())
161
  {
162
57085
    return;
163
  }
164
3334905
  if (d_thss != nullptr)
165
  {
166
    bool isDecision =
167
218465
        d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
168
218465
    d_thss->assertNode(fact, isDecision);
169
  }
170
3334905
  switch (atom.getKind())
171
  {
172
3118570
    case kind::EQUAL:
173
    {
174
3118570
      if (logicInfo().isHigherOrder() && options::ufHoExt())
175
      {
176
33184
        if (!pol && !d_state.isInConflict() && atom[0].getType().isFunction())
177
        {
178
          // apply extensionality eagerly using the ho extension
179
3725
          d_ho->applyExtensionality(fact);
180
        }
181
      }
182
    }
183
3118570
    break;
184
13632
    case kind::CARDINALITY_CONSTRAINT:
185
    case kind::COMBINED_CARDINALITY_CONSTRAINT:
186
    {
187
13632
      if (d_thss == nullptr)
188
      {
189
        if (!logicInfo().hasCardinalityConstraints())
190
        {
191
          std::stringstream ss;
192
          ss << "Cardinality constraint " << atom
193
             << " was asserted, but the logic does not allow it." << std::endl;
194
          ss << "Try using a logic containing \"UFC\"." << std::endl;
195
          throw Exception(ss.str());
196
        }
197
        else
198
        {
199
          // support for cardinality constraints is not enabled, set incomplete
200
          d_im.setIncomplete(IncompleteId::UF_CARD_DISABLED);
201
        }
202
      }
203
    }
204
13632
    break;
205
202703
    default: break;
206
  }
207
}
208
//--------------------------------- end standard check
209
210
466317
TrustNode TheoryUF::ppRewrite(TNode node, std::vector<SkolemLemma>& lems)
211
{
212
932634
  Trace("uf-exp-def") << "TheoryUF::ppRewrite: expanding definition : " << node
213
466317
                      << std::endl;
214
466317
  Kind k = node.getKind();
215
466317
  if (k == kind::HO_APPLY)
216
  {
217
284
    if (!logicInfo().isHigherOrder())
218
    {
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
466033
  else if (k == kind::APPLY_UF)
233
  {
234
    // check for higher-order
235
    // logic exception if higher-order is not enabled
236
258879
    if (isHigherOrderType(node.getOperator().getType())
237
258879
        && !logicInfo().isHigherOrder())
238
    {
239
      std::stringstream ss;
240
      ss << "UF received an application whose operator has higher-order type "
241
         << node
242
         << ", which is only supported with higher-order logic. Try adding the "
243
            "logic prefix HO_.";
244
      throw LogicException(ss.str());
245
    }
246
  }
247
466204
  return TrustNode::null();
248
}
249
250
381061
void TheoryUF::preRegisterTerm(TNode node)
251
{
252
381061
  Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
253
254
381061
  if (d_thss != NULL) {
255
45079
    d_thss->preRegisterTerm(node);
256
  }
257
258
  // we always use APPLY_UF if not higher-order, HO_APPLY if higher-order
259
381061
  Assert(node.getKind() != kind::HO_APPLY || logicInfo().isHigherOrder());
260
261
381061
  Kind k = node.getKind();
262
381061
  switch (k)
263
  {
264
167606
    case kind::EQUAL:
265
      // Add the trigger for equality
266
167606
      d_equalityEngine->addTriggerPredicate(node);
267
167606
      break;
268
137765
    case kind::APPLY_UF:
269
    case kind::HO_APPLY:
270
    {
271
      // Maybe it's a predicate
272
137765
      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
108284
        d_equalityEngine->addTerm(node);
281
      }
282
      // Remember the function and predicate terms
283
137765
      d_functionsTerms.push_back(node);
284
    }
285
137765
    break;
286
3751
  case kind::CARDINALITY_CONSTRAINT:
287
  case kind::COMBINED_CARDINALITY_CONSTRAINT:
288
    //do nothing
289
3751
    break;
290
71939
  default:
291
    // Variables etc
292
71939
    d_equalityEngine->addTerm(node);
293
71939
    break;
294
  }
295
381061
}
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
104165
TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); }
317
318
13512
bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
319
{
320
13512
  if (logicInfo().isHigherOrder())
321
  {
322
    // must add extensionality disequalities for all pairs of (non-disequal)
323
    // function equivalence classes.
324
404
    if (!d_ho->collectModelInfoHo(m, termSet))
325
    {
326
      Trace("uf") << "Collect model info fail HO" << std::endl;
327
      return false;
328
    }
329
  }
330
331
13512
  Debug("uf") << "UF : finish collectModelInfo " << std::endl;
332
13512
  return true;
333
}
334
335
15250
void TheoryUF::presolve() {
336
  // TimerStat::CodeTimer codeTimer(d_presolveTimer);
337
338
15250
  Debug("uf") << "uf: begin presolve()" << endl;
339
15250
  if(options::ufSymmetryBreaker()) {
340
306
    vector<Node> newClauses;
341
153
    d_symb.apply(newClauses);
342
155
    for(vector<Node>::const_iterator i = newClauses.begin();
343
155
        i != newClauses.end();
344
        ++i) {
345
2
      Debug("uf") << "uf: generating a lemma: " << *i << std::endl;
346
      // no proof generator provided
347
2
      d_im.lemma(*i, InferenceId::UF_BREAK_SYMMETRY);
348
    }
349
  }
350
15250
  if( d_thss ){
351
338
    d_thss->presolve();
352
  }
353
15250
  Debug("uf") << "uf: end presolve()" << endl;
354
15250
}
355
356
105454
void TheoryUF::ppStaticLearn(TNode n, NodeBuilder& learned)
357
{
358
  //TimerStat::CodeTimer codeTimer(d_staticLearningTimer);
359
360
210908
  vector<TNode> workList;
361
105454
  workList.push_back(n);
362
210908
  std::unordered_set<TNode> processed;
363
364
4879256
  while(!workList.empty()) {
365
2386901
    n = workList.back();
366
367
2410451
    if (n.isClosure())
368
    {
369
      // unsafe to go under quantifiers; we might pull bound vars out of scope!
370
23550
      processed.insert(n);
371
23550
      workList.pop_back();
372
23550
      continue;
373
    }
374
375
2363351
    bool unprocessedChildren = false;
376
7591176
    for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ++i) {
377
5227825
      if(processed.find(*i) == processed.end()) {
378
        // unprocessed child
379
1536795
        workList.push_back(*i);
380
1536795
        unprocessedChildren = true;
381
      }
382
    }
383
384
2363351
    if(unprocessedChildren) {
385
744652
      continue;
386
    }
387
388
1618699
    workList.pop_back();
389
    // has node n been processed in the meantime ?
390
1618699
    if(processed.find(n) != processed.end()) {
391
19724
      continue;
392
    }
393
1598975
    processed.insert(n);
394
395
    // == DIAMONDS ==
396
397
3197950
    Debug("diamonds") << "===================== looking at" << endl
398
1598975
                      << n << endl;
399
400
    // binary OR of binary ANDs of EQUALities
401
4017383
    if(n.getKind() == kind::OR && n.getNumChildren() == 2 &&
402
2052609
       n[0].getKind() == kind::AND && n[0].getNumChildren() == 2 &&
403
1619269
       n[1].getKind() == kind::AND && n[1].getNumChildren() == 2 &&
404
1605165
       (n[0][0].getKind() == kind::EQUAL) &&
405
1601627
       (n[0][1].getKind() == kind::EQUAL) &&
406
4799509
       (n[1][0].getKind() == kind::EQUAL) &&
407
1600267
       (n[1][1].getKind() == kind::EQUAL)) {
408
      // now we have (a = b && c = d) || (e = f && g = h)
409
410
634
      Debug("diamonds") << "has form of a diamond!" << endl;
411
412
      TNode
413
1250
        a = n[0][0][0], b = n[0][0][1],
414
1250
        c = n[0][1][0], d = n[0][1][1],
415
1250
        e = n[1][0][0], f = n[1][0][1],
416
1250
        g = n[1][1][0], h = n[1][1][1];
417
418
      // test that one of {a, b} = one of {c, d}, and make "b" the
419
      // shared node (i.e. put in the form (a = b && b = d))
420
      // note we don't actually care about the shared ones, so the
421
      // "swaps" below are one-sided, ignoring b and c
422
634
      if(a == c) {
423
16
        a = b;
424
618
      } else if(a == d) {
425
442
        a = b;
426
442
        d = c;
427
176
      } else if(b == c) {
428
        // nothing to do
429
52
      } else if(b == d) {
430
20
        d = c;
431
      } else {
432
        // condition not satisfied
433
16
        Debug("diamonds") << "+ A fails" << endl;
434
16
        continue;
435
      }
436
437
618
      Debug("diamonds") << "+ A holds" << endl;
438
439
      // same: one of {e, f} = one of {g, h}, and make "f" the
440
      // shared node (i.e. put in the form (e = f && f = h))
441
618
      if(e == g) {
442
16
        e = f;
443
602
      } else if(e == h) {
444
454
        e = f;
445
454
        h = g;
446
148
      } else if(f == g) {
447
        // nothing to do
448
10
      } else if(f == h) {
449
6
        h = g;
450
      } else {
451
        // condition not satisfied
452
2
        Debug("diamonds") << "+ B fails" << endl;
453
2
        continue;
454
      }
455
456
616
      Debug("diamonds") << "+ B holds" << endl;
457
458
      // now we have (a = b && b = d) || (e = f && f = h)
459
      // test that {a, d} == {e, h}
460
1232
      if( (a == e && d == h) ||
461
          (a == h && d == e) ) {
462
        // learn: n implies a == d
463
616
        Debug("diamonds") << "+ C holds" << endl;
464
1232
        Node newEquality = a.eqNode(d);
465
616
        Debug("diamonds") << "  ==> " << newEquality << endl;
466
616
        learned << n.impNode(newEquality);
467
      } else {
468
        Debug("diamonds") << "+ C fails" << endl;
469
      }
470
    }
471
  }
472
473
105454
  if(options::ufSymmetryBreaker()) {
474
24124
    d_symb.assertFormula(n);
475
  }
476
105454
} /* TheoryUF::ppStaticLearn() */
477
478
2487
EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
479
480
  // Check for equality (simplest)
481
2487
  if (d_equalityEngine->areEqual(a, b))
482
  {
483
    // The terms are implied to be equal
484
    return EQUALITY_TRUE;
485
  }
486
487
  // Check for disequality
488
2487
  if (d_equalityEngine->areDisequal(a, b, false))
489
  {
490
    // The terms are implied to be dis-equal
491
    return EQUALITY_FALSE;
492
  }
493
494
  // All other terms we interpret as dis-equal in the model
495
2487
  return EQUALITY_FALSE_IN_MODEL;
496
}
497
498
1463989
bool TheoryUF::areCareDisequal(TNode x, TNode y){
499
1463989
  Assert(d_equalityEngine->hasTerm(x));
500
1463989
  Assert(d_equalityEngine->hasTerm(y));
501
4391967
  if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
502
4391967
      && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
503
  {
504
    TNode x_shared =
505
1428416
        d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
506
    TNode y_shared =
507
1428416
        d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
508
1173326
    EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
509
1173326
    if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
510
918236
      return true;
511
    }
512
  }
513
545753
  return false;
514
}
515
516
446095
void TheoryUF::addCarePairs(const TNodeTrie* t1,
517
                            const TNodeTrie* t2,
518
                            unsigned arity,
519
                            unsigned depth)
520
{
521
446095
  if( depth==arity ){
522
131855
    if( t2!=NULL ){
523
263710
      Node f1 = t1->getData();
524
263710
      Node f2 = t2->getData();
525
131855
      if (!d_equalityEngine->areEqual(f1, f2))
526
      {
527
122030
        Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
528
244060
        vector< pair<TNode, TNode> > currentPairs;
529
332578
        for (size_t k = 0, nchildren = f1.getNumChildren(); k < nchildren; ++k)
530
        {
531
421096
          TNode x = f1[k];
532
421096
          TNode y = f2[k];
533
210548
          Assert(d_equalityEngine->hasTerm(x));
534
210548
          Assert(d_equalityEngine->hasTerm(y));
535
210548
          Assert(!d_equalityEngine->areDisequal(x, y, false));
536
210548
          Assert(!areCareDisequal(x, y));
537
210548
          if (!d_equalityEngine->areEqual(x, y))
538
          {
539
390234
            if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
540
390234
                && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
541
            {
542
              TNode x_shared =
543
86530
                  d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
544
              TNode y_shared =
545
86530
                  d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
546
43265
              currentPairs.push_back(make_pair(x_shared, y_shared));
547
            }
548
          }
549
        }
550
165295
        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
551
43265
          Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
552
43265
          addCarePair(currentPairs[c].first, currentPairs[c].second);
553
        }
554
      }
555
    }
556
  }else{
557
314240
    if( t2==NULL ){
558
110890
      if( depth<(arity-1) ){
559
        //add care pairs internal to each child
560
130729
        for (const std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
561
        {
562
75260
          addCarePairs(&tt.second, NULL, arity, depth + 1);
563
        }
564
      }
565
      //add care pairs based on each pair of non-disequal arguments
566
540978
      for (std::map<TNode, TNodeTrie>::const_iterator it = t1->d_data.begin();
567
540978
           it != t1->d_data.end();
568
           ++it)
569
      {
570
430088
        std::map<TNode, TNodeTrie>::const_iterator it2 = it;
571
430088
        ++it2;
572
5639500
        for( ; it2 != t1->d_data.end(); ++it2 ){
573
2604706
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
574
          {
575
943895
            if( !areCareDisequal(it->first, it2->first) ){
576
243783
              addCarePairs( &it->second, &it2->second, arity, depth+1 );
577
            }
578
          }
579
        }
580
      }
581
    }else{
582
      //add care pairs based on product of indices, non-disequal arguments
583
505806
      for (const std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
584
      {
585
624532
        for (const std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
586
        {
587
322076
          if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
588
          {
589
309546
            if (!areCareDisequal(tt1.first, tt2.first))
590
            {
591
91422
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1);
592
            }
593
          }
594
        }
595
      }
596
    }
597
  }
598
446095
}
599
600
24221
void TheoryUF::computeCareGraph() {
601
24221
  if (d_sharedTerms.empty())
602
  {
603
8362
    return;
604
  }
605
  // Use term indexing. We build separate indices for APPLY_UF and HO_APPLY.
606
  // We maintain indices per operator for the former, and indices per
607
  // function type for the latter.
608
31718
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..."
609
15859
                       << std::endl;
610
31718
  std::map<Node, TNodeTrie> index;
611
31718
  std::map<TypeNode, TNodeTrie> hoIndex;
612
31718
  std::map<Node, size_t> arity;
613
444666
  for (TNode app : d_functionsTerms)
614
  {
615
857614
    std::vector<TNode> reps;
616
428807
    bool has_trigger_arg = false;
617
1005301
    for (const Node& j : app)
618
    {
619
576494
      reps.push_back(d_equalityEngine->getRepresentative(j));
620
576494
      if (d_equalityEngine->isTriggerTerm(j, THEORY_UF))
621
      {
622
503530
        has_trigger_arg = true;
623
      }
624
    }
625
428807
    if (has_trigger_arg)
626
    {
627
387279
      if (app.getKind() == kind::APPLY_UF)
628
      {
629
774494
        Node op = app.getOperator();
630
387247
        index[op].addTerm(app, reps);
631
387247
        arity[op] = reps.size();
632
      }
633
      else
634
      {
635
32
        Assert(app.getKind() == kind::HO_APPLY);
636
        // add it to the hoIndex for the function type
637
32
        hoIndex[app[0].getType()].addTerm(app, reps);
638
      }
639
    }
640
  }
641
  // for each index
642
51479
  for (std::pair<const Node, TNodeTrie>& tt : index)
643
  {
644
71240
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
645
35620
                         << tt.first << "..." << std::endl;
646
35620
    Assert(arity.find(tt.first) != arity.end());
647
35620
    addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
648
  }
649
15869
  for (std::pair<const TypeNode, TNodeTrie>& tt : hoIndex)
650
  {
651
20
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process ho index "
652
10
                         << tt.first << "..." << std::endl;
653
    // the arity of HO_APPLY is always two
654
10
    addCarePairs(&tt.second, nullptr, 2, 0);
655
  }
656
31718
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished."
657
15859
                       << std::endl;
658
}/* TheoryUF::computeCareGraph() */
659
660
272886
void TheoryUF::eqNotifyNewClass(TNode t) {
661
272886
  if (d_thss != NULL) {
662
52811
    d_thss->newEqClass(t);
663
  }
664
272886
}
665
666
4593957
void TheoryUF::eqNotifyMerge(TNode t1, TNode t2)
667
{
668
4593957
  if (d_thss != NULL) {
669
282285
    d_thss->merge(t1, t2);
670
  }
671
4593957
}
672
673
900960
void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
674
900960
  if (d_thss != NULL) {
675
21054
    d_thss->assertDisequal(t1, t2, reason);
676
  }
677
900960
}
678
679
86293
bool TheoryUF::isHigherOrderType(TypeNode tn)
680
{
681
86293
  Assert(tn.isFunction());
682
86293
  std::map<TypeNode, bool>::iterator it = d_isHoType.find(tn);
683
86293
  if (it != d_isHoType.end())
684
  {
685
81324
    return it->second;
686
  }
687
4969
  bool ret = false;
688
9938
  const std::vector<TypeNode>& argTypes = tn.getArgTypes();
689
14222
  for (const TypeNode& tnc : argTypes)
690
  {
691
9324
    if (tnc.isFunction())
692
    {
693
71
      ret = true;
694
71
      break;
695
    }
696
  }
697
4969
  d_isHoType[tn] = ret;
698
4969
  return ret;
699
}
700
701
}  // namespace uf
702
}  // namespace theory
703
29502
}  // namespace cvc5