GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model.cpp Lines: 378 431 87.7 %
Date: 2021-08-16 Branches: 788 1851 42.6 %

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