GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model.cpp Lines: 376 427 88.1 %
Date: 2021-05-22 Branches: 784 1853 42.3 %

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