GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/uf/theory_uf.cpp Lines: 306 349 87.7 %
Date: 2021-11-05 Branches: 677 1354 50.0 %

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
15271
TheoryUF::TheoryUF(Env& env,
44
                   OutputChannel& out,
45
                   Valuation valuation,
46
15271
                   std::string instanceName)
47
    : Theory(THEORY_UF, env, out, valuation, instanceName),
48
      d_thss(nullptr),
49
      d_ho(nullptr),
50
      d_functionsTerms(context()),
51
15271
      d_symb(userContext(), instanceName),
52
15271
      d_rewriter(logicInfo().isHigherOrder()),
53
      d_state(env, valuation),
54
30542
      d_im(env, *this, d_state, "theory::uf::" + instanceName, false),
55
76355
      d_notify(d_im, *this)
56
{
57
15271
  d_true = NodeManager::currentNM()->mkConst( true );
58
  // indicate we are using the default theory state and inference managers
59
15271
  d_theoryState = &d_state;
60
15271
  d_inferManager = &d_im;
61
15271
}
62
63
30532
TheoryUF::~TheoryUF() {
64
30532
}
65
66
15271
TheoryRewriter* TheoryUF::getTheoryRewriter() { return &d_rewriter; }
67
68
7987
ProofRuleChecker* TheoryUF::getProofChecker() { return &d_checker; }
69
70
15271
bool TheoryUF::needsEqualityEngine(EeSetupInfo& esi)
71
{
72
15271
  esi.d_notify = &d_notify;
73
15271
  esi.d_name = d_instanceName + "theory::uf::ee";
74
30542
  if (options::finiteModelFind()
75
15271
      && options::ufssMode() != options::UfssMode::NONE)
76
  {
77
    // need notifications about sorts
78
294
    esi.d_notifyNewClass = true;
79
294
    esi.d_notifyMerge = true;
80
294
    esi.d_notifyDisequal = true;
81
  }
82
15271
  return true;
83
}
84
85
15271
void TheoryUF::finishInit() {
86
15271
  Assert(d_equalityEngine != nullptr);
87
  // combined cardinality constraints are not evaluated in getModelValue
88
15271
  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
30542
  if (options::finiteModelFind()
93
15271
      && options::ufssMode() != options::UfssMode::NONE)
94
  {
95
294
    d_thss.reset(new CardinalityExtension(d_env, d_state, d_im, this));
96
  }
97
  // The kinds we are treating as function application in congruence
98
15271
  bool isHo = logicInfo().isHigherOrder();
99
15271
  d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, isHo);
100
15271
  if (isHo)
101
  {
102
238
    d_equalityEngine->addFunctionKind(kind::HO_APPLY);
103
238
    d_ho.reset(new HoExtension(d_env, d_state, d_im));
104
  }
105
15271
}
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
23925
bool TheoryUF::needsCheckLastEffort()
132
{
133
  // last call effort needed if using finite model finding
134
23925
  return d_thss != nullptr;
135
}
136
137
1207712
void TheoryUF::postCheck(Effort level)
138
{
139
1207712
  if (d_state.isInConflict())
140
  {
141
48939
    return;
142
  }
143
  // check with the cardinality constraints extension
144
1158773
  if (d_thss != nullptr)
145
  {
146
87938
    d_thss->check(level);
147
  }
148
  // check with the higher-order extension at full effort
149
1158773
  if (!d_state.isInConflict() && fullEffort(level))
150
  {
151
84398
    if (logicInfo().isHigherOrder())
152
    {
153
1071
      d_ho->check();
154
    }
155
  }
156
}
157
158
3065845
void TheoryUF::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
159
{
160
3065845
  if (d_state.isInConflict())
161
  {
162
47964
    return;
163
  }
164
3017881
  if (d_thss != nullptr)
165
  {
166
    bool isDecision =
167
211632
        d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
168
211632
    d_thss->assertNode(fact, isDecision);
169
  }
170
3017881
  switch (atom.getKind())
171
  {
172
2823086
    case kind::EQUAL:
173
    {
174
2823086
      if (logicInfo().isHigherOrder() && options().uf.ufHoExt)
175
      {
176
56339
        if (!pol && !d_state.isInConflict() && atom[0].getType().isFunction())
177
        {
178
          // apply extensionality eagerly using the ho extension
179
3629
          d_ho->applyExtensionality(fact);
180
        }
181
      }
182
    }
183
2823086
    break;
184
13888
    case kind::CARDINALITY_CONSTRAINT:
185
    case kind::COMBINED_CARDINALITY_CONSTRAINT:
186
    {
187
13888
      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
13888
    break;
205
180907
    default: break;
206
  }
207
}
208
//--------------------------------- end standard check
209
210
479519
TrustNode TheoryUF::ppRewrite(TNode node, std::vector<SkolemLemma>& lems)
211
{
212
959038
  Trace("uf-exp-def") << "TheoryUF::ppRewrite: expanding definition : " << node
213
479519
                      << std::endl;
214
479519
  Kind k = node.getKind();
215
479519
  if (k == kind::HO_APPLY || (node.isVar() && node.getType().isFunction()))
216
  {
217
996
    if (!logicInfo().isHigherOrder())
218
    {
219
4
      std::stringstream ss;
220
2
      ss << "Partial function applications are only supported with "
221
            "higher-order logic. Try adding the logic prefix HO_.";
222
2
      throw LogicException(ss.str());
223
    }
224
1873
    Node ret = d_ho->ppRewrite(node);
225
994
    if (ret != node)
226
    {
227
230
      Trace("uf-exp-def") << "TheoryUF::ppRewrite: higher-order: " << node
228
115
                          << " to " << ret << std::endl;
229
115
      return TrustNode::mkTrustRewrite(node, ret, nullptr);
230
    }
231
  }
232
478523
  else if (k == kind::APPLY_UF)
233
  {
234
    // check for higher-order
235
    // logic exception if higher-order is not enabled
236
266886
    if (isHigherOrderType(node.getOperator().getType())
237
266886
        && !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
479402
  return TrustNode::null();
248
}
249
250
394592
void TheoryUF::preRegisterTerm(TNode node)
251
{
252
394592
  Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
253
254
394592
  if (d_thss != nullptr)
255
  {
256
43237
    d_thss->preRegisterTerm(node);
257
  }
258
259
  // we always use APPLY_UF if not higher-order, HO_APPLY if higher-order
260
394592
  Assert(node.getKind() != kind::HO_APPLY || logicInfo().isHigherOrder());
261
262
394592
  Kind k = node.getKind();
263
394592
  switch (k)
264
  {
265
170448
    case kind::EQUAL:
266
      // Add the trigger for equality
267
170448
      d_equalityEngine->addTriggerPredicate(node);
268
170448
      break;
269
144182
    case kind::APPLY_UF:
270
    case kind::HO_APPLY:
271
    {
272
      // Maybe it's a predicate
273
144182
      if (node.getType().isBoolean())
274
      {
275
        // Get triggered for both equal and dis-equal
276
30362
        d_equalityEngine->addTriggerPredicate(node);
277
      }
278
      else
279
      {
280
        // Function applications/predicates
281
113820
        d_equalityEngine->addTerm(node);
282
      }
283
      // Remember the function and predicate terms
284
144182
      d_functionsTerms.push_back(node);
285
    }
286
144182
    break;
287
3791
  case kind::CARDINALITY_CONSTRAINT:
288
  case kind::COMBINED_CARDINALITY_CONSTRAINT:
289
    //do nothing
290
3791
    break;
291
  case kind::UNINTERPRETED_CONSTANT:
292
  {
293
    // Uninterpreted constants should only appear in models, and should
294
    // never appear in constraints. They are unallowed to ever appear in
295
    // constraints since the cardinality of an uninterpreted sort may have
296
    // an upper bound, e.g. if (forall ((x U) (y U)) (= x y)) holds, then
297
    // @uc_U_2 is a ill-formed term, as its existence cannot be assumed.
298
    // The parser prevents the user from ever constructing uninterpreted
299
    // constants. However, they may be exported via models to API users.
300
    // It is thus possible that these uninterpreted constants are asserted
301
    // back in constraints, hence this check is necessary.
302
    throw LogicException(
303
        "An uninterpreted constant was preregistered to the UF theory.");
304
  }
305
  break;
306
76171
  default:
307
    // Variables etc
308
76171
    d_equalityEngine->addTerm(node);
309
76171
    break;
310
  }
311
394592
}
312
313
void TheoryUF::explain(TNode literal, Node& exp)
314
{
315
  Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
316
  std::vector<TNode> assumptions;
317
  // Do the work
318
  bool polarity = literal.getKind() != kind::NOT;
319
  TNode atom = polarity ? literal : literal[0];
320
  if (atom.getKind() == kind::EQUAL)
321
  {
322
    d_equalityEngine->explainEquality(
323
        atom[0], atom[1], polarity, assumptions, nullptr);
324
  }
325
  else
326
  {
327
    d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr);
328
  }
329
  exp = mkAnd(assumptions);
330
}
331
332
88738
TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); }
333
334
21656
bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
335
{
336
21656
  if (logicInfo().isHigherOrder())
337
  {
338
    // must add extensionality disequalities for all pairs of (non-disequal)
339
    // function equivalence classes.
340
365
    if (!d_ho->collectModelInfoHo(m, termSet))
341
    {
342
      Trace("uf") << "Collect model info fail HO" << std::endl;
343
      return false;
344
    }
345
  }
346
347
21656
  Debug("uf") << "UF : finish collectModelInfo " << std::endl;
348
21656
  return true;
349
}
350
351
20558
void TheoryUF::presolve() {
352
  // TimerStat::CodeTimer codeTimer(d_presolveTimer);
353
354
20558
  Debug("uf") << "uf: begin presolve()" << endl;
355
20558
  if(options::ufSymmetryBreaker()) {
356
292
    vector<Node> newClauses;
357
146
    d_symb.apply(newClauses);
358
166
    for(vector<Node>::const_iterator i = newClauses.begin();
359
166
        i != newClauses.end();
360
        ++i) {
361
20
      Debug("uf") << "uf: generating a lemma: " << *i << std::endl;
362
      // no proof generator provided
363
20
      d_im.lemma(*i, InferenceId::UF_BREAK_SYMMETRY);
364
    }
365
  }
366
20558
  if( d_thss ){
367
344
    d_thss->presolve();
368
  }
369
20558
  Debug("uf") << "uf: end presolve()" << endl;
370
20558
}
371
372
250915
void TheoryUF::ppStaticLearn(TNode n, NodeBuilder& learned)
373
{
374
  //TimerStat::CodeTimer codeTimer(d_staticLearningTimer);
375
376
501830
  vector<TNode> workList;
377
250915
  workList.push_back(n);
378
501830
  std::unordered_set<TNode> processed;
379
380
9231865
  while(!workList.empty()) {
381
4490475
    n = workList.back();
382
383
4514054
    if (n.isClosure())
384
    {
385
      // unsafe to go under quantifiers; we might pull bound vars out of scope!
386
23579
      processed.insert(n);
387
23579
      workList.pop_back();
388
23579
      continue;
389
    }
390
391
4466896
    bool unprocessedChildren = false;
392
11600771
    for(TNode::iterator i = n.begin(), iend = n.end(); i != iend; ++i) {
393
7133875
      if(processed.find(*i) == processed.end()) {
394
        // unprocessed child
395
2605027
        workList.push_back(*i);
396
2605027
        unprocessedChildren = true;
397
      }
398
    }
399
400
4466896
    if(unprocessedChildren) {
401
1634533
      continue;
402
    }
403
404
2832363
    workList.pop_back();
405
    // has node n been processed in the meantime ?
406
2832363
    if(processed.find(n) != processed.end()) {
407
43977
      continue;
408
    }
409
2788386
    processed.insert(n);
410
411
    // == DIAMONDS ==
412
413
5576772
    Debug("diamonds") << "===================== looking at" << endl
414
2788386
                      << n << endl;
415
416
    // binary OR of binary ANDs of EQUALities
417
5889510
    if(n.getKind() == kind::OR && n.getNumChildren() == 2 &&
418
2970114
       n[0].getKind() == kind::AND && n[0].getNumChildren() == 2 &&
419
2809488
       n[1].getKind() == kind::AND && n[1].getNumChildren() == 2 &&
420
2794796
       (n[0][0].getKind() == kind::EQUAL) &&
421
2791152
       (n[0][1].getKind() == kind::EQUAL) &&
422
8367766
       (n[1][0].getKind() == kind::EQUAL) &&
423
2789690
       (n[1][1].getKind() == kind::EQUAL)) {
424
      // now we have (a = b && c = d) || (e = f && g = h)
425
426
640
      Debug("diamonds") << "has form of a diamond!" << endl;
427
428
      TNode
429
1256
        a = n[0][0][0], b = n[0][0][1],
430
1256
        c = n[0][1][0], d = n[0][1][1],
431
1256
        e = n[1][0][0], f = n[1][0][1],
432
1256
        g = n[1][1][0], h = n[1][1][1];
433
434
      // test that one of {a, b} = one of {c, d}, and make "b" the
435
      // shared node (i.e. put in the form (a = b && b = d))
436
      // note we don't actually care about the shared ones, so the
437
      // "swaps" below are one-sided, ignoring b and c
438
640
      if(a == c) {
439
16
        a = b;
440
624
      } else if(a == d) {
441
442
        a = b;
442
442
        d = c;
443
182
      } else if(b == c) {
444
        // nothing to do
445
64
      } else if(b == d) {
446
20
        d = c;
447
      } else {
448
        // condition not satisfied
449
22
        Debug("diamonds") << "+ A fails" << endl;
450
22
        continue;
451
      }
452
453
618
      Debug("diamonds") << "+ A holds" << endl;
454
455
      // same: one of {e, f} = one of {g, h}, and make "f" the
456
      // shared node (i.e. put in the form (e = f && f = h))
457
618
      if(e == g) {
458
16
        e = f;
459
602
      } else if(e == h) {
460
454
        e = f;
461
454
        h = g;
462
148
      } else if(f == g) {
463
        // nothing to do
464
10
      } else if(f == h) {
465
6
        h = g;
466
      } else {
467
        // condition not satisfied
468
2
        Debug("diamonds") << "+ B fails" << endl;
469
2
        continue;
470
      }
471
472
616
      Debug("diamonds") << "+ B holds" << endl;
473
474
      // now we have (a = b && b = d) || (e = f && f = h)
475
      // test that {a, d} == {e, h}
476
1232
      if( (a == e && d == h) ||
477
          (a == h && d == e) ) {
478
        // learn: n implies a == d
479
616
        Debug("diamonds") << "+ C holds" << endl;
480
1232
        Node newEquality = a.eqNode(d);
481
616
        Debug("diamonds") << "  ==> " << newEquality << endl;
482
616
        learned << n.impNode(newEquality);
483
      } else {
484
        Debug("diamonds") << "+ C fails" << endl;
485
      }
486
    }
487
  }
488
489
250915
  if(options::ufSymmetryBreaker()) {
490
31222
    d_symb.assertFormula(n);
491
  }
492
250915
} /* TheoryUF::ppStaticLearn() */
493
494
2491
EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
495
496
  // Check for equality (simplest)
497
2491
  if (d_equalityEngine->areEqual(a, b))
498
  {
499
    // The terms are implied to be equal
500
    return EQUALITY_TRUE;
501
  }
502
503
  // Check for disequality
504
2491
  if (d_equalityEngine->areDisequal(a, b, false))
505
  {
506
    // The terms are implied to be dis-equal
507
    return EQUALITY_FALSE;
508
  }
509
510
  // All other terms we interpret as dis-equal in the model
511
2491
  return EQUALITY_FALSE_IN_MODEL;
512
}
513
514
1295857
bool TheoryUF::areCareDisequal(TNode x, TNode y)
515
{
516
3887571
  if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
517
3887571
      && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
518
  {
519
    TNode x_shared =
520
1236452
        d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
521
    TNode y_shared =
522
1236452
        d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
523
1006333
    EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
524
1006333
    if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
525
776214
      return true;
526
    }
527
  }
528
519643
  return false;
529
}
530
531
426559
void TheoryUF::addCarePairs(const TNodeTrie* t1,
532
                            const TNodeTrie* t2,
533
                            unsigned arity,
534
                            unsigned depth)
535
{
536
  // Note we use d_state instead of d_equalityEngine in this method in several
537
  // places to be robust to cases where the tries have terms that do not
538
  // exist in the equality engine, which can be the case if higher order.
539
426559
  if( depth==arity ){
540
119302
    if( t2!=NULL ){
541
238604
      Node f1 = t1->getData();
542
238604
      Node f2 = t2->getData();
543
119302
      if (!d_state.areEqual(f1, f2))
544
      {
545
110597
        Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
546
221194
        vector< pair<TNode, TNode> > currentPairs;
547
309284
        for (size_t k = 0, nchildren = f1.getNumChildren(); k < nchildren; ++k)
548
        {
549
397374
          TNode x = f1[k];
550
397374
          TNode y = f2[k];
551
198687
          Assert(!d_state.areDisequal(x, y));
552
198687
          Assert(!areCareDisequal(x, y));
553
198687
          if (!d_state.areEqual(x, y))
554
          {
555
356964
            if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
556
356964
                && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
557
            {
558
              TNode x_shared =
559
64592
                  d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
560
              TNode y_shared =
561
64592
                  d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
562
32296
              currentPairs.push_back(make_pair(x_shared, y_shared));
563
            }
564
          }
565
        }
566
142893
        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
567
32296
          Debug("uf::sharing") << "TheoryUf::computeCareGraph(): adding to care-graph" << std::endl;
568
32296
          addCarePair(currentPairs[c].first, currentPairs[c].second);
569
        }
570
      }
571
    }
572
  }else{
573
307257
    if( t2==NULL ){
574
105603
      if( depth<(arity-1) ){
575
        //add care pairs internal to each child
576
131912
        for (const std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
577
        {
578
75869
          addCarePairs(&tt.second, NULL, arity, depth + 1);
579
        }
580
      }
581
      //add care pairs based on each pair of non-disequal arguments
582
454540
      for (std::map<TNode, TNodeTrie>::const_iterator it = t1->d_data.begin();
583
454540
           it != t1->d_data.end();
584
           ++it)
585
      {
586
348937
        std::map<TNode, TNodeTrie>::const_iterator it2 = it;
587
348937
        ++it2;
588
4507109
        for( ; it2 != t1->d_data.end(); ++it2 ){
589
2079086
          if (!d_state.areDisequal(it->first, it2->first))
590
          {
591
786525
            if( !areCareDisequal(it->first, it2->first) ){
592
230208
              addCarePairs( &it->second, &it2->second, arity, depth+1 );
593
            }
594
          }
595
        }
596
      }
597
    }else{
598
      //add care pairs based on product of indices, non-disequal arguments
599
503056
      for (const std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
600
      {
601
624751
        for (const std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
602
        {
603
323349
          if (!d_state.areDisequal(tt1.first, tt2.first))
604
          {
605
310645
            if (!areCareDisequal(tt1.first, tt2.first))
606
            {
607
90748
              addCarePairs(&tt1.second, &tt2.second, arity, depth + 1);
608
            }
609
          }
610
        }
611
      }
612
    }
613
  }
614
426559
}
615
616
30593
void TheoryUF::computeCareGraph() {
617
30593
  if (d_sharedTerms.empty())
618
  {
619
11610
    return;
620
  }
621
18983
  NodeManager* nm = NodeManager::currentNM();
622
  // Use term indexing. We build separate indices for APPLY_UF and HO_APPLY.
623
  // We maintain indices per operator for the former, and indices per
624
  // function type for the latter.
625
37966
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..."
626
18983
                       << std::endl;
627
  // temporary keep set for higher-order indexing below
628
37966
  std::vector<Node> keep;
629
37966
  std::map<Node, TNodeTrie> index;
630
37966
  std::map<TypeNode, TNodeTrie> hoIndex;
631
37966
  std::map<Node, size_t> arity;
632
361100
  for (TNode app : d_functionsTerms)
633
  {
634
684234
    std::vector<TNode> reps;
635
342117
    bool has_trigger_arg = false;
636
830810
    for (const Node& j : app)
637
    {
638
488693
      reps.push_back(d_equalityEngine->getRepresentative(j));
639
488693
      if (d_equalityEngine->isTriggerTerm(j, THEORY_UF))
640
      {
641
417343
        has_trigger_arg = true;
642
      }
643
    }
644
342117
    if (has_trigger_arg)
645
    {
646
301636
      if (app.getKind() == kind::APPLY_UF)
647
      {
648
603188
        Node op = app.getOperator();
649
301594
        index[op].addTerm(app, reps);
650
301594
        arity[op] = reps.size();
651
301594
        if (logicInfo().isHigherOrder() && d_equalityEngine->hasTerm(op))
652
        {
653
          // Since we use a lazy app-completion scheme for equating fully
654
          // and partially applied versions of terms, we must add all
655
          // sub-chains to the HO index if the operator of this term occurs
656
          // in a higher-order context in the equality engine.  In other words,
657
          // for (f a b c), this will add the terms:
658
          // (HO_APPLY f a), (HO_APPLY (HO_APPLY f a) b),
659
          // (HO_APPLY (HO_APPLY (HO_APPLY f a) b) c) to the higher-order
660
          // term index for consideration when computing care pairs.
661
922
          Node curr = op;
662
1211
          for (const Node& c : app)
663
          {
664
1500
            Node happ = nm->mkNode(kind::HO_APPLY, curr, c);
665
750
            hoIndex[curr.getType()].addTerm(happ, {curr, c});
666
750
            curr = happ;
667
750
            keep.push_back(happ);
668
          }
669
        }
670
      }
671
      else
672
      {
673
42
        Assert(app.getKind() == kind::HO_APPLY);
674
        // add it to the hoIndex for the function type
675
42
        hoIndex[app[0].getType()].addTerm(app, reps);
676
      }
677
    }
678
  }
679
  // for each index
680
48443
  for (std::pair<const Node, TNodeTrie>& tt : index)
681
  {
682
58920
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
683
29460
                         << tt.first << "..." << std::endl;
684
29460
    Assert(arity.find(tt.first) != arity.end());
685
29460
    addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
686
  }
687
19257
  for (std::pair<const TypeNode, TNodeTrie>& tt : hoIndex)
688
  {
689
548
    Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process ho index "
690
274
                         << tt.first << "..." << std::endl;
691
    // the arity of HO_APPLY is always two
692
274
    addCarePairs(&tt.second, nullptr, 2, 0);
693
  }
694
37966
  Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished."
695
18983
                       << std::endl;
696
}/* TheoryUF::computeCareGraph() */
697
698
318300
void TheoryUF::eqNotifyNewClass(TNode t) {
699
318300
  if (d_thss != NULL) {
700
51519
    d_thss->newEqClass(t);
701
  }
702
318300
}
703
704
4058720
void TheoryUF::eqNotifyMerge(TNode t1, TNode t2)
705
{
706
4058720
  if (d_thss != NULL) {
707
274247
    d_thss->merge(t1, t2);
708
  }
709
4058720
}
710
711
867897
void TheoryUF::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
712
867897
  if (d_thss != NULL) {
713
20605
    d_thss->assertDisequal(t1, t2, reason);
714
  }
715
867897
}
716
717
88962
bool TheoryUF::isHigherOrderType(TypeNode tn)
718
{
719
88962
  Assert(tn.isFunction());
720
88962
  std::map<TypeNode, bool>::iterator it = d_isHoType.find(tn);
721
88962
  if (it != d_isHoType.end())
722
  {
723
83719
    return it->second;
724
  }
725
5243
  bool ret = false;
726
10486
  const std::vector<TypeNode>& argTypes = tn.getArgTypes();
727
14872
  for (const TypeNode& tnc : argTypes)
728
  {
729
9703
    if (tnc.isFunction())
730
    {
731
74
      ret = true;
732
74
      break;
733
    }
734
  }
735
5243
  d_isHoType[tn] = ret;
736
5243
  return ret;
737
}
738
739
}  // namespace uf
740
}  // namespace theory
741
31125
}  // namespace cvc5