GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model.cpp Lines: 382 428 89.3 %
Date: 2021-09-07 Branches: 796 1849 43.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Clark Barrett, Morgan Deters
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
 * Implementation of model class.
14
 */
15
#include "theory/theory_model.h"
16
17
#include "expr/node_algorithm.h"
18
#include "options/quantifiers_options.h"
19
#include "options/smt_options.h"
20
#include "options/theory_options.h"
21
#include "options/uf_options.h"
22
#include "smt/env.h"
23
#include "smt/smt_engine.h"
24
#include "theory/rewriter.h"
25
#include "theory/trust_substitutions.h"
26
#include "util/rational.h"
27
28
using namespace std;
29
using namespace cvc5::kind;
30
using namespace cvc5::context;
31
32
namespace cvc5 {
33
namespace theory {
34
35
9926
TheoryModel::TheoryModel(Env& env, std::string name, bool enableFuncModels)
36
    : EnvObj(env),
37
      d_name(name),
38
      d_equalityEngine(nullptr),
39
      d_using_model_core(false),
40
9926
      d_enableFuncModels(enableFuncModels)
41
{
42
  // must use function models when ufHo is enabled
43
9926
  Assert(d_enableFuncModels || !logicInfo().isHigherOrder());
44
9926
  d_true = NodeManager::currentNM()->mkConst( true );
45
9926
  d_false = NodeManager::currentNM()->mkConst( false );
46
9926
}
47
48
19846
TheoryModel::~TheoryModel() {}
49
50
9926
void TheoryModel::finishInit(eq::EqualityEngine* ee)
51
{
52
9926
  Assert(ee != nullptr);
53
9926
  d_equalityEngine = ee;
54
  // The kinds we are treating as function application in congruence
55
19852
  d_equalityEngine->addFunctionKind(
56
9926
      kind::APPLY_UF, false, logicInfo().isHigherOrder());
57
9926
  d_equalityEngine->addFunctionKind(kind::HO_APPLY);
58
9926
  d_equalityEngine->addFunctionKind(kind::SELECT);
59
  // d_equalityEngine->addFunctionKind(kind::STORE);
60
9926
  d_equalityEngine->addFunctionKind(kind::APPLY_CONSTRUCTOR);
61
9926
  d_equalityEngine->addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
62
9926
  d_equalityEngine->addFunctionKind(kind::APPLY_TESTER);
63
  // do not interpret APPLY_UF if we are not assigning function values
64
9926
  if (!d_enableFuncModels)
65
  {
66
    setSemiEvaluatedKind(kind::APPLY_UF);
67
  }
68
  // Equal and not terms are not relevant terms. In other words, asserted
69
  // equalities and negations of predicates (as terms) do not need to be sent
70
  // to the model. Regardless, theories should send information to the model
71
  // that ensures that all assertions are satisfied.
72
9926
  setIrrelevantKind(EQUAL);
73
9926
  setIrrelevantKind(NOT);
74
9926
}
75
76
21271
void TheoryModel::reset(){
77
21271
  d_modelCache.clear();
78
21271
  d_sep_heap = Node::null();
79
21271
  d_sep_nil_eq = Node::null();
80
21271
  d_approximations.clear();
81
21271
  d_approx_list.clear();
82
21271
  d_reps.clear();
83
21271
  d_assignExcSet.clear();
84
21271
  d_aesMaster.clear();
85
21271
  d_aesSlaves.clear();
86
21271
  d_rep_set.clear();
87
21271
  d_uf_terms.clear();
88
21271
  d_ho_uf_terms.clear();
89
21271
  d_uf_models.clear();
90
21271
  d_using_model_core = false;
91
21271
  d_model_core.clear();
92
21271
}
93
94
7
void TheoryModel::setHeapModel( Node h, Node neq ) {
95
7
  d_sep_heap = h;
96
7
  d_sep_nil_eq = neq;
97
7
}
98
99
10
bool TheoryModel::getHeapModel(Node& h, Node& neq) const
100
{
101
10
  if (d_sep_heap.isNull() || d_sep_nil_eq.isNull())
102
  {
103
4
    return false;
104
  }
105
6
  h = d_sep_heap;
106
6
  neq = d_sep_nil_eq;
107
6
  return true;
108
}
109
110
5374
bool TheoryModel::hasApproximations() const { return !d_approx_list.empty(); }
111
112
std::vector<std::pair<Node, Node> > TheoryModel::getApproximations() const
113
{
114
  return d_approx_list;
115
}
116
117
14
std::vector<Node> TheoryModel::getDomainElements(TypeNode tn) const
118
{
119
  // must be an uninterpreted sort
120
14
  Assert(tn.isSort());
121
28
  std::vector<Node> elements;
122
14
  const std::vector<Node>* type_refs = d_rep_set.getTypeRepsOrNull(tn);
123
14
  if (type_refs == nullptr || type_refs->empty())
124
  {
125
    // This is called when t is a sort that does not occur in this model.
126
    // Sorts are always interpreted as non-empty, thus we add a single element.
127
4
    elements.push_back(tn.mkGroundTerm());
128
4
    return elements;
129
  }
130
10
  return *type_refs;
131
}
132
133
293488
Node TheoryModel::getValue(TNode n) const
134
{
135
  //apply substitutions
136
293488
  Node nn = d_env.getTopLevelSubstitutions().apply(n);
137
293488
  Debug("model-getvalue-debug") << "[model-getvalue] getValue : substitute " << n << " to " << nn << std::endl;
138
  //get value in model
139
293488
  nn = getModelValue(nn);
140
293488
  if (nn.isNull())
141
  {
142
    return nn;
143
  }
144
293488
  else if (nn.getKind() == kind::LAMBDA)
145
  {
146
51
    if (options::condenseFunctionValues())
147
    {
148
      // normalize the body. Do not normalize the entire node, which
149
      // involves array normalization.
150
51
      NodeManager* nm = NodeManager::currentNM();
151
51
      nn = nm->mkNode(kind::LAMBDA, nn[0], Rewriter::rewrite(nn[1]));
152
    }
153
  }
154
  else
155
  {
156
    //normalize
157
293437
    nn = Rewriter::rewrite(nn);
158
  }
159
586976
  Debug("model-getvalue") << "[model-getvalue] getValue( " << n << " ): " << std::endl
160
293488
                          << "[model-getvalue] returning " << nn << std::endl;
161
293488
  return nn;
162
}
163
164
6
bool TheoryModel::isModelCoreSymbol(Node s) const
165
{
166
6
  if (!d_using_model_core)
167
  {
168
    return true;
169
  }
170
6
  Assert(s.isVar() && s.getKind() != BOUND_VARIABLE);
171
6
  return d_model_core.find(s) != d_model_core.end();
172
}
173
174
159
Cardinality TheoryModel::getCardinality(TypeNode tn) const
175
{
176
  //for now, we only handle cardinalities for uninterpreted sorts
177
159
  if (!tn.isSort())
178
  {
179
    Debug("model-getvalue-debug")
180
        << "Get cardinality other sort, unknown." << std::endl;
181
    return Cardinality( CardinalityUnknown() );
182
  }
183
159
  if (d_rep_set.hasType(tn))
184
  {
185
318
    Debug("model-getvalue-debug")
186
159
        << "Get cardinality sort, #rep : "
187
159
        << d_rep_set.getNumRepresentatives(tn) << std::endl;
188
159
    return Cardinality(d_rep_set.getNumRepresentatives(tn));
189
  }
190
  Debug("model-getvalue-debug")
191
      << "Get cardinality sort, unconstrained, return 1." << std::endl;
192
  return Cardinality(1);
193
}
194
195
1408192
Node TheoryModel::getModelValue(TNode n) const
196
{
197
1408192
  std::unordered_map<Node, Node>::iterator it = d_modelCache.find(n);
198
1408192
  if (it != d_modelCache.end()) {
199
804208
    return (*it).second;
200
  }
201
603984
  Debug("model-getvalue-debug") << "Get model value " << n << " ... ";
202
603984
  Debug("model-getvalue-debug") << d_equalityEngine->hasTerm(n) << std::endl;
203
603984
  Kind nk = n.getKind();
204
603984
  if (n.isConst() || nk == BOUND_VARIABLE)
205
  {
206
32631
    d_modelCache[n] = n;
207
32631
    return n;
208
  }
209
210
1142706
  Node ret = n;
211
571353
  NodeManager* nm = NodeManager::currentNM();
212
213
  // If it has children, evaluate them. We do this even if n is an unevaluatable
214
  // or semi-unevaluatable operator. Notice this includes quantified
215
  // formulas. It may not be possible in general to evaluate bodies of
216
  // quantified formulas, because they have free variables. Regardless, we
217
  // may often be able to evaluate the body of a quantified formula to true,
218
  // e.g. forall x. P(x) where P = lambda x. true.
219
571353
  if (n.getNumChildren() > 0)
220
  {
221
909284
    Debug("model-getvalue-debug")
222
454642
        << "Get model value children " << n << std::endl;
223
455111
    std::vector<Node> children;
224
454642
    if (n.getKind() == APPLY_UF)
225
    {
226
19448
      Node op = getModelValue(n.getOperator());
227
9724
      Debug("model-getvalue-debug") << "  operator : " << op << std::endl;
228
9724
      children.push_back(op);
229
    }
230
444918
    else if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
231
    {
232
5680
      children.push_back(n.getOperator());
233
    }
234
    // evaluate the children
235
1560297
    for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; ++i)
236
    {
237
1105655
      if (n.isClosure() && i==0)
238
      {
239
        // do not evaluate bound variable lists
240
675
        ret = n[0];
241
      }
242
      else
243
      {
244
1104980
        ret = getModelValue(n[i]);
245
      }
246
2211310
      Debug("model-getvalue-debug")
247
1105655
          << "  " << n << "[" << i << "] is " << ret << std::endl;
248
1105655
      children.push_back(ret);
249
    }
250
454642
    ret = nm->mkNode(n.getKind(), children);
251
454642
    Debug("model-getvalue-debug") << "ret (pre-rewrite): " << ret << std::endl;
252
454642
    ret = Rewriter::rewrite(ret);
253
454642
    Debug("model-getvalue-debug") << "ret (post-rewrite): " << ret << std::endl;
254
    // special cases
255
454642
    if (ret.getKind() == kind::CARDINALITY_CONSTRAINT)
256
    {
257
318
      Debug("model-getvalue-debug")
258
159
          << "get cardinality constraint " << ret[0].getType() << std::endl;
259
477
      ret = nm->mkConst(getCardinality(ret[0].getType()).getFiniteCardinality()
260
636
                        <= ret[1].getConst<Rational>().getNumerator());
261
    }
262
454483
    else if (ret.getKind() == kind::CARDINALITY_VALUE)
263
    {
264
      Debug("model-getvalue-debug")
265
          << "get cardinality value " << ret[0].getType() << std::endl;
266
      ret = nm->mkConst(
267
          Rational(getCardinality(ret[0].getType()).getFiniteCardinality()));
268
    }
269
    // if the value was constant, we return it. If it was non-constant,
270
    // we only return it if we an evaluated kind. This can occur if the
271
    // children of n failed to evaluate.
272
1368996
    if (ret.isConst() || (
273
460181
     d_unevaluated_kinds.find(nk) == d_unevaluated_kinds.end()
274
459712
      && d_semi_evaluated_kinds.find(nk) == d_semi_evaluated_kinds.end()))
275
    {
276
454173
      d_modelCache[n] = ret;
277
454173
      return ret;
278
    }
279
  }
280
  // it might be approximate
281
117180
  std::map<Node, Node>::const_iterator ita = d_approximations.find(n);
282
117180
  if (ita != d_approximations.end())
283
  {
284
    // If the value of n is approximate based on predicate P(n), we return
285
    // witness z. P(z).
286
4
    Node v = nm->mkBoundVar(n.getType());
287
4
    Node bvl = nm->mkNode(BOUND_VAR_LIST, v);
288
4
    Node answer = nm->mkNode(WITNESS, bvl, ita->second.substitute(n, v));
289
2
    d_modelCache[n] = answer;
290
2
    return answer;
291
  }
292
  // must rewrite the term at this point
293
117178
  ret = Rewriter::rewrite(n);
294
  // return the representative of the term in the equality engine, if it exists
295
234356
  TypeNode t = ret.getType();
296
  bool eeHasTerm;
297
117178
  if (!logicInfo().isHigherOrder() && (t.isFunction() || t.isPredicate()))
298
  {
299
    // functions are in the equality engine, but *not* as first-class members
300
    // when higher-order is disabled. In this case, we cannot query
301
    // representatives for functions since they are "internal" nodes according
302
    // to the equality engine despite hasTerm returning true. However, they are
303
    // first class members when higher-order is enabled. Hence, the special
304
    // case here.
305
1131
    eeHasTerm = false;
306
  }
307
  else
308
  {
309
116047
    eeHasTerm = d_equalityEngine->hasTerm(ret);
310
  }
311
117178
  if (eeHasTerm)
312
  {
313
217474
    Debug("model-getvalue-debug")
314
108737
        << "get value from representative " << ret << "..." << std::endl;
315
108737
    ret = d_equalityEngine->getRepresentative(ret);
316
108737
    Assert(d_reps.find(ret) != d_reps.end());
317
108737
    std::map<Node, Node>::const_iterator it2 = d_reps.find(ret);
318
108737
    if (it2 != d_reps.end())
319
    {
320
108737
      ret = it2->second;
321
108737
      d_modelCache[n] = ret;
322
108737
      return ret;
323
    }
324
  }
325
326
  // if we are a evaluated or semi-evaluated kind, return an arbitrary value
327
  // if we are not in the d_unevaluated_kinds map, we are evaluated
328
8441
  if (d_unevaluated_kinds.find(nk) == d_unevaluated_kinds.end())
329
  {
330
8378
    if (t.isFunction() || t.isPredicate())
331
    {
332
1131
      if (d_enableFuncModels)
333
      {
334
1131
        std::map<Node, Node>::const_iterator entry = d_uf_models.find(n);
335
1131
        if (entry != d_uf_models.end())
336
        {
337
          // Existing function
338
1086
          ret = entry->second;
339
1086
          d_modelCache[n] = ret;
340
1086
          return ret;
341
        }
342
        // Unknown function symbol: return LAMBDA x. c, where c is the first
343
        // constant in the enumeration of the range type
344
90
        vector<TypeNode> argTypes = t.getArgTypes();
345
90
        vector<Node> args;
346
123
        for (unsigned i = 0, size = argTypes.size(); i < size; ++i)
347
        {
348
78
          args.push_back(nm->mkBoundVar(argTypes[i]));
349
        }
350
90
        Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args);
351
90
        TypeEnumerator te(t.getRangeType());
352
45
        ret = nm->mkNode(kind::LAMBDA, boundVarList, *te);
353
      }
354
      else
355
      {
356
        // if func models not enabled, throw an error
357
        Unreachable();
358
      }
359
    }
360
7247
    else if (!t.isFirstClass())
361
    {
362
      // this is the class for regular expressions
363
      // we simply invoke the rewriter on them
364
23
      ret = Rewriter::rewrite(ret);
365
    }
366
    else
367
    {
368
      // Unknown term - return first enumerated value for this type
369
14448
      TypeEnumerator te(n.getType());
370
7224
      ret = *te;
371
    }
372
7292
    d_modelCache[n] = ret;
373
7292
    return ret;
374
  }
375
376
63
  d_modelCache[n] = n;
377
63
  return n;
378
}
379
380
/** add term */
381
1303967
void TheoryModel::addTermInternal(TNode n)
382
{
383
1303967
  Assert(d_equalityEngine->hasTerm(n));
384
1303967
  Trace("model-builder-debug2") << "TheoryModel::addTerm : " << n << std::endl;
385
  //must collect UF terms
386
1303967
  if (n.getKind()==APPLY_UF) {
387
108078
    Node op = n.getOperator();
388
54039
    if( std::find( d_uf_terms[ op ].begin(), d_uf_terms[ op ].end(), n )==d_uf_terms[ op ].end() ){
389
54039
      d_uf_terms[ op ].push_back( n );
390
54039
      Trace("model-builder-fun") << "Add apply term " << n << std::endl;
391
    }
392
1249928
  }else if( n.getKind()==HO_APPLY ){
393
5052
    Node op = n[0];
394
2526
    if( std::find( d_ho_uf_terms[ op ].begin(), d_ho_uf_terms[ op ].end(), n )==d_ho_uf_terms[ op ].end() ){
395
2526
      d_ho_uf_terms[ op ].push_back( n );
396
2526
      Trace("model-builder-fun") << "Add ho apply term " << n << std::endl;
397
    }
398
  }
399
  // all functions must be included, marked as higher-order
400
1303967
  if( n.getType().isFunction() ){
401
1386
    Trace("model-builder-fun") << "Add function variable (without term) " << n << std::endl;
402
1386
    if( d_uf_terms.find( n )==d_uf_terms.end() ){
403
1267
      d_uf_terms[n].clear();
404
    }
405
1386
    if( d_ho_uf_terms.find( n )==d_ho_uf_terms.end() ){
406
1143
      d_ho_uf_terms[n].clear();
407
    }
408
  }
409
1303967
}
410
411
/** assert equality */
412
659825
bool TheoryModel::assertEquality(TNode a, TNode b, bool polarity)
413
{
414
659825
  Assert(d_equalityEngine->consistent());
415
659825
  if (a == b && polarity) {
416
923
    return true;
417
  }
418
658902
  Trace("model-builder-assertions") << "(assert " << (polarity ? "(= " : "(not (= ") << a << " " << b << (polarity ? "));" : ")));") << endl;
419
658902
  d_equalityEngine->assertEquality( a.eqNode(b), polarity, Node::null() );
420
658902
  return d_equalityEngine->consistent();
421
}
422
423
/** assert predicate */
424
263165
bool TheoryModel::assertPredicate(TNode a, bool polarity)
425
{
426
263165
  Assert(d_equalityEngine->consistent());
427
554993
  if ((a == d_true && polarity) ||
428
263165
      (a == d_false && (!polarity))) {
429
57326
    return true;
430
  }
431
205839
  if (a.getKind() == EQUAL) {
432
    Trace("model-builder-assertions") << "(assert " << (polarity ? " " : "(not ") << a << (polarity ? ");" : "));") << endl;
433
    d_equalityEngine->assertEquality( a, polarity, Node::null() );
434
  } else {
435
205839
    Trace("model-builder-assertions") << "(assert " << (polarity ? "" : "(not ") << a << (polarity ? ");" : "));") << endl;
436
205839
    d_equalityEngine->assertPredicate( a, polarity, Node::null() );
437
  }
438
205839
  return d_equalityEngine->consistent();
439
}
440
441
/** assert equality engine */
442
28663
bool TheoryModel::assertEqualityEngine(const eq::EqualityEngine* ee,
443
                                       const std::set<Node>* termSet)
444
{
445
28663
  Assert(d_equalityEngine->consistent());
446
28663
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
447
2940001
  for (; !eqcs_i.isFinished(); ++eqcs_i) {
448
2911338
    Node eqc = (*eqcs_i);
449
1455669
    bool predicate = false;
450
1455669
    bool predTrue = false;
451
1455669
    bool predFalse = false;
452
1455669
    Trace("model-builder-debug") << "...asserting terms in equivalence class " << eqc;
453
1455669
    if (eqc.getType().isBoolean()) {
454
184335
      predicate = true;
455
184335
      predTrue = ee->areEqual(eqc, d_true);
456
184335
      predFalse = ee->areEqual(eqc, d_false);
457
184335
      Trace("model-builder-debug") << ", pred = " << predTrue << "/" << predFalse;
458
    }
459
1455669
    Trace("model-builder-debug") << std::endl;
460
1455669
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
461
1455669
    bool first = true;
462
2911338
    Node rep;
463
9916895
    for (; !eqc_i.isFinished(); ++eqc_i) {
464
5647871
      Node n = *eqc_i;
465
      // notice that constants are always relevant
466
11274581
      if (termSet != nullptr && termSet->find(n) == termSet->end()
467
7349146
          && !n.isConst())
468
      {
469
5626710
        Trace("model-builder-debug")
470
2813355
            << "...skip node " << n << " in eqc " << eqc << std::endl;
471
2813355
        continue;
472
      }
473
1417258
      if (predicate) {
474
162874
        if (predTrue || predFalse)
475
        {
476
325716
          if (!assertPredicate(n, predTrue))
477
          {
478
            return false;
479
          }
480
        }
481
        else {
482
16
          if (first) {
483
16
            rep = n;
484
16
            first = false;
485
          }
486
          else {
487
            Node eq = (n).eqNode(rep);
488
            Trace("model-builder-assertions")
489
                << "(assert " << eq << ");" << std::endl;
490
            d_equalityEngine->assertEquality(eq, true, Node::null());
491
            if (!d_equalityEngine->consistent())
492
            {
493
              return false;
494
            }
495
          }
496
        }
497
      } else {
498
1254384
        if (first) {
499
881282
          rep = n;
500
          //add the term (this is specifically for the case of singleton equivalence classes)
501
881282
          if (rep.getType().isFirstClass())
502
          {
503
879502
            d_equalityEngine->addTerm( rep );
504
879502
            Trace("model-builder-debug") << "Add term to ee within assertEqualityEngine: " << rep << std::endl;
505
          }
506
881282
          first = false;
507
        }
508
        else {
509
373102
          if (!assertEquality(n, rep, true))
510
          {
511
            return false;
512
          }
513
        }
514
      }
515
    }
516
  }
517
28663
  return true;
518
}
519
520
45633
void TheoryModel::assertSkeleton(TNode n)
521
{
522
45633
  Trace("model-builder-reps") << "Assert skeleton : " << n << std::endl;
523
91266
  Trace("model-builder-reps") << "...rep eqc is : " << getRepresentative(n)
524
45633
                              << std::endl;
525
45633
  d_reps[ n ] = n;
526
45633
}
527
528
10
void TheoryModel::setAssignmentExclusionSet(TNode n,
529
                                            const std::vector<Node>& eset)
530
{
531
  // should not be assigned yet
532
10
  Assert(d_assignExcSet.find(n) == d_assignExcSet.end());
533
20
  Trace("model-builder-debug")
534
10
      << "Exclude values of " << n << " : " << eset << std::endl;
535
10
  std::vector<Node>& aes = d_assignExcSet[n];
536
10
  aes.insert(aes.end(), eset.begin(), eset.end());
537
10
}
538
539
10
void TheoryModel::setAssignmentExclusionSetGroup(
540
    const std::vector<TNode>& group, const std::vector<Node>& eset)
541
{
542
10
  if (group.empty())
543
  {
544
    return;
545
  }
546
  // for efficiency, we store a single copy of eset and set a slave/master
547
  // relationship
548
10
  setAssignmentExclusionSet(group[0], eset);
549
10
  std::vector<Node>& gslaves = d_aesSlaves[group[0]];
550
45
  for (unsigned i = 1, gsize = group.size(); i < gsize; ++i)
551
  {
552
70
    Node gs = group[i];
553
    // set master
554
35
    d_aesMaster[gs] = group[0];
555
    // add to slaves
556
35
    gslaves.push_back(gs);
557
  }
558
}
559
560
585268
bool TheoryModel::getAssignmentExclusionSet(TNode n,
561
                                            std::vector<Node>& group,
562
                                            std::vector<Node>& eset)
563
{
564
  // does it have a master?
565
585268
  std::map<Node, Node>::iterator itm = d_aesMaster.find(n);
566
585268
  if (itm != d_aesMaster.end())
567
  {
568
    return getAssignmentExclusionSet(itm->second, group, eset);
569
  }
570
585268
  std::map<Node, std::vector<Node> >::iterator ita = d_assignExcSet.find(n);
571
585268
  if (ita == d_assignExcSet.end())
572
  {
573
585258
    return false;
574
  }
575
10
  eset.insert(eset.end(), ita->second.begin(), ita->second.end());
576
10
  group.push_back(n);
577
  // does it have slaves?
578
10
  ita = d_aesSlaves.find(n);
579
10
  if (ita != d_aesSlaves.end())
580
  {
581
10
    group.insert(group.end(), ita->second.begin(), ita->second.end());
582
  }
583
10
  return true;
584
}
585
586
16684
bool TheoryModel::hasAssignmentExclusionSets() const
587
{
588
16684
  return !d_assignExcSet.empty();
589
}
590
591
29
void TheoryModel::recordApproximation(TNode n, TNode pred)
592
{
593
58
  Trace("model-builder-debug")
594
29
      << "Record approximation : " << n << " satisfies the predicate " << pred
595
29
      << std::endl;
596
29
  Assert(d_approximations.find(n) == d_approximations.end());
597
29
  Assert(pred.getType().isBoolean());
598
29
  d_approximations[n] = pred;
599
29
  d_approx_list.push_back(std::pair<Node, Node>(n, pred));
600
  // model cache is invalid
601
29
  d_modelCache.clear();
602
29
}
603
void TheoryModel::recordApproximation(TNode n, TNode pred, Node witness)
604
{
605
  Node predDisj = NodeManager::currentNM()->mkNode(OR, n.eqNode(witness), pred);
606
  recordApproximation(n, predDisj);
607
}
608
8
bool TheoryModel::isUsingModelCore() const { return d_using_model_core; }
609
2
void TheoryModel::setUsingModelCore()
610
{
611
2
  d_using_model_core = true;
612
2
  d_model_core.clear();
613
2
}
614
615
4
void TheoryModel::recordModelCoreSymbol(Node sym) { d_model_core.insert(sym); }
616
617
106342
void TheoryModel::setUnevaluatedKind(Kind k) { d_unevaluated_kinds.insert(k); }
618
619
19852
void TheoryModel::setSemiEvaluatedKind(Kind k)
620
{
621
19852
  d_semi_evaluated_kinds.insert(k);
622
19852
}
623
624
29778
void TheoryModel::setIrrelevantKind(Kind k) { d_irrKinds.insert(k); }
625
626
6956965
const std::set<Kind>& TheoryModel::getIrrelevantKinds() const
627
{
628
6956965
  return d_irrKinds;
629
}
630
631
10132
bool TheoryModel::isLegalElimination(TNode x, TNode val)
632
{
633
10132
  return !expr::hasSubtermKinds(d_unevaluated_kinds, val);
634
}
635
636
22436
bool TheoryModel::hasTerm(TNode a)
637
{
638
22436
  return d_equalityEngine->hasTerm( a );
639
}
640
641
521370
Node TheoryModel::getRepresentative(TNode a)
642
{
643
521370
  if( d_equalityEngine->hasTerm( a ) ){
644
985004
    Node r = d_equalityEngine->getRepresentative( a );
645
492502
    if( d_reps.find( r )!=d_reps.end() ){
646
446466
      return d_reps[ r ];
647
    }else{
648
46036
      return r;
649
    }
650
  }else{
651
28868
    return a;
652
  }
653
}
654
655
2526
bool TheoryModel::areEqual(TNode a, TNode b)
656
{
657
2526
  if( a==b ){
658
2105
    return true;
659
421
  }else if( d_equalityEngine->hasTerm( a ) && d_equalityEngine->hasTerm( b ) ){
660
421
    return d_equalityEngine->areEqual( a, b );
661
  }else{
662
    return false;
663
  }
664
}
665
666
bool TheoryModel::areDisequal(TNode a, TNode b)
667
{
668
  if( d_equalityEngine->hasTerm( a ) && d_equalityEngine->hasTerm( b ) ){
669
    return d_equalityEngine->areDisequal( a, b, false );
670
  }else{
671
    return false;
672
  }
673
}
674
675
7221
bool TheoryModel::hasUfTerms(Node f) const
676
{
677
7221
  return d_uf_terms.find(f) != d_uf_terms.end();
678
}
679
680
5443
const std::vector<Node>& TheoryModel::getUfTerms(Node f) const
681
{
682
5443
  const auto it = d_uf_terms.find(f);
683
5443
  Assert(it != d_uf_terms.end());
684
5443
  return it->second;
685
}
686
687
18730
bool TheoryModel::areFunctionValuesEnabled() const
688
{
689
18730
  return d_enableFuncModels;
690
}
691
692
12767
void TheoryModel::assignFunctionDefinition( Node f, Node f_def ) {
693
12767
  Trace("model-builder") << "  Assigning function (" << f << ") to (" << f_def << ")" << endl;
694
12767
  Assert(d_uf_models.find(f) == d_uf_models.end());
695
696
12767
  if (logicInfo().isHigherOrder())
697
  {
698
    //we must rewrite the function value since the definition needs to be a constant value
699
1040
    f_def = Rewriter::rewrite( f_def );
700
2080
    Trace("model-builder-debug")
701
1040
        << "Model value (post-rewrite) : " << f_def << std::endl;
702
1040
    Assert(f_def.isConst()) << "Non-constant f_def: " << f_def;
703
  }
704
705
  // d_uf_models only stores models for variables
706
12767
  if( f.isVar() ){
707
12638
    d_uf_models[f] = f_def;
708
  }
709
710
12767
  if (logicInfo().isHigherOrder() && d_equalityEngine->hasTerm(f))
711
  {
712
1036
    Trace("model-builder-debug") << "  ...function is first-class member of equality engine" << std::endl;
713
    // assign to representative if higher-order
714
2072
    Node r = d_equalityEngine->getRepresentative( f );
715
    //always replace the representative, since it is initially assigned to itself
716
1036
    Trace("model-builder") << "    Assign: Setting function rep " << r << " to " << f_def << endl;
717
1036
    d_reps[r] = f_def;
718
    // also assign to other assignable functions in the same equivalence class
719
1036
    eq::EqClassIterator eqc_i = eq::EqClassIterator(r,d_equalityEngine);
720
3808
    while( !eqc_i.isFinished() ) {
721
2772
      Node n = *eqc_i;
722
      // if an unassigned variable function
723
1386
      if( n.isVar() && d_uf_terms.find( n )!=d_uf_terms.end() && !hasAssignedFunctionDefinition( n ) ){
724
259
        d_uf_models[n] = f_def;
725
259
        Trace("model-builder") << "  Assigning function (" << n << ") to function definition of " << f << std::endl;
726
      }
727
1386
      ++eqc_i;
728
    }
729
1036
    Trace("model-builder-debug") << "  ...finished." << std::endl;
730
  }
731
12767
}
732
733
16684
std::vector< Node > TheoryModel::getFunctionsToAssign() {
734
16684
  std::vector< Node > funcs_to_assign;
735
33368
  std::map< Node, Node > func_to_rep;
736
737
  // collect functions
738
28023
  for( std::map< Node, std::vector< Node > >::iterator it = d_uf_terms.begin(); it != d_uf_terms.end(); ++it ){
739
22678
    Node n = it->first;
740
11339
    Assert(!n.isNull());
741
    // should not have been solved for in a substitution
742
11339
    Assert(d_env.getTopLevelSubstitutions().apply(n) == n);
743
11339
    if( !hasAssignedFunctionDefinition( n ) ){
744
5896
      Trace("model-builder-fun-debug") << "Look at function : " << n << std::endl;
745
5896
      if (logicInfo().isHigherOrder())
746
      {
747
        // if in higher-order mode, assign function definitions modulo equality
748
2772
        Node r = getRepresentative( n );
749
1386
        std::map< Node, Node >::iterator itf = func_to_rep.find( r );
750
1386
        if( itf==func_to_rep.end() ){
751
1036
          func_to_rep[r] = n;
752
1036
          funcs_to_assign.push_back( n );
753
1036
          Trace("model-builder-fun") << "Make function " << n;
754
1036
          Trace("model-builder-fun") << " the assignable function in its equivalence class." << std::endl;
755
        }else{
756
          // must combine uf terms
757
350
          Trace("model-builder-fun") << "Copy " << it->second.size() << " uf terms";
758
350
          d_uf_terms[itf->second].insert( d_uf_terms[itf->second].end(), it->second.begin(), it->second.end() );
759
350
          std::map< Node, std::vector< Node > >::iterator ith = d_ho_uf_terms.find( n );
760
350
          if( ith!=d_ho_uf_terms.end() ){
761
350
            d_ho_uf_terms[itf->second].insert( d_ho_uf_terms[itf->second].end(), ith->second.begin(), ith->second.end() );
762
350
            Trace("model-builder-fun") << " and " << ith->second.size() << " ho uf terms";
763
          }
764
350
          Trace("model-builder-fun") << " from " << n << " to its assignable representative function " << itf->second << std::endl;
765
350
          it->second.clear();
766
        }
767
      }else{
768
4510
        Trace("model-builder-fun") << "Function to assign : " << n << std::endl;
769
4510
        funcs_to_assign.push_back( n );
770
      }
771
    }
772
  }
773
774
16684
  Trace("model-builder-fun") << "return " << funcs_to_assign.size() << " functions to assign..." << std::endl;
775
33368
  return funcs_to_assign;
776
}
777
778
9926
const std::string& TheoryModel::getName() const { return d_name; }
779
780
std::string TheoryModel::debugPrintModelEqc() const
781
{
782
  std::stringstream ss;
783
  ss << "--- Equivalence classes:" << std::endl;
784
  ss << d_equalityEngine->debugPrintEqc() << std::endl;
785
  ss << "--- Representative map: " << std::endl;
786
  for (const std::pair<const Node, Node>& r : d_reps)
787
  {
788
    ss << r.first << " -> " << r.second << std::endl;
789
  }
790
  ss << "---" << std::endl;
791
  return ss.str();
792
}
793
794
}  // namespace theory
795
29502
}  // namespace cvc5