GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/theory_uf.cpp Lines: 290 333 87.1 %
Date: 2021-05-22 Branches: 643 1350 47.6 %

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 "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 cvc5 {
39
namespace theory {
40
namespace uf {
41
42
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
43
9460
TheoryUF::TheoryUF(context::Context* c,
44
                   context::UserContext* u,
45
                   OutputChannel& out,
46
                   Valuation valuation,
47
                   const LogicInfo& logicInfo,
48
                   ProofNodeManager* pnm,
49
9460
                   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
18920
      d_im(*this, d_state, pnm, "theory::uf::" + instanceName, false),
57
28380
      d_notify(d_im, *this)
58
{
59
9460
  d_true = NodeManager::currentNM()->mkConst( true );
60
  // indicate we are using the default theory state and inference managers
61
9460
  d_theoryState = &d_state;
62
9460
  d_inferManager = &d_im;
63
9460
}
64
65
18920
TheoryUF::~TheoryUF() {
66
18920
}
67
68
9460
TheoryRewriter* TheoryUF::getTheoryRewriter() { return &d_rewriter; }
69
70
3600
ProofRuleChecker* TheoryUF::getProofChecker() { return &d_checker; }
71
72
9460
bool TheoryUF::needsEqualityEngine(EeSetupInfo& esi)
73
{
74
9460
  esi.d_notify = &d_notify;
75
9460
  esi.d_name = d_instanceName + "theory::uf::ee";
76
9460
  return true;
77
}
78
79
9460
void TheoryUF::finishInit() {
80
9460
  Assert(d_equalityEngine != nullptr);
81
  // combined cardinality constraints are not evaluated in getModelValue
82
9460
  d_valuation.setUnevaluatedKind(kind::COMBINED_CARDINALITY_CONSTRAINT);
83
  // Initialize the cardinality constraints solver if the logic includes UF,
84
  // finite model finding is enabled, and it is not disabled by
85
  // options::ufssMode().
86
18920
  if (options::finiteModelFind()
87
9460
      && options::ufssMode() != options::UfssMode::NONE)
88
  {
89
282
    d_thss.reset(new CardinalityExtension(d_state, d_im, this));
90
  }
91
  // The kinds we are treating as function application in congruence
92
9460
  d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, options::ufHo());
93
9460
  if (options::ufHo())
94
  {
95
200
    d_equalityEngine->addFunctionKind(kind::HO_APPLY);
96
200
    d_ho.reset(new HoExtension(d_state, d_im));
97
  }
98
9460
}
99
100
static Node mkAnd(const std::vector<TNode>& conjunctions) {
101
  Assert(conjunctions.size() > 0);
102
103
  std::set<TNode> all;
104
  all.insert(conjunctions.begin(), conjunctions.end());
105
106
  if (all.size() == 1) {
107
    // All the same, or just one
108
    return conjunctions[0];
109
  }
110
111
  NodeBuilder conjunction(kind::AND);
112
  std::set<TNode>::const_iterator it = all.begin();
113
  std::set<TNode>::const_iterator it_end = all.end();
114
  while (it != it_end) {
115
    conjunction << *it;
116
    ++ it;
117
  }
118
119
  return conjunction;
120
}/* mkAnd() */
121
122
//--------------------------------- standard check
123
124
14403
bool TheoryUF::needsCheckLastEffort()
125
{
126
  // last call effort needed if using finite model finding
127
14403
  return d_thss != nullptr;
128
}
129
130
1131861
void TheoryUF::postCheck(Effort level)
131
{
132
1131861
  if (d_state.isInConflict())
133
  {
134
59421
    return;
135
  }
136
  // check with the cardinality constraints extension
137
1072440
  if (d_thss != nullptr)
138
  {
139
137479
    d_thss->check(level);
140
  }
141
  // check with the higher-order extension at full effort
142
1072440
  if (!d_state.isInConflict() && fullEffort(level))
143
  {
144
56107
    if (options::ufHo())
145
    {
146
1041
      d_ho->check();
147
    }
148
  }
149
}
150
151
3131679
bool TheoryUF::preNotifyFact(
152
    TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
153
{
154
3131679
  if (d_thss != nullptr)
155
  {
156
    bool isDecision =
157
293698
        d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
158
293698
    d_thss->assertNode(fact, isDecision);
159
293698
    if (d_state.isInConflict())
160
    {
161
1126
      return true;
162
    }
163
  }
164
6261106
  if (atom.getKind() == kind::CARDINALITY_CONSTRAINT
165
3130553
      || atom.getKind() == kind::COMBINED_CARDINALITY_CONSTRAINT)
166
  {
167
12806
    if (d_thss == nullptr)
168
    {
169
      if (!getLogicInfo().hasCardinalityConstraints())
170
      {
171
        std::stringstream ss;
172
        ss << "Cardinality constraint " << atom
173
           << " was asserted, but the logic does not allow it." << std::endl;
174
        ss << "Try using a logic containing \"UFC\"." << std::endl;
175
        throw Exception(ss.str());
176
      }
177
      else
178
      {
179
        // support for cardinality constraints is not enabled, set incomplete
180
        d_im.setIncomplete(IncompleteId::UF_CARD_DISABLED);
181
      }
182
    }
183
    // don't need to assert cardinality constraints if not producing models
184
12806
    return !options::produceModels();
185
  }
186
3117747
  return false;
187
}
188
189
3120874
void TheoryUF::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
190
{
191
3120874
  if (!d_state.isInConflict() && atom.getKind() == kind::EQUAL)
192
  {
193
2853003
    if (options::ufHo() && options::ufHoExt())
194
    {
195
71419
      if (!pol && !d_state.isInConflict() && atom[0].getType().isFunction())
196
      {
197
        // apply extensionality eagerly using the ho extension
198
301
        d_ho->applyExtensionality(fact);
199
      }
200
    }
201
  }
202
3120874
}
203
//--------------------------------- end standard check
204
205
463736
TrustNode TheoryUF::ppRewrite(TNode node, std::vector<SkolemLemma>& lems)
206
{
207
927472
  Trace("uf-exp-def") << "TheoryUF::ppRewrite: expanding definition : " << node
208
463736
                      << std::endl;
209
463736
  Kind k = node.getKind();
210
463736
  if (k == kind::HO_APPLY)
211
  {
212
276
    if( !options::ufHo() ){
213
      std::stringstream ss;
214
      ss << "Partial function applications are not supported in default mode, try --uf-ho.";
215
      throw LogicException(ss.str());
216
    }
217
431
    Node ret = d_ho->ppRewrite(node);
218
276
    if (ret != node)
219
    {
220
242
      Trace("uf-exp-def") << "TheoryUF::ppRewrite: higher-order: " << node
221
121
                          << " to " << ret << std::endl;
222
121
      return TrustNode::mkTrustRewrite(node, ret, nullptr);
223
    }
224
  }
225
463460
  else if (k == kind::APPLY_UF)
226
  {
227
    // check for higher-order
228
    // logic exception if higher-order is not enabled
229
86794
    if (isHigherOrderType(node.getOperator().getType()) && !options::ufHo())
230
    {
231
      std::stringstream ss;
232
      ss << "UF received an application whose operator has higher-order type "
233
         << node << ", which is not supported by default, try --uf-ho";
234
      throw LogicException(ss.str());
235
    }
236
  }
237
463615
  return TrustNode::null();
238
}
239
240
381121
void TheoryUF::preRegisterTerm(TNode node)
241
{
242
381121
  Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
243
244
381121
  if (d_thss != NULL) {
245
45400
    d_thss->preRegisterTerm(node);
246
  }
247
248
  // we always use APPLY_UF if not higher-order, HO_APPLY if higher-order
249
  //Assert( node.getKind()!=kind::APPLY_UF || !options::ufHo() );
250
381121
  Assert(node.getKind() != kind::HO_APPLY || options::ufHo());
251
252
381121
  Kind k = node.getKind();
253
381121
  switch (k)
254
  {
255
167061
    case kind::EQUAL:
256
      // Add the trigger for equality
257
167061
      d_equalityEngine->addTriggerPredicate(node);
258
167061
      break;
259
139402
    case kind::APPLY_UF:
260
    case kind::HO_APPLY:
261
    {
262
      // Maybe it's a predicate
263
139402
      if (node.getType().isBoolean())
264
      {
265
        // Get triggered for both equal and dis-equal
266
29579
        d_equalityEngine->addTriggerPredicate(node);
267
      }
268
      else
269
      {
270
        // Function applications/predicates
271
109823
        d_equalityEngine->addTerm(node);
272
      }
273
      // Remember the function and predicate terms
274
139402
      d_functionsTerms.push_back(node);
275
    }
276
139402
    break;
277
3819
  case kind::CARDINALITY_CONSTRAINT:
278
  case kind::COMBINED_CARDINALITY_CONSTRAINT:
279
    //do nothing
280
3819
    break;
281
70839
  default:
282
    // Variables etc
283
70839
    d_equalityEngine->addTerm(node);
284
70839
    break;
285
  }
286
381121
}
287
288
void TheoryUF::explain(TNode literal, Node& exp)
289
{
290
  Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
291
  std::vector<TNode> assumptions;
292
  // Do the work
293
  bool polarity = literal.getKind() != kind::NOT;
294
  TNode atom = polarity ? literal : literal[0];
295
  if (atom.getKind() == kind::EQUAL)
296
  {
297
    d_equalityEngine->explainEquality(
298
        atom[0], atom[1], polarity, assumptions, nullptr);
299
  }
300
  else
301
  {
302
    d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr);
303
  }
304
  exp = mkAnd(assumptions);
305
}
306
307
110056
TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); }
308
309
12523
bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
310
{
311
12523
  if( options::ufHo() ){
312
    // must add extensionality disequalities for all pairs of (non-disequal)
313
    // function equivalence classes.
314
431
    if (!d_ho->collectModelInfoHo(m, termSet))
315
    {
316
      Trace("uf") << "Collect model info fail HO" << std::endl;
317
      return false;
318
    }
319
  }
320
321
12523
  Debug("uf") << "UF : finish collectModelInfo " << std::endl;
322
12523
  return true;
323
}
324
325
14314
void TheoryUF::presolve() {
326
  // TimerStat::CodeTimer codeTimer(d_presolveTimer);
327
328
14314
  Debug("uf") << "uf: begin presolve()" << endl;
329
14314
  if(options::ufSymmetryBreaker()) {
330
304
    vector<Node> newClauses;
331
152
    d_symb.apply(newClauses);
332
154
    for(vector<Node>::const_iterator i = newClauses.begin();
333
154
        i != newClauses.end();
334
        ++i) {
335
2
      Debug("uf") << "uf: generating a lemma: " << *i << std::endl;
336
      // no proof generator provided
337
2
      d_im.lemma(*i, InferenceId::UF_BREAK_SYMMETRY);
338
    }
339
  }
340
14314
  if( d_thss ){
341
332
    d_thss->presolve();
342
  }
343
14314
  Debug("uf") << "uf: end presolve()" << endl;
344
14314
}
345
346
104082
void TheoryUF::ppStaticLearn(TNode n, NodeBuilder& learned)
347
{
348
  //TimerStat::CodeTimer codeTimer(d_staticLearningTimer);
349
350
208164
  vector<TNode> workList;
351
104082
  workList.push_back(n);
352
208164
  std::unordered_set<TNode> processed;
353
354
5002608
  while(!workList.empty()) {
355
2449263
    n = workList.back();
356
357
2472933
    if (n.isClosure())
358
    {
359
      // unsafe to go under quantifiers; we might pull bound vars out of scope!
360
23670
      processed.insert(n);
361
23670
      workList.pop_back();
362
23670
      continue;
363
    }
364
365
2425593
    bool unprocessedChildren = false;
366
7963014
    for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ++i) {
367
5537421
      if(processed.find(*i) == processed.end()) {
368
        // unprocessed child
369
1579443
        workList.push_back(*i);
370
1579443
        unprocessedChildren = true;
371
      }
372
    }
373
374
2425593
    if(unprocessedChildren) {
375
765738
      continue;
376
    }
377
378
1659855
    workList.pop_back();
379
    // has node n been processed in the meantime ?
380
1659855
    if(processed.find(n) != processed.end()) {
381
19893
      continue;
382
    }
383
1639962
    processed.insert(n);
384
385
    // == DIAMONDS ==
386
387
3279924
    Debug("diamonds") << "===================== looking at" << endl
388
1639962
                      << n << endl;
389
390
    // binary OR of binary ANDs of EQUALities
391
4120775
    if(n.getKind() == kind::OR && n.getNumChildren() == 2 &&
392
2101888
       n[0].getKind() == kind::AND && n[0].getNumChildren() == 2 &&
393
1660344
       n[1].getKind() == kind::AND && n[1].getNumChildren() == 2 &&
394
1646156
       (n[0][0].getKind() == kind::EQUAL) &&
395
1642614
       (n[0][1].getKind() == kind::EQUAL) &&
396
4922470
       (n[1][0].getKind() == kind::EQUAL) &&
397
1641254
       (n[1][1].getKind() == kind::EQUAL)) {
398
      // now we have (a = b && c = d) || (e = f && g = h)
399
400
634
      Debug("diamonds") << "has form of a diamond!" << endl;
401
402
      TNode
403
1250
        a = n[0][0][0], b = n[0][0][1],
404
1250
        c = n[0][1][0], d = n[0][1][1],
405
1250
        e = n[1][0][0], f = n[1][0][1],
406
1250
        g = n[1][1][0], h = n[1][1][1];
407
408
      // test that one of {a, b} = one of {c, d}, and make "b" the
409
      // shared node (i.e. put in the form (a = b && b = d))
410
      // note we don't actually care about the shared ones, so the
411
      // "swaps" below are one-sided, ignoring b and c
412
634
      if(a == c) {
413
16
        a = b;
414
618
      } else if(a == d) {
415
442
        a = b;
416
442
        d = c;
417
176
      } else if(b == c) {
418
        // nothing to do
419
52
      } else if(b == d) {
420
20
        d = c;
421
      } else {
422
        // condition not satisfied
423
16
        Debug("diamonds") << "+ A fails" << endl;
424
16
        continue;
425
      }
426
427
618
      Debug("diamonds") << "+ A holds" << endl;
428
429
      // same: one of {e, f} = one of {g, h}, and make "f" the
430
      // shared node (i.e. put in the form (e = f && f = h))
431
618
      if(e == g) {
432
16
        e = f;
433
602
      } else if(e == h) {
434
454
        e = f;
435
454
        h = g;
436
148
      } else if(f == g) {
437
        // nothing to do
438
10
      } else if(f == h) {
439
6
        h = g;
440
      } else {
441
        // condition not satisfied
442
2
        Debug("diamonds") << "+ B fails" << endl;
443
2
        continue;
444
      }
445
446
616
      Debug("diamonds") << "+ B holds" << endl;
447
448
      // now we have (a = b && b = d) || (e = f && f = h)
449
      // test that {a, d} == {e, h}
450
1232
      if( (a == e && d == h) ||
451
          (a == h && d == e) ) {
452
        // learn: n implies a == d
453
616
        Debug("diamonds") << "+ C holds" << endl;
454
1232
        Node newEquality = a.eqNode(d);
455
616
        Debug("diamonds") << "  ==> " << newEquality << endl;
456
616
        learned << n.impNode(newEquality);
457
      } else {
458
        Debug("diamonds") << "+ C fails" << endl;
459
      }
460
    }
461
  }
462
463
104082
  if(options::ufSymmetryBreaker()) {
464
24122
    d_symb.assertFormula(n);
465
  }
466
104082
} /* TheoryUF::ppStaticLearn() */
467
468
1979
EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
469
470
  // Check for equality (simplest)
471
1979
  if (d_equalityEngine->areEqual(a, b))
472
  {
473
    // The terms are implied to be equal
474
    return EQUALITY_TRUE;
475
  }
476
477
  // Check for disequality
478
1979
  if (d_equalityEngine->areDisequal(a, b, false))
479
  {
480
    // The terms are implied to be dis-equal
481
    return EQUALITY_FALSE;
482
  }
483
484
  // All other terms we interpret as dis-equal in the model
485
1979
  return EQUALITY_FALSE_IN_MODEL;
486
}
487
488
1343934
bool TheoryUF::areCareDisequal(TNode x, TNode y){
489
1343934
  Assert(d_equalityEngine->hasTerm(x));
490
1343934
  Assert(d_equalityEngine->hasTerm(y));
491
4031802
  if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
492
4031802
      && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
493
  {
494
    TNode x_shared =
495
1279685
        d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
496
    TNode y_shared =
497
1279685
        d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
498
1043443
    EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
499
1043443
    if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
500
807201
      return true;
501
    }
502
  }
503
536733
  return false;
504
}
505
506
439649
void TheoryUF::addCarePairs(const TNodeTrie* t1,
507
                            const TNodeTrie* t2,
508
                            unsigned arity,
509
                            unsigned depth)
510
{
511
439649
  if( depth==arity ){
512
122697
    if( t2!=NULL ){
513
245394
      Node f1 = t1->getData();
514
245394
      Node f2 = t2->getData();
515
122697
      if (!d_equalityEngine->areEqual(f1, f2))
516
      {
517
112771
        Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
518
225542
        vector< pair<TNode, TNode> > currentPairs;
519
313330
        for (size_t k = 0, nchildren = f1.getNumChildren(); k < nchildren; ++k)
520
        {
521
401118
          TNode x = f1[k];
522
401118
          TNode y = f2[k];
523
200559
          Assert(d_equalityEngine->hasTerm(x));
524
200559
          Assert(d_equalityEngine->hasTerm(y));
525
200559
          Assert(!d_equalityEngine->areDisequal(x, y, false));
526
200559
          Assert(!areCareDisequal(x, y));
527
200559
          if (!d_equalityEngine->areEqual(x, y))
528
          {
529
357363
            if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
530
357363
                && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
531
            {
532
              TNode x_shared =
533
65124
                  d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
534
              TNode y_shared =
535
65124
                  d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
536
32562
              currentPairs.push_back(make_pair(x_shared, y_shared));
537
            }
538
          }
539
        }
540
145333
        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
541
32562
          Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
542
32562
          addCarePair(currentPairs[c].first, currentPairs[c].second);
543
        }
544
      }
545
    }
546
  }else{
547
316952
    if( t2==NULL ){
548
103475
      if( depth<(arity-1) ){
549
        //add care pairs internal to each child
550
127255
        for (const std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
551
        {
552
73711
          addCarePairs(&tt.second, NULL, arity, depth + 1);
553
        }
554
      }
555
      //add care pairs based on each pair of non-disequal arguments
556
453955
      for (std::map<TNode, TNodeTrie>::const_iterator it = t1->d_data.begin();
557
453955
           it != t1->d_data.end();
558
           ++it)
559
      {
560
350480
        std::map<TNode, TNodeTrie>::const_iterator it2 = it;
561
350480
        ++it2;
562
4683722
        for( ; it2 != t1->d_data.end(); ++it2 ){
563
2166621
          if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
564
          {
565
813462
            if( !areCareDisequal(it->first, it2->first) ){
566
242900
              addCarePairs( &it->second, &it2->second, arity, depth+1 );
567
            }
568
          }
569
        }
570
      }
571
    }else{
572
      //add care pairs based on product of indices, non-disequal arguments
573
530694
      for (const std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
574
      {
575
669295
        for (const std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
576
        {
577
352078
          if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
578
          {
579
329913
            if (!areCareDisequal(tt1.first, tt2.first))
580
            {
581
93274
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1);
582
            }
583
          }
584
        }
585
      }
586
    }
587
  }
588
439649
}
589
590
20895
void TheoryUF::computeCareGraph() {
591
20895
  if (d_sharedTerms.empty())
592
  {
593
7647
    return;
594
  }
595
  // Use term indexing. We build separate indices for APPLY_UF and HO_APPLY.
596
  // We maintain indices per operator for the former, and indices per
597
  // function type for the latter.
598
26496
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..."
599
13248
                       << std::endl;
600
26496
  std::map<Node, TNodeTrie> index;
601
26496
  std::map<TypeNode, TNodeTrie> hoIndex;
602
26496
  std::map<Node, size_t> arity;
603
376745
  for (TNode app : d_functionsTerms)
604
  {
605
726994
    std::vector<TNode> reps;
606
363497
    bool has_trigger_arg = false;
607
875397
    for (const Node& j : app)
608
    {
609
511900
      reps.push_back(d_equalityEngine->getRepresentative(j));
610
511900
      if (d_equalityEngine->isTriggerTerm(j, THEORY_UF))
611
      {
612
419719
        has_trigger_arg = true;
613
      }
614
    }
615
363497
    if (has_trigger_arg)
616
    {
617
309737
      if (app.getKind() == kind::APPLY_UF)
618
      {
619
619410
        Node op = app.getOperator();
620
309705
        index[op].addTerm(app, reps);
621
309705
        arity[op] = reps.size();
622
      }
623
      else
624
      {
625
32
        Assert(app.getKind() == kind::HO_APPLY);
626
        // add it to the hoIndex for the function type
627
32
        hoIndex[app[0].getType()].addTerm(app, reps);
628
      }
629
    }
630
  }
631
  // for each index
632
43002
  for (std::pair<const Node, TNodeTrie>& tt : index)
633
  {
634
59508
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
635
29754
                         << tt.first << "..." << std::endl;
636
29754
    Assert(arity.find(tt.first) != arity.end());
637
29754
    addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
638
  }
639
13258
  for (std::pair<const TypeNode, TNodeTrie>& tt : hoIndex)
640
  {
641
20
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process ho index "
642
10
                         << tt.first << "..." << std::endl;
643
    // the arity of HO_APPLY is always two
644
10
    addCarePairs(&tt.second, nullptr, 2, 0);
645
  }
646
26496
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished."
647
13248
                       << std::endl;
648
}/* TheoryUF::computeCareGraph() */
649
650
248750
void TheoryUF::eqNotifyNewClass(TNode t) {
651
248750
  if (d_thss != NULL) {
652
32038
    d_thss->newEqClass(t);
653
  }
654
248750
}
655
656
4527887
void TheoryUF::eqNotifyMerge(TNode t1, TNode t2)
657
{
658
4527887
  if (d_thss != NULL) {
659
427827
    d_thss->merge(t1, t2);
660
  }
661
4527887
}
662
663
827127
void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
664
827127
  if (d_thss != NULL) {
665
25723
    d_thss->assertDisequal(t1, t2, reason);
666
  }
667
827127
}
668
669
86794
bool TheoryUF::isHigherOrderType(TypeNode tn)
670
{
671
86794
  Assert(tn.isFunction());
672
86794
  std::map<TypeNode, bool>::iterator it = d_isHoType.find(tn);
673
86794
  if (it != d_isHoType.end())
674
  {
675
81958
    return it->second;
676
  }
677
4836
  bool ret = false;
678
9672
  const std::vector<TypeNode>& argTypes = tn.getArgTypes();
679
13926
  for (const TypeNode& tnc : argTypes)
680
  {
681
9155
    if (tnc.isFunction())
682
    {
683
65
      ret = true;
684
65
      break;
685
    }
686
  }
687
4836
  d_isHoType[tn] = ret;
688
4836
  return ret;
689
}
690
691
}  // namespace uf
692
}  // namespace theory
693
28194
}  // namespace cvc5