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