GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model.cpp Lines: 370 424 87.3 %
Date: 2021-11-07 Branches: 764 1815 42.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/cardinality_constraint.h"
18
#include "expr/node_algorithm.h"
19
#include "options/quantifiers_options.h"
20
#include "options/smt_options.h"
21
#include "options/theory_options.h"
22
#include "options/uf_options.h"
23
#include "smt/env.h"
24
#include "smt/solver_engine.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
15273
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
15273
      d_enableFuncModels(enableFuncModels)
41
{
42
  // must use function models when ufHo is enabled
43
15273
  Assert(d_enableFuncModels || !logicInfo().isHigherOrder());
44
15273
  d_true = NodeManager::currentNM()->mkConst( true );
45
15273
  d_false = NodeManager::currentNM()->mkConst( false );
46
15273
}
47
48
30536
TheoryModel::~TheoryModel() {}
49
50
15273
void TheoryModel::finishInit(eq::EqualityEngine* ee)
51
{
52
15273
  Assert(ee != nullptr);
53
15273
  d_equalityEngine = ee;
54
  // The kinds we are treating as function application in congruence
55
30546
  d_equalityEngine->addFunctionKind(
56
15273
      kind::APPLY_UF, false, logicInfo().isHigherOrder());
57
15273
  d_equalityEngine->addFunctionKind(kind::HO_APPLY);
58
15273
  d_equalityEngine->addFunctionKind(kind::SELECT);
59
  // d_equalityEngine->addFunctionKind(kind::STORE);
60
15273
  d_equalityEngine->addFunctionKind(kind::APPLY_CONSTRUCTOR);
61
15273
  d_equalityEngine->addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
62
15273
  d_equalityEngine->addFunctionKind(kind::APPLY_TESTER);
63
  // do not interpret APPLY_UF if we are not assigning function values
64
15273
  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
15273
  setIrrelevantKind(EQUAL);
73
15273
  setIrrelevantKind(NOT);
74
15273
}
75
76
29793
void TheoryModel::reset(){
77
29793
  d_modelCache.clear();
78
29793
  d_sep_heap = Node::null();
79
29793
  d_sep_nil_eq = Node::null();
80
29793
  d_approximations.clear();
81
29793
  d_approx_list.clear();
82
29793
  d_reps.clear();
83
29793
  d_assignExcSet.clear();
84
29793
  d_aesMaster.clear();
85
29793
  d_aesSlaves.clear();
86
29793
  d_rep_set.clear();
87
29793
  d_uf_terms.clear();
88
29793
  d_ho_uf_terms.clear();
89
29793
  d_uf_models.clear();
90
29793
  d_using_model_core = false;
91
29793
  d_model_core.clear();
92
29793
}
93
94
6
void TheoryModel::setHeapModel( Node h, Node neq ) {
95
6
  d_sep_heap = h;
96
6
  d_sep_nil_eq = neq;
97
6
}
98
99
3871
bool TheoryModel::getHeapModel(Node& h, Node& neq) const
100
{
101
3871
  if (d_sep_heap.isNull() || d_sep_nil_eq.isNull())
102
  {
103
3865
    return false;
104
  }
105
6
  h = d_sep_heap;
106
6
  neq = d_sep_nil_eq;
107
6
  return true;
108
}
109
110
12874
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
18
std::vector<Node> TheoryModel::getDomainElements(TypeNode tn) const
118
{
119
  // must be an uninterpreted sort
120
18
  Assert(tn.isSort());
121
36
  std::vector<Node> elements;
122
18
  const std::vector<Node>* type_refs = d_rep_set.getTypeRepsOrNull(tn);
123
18
  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
14
  return *type_refs;
131
}
132
133
311523
Node TheoryModel::getValue(TNode n) const
134
{
135
  //apply substitutions
136
311523
  Node nn = d_env.getTopLevelSubstitutions().apply(n);
137
311523
  Debug("model-getvalue-debug") << "[model-getvalue] getValue : substitute " << n << " to " << nn << std::endl;
138
  //get value in model
139
311523
  nn = getModelValue(nn);
140
311523
  if (nn.isNull())
141
  {
142
    return nn;
143
  }
144
311523
  else if (nn.getKind() == kind::LAMBDA)
145
  {
146
59
    if (options().theory.condenseFunctionValues)
147
    {
148
      // normalize the body. Do not normalize the entire node, which
149
      // involves array normalization.
150
59
      NodeManager* nm = NodeManager::currentNM();
151
59
      nn = nm->mkNode(kind::LAMBDA, nn[0], rewrite(nn[1]));
152
    }
153
  }
154
  else
155
  {
156
    //normalize
157
311464
    nn = rewrite(nn);
158
  }
159
623046
  Debug("model-getvalue") << "[model-getvalue] getValue( " << n << " ): " << std::endl
160
311523
                          << "[model-getvalue] returning " << nn << std::endl;
161
311523
  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
Cardinality TheoryModel::getCardinality(TypeNode tn) const
175
{
176
  //for now, we only handle cardinalities for uninterpreted sorts
177
  if (!tn.isSort())
178
  {
179
    Debug("model-getvalue-debug")
180
        << "Get cardinality other sort, unknown." << std::endl;
181
    return Cardinality( CardinalityUnknown() );
182
  }
183
  if (d_rep_set.hasType(tn))
184
  {
185
    Debug("model-getvalue-debug")
186
        << "Get cardinality sort, #rep : "
187
        << d_rep_set.getNumRepresentatives(tn) << std::endl;
188
    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
1025567
Node TheoryModel::getModelValue(TNode n) const
196
{
197
1025567
  std::unordered_map<Node, Node>::iterator it = d_modelCache.find(n);
198
1025567
  if (it != d_modelCache.end()) {
199
544802
    return (*it).second;
200
  }
201
480765
  Debug("model-getvalue-debug") << "Get model value " << n << " ... ";
202
480765
  Debug("model-getvalue-debug") << d_equalityEngine->hasTerm(n) << std::endl;
203
480765
  Kind nk = n.getKind();
204
480765
  if (n.isConst() || nk == BOUND_VARIABLE)
205
  {
206
34469
    d_modelCache[n] = n;
207
34469
    return n;
208
  }
209
210
892592
  Node ret = n;
211
446296
  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
446296
  if (n.getNumChildren() > 0)
220
  {
221
683486
    Debug("model-getvalue-debug")
222
341743
        << "Get model value children " << n << std::endl;
223
342105
    std::vector<Node> children;
224
341743
    if (n.getKind() == APPLY_UF)
225
    {
226
19570
      Node op = getModelValue(n.getOperator());
227
9785
      Debug("model-getvalue-debug") << "  operator : " << op << std::endl;
228
9785
      children.push_back(op);
229
    }
230
331958
    else if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
231
    {
232
6146
      children.push_back(n.getOperator());
233
    }
234
    // evaluate the children
235
1046690
    for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; ++i)
236
    {
237
704947
      if (n.isClosure() && i==0)
238
      {
239
        // do not evaluate bound variable lists
240
688
        ret = n[0];
241
      }
242
      else
243
      {
244
704259
        ret = getModelValue(n[i]);
245
      }
246
1409894
      Debug("model-getvalue-debug")
247
704947
          << "  " << n << "[" << i << "] is " << ret << std::endl;
248
704947
      children.push_back(ret);
249
    }
250
341743
    ret = nm->mkNode(n.getKind(), children);
251
341743
    Debug("model-getvalue-debug") << "ret (pre-rewrite): " << ret << std::endl;
252
341743
    ret = rewrite(ret);
253
341743
    Debug("model-getvalue-debug") << "ret (post-rewrite): " << ret << std::endl;
254
    // special cases
255
341743
    if (ret.getKind() == kind::CARDINALITY_CONSTRAINT)
256
    {
257
      const CardinalityConstraint& cc =
258
          ret.getOperator().getConst<CardinalityConstraint>();
259
      Debug("model-getvalue-debug")
260
          << "get cardinality constraint " << cc.getType() << std::endl;
261
      ret = nm->mkConst(getCardinality(cc.getType()).getFiniteCardinality()
262
                        <= cc.getUpperBound());
263
    }
264
    // if the value was constant, we return it. If it was non-constant,
265
    // we only return it if we an evaluated kind. This can occur if the
266
    // children of n failed to evaluate.
267
1030376
    if (ret.isConst() || (
268
347252
     d_unevaluated_kinds.find(nk) == d_unevaluated_kinds.end()
269
346890
      && d_semi_evaluated_kinds.find(nk) == d_semi_evaluated_kinds.end()))
270
    {
271
341381
      d_modelCache[n] = ret;
272
341381
      return ret;
273
    }
274
  }
275
  // it might be approximate
276
104915
  std::map<Node, Node>::const_iterator ita = d_approximations.find(n);
277
104915
  if (ita != d_approximations.end())
278
  {
279
    // If the value of n is approximate based on predicate P(n), we return
280
    // witness z. P(z).
281
4
    Node v = nm->mkBoundVar(n.getType());
282
4
    Node bvl = nm->mkNode(BOUND_VAR_LIST, v);
283
4
    Node answer = nm->mkNode(WITNESS, bvl, ita->second.substitute(n, v));
284
2
    d_modelCache[n] = answer;
285
2
    return answer;
286
  }
287
  // must rewrite the term at this point
288
104913
  ret = rewrite(n);
289
  // return the representative of the term in the equality engine, if it exists
290
209826
  TypeNode t = ret.getType();
291
  bool eeHasTerm;
292
104913
  if (!logicInfo().isHigherOrder() && (t.isFunction() || t.isPredicate()))
293
  {
294
    // functions are in the equality engine, but *not* as first-class members
295
    // when higher-order is disabled. In this case, we cannot query
296
    // representatives for functions since they are "internal" nodes according
297
    // to the equality engine despite hasTerm returning true. However, they are
298
    // first class members when higher-order is enabled. Hence, the special
299
    // case here.
300
1130
    eeHasTerm = false;
301
  }
302
  else
303
  {
304
103783
    eeHasTerm = d_equalityEngine->hasTerm(ret);
305
  }
306
104913
  if (eeHasTerm)
307
  {
308
192134
    Debug("model-getvalue-debug")
309
96067
        << "get value from representative " << ret << "..." << std::endl;
310
96067
    ret = d_equalityEngine->getRepresentative(ret);
311
96067
    Assert(d_reps.find(ret) != d_reps.end());
312
96067
    std::map<Node, Node>::const_iterator it2 = d_reps.find(ret);
313
96067
    if (it2 != d_reps.end())
314
    {
315
96067
      ret = it2->second;
316
96067
      d_modelCache[n] = ret;
317
96067
      return ret;
318
    }
319
  }
320
321
  // if we are a evaluated or semi-evaluated kind, return an arbitrary value
322
  // if we are not in the d_unevaluated_kinds map, we are evaluated
323
8846
  if (d_unevaluated_kinds.find(nk) == d_unevaluated_kinds.end())
324
  {
325
8781
    if (t.isFunction() || t.isPredicate())
326
    {
327
1131
      if (d_enableFuncModels)
328
      {
329
1131
        std::map<Node, Node>::const_iterator entry = d_uf_models.find(n);
330
1131
        if (entry != d_uf_models.end())
331
        {
332
          // Existing function
333
1085
          ret = entry->second;
334
1085
          d_modelCache[n] = ret;
335
1085
          return ret;
336
        }
337
        // Unknown function symbol: return LAMBDA x. c, where c is the first
338
        // constant in the enumeration of the range type
339
92
        vector<TypeNode> argTypes = t.getArgTypes();
340
92
        vector<Node> args;
341
125
        for (unsigned i = 0, size = argTypes.size(); i < size; ++i)
342
        {
343
79
          args.push_back(nm->mkBoundVar(argTypes[i]));
344
        }
345
92
        Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args);
346
92
        TypeEnumerator te(t.getRangeType());
347
46
        ret = nm->mkNode(kind::LAMBDA, boundVarList, *te);
348
      }
349
      else
350
      {
351
        // if func models not enabled, throw an error
352
        Unreachable();
353
      }
354
    }
355
7650
    else if (!t.isFirstClass())
356
    {
357
      // this is the class for regular expressions
358
      // we simply invoke the rewriter on them
359
24
      ret = rewrite(ret);
360
    }
361
    else
362
    {
363
      // Unknown term - return first enumerated value for this type
364
15252
      TypeEnumerator te(n.getType());
365
7626
      ret = *te;
366
    }
367
7696
    d_modelCache[n] = ret;
368
7696
    return ret;
369
  }
370
371
65
  d_modelCache[n] = n;
372
65
  return n;
373
}
374
375
/** add term */
376
2034716
void TheoryModel::addTermInternal(TNode n)
377
{
378
2034716
  Assert(d_equalityEngine->hasTerm(n));
379
2034716
  Trace("model-builder-debug2") << "TheoryModel::addTerm : " << n << std::endl;
380
  //must collect UF terms
381
2034716
  if (n.getKind()==APPLY_UF) {
382
106818
    Node op = n.getOperator();
383
53409
    if( std::find( d_uf_terms[ op ].begin(), d_uf_terms[ op ].end(), n )==d_uf_terms[ op ].end() ){
384
53409
      d_uf_terms[ op ].push_back( n );
385
53409
      Trace("model-builder-fun") << "Add apply term " << n << std::endl;
386
    }
387
1981307
  }else if( n.getKind()==HO_APPLY ){
388
2490
    Node op = n[0];
389
1245
    if( std::find( d_ho_uf_terms[ op ].begin(), d_ho_uf_terms[ op ].end(), n )==d_ho_uf_terms[ op ].end() ){
390
1245
      d_ho_uf_terms[ op ].push_back( n );
391
1245
      Trace("model-builder-fun") << "Add ho apply term " << n << std::endl;
392
    }
393
  }
394
  // all functions must be included, marked as higher-order
395
2034716
  if( n.getType().isFunction() ){
396
516
    Trace("model-builder-fun") << "Add function variable (without term) " << n << std::endl;
397
516
    if( d_uf_terms.find( n )==d_uf_terms.end() ){
398
379
      d_uf_terms[n].clear();
399
    }
400
516
    if( d_ho_uf_terms.find( n )==d_ho_uf_terms.end() ){
401
246
      d_ho_uf_terms[n].clear();
402
    }
403
  }
404
2034716
}
405
406
/** assert equality */
407
1200059
bool TheoryModel::assertEquality(TNode a, TNode b, bool polarity)
408
{
409
1200059
  Assert(d_equalityEngine->consistent());
410
1200059
  if (a == b && polarity) {
411
10727
    return true;
412
  }
413
1189332
  Trace("model-builder-assertions") << "(assert " << (polarity ? "(= " : "(not (= ") << a << " " << b << (polarity ? "));" : ")));") << endl;
414
1189332
  d_equalityEngine->assertEquality( a.eqNode(b), polarity, Node::null() );
415
1189332
  return d_equalityEngine->consistent();
416
}
417
418
/** assert predicate */
419
341341
bool TheoryModel::assertPredicate(TNode a, bool polarity)
420
{
421
341341
  Assert(d_equalityEngine->consistent());
422
729334
  if ((a == d_true && polarity) ||
423
341341
      (a == d_false && (!polarity))) {
424
93304
    return true;
425
  }
426
248037
  if (a.getKind() == EQUAL) {
427
    Trace("model-builder-assertions") << "(assert " << (polarity ? " " : "(not ") << a << (polarity ? ");" : "));") << endl;
428
    d_equalityEngine->assertEquality( a, polarity, Node::null() );
429
  } else {
430
248037
    Trace("model-builder-assertions") << "(assert " << (polarity ? "" : "(not ") << a << (polarity ? ");" : "));") << endl;
431
248037
    d_equalityEngine->assertPredicate( a, polarity, Node::null() );
432
  }
433
248037
  return d_equalityEngine->consistent();
434
}
435
436
/** assert equality engine */
437
46652
bool TheoryModel::assertEqualityEngine(const eq::EqualityEngine* ee,
438
                                       const std::set<Node>* termSet)
439
{
440
46652
  Assert(d_equalityEngine->consistent());
441
46652
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
442
5204784
  for (; !eqcs_i.isFinished(); ++eqcs_i) {
443
5158132
    Node eqc = (*eqcs_i);
444
2579066
    bool predicate = false;
445
2579066
    bool predTrue = false;
446
2579066
    bool predFalse = false;
447
2579066
    Trace("model-builder-debug") << "...asserting terms in equivalence class " << eqc;
448
2579066
    if (eqc.getType().isBoolean()) {
449
418015
      predicate = true;
450
418015
      predTrue = ee->areEqual(eqc, d_true);
451
418015
      predFalse = ee->areEqual(eqc, d_false);
452
418015
      Trace("model-builder-debug") << ", pred = " << predTrue << "/" << predFalse;
453
    }
454
2579066
    Trace("model-builder-debug") << std::endl;
455
2579066
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
456
2579066
    bool first = true;
457
5158132
    Node rep;
458
19443256
    for (; !eqc_i.isFinished(); ++eqc_i) {
459
10808309
      Node n = *eqc_i;
460
      // notice that constants are always relevant
461
22920071
      if (termSet != nullptr && termSet->find(n) == termSet->end()
462
14967066
          && !n.isConst())
463
      {
464
12111762
        Trace("model-builder-debug")
465
6055881
            << "...skip node " << n << " in eqc " << eqc << std::endl;
466
6055881
        continue;
467
      }
468
2376214
      if (predicate) {
469
247852
        if (predTrue || predFalse)
470
        {
471
495680
          if (!assertPredicate(n, predTrue))
472
          {
473
            return false;
474
          }
475
        }
476
        else {
477
12
          if (first) {
478
12
            rep = n;
479
12
            first = false;
480
          }
481
          else {
482
            Node eq = (n).eqNode(rep);
483
            Trace("model-builder-assertions")
484
                << "(assert " << eq << ");" << std::endl;
485
            d_equalityEngine->assertEquality(eq, true, Node::null());
486
            if (!d_equalityEngine->consistent())
487
            {
488
              return false;
489
            }
490
          }
491
        }
492
      } else {
493
2128362
        if (first) {
494
1437189
          rep = n;
495
          //add the term (this is specifically for the case of singleton equivalence classes)
496
1437189
          if (rep.getType().isFirstClass())
497
          {
498
1435373
            d_equalityEngine->addTerm( rep );
499
1435373
            Trace("model-builder-debug") << "Add term to ee within assertEqualityEngine: " << rep << std::endl;
500
          }
501
1437189
          first = false;
502
        }
503
        else {
504
691173
          if (!assertEquality(n, rep, true))
505
          {
506
            return false;
507
          }
508
        }
509
      }
510
    }
511
  }
512
46652
  return true;
513
}
514
515
104855
void TheoryModel::assertSkeleton(TNode n)
516
{
517
104855
  Trace("model-builder-reps") << "Assert skeleton : " << n << std::endl;
518
209710
  Trace("model-builder-reps") << "...rep eqc is : " << getRepresentative(n)
519
104855
                              << std::endl;
520
104855
  d_reps[ n ] = n;
521
104855
}
522
523
10
void TheoryModel::setAssignmentExclusionSet(TNode n,
524
                                            const std::vector<Node>& eset)
525
{
526
  // should not be assigned yet
527
10
  Assert(d_assignExcSet.find(n) == d_assignExcSet.end());
528
20
  Trace("model-builder-debug")
529
10
      << "Exclude values of " << n << " : " << eset << std::endl;
530
10
  std::vector<Node>& aes = d_assignExcSet[n];
531
10
  aes.insert(aes.end(), eset.begin(), eset.end());
532
10
}
533
534
10
void TheoryModel::setAssignmentExclusionSetGroup(
535
    const std::vector<TNode>& group, const std::vector<Node>& eset)
536
{
537
10
  if (group.empty())
538
  {
539
    return;
540
  }
541
  // for efficiency, we store a single copy of eset and set a slave/master
542
  // relationship
543
10
  setAssignmentExclusionSet(group[0], eset);
544
10
  std::vector<Node>& gslaves = d_aesSlaves[group[0]];
545
45
  for (unsigned i = 1, gsize = group.size(); i < gsize; ++i)
546
  {
547
70
    Node gs = group[i];
548
    // set master
549
35
    d_aesMaster[gs] = group[0];
550
    // add to slaves
551
35
    gslaves.push_back(gs);
552
  }
553
}
554
555
992191
bool TheoryModel::getAssignmentExclusionSet(TNode n,
556
                                            std::vector<Node>& group,
557
                                            std::vector<Node>& eset)
558
{
559
  // does it have a master?
560
992191
  std::map<Node, Node>::iterator itm = d_aesMaster.find(n);
561
992191
  if (itm != d_aesMaster.end())
562
  {
563
    return getAssignmentExclusionSet(itm->second, group, eset);
564
  }
565
992191
  std::map<Node, std::vector<Node> >::iterator ita = d_assignExcSet.find(n);
566
992191
  if (ita == d_assignExcSet.end())
567
  {
568
992181
    return false;
569
  }
570
10
  eset.insert(eset.end(), ita->second.begin(), ita->second.end());
571
10
  group.push_back(n);
572
  // does it have slaves?
573
10
  ita = d_aesSlaves.find(n);
574
10
  if (ita != d_aesSlaves.end())
575
  {
576
10
    group.insert(group.end(), ita->second.begin(), ita->second.end());
577
  }
578
10
  return true;
579
}
580
581
24989
bool TheoryModel::hasAssignmentExclusionSets() const
582
{
583
24989
  return !d_assignExcSet.empty();
584
}
585
586
30
void TheoryModel::recordApproximation(TNode n, TNode pred)
587
{
588
60
  Trace("model-builder-debug")
589
30
      << "Record approximation : " << n << " satisfies the predicate " << pred
590
30
      << std::endl;
591
30
  Assert(d_approximations.find(n) == d_approximations.end());
592
30
  Assert(pred.getType().isBoolean());
593
30
  d_approximations[n] = pred;
594
30
  d_approx_list.push_back(std::pair<Node, Node>(n, pred));
595
  // model cache is invalid
596
30
  d_modelCache.clear();
597
30
}
598
void TheoryModel::recordApproximation(TNode n, TNode pred, Node witness)
599
{
600
  Node predDisj = NodeManager::currentNM()->mkNode(OR, n.eqNode(witness), pred);
601
  recordApproximation(n, predDisj);
602
}
603
8
bool TheoryModel::isUsingModelCore() const { return d_using_model_core; }
604
2
void TheoryModel::setUsingModelCore()
605
{
606
2
  d_using_model_core = true;
607
2
  d_model_core.clear();
608
2
}
609
610
4
void TheoryModel::recordModelCoreSymbol(Node sym) { d_model_core.insert(sym); }
611
612
171637
void TheoryModel::setUnevaluatedKind(Kind k) { d_unevaluated_kinds.insert(k); }
613
614
30546
void TheoryModel::setSemiEvaluatedKind(Kind k)
615
{
616
30546
  d_semi_evaluated_kinds.insert(k);
617
30546
}
618
619
45819
void TheoryModel::setIrrelevantKind(Kind k) { d_irrKinds.insert(k); }
620
621
17806644
const std::set<Kind>& TheoryModel::getIrrelevantKinds() const
622
{
623
17806644
  return d_irrKinds;
624
}
625
626
11181
bool TheoryModel::isLegalElimination(TNode x, TNode val)
627
{
628
11181
  return !expr::hasSubtermKinds(d_unevaluated_kinds, val);
629
}
630
631
23029
bool TheoryModel::hasTerm(TNode a)
632
{
633
23029
  return d_equalityEngine->hasTerm( a );
634
}
635
636
589894
Node TheoryModel::getRepresentative(TNode a)
637
{
638
589894
  if( d_equalityEngine->hasTerm( a ) ){
639
1119564
    Node r = d_equalityEngine->getRepresentative( a );
640
559782
    if( d_reps.find( r )!=d_reps.end() ){
641
454514
      return d_reps[ r ];
642
    }else{
643
105268
      return r;
644
    }
645
  }else{
646
30112
    return a;
647
  }
648
}
649
650
1207
bool TheoryModel::areEqual(TNode a, TNode b)
651
{
652
1207
  if( a==b ){
653
771
    return true;
654
436
  }else if( d_equalityEngine->hasTerm( a ) && d_equalityEngine->hasTerm( b ) ){
655
436
    return d_equalityEngine->areEqual( a, b );
656
  }else{
657
    return false;
658
  }
659
}
660
661
bool TheoryModel::areDisequal(TNode a, TNode b)
662
{
663
  if( d_equalityEngine->hasTerm( a ) && d_equalityEngine->hasTerm( b ) ){
664
    return d_equalityEngine->areDisequal( a, b, false );
665
  }else{
666
    return false;
667
  }
668
}
669
670
7286
bool TheoryModel::hasUfTerms(Node f) const
671
{
672
7286
  return d_uf_terms.find(f) != d_uf_terms.end();
673
}
674
675
5528
const std::vector<Node>& TheoryModel::getUfTerms(Node f) const
676
{
677
5528
  const auto it = d_uf_terms.find(f);
678
5528
  Assert(it != d_uf_terms.end());
679
5528
  return it->second;
680
}
681
682
27110
bool TheoryModel::areFunctionValuesEnabled() const
683
{
684
27110
  return d_enableFuncModels;
685
}
686
687
12548
void TheoryModel::assignFunctionDefinition( Node f, Node f_def ) {
688
12548
  Trace("model-builder") << "  Assigning function (" << f << ") to (" << f_def << ")" << endl;
689
12548
  Assert(d_uf_models.find(f) == d_uf_models.end());
690
691
12548
  if (logicInfo().isHigherOrder())
692
  {
693
    //we must rewrite the function value since the definition needs to be a constant value
694
388
    f_def = rewrite(f_def);
695
776
    Trace("model-builder-debug")
696
388
        << "Model value (post-rewrite) : " << f_def << std::endl;
697
388
    Assert(f_def.isConst()) << "Non-constant f_def: " << f_def;
698
  }
699
700
  // d_uf_models only stores models for variables
701
12548
  if( f.isVar() ){
702
12401
    d_uf_models[f] = f_def;
703
  }
704
705
12548
  if (logicInfo().isHigherOrder() && d_equalityEngine->hasTerm(f))
706
  {
707
380
    Trace("model-builder-debug") << "  ...function is first-class member of equality engine" << std::endl;
708
    // assign to representative if higher-order
709
760
    Node r = d_equalityEngine->getRepresentative( f );
710
    //always replace the representative, since it is initially assigned to itself
711
380
    Trace("model-builder") << "    Assign: Setting function rep " << r << " to " << f_def << endl;
712
380
    d_reps[r] = f_def;
713
    // also assign to other assignable functions in the same equivalence class
714
380
    eq::EqClassIterator eqc_i = eq::EqClassIterator(r,d_equalityEngine);
715
1412
    while( !eqc_i.isFinished() ) {
716
1032
      Node n = *eqc_i;
717
      // if an unassigned variable function
718
516
      if( n.isVar() && d_uf_terms.find( n )!=d_uf_terms.end() && !hasAssignedFunctionDefinition( n ) ){
719
39
        d_uf_models[n] = f_def;
720
39
        Trace("model-builder") << "  Assigning function (" << n << ") to function definition of " << f << std::endl;
721
      }
722
516
      ++eqc_i;
723
    }
724
380
    Trace("model-builder-debug") << "  ...finished." << std::endl;
725
  }
726
12548
}
727
728
24989
std::vector< Node > TheoryModel::getFunctionsToAssign() {
729
24989
  std::vector< Node > funcs_to_assign;
730
49978
  std::map< Node, Node > func_to_rep;
731
732
  // collect functions
733
35915
  for( std::map< Node, std::vector< Node > >::iterator it = d_uf_terms.begin(); it != d_uf_terms.end(); ++it ){
734
21852
    Node n = it->first;
735
10926
    Assert(!n.isNull());
736
    // should not have been solved for in a substitution
737
10926
    Assert(d_env.getTopLevelSubstitutions().apply(n) == n);
738
10926
    if( !hasAssignedFunctionDefinition( n ) ){
739
5398
      Trace("model-builder-fun-debug") << "Look at function : " << n << std::endl;
740
5398
      if (logicInfo().isHigherOrder())
741
      {
742
        // if in higher-order mode, assign function definitions modulo equality
743
1004
        Node r = getRepresentative( n );
744
502
        std::map< Node, Node >::iterator itf = func_to_rep.find( r );
745
502
        if( itf==func_to_rep.end() ){
746
366
          func_to_rep[r] = n;
747
366
          funcs_to_assign.push_back( n );
748
366
          Trace("model-builder-fun") << "Make function " << n;
749
366
          Trace("model-builder-fun") << " the assignable function in its equivalence class." << std::endl;
750
        }else{
751
          // must combine uf terms
752
136
          Trace("model-builder-fun") << "Copy " << it->second.size() << " uf terms";
753
136
          d_uf_terms[itf->second].insert( d_uf_terms[itf->second].end(), it->second.begin(), it->second.end() );
754
136
          std::map< Node, std::vector< Node > >::iterator ith = d_ho_uf_terms.find( n );
755
136
          if( ith!=d_ho_uf_terms.end() ){
756
136
            d_ho_uf_terms[itf->second].insert( d_ho_uf_terms[itf->second].end(), ith->second.begin(), ith->second.end() );
757
136
            Trace("model-builder-fun") << " and " << ith->second.size() << " ho uf terms";
758
          }
759
136
          Trace("model-builder-fun") << " from " << n << " to its assignable representative function " << itf->second << std::endl;
760
136
          it->second.clear();
761
        }
762
      }else{
763
4896
        Trace("model-builder-fun") << "Function to assign : " << n << std::endl;
764
4896
        funcs_to_assign.push_back( n );
765
      }
766
    }
767
  }
768
769
24989
  Trace("model-builder-fun") << "return " << funcs_to_assign.size() << " functions to assign..." << std::endl;
770
49978
  return funcs_to_assign;
771
}
772
773
15273
const std::string& TheoryModel::getName() const { return d_name; }
774
775
std::string TheoryModel::debugPrintModelEqc() const
776
{
777
  std::stringstream ss;
778
  ss << "--- Equivalence classes:" << std::endl;
779
  ss << d_equalityEngine->debugPrintEqc() << std::endl;
780
  ss << "--- Representative map: " << std::endl;
781
  for (const std::pair<const Node, Node>& r : d_reps)
782
  {
783
    ss << r.first << " -> " << r.second << std::endl;
784
  }
785
  ss << "---" << std::endl;
786
  return ss.str();
787
}
788
789
}  // namespace theory
790
31137
}  // namespace cvc5