GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model_builder.cpp Lines: 623 668 93.3 %
Date: 2021-11-07 Branches: 1203 2851 42.2 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Clark Barrett, Andres Noetzli
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 theory model buidler class.
14
 */
15
#include "theory/theory_model_builder.h"
16
17
#include "expr/dtype.h"
18
#include "expr/dtype_cons.h"
19
#include "expr/uninterpreted_constant.h"
20
#include "options/quantifiers_options.h"
21
#include "options/smt_options.h"
22
#include "options/strings_options.h"
23
#include "options/theory_options.h"
24
#include "options/uf_options.h"
25
#include "smt/env.h"
26
#include "theory/rewriter.h"
27
#include "theory/uf/theory_uf_model.h"
28
29
using namespace std;
30
using namespace cvc5::kind;
31
using namespace cvc5::context;
32
33
namespace cvc5 {
34
namespace theory {
35
36
18396
TheoryEngineModelBuilder::TheoryEngineModelBuilder(Env& env) : EnvObj(env) {}
37
38
10
void TheoryEngineModelBuilder::Assigner::initialize(
39
    TypeNode tn, TypeEnumeratorProperties* tep, const std::vector<Node>& aes)
40
{
41
10
  d_te.reset(new TypeEnumerator(tn, tep));
42
10
  d_assignExcSet.insert(d_assignExcSet.end(), aes.begin(), aes.end());
43
10
}
44
45
45
Node TheoryEngineModelBuilder::Assigner::getNextAssignment()
46
{
47
45
  Assert(d_te != nullptr);
48
90
  Node n;
49
45
  bool success = false;
50
45
  TypeEnumerator& te = *d_te;
51
  // Check if we have run out of elements. This should never happen; if it
52
  // does we assert false and return null.
53
45
  if (te.isFinished())
54
  {
55
    Assert(false);
56
    return Node::null();
57
  }
58
  // must increment until we find one that is not in the assignment
59
  // exclusion set
60
12
  do
61
  {
62
57
    n = *te;
63
57
    success = std::find(d_assignExcSet.begin(), d_assignExcSet.end(), n)
64
114
              == d_assignExcSet.end();
65
    // increment regardless of fail or succeed, to set up the next value
66
57
    ++te;
67
57
  } while (!success);
68
45
  return n;
69
}
70
71
321799
Node TheoryEngineModelBuilder::evaluateEqc(TheoryModel* m, TNode r)
72
{
73
321799
  eq::EqClassIterator eqc_i = eq::EqClassIterator(r, m->d_equalityEngine);
74
327973
  for (; !eqc_i.isFinished(); ++eqc_i)
75
  {
76
325971
    Node n = *eqc_i;
77
322884
    Trace("model-builder-debug") << "Look at term : " << n << std::endl;
78
322884
    if (!isAssignable(n))
79
    {
80
322327
      Trace("model-builder-debug") << "...try to normalize" << std::endl;
81
324857
      Node normalized = normalize(m, n, true);
82
322327
      if (normalized.isConst())
83
      {
84
319797
        return normalized;
85
      }
86
    }
87
  }
88
2002
  return Node::null();
89
}
90
91
45
bool TheoryEngineModelBuilder::isAssignerActive(TheoryModel* tm, Assigner& a)
92
{
93
45
  if (a.d_isActive)
94
  {
95
35
    return true;
96
  }
97
10
  std::vector<Node>& eset = a.d_assignExcSet;
98
10
  std::map<Node, Node>::iterator it;
99
30
  for (unsigned i = 0, size = eset.size(); i < size; i++)
100
  {
101
    // Members of exclusion set must have values, otherwise we are not yet
102
    // assignable.
103
26
    Node er = eset[i];
104
20
    if (er.isConst())
105
    {
106
      // already processed
107
14
      continue;
108
    }
109
    // Assignable members of assignment exclusion set should be representatives
110
    // of their equivalence classes. This ensures we look up the constant
111
    // representatives for assignable members of assignment exclusion sets.
112
6
    Assert(er == tm->getRepresentative(er));
113
6
    it = d_constantReps.find(er);
114
6
    if (it == d_constantReps.end())
115
    {
116
      Trace("model-build-aes")
117
          << "isAssignerActive: not active due to " << er << std::endl;
118
      return false;
119
    }
120
    // update
121
6
    eset[i] = it->second;
122
  }
123
10
  Trace("model-build-aes") << "isAssignerActive: active!" << std::endl;
124
10
  a.d_isActive = true;
125
10
  return true;
126
}
127
128
3949502
bool TheoryEngineModelBuilder::isAssignable(TNode n)
129
{
130
3949502
  if (n.getKind() == kind::SELECT || n.getKind() == kind::APPLY_SELECTOR_TOTAL)
131
  {
132
    // selectors are always assignable (where we guarantee that they are not
133
    // evaluatable here)
134
487672
    if (!logicInfo().isHigherOrder())
135
    {
136
478860
      Assert(!n.getType().isFunction());
137
478860
      return true;
138
    }
139
    else
140
    {
141
      // might be a function field
142
8812
      return !n.getType().isFunction();
143
    }
144
  }
145
3461830
  else if (n.getKind() == kind::FLOATINGPOINT_COMPONENT_SIGN)
146
  {
147
    // Extracting the sign of a floating-point number acts similar to a
148
    // selector on a datatype, i.e. if `(sign x)` wasn't assigned a value, we
149
    // can pick an arbitrary one. Note that the other components of a
150
    // floating-point number should always be assigned a value.
151
1562
    return true;
152
  }
153
  else
154
  {
155
    // non-function variables, and fully applied functions
156
3460268
    if (!logicInfo().isHigherOrder())
157
    {
158
      // no functions exist, all functions are fully applied
159
3433047
      Assert(n.getKind() != kind::HO_APPLY);
160
3433047
      Assert(!n.getType().isFunction());
161
3433047
      return n.isVar() || n.getKind() == kind::APPLY_UF;
162
    }
163
    else
164
    {
165
      // Assert( n.getKind() != kind::APPLY_UF );
166
58430
      return (n.isVar() && !n.getType().isFunction())
167
24227
             || n.getKind() == kind::APPLY_UF
168
83665
             || (n.getKind() == kind::HO_APPLY
169
30196
                 && n[0].getType().getNumChildren() == 2);
170
    }
171
  }
172
}
173
174
4628863
void TheoryEngineModelBuilder::addAssignableSubterms(TNode n,
175
                                                     TheoryModel* tm,
176
                                                     NodeSet& cache)
177
{
178
4628863
  if (n.isClosure())
179
  {
180
35490
    return;
181
  }
182
4593373
  if (cache.find(n) != cache.end())
183
  {
184
2512890
    return;
185
  }
186
2080483
  if (isAssignable(n))
187
  {
188
554096
    tm->d_equalityEngine->addTerm(n);
189
  }
190
4674630
  for (TNode::iterator child_it = n.begin(); child_it != n.end(); ++child_it)
191
  {
192
2594147
    addAssignableSubterms(*child_it, tm, cache);
193
  }
194
2080483
  cache.insert(n);
195
}
196
197
852654
void TheoryEngineModelBuilder::assignConstantRep(TheoryModel* tm,
198
                                                 Node eqc,
199
                                                 Node constRep)
200
{
201
852654
  d_constantReps[eqc] = constRep;
202
1705308
  Trace("model-builder") << "    Assign: Setting constant rep of " << eqc
203
852654
                         << " to " << constRep << endl;
204
852654
  tm->d_rep_set.setTermForRepresentative(constRep, eqc);
205
852654
}
206
207
54
bool TheoryEngineModelBuilder::isExcludedCdtValue(
208
    Node val,
209
    std::set<Node>* repSet,
210
    std::map<Node, Node>& assertedReps,
211
    Node eqc)
212
{
213
108
  Trace("model-builder-debug")
214
54
      << "Is " << val << " and excluded codatatype value for " << eqc << "? "
215
54
      << std::endl;
216
110
  for (set<Node>::iterator i = repSet->begin(); i != repSet->end(); ++i)
217
  {
218
71
    Assert(assertedReps.find(*i) != assertedReps.end());
219
127
    Node rep = assertedReps[*i];
220
71
    Trace("model-builder-debug") << "  Rep : " << rep << std::endl;
221
    // check whether it is possible that rep will be assigned the same value
222
    // as val.
223
71
    if (isCdtValueMatch(val, rep))
224
    {
225
15
      return true;
226
    }
227
  }
228
39
  return false;
229
}
230
231
184
bool TheoryEngineModelBuilder::isCdtValueMatch(Node v, Node r)
232
{
233
184
  if (r == v)
234
  {
235
    // values equal match trivially
236
50
    return true;
237
  }
238
134
  else if (v.isConst() && r.isConst())
239
  {
240
    // distinct constant values do not match
241
8
    return false;
242
  }
243
126
  else if (r.getKind() == kind::APPLY_CONSTRUCTOR)
244
  {
245
71
    if (v.getKind() != kind::APPLY_CONSTRUCTOR)
246
    {
247
      Assert(v.getKind() == kind::CODATATYPE_BOUND_VARIABLE);
248
      // v is the position of a loop. It may be possible to match, we return
249
      // true, which is an over-approximation of when it is unsafe to use v.
250
      return true;
251
    }
252
71
    if (v.getOperator() == r.getOperator())
253
    {
254
128
      for (size_t i = 0, nchild = v.getNumChildren(); i < nchild; i++)
255
      {
256
113
        if (!isCdtValueMatch(v[i], r[i]))
257
        {
258
          // if one child fails to match, we cannot match
259
48
          return false;
260
        }
261
      }
262
15
      return true;
263
    }
264
    // operators do not match
265
8
    return false;
266
  }
267
55
  else if (v.getKind() == kind::APPLY_CONSTRUCTOR)
268
  {
269
    // v has a constructor in a position that we have yet to fill in r.
270
    // we are either a finite type in which case this subfield of r can be
271
    // assigned a default value (or otherwise would have been split on).
272
    // otherwise we are an infinite type and the subfield of r will be
273
    // chosen not to clash with the subfield of v.
274
40
    return false;
275
  }
276
15
  return true;
277
}
278
279
10136
bool TheoryEngineModelBuilder::involvesUSort(TypeNode tn) const
280
{
281
10136
  if (tn.isSort())
282
  {
283
7
    return true;
284
  }
285
10129
  else if (tn.isArray())
286
  {
287
51
    return involvesUSort(tn.getArrayIndexType())
288
51
           || involvesUSort(tn.getArrayConstituentType());
289
  }
290
10112
  else if (tn.isSet())
291
  {
292
4
    return involvesUSort(tn.getSetElementType());
293
  }
294
10108
  else if (tn.isDatatype())
295
  {
296
9946
    const DType& dt = tn.getDType();
297
9946
    return dt.involvesUninterpretedType();
298
  }
299
  else
300
  {
301
162
    return false;
302
  }
303
}
304
305
35731
bool TheoryEngineModelBuilder::isExcludedUSortValue(
306
    std::map<TypeNode, unsigned>& eqc_usort_count,
307
    Node v,
308
    std::map<Node, bool>& visited)
309
{
310
35731
  Assert(v.isConst());
311
35731
  if (visited.find(v) == visited.end())
312
  {
313
26442
    visited[v] = true;
314
52692
    TypeNode tn = v.getType();
315
26442
    if (tn.isSort())
316
    {
317
384
      Trace("model-builder-debug") << "Is excluded usort value : " << v << " "
318
192
                                   << tn << std::endl;
319
192
      unsigned card = eqc_usort_count[tn];
320
192
      Trace("model-builder-debug") << "  Cardinality is " << card << std::endl;
321
      unsigned index =
322
192
          v.getConst<UninterpretedConstant>().getIndex().toUnsignedInt();
323
192
      Trace("model-builder-debug") << "  Index is " << index << std::endl;
324
192
      return index > 0 && index >= card;
325
    }
326
56464
    for (unsigned i = 0; i < v.getNumChildren(); i++)
327
    {
328
30214
      if (isExcludedUSortValue(eqc_usort_count, v[i], visited))
329
      {
330
        return true;
331
      }
332
    }
333
  }
334
35539
  return false;
335
}
336
337
539004
void TheoryEngineModelBuilder::addToTypeList(
338
    TypeNode tn,
339
    std::vector<TypeNode>& type_list,
340
    std::unordered_set<TypeNode>& visiting)
341
{
342
539004
  if (std::find(type_list.begin(), type_list.end(), tn) == type_list.end())
343
  {
344
167151
    if (visiting.find(tn) == visiting.end())
345
    {
346
52002
      visiting.insert(tn);
347
      /* This must make a recursive call on all types that are subterms of
348
       * values of the current type.
349
       * Note that recursive traversal here is over enumerated expressions
350
       * (very low expression depth). */
351
52002
      if (tn.isArray())
352
      {
353
500
        addToTypeList(tn.getArrayIndexType(), type_list, visiting);
354
500
        addToTypeList(tn.getArrayConstituentType(), type_list, visiting);
355
      }
356
51502
      else if (tn.isSet())
357
      {
358
631
        addToTypeList(tn.getSetElementType(), type_list, visiting);
359
      }
360
50871
      else if (tn.isDatatype())
361
      {
362
30156
        const DType& dt = tn.getDType();
363
214969
        for (unsigned i = 0; i < dt.getNumConstructors(); i++)
364
        {
365
357772
          for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
366
          {
367
345918
            TypeNode ctn = dt[i][j].getRangeType();
368
172959
            addToTypeList(ctn, type_list, visiting);
369
          }
370
        }
371
      }
372
52002
      Assert(std::find(type_list.begin(), type_list.end(), tn)
373
             == type_list.end());
374
52002
      type_list.push_back(tn);
375
    }
376
  }
377
539004
}
378
379
24989
bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm)
380
{
381
24989
  Trace("model-builder") << "TheoryEngineModelBuilder: buildModel" << std::endl;
382
383
49978
  Trace("model-builder")
384
24989
      << "TheoryEngineModelBuilder: Preprocess build model..." << std::endl;
385
  // model-builder specific initialization
386
24989
  if (!preProcessBuildModel(tm))
387
  {
388
    Trace("model-builder")
389
        << "TheoryEngineModelBuilder: fail preprocess build model."
390
        << std::endl;
391
    return false;
392
  }
393
394
49978
  Trace("model-builder")
395
      << "TheoryEngineModelBuilder: Add assignable subterms "
396
24989
         ", collect representatives and compute assignable information..."
397
24989
      << std::endl;
398
399
  // type enumerator properties
400
24989
  bool tepFixUSortCard = options().quantifiers.finiteModelFind;
401
24989
  uint32_t tepStrAlphaCard = options().strings.stringsAlphaCard;
402
49978
  TypeEnumeratorProperties tep(tepFixUSortCard, tepStrAlphaCard);
403
404
  // In the first step of model building, we do a traversal of the
405
  // equality engine and record the information in the following:
406
407
  // The constant representatives, per equivalence class
408
24989
  d_constantReps.clear();
409
  // The representatives that have been asserted by theories. This includes
410
  // non-constant "skeletons" that have been specified by parametric theories.
411
49978
  std::map<Node, Node> assertedReps;
412
  // A parition of the set of equivalence classes that have:
413
  // (1) constant representatives,
414
  // (2) an assigned representative specified by a theory in collectModelInfo,
415
  // (3) no assigned representative.
416
49978
  TypeSet typeConstSet, typeRepSet, typeNoRepSet;
417
  // An ordered list of types, such that T1 comes before T2 if T1 is a
418
  // "component type" of T2, e.g. U comes before (Set U). This is only strictly
419
  // necessary for finite model finding + parametric types instantiated with
420
  // uninterpreted sorts, but is probably a good idea to do in general since it
421
  // leads to models with smaller term sizes. -AJR
422
49978
  std::vector<TypeNode> type_list;
423
  // The count of equivalence classes per sort (for finite model finding).
424
49978
  std::map<TypeNode, unsigned> eqc_usort_count;
425
426
  // the set of equivalence classes that are "assignable", i.e. those that have
427
  // an assignable expression in them (see isAssignable), and have not already
428
  // been assigned a constant.
429
49978
  std::unordered_set<Node> assignableEqc;
430
  // The set of equivalence classes that are "evaluable", i.e. those that have
431
  // an expression in them that is not assignable, and have not already been
432
  // assigned a constant.
433
49978
  std::unordered_set<Node> evaluableEqc;
434
  // Assigner objects for relevant equivalence classes that require special
435
  // ways of assigning values, e.g. those that take into account assignment
436
  // exclusion sets.
437
49978
  std::map<Node, Assigner> eqcToAssigner;
438
  // A map from equivalence classes to the equivalence class that it shares an
439
  // assigner object with (all elements in the range of this map are in the
440
  // domain of eqcToAssigner).
441
49978
  std::map<Node, Node> eqcToAssignerMaster;
442
443
  // Loop through equivalence classes of the equality engine of the model.
444
24989
  eq::EqualityEngine* ee = tm->d_equalityEngine;
445
49978
  NodeSet assignableCache;
446
24989
  std::map<Node, Node>::iterator itm;
447
24989
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
448
  // should we compute assigner objects?
449
24989
  bool computeAssigners = tm->hasAssignmentExclusionSets();
450
  // the set of exclusion sets we have processed
451
49978
  std::unordered_set<Node> processedExcSet;
452
1731087
  for (; !eqcs_i.isFinished(); ++eqcs_i)
453
  {
454
1217463
    Node eqc = *eqcs_i;
455
853049
    Trace("model-builder") << "  Processing EQC " << eqc << std::endl;
456
    // Information computed for each equivalence class
457
458
    // The assigned represenative and constant representative
459
1217463
    Node rep, constRep;
460
    // A flag set to true if the current equivalence class is assignable (see
461
    // assignableEqc).
462
853049
    bool assignable = false;
463
    // Set to true if the current equivalence class is evaluatable (see
464
    // evaluableEqc).
465
853049
    bool evaluable = false;
466
    // Set to true if a term in the current equivalence class has been given an
467
    // assignment exclusion set.
468
853049
    bool hasESet CVC5_UNUSED = false;
469
    // Set to true if we found that a term in the current equivalence class has
470
    // been given an assignment exclusion set, and we have not seen this term
471
    // as part of a previous assignment exclusion group. In other words, when
472
    // this flag is true we construct a new assigner object with the current
473
    // equivalence class as its master.
474
853049
    bool foundESet = false;
475
    // The assignment exclusion set for the current equivalence class.
476
1217463
    std::vector<Node> eset;
477
    // The group to which this equivalence class belongs when exclusion sets
478
    // were assigned (see the argument group of
479
    // TheoryModel::getAssignmentExclusionSet).
480
1217463
    std::vector<Node> esetGroup;
481
482
    // Loop through terms in this EC
483
853049
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
484
4922481
    for (; !eqc_i.isFinished(); ++eqc_i)
485
    {
486
2034922
      Node n = *eqc_i;
487
2034716
      Trace("model-builder") << "    Processing Term: " << n << endl;
488
489
      // For each term n in this equivalence class, below we register its
490
      // assignable subterms, compute whether it is a constant or assigned
491
      // representative, then if we don't have a constant representative,
492
      // compute information regarding how we will assign values.
493
494
      // (1) Add assignable subterms, which ensures that e.g. models for
495
      // uninterpreted functions take into account all subterms in the
496
      // equality engine of the model
497
2034716
      addAssignableSubterms(n, tm, assignableCache);
498
      // model-specific processing of the term
499
2034716
      tm->addTermInternal(n);
500
501
      // (2) Record constant representative or assign representative, if
502
      // applicable
503
2523351
      if (n.isConst())
504
      {
505
488635
        Assert(constRep.isNull());
506
488635
        constRep = n;
507
977270
        Trace("model-builder")
508
488635
            << "    ..ConstRep( " << eqc << " ) = " << constRep << std::endl;
509
        // if we have a constant representative, nothing else matters
510
488635
        continue;
511
      }
512
513
      // If we don't have a constant rep, check if this is an assigned rep.
514
1546081
      itm = tm->d_reps.find(n);
515
1546081
      if (itm != tm->d_reps.end())
516
      {
517
        // Notice that this equivalence class may contain multiple terms that
518
        // were specified as being a representative, since e.g. datatypes may
519
        // assert representative for two constructor terms that are not in the
520
        // care graph and are merged during collectModeInfo due to equality
521
        // information from another theory. We overwrite the value of rep in
522
        // these cases here.
523
31051
        rep = itm->second;
524
62102
        Trace("model-builder")
525
31051
            << "    ..Rep( " << eqc << " ) = " << rep << std::endl;
526
      }
527
528
      // (3) Finally, process assignable information
529
2538066
      if (!isAssignable(n))
530
      {
531
991985
        evaluable = true;
532
        // expressions that are not assignable should not be given assignment
533
        // exclusion sets
534
991985
        Assert(!tm->getAssignmentExclusionSet(n, esetGroup, eset));
535
991985
        continue;
536
      }
537
554096
      assignable = true;
538
554096
      if (!computeAssigners)
539
      {
540
        // we don't compute assigners, skip
541
553855
        continue;
542
      }
543
      // process the assignment exclusion set for term n
544
      // was it processed based on a master exclusion group (see
545
      // eqcToAssignerMaster)?
546
276
      if (processedExcSet.find(n) != processedExcSet.end())
547
      {
548
        // Should not have two assignment exclusion sets for the same
549
        // equivalence class
550
35
        Assert(!hasESet);
551
35
        Assert(eqcToAssignerMaster.find(eqc) != eqcToAssignerMaster.end());
552
        // already processed as a slave term
553
35
        hasESet = true;
554
35
        continue;
555
      }
556
      // was it assigned one?
557
206
      if (tm->getAssignmentExclusionSet(n, esetGroup, eset))
558
      {
559
        // Should not have two assignment exclusion sets for the same
560
        // equivalence class
561
10
        Assert(!hasESet);
562
10
        foundESet = true;
563
10
        hasESet = true;
564
      }
565
    }
566
567
    // finished traversing the equality engine
568
1217463
    TypeNode eqct = eqc.getType();
569
    // count the number of equivalence classes of sorts in finite model finding
570
853049
    if (options().quantifiers.finiteModelFind)
571
    {
572
19770
      if (eqct.isSort())
573
      {
574
3688
        eqc_usort_count[eqct]++;
575
      }
576
    }
577
    // Assign representative for this equivalence class
578
1341684
    if (!constRep.isNull())
579
    {
580
      // Theories should not specify a rep if there is already a constant in the
581
      // equivalence class. However, it may be the case that the representative
582
      // specified by a theory may be merged with a constant based on equality
583
      // information from another class. Thus, rep may be non-null here.
584
      // Regardless, we assign constRep as the representative here.
585
488635
      assignConstantRep(tm, eqc, constRep);
586
488635
      typeConstSet.add(eqct.getBaseType(), constRep);
587
488635
      continue;
588
    }
589
364414
    else if (!rep.isNull())
590
    {
591
31005
      assertedReps[eqc] = rep;
592
31005
      typeRepSet.add(eqct.getBaseType(), eqc);
593
62010
      std::unordered_set<TypeNode> visiting;
594
31005
      addToTypeList(eqct.getBaseType(), type_list, visiting);
595
    }
596
    else
597
    {
598
333409
      typeNoRepSet.add(eqct, eqc);
599
666818
      std::unordered_set<TypeNode> visiting;
600
333409
      addToTypeList(eqct, type_list, visiting);
601
    }
602
603
364414
    if (assignable)
604
    {
605
42388
      assignableEqc.insert(eqc);
606
    }
607
364414
    if (evaluable)
608
    {
609
351206
      evaluableEqc.insert(eqc);
610
    }
611
    // If we found an assignment exclusion set, we construct a new assigner
612
    // object.
613
364414
    if (foundESet)
614
    {
615
      // we don't accept assignment exclusion sets for evaluable eqc
616
10
      Assert(!evaluable);
617
      // construct the assigner
618
10
      Assigner& a = eqcToAssigner[eqc];
619
      // Take the representatives of each term in the assignment exclusion
620
      // set, which ensures we can look up their value in d_constReps later.
621
20
      std::vector<Node> aes;
622
30
      for (const Node& e : eset)
623
      {
624
        // Should only supply terms that occur in the model or constants
625
        // in assignment exclusion sets.
626
20
        Assert(tm->hasTerm(e) || e.isConst());
627
40
        Node er = tm->hasTerm(e) ? tm->getRepresentative(e) : e;
628
20
        aes.push_back(er);
629
      }
630
      // initialize
631
10
      a.initialize(eqc.getType(), &tep, aes);
632
      // all others in the group are slaves of this
633
55
      for (const Node& g : esetGroup)
634
      {
635
45
        Assert(isAssignable(g));
636
45
        if (!tm->hasTerm(g))
637
        {
638
          // Ignore those that aren't in the model, in the case the user
639
          // has supplied an assignment exclusion set to a variable not in
640
          // the model.
641
          continue;
642
        }
643
90
        Node gr = tm->getRepresentative(g);
644
45
        if (gr != eqc)
645
        {
646
35
          eqcToAssignerMaster[gr] = eqc;
647
          // remember that this term has been processed
648
35
          processedExcSet.insert(g);
649
        }
650
      }
651
    }
652
  }
653
654
  // Now finished initialization
655
656
  // Compute type enumerator properties. This code ensures we do not
657
  // enumerate terms that have uninterpreted constants that violate the
658
  // bounds imposed by finite model finding. For example, if finite
659
  // model finding insists that there are only 2 values { U1, U2 } of type U,
660
  // then the type enumerator for list of U should enumerate:
661
  //   nil, (cons U1 nil), (cons U2 nil), (cons U1 (cons U1 nil)), ...
662
  // instead of enumerating (cons U3 nil).
663
24989
  if (options().quantifiers.finiteModelFind)
664
  {
665
957
    tep.d_fixed_usort_card = true;
666
2947
    for (std::map<TypeNode, unsigned>::iterator it = eqc_usort_count.begin();
667
2947
         it != eqc_usort_count.end();
668
         ++it)
669
    {
670
3980
      Trace("model-builder") << "Fixed bound (#eqc) for " << it->first << " : "
671
1990
                             << it->second << std::endl;
672
1990
      tep.d_fixed_card[it->first] = Integer(it->second);
673
    }
674
957
    typeConstSet.setTypeEnumeratorProperties(&tep);
675
  }
676
677
  // Need to ensure that each EC has a constant representative.
678
679
24989
  Trace("model-builder") << "Processing EC's..." << std::endl;
680
681
24989
  TypeSet::iterator it;
682
24989
  vector<TypeNode>::iterator type_it;
683
24989
  set<Node>::iterator i, i2;
684
24989
  bool changed, unassignedAssignable, assignOne = false;
685
49978
  set<TypeNode> evaluableSet;
686
687
  // Double-fixed-point loop
688
  // Outer loop handles a special corner case (see code at end of loop for
689
  // details)
690
  for (;;)
691
  {
692
    // Inner fixed-point loop: we are trying to learn constant values for every
693
    // EC.  Each time through this loop, we process all of the
694
    // types by type and may learn some new EC values.  EC's in one type may
695
    // depend on EC's in another type, so we need a fixed-point loop
696
    // to ensure that we learn as many EC values as possible
697
55668
    do
698
    {
699
55668
      changed = false;
700
55668
      unassignedAssignable = false;
701
55668
      evaluableSet.clear();
702
703
      // Iterate over all types we've seen
704
257016
      for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
705
      {
706
402696
        TypeNode t = *type_it;
707
402696
        TypeNode tb = t.getBaseType();
708
201348
        set<Node>* noRepSet = typeNoRepSet.getSet(t);
709
710
        // 1. Try to evaluate the EC's in this type
711
201348
        if (noRepSet != NULL && !noRepSet->empty())
712
        {
713
72374
          Trace("model-builder") << "  Eval phase, working on type: " << t
714
36187
                                 << endl;
715
          bool evaluable;
716
36187
          d_normalizedCache.clear();
717
778366
          for (i = noRepSet->begin(); i != noRepSet->end();)
718
          {
719
742179
            i2 = i;
720
742179
            ++i;
721
1484358
            Trace("model-builder-debug") << "Look at eqc : " << (*i2)
722
742179
                                         << std::endl;
723
1484358
            Node normalized;
724
            // only possible to normalize if we are evaluable
725
742179
            evaluable = evaluableEqc.find(*i2) != evaluableEqc.end();
726
742179
            if (evaluable)
727
            {
728
321799
              normalized = evaluateEqc(tm, *i2);
729
            }
730
742179
            if (!normalized.isNull())
731
            {
732
319797
              Assert(normalized.isConst());
733
319797
              typeConstSet.add(tb, normalized);
734
319797
              assignConstantRep(tm, *i2, normalized);
735
639594
              Trace("model-builder") << "    Eval: Setting constant rep of "
736
319797
                                     << (*i2) << " to " << normalized << endl;
737
319797
              changed = true;
738
319797
              noRepSet->erase(i2);
739
            }
740
            else
741
            {
742
422382
              if (evaluable)
743
              {
744
2002
                evaluableSet.insert(tb);
745
              }
746
              // If assignable, remember there is an equivalence class that is
747
              // not assigned and assignable.
748
422382
              if (assignableEqc.find(*i2) != assignableEqc.end())
749
              {
750
420442
                unassignedAssignable = true;
751
              }
752
            }
753
          }
754
        }
755
756
        // 2. Normalize any non-const representative terms for this type
757
201348
        set<Node>* repSet = typeRepSet.getSet(t);
758
201348
        if (repSet != NULL && !repSet->empty())
759
        {
760
87568
          Trace("model-builder")
761
43784
              << "  Normalization phase, working on type: " << t << endl;
762
43784
          d_normalizedCache.clear();
763
285739
          for (i = repSet->begin(); i != repSet->end();)
764
          {
765
241955
            Assert(assertedReps.find(*i) != assertedReps.end());
766
483910
            Node rep = assertedReps[*i];
767
483910
            Node normalized = normalize(tm, rep, false);
768
483910
            Trace("model-builder") << "    Normalizing rep (" << rep
769
241955
                                   << "), normalized to (" << normalized << ")"
770
241955
                                   << endl;
771
241955
            if (normalized.isConst())
772
            {
773
31005
              changed = true;
774
31005
              typeConstSet.add(tb, normalized);
775
31005
              assignConstantRep(tm, *i, normalized);
776
31005
              assertedReps.erase(*i);
777
31005
              i2 = i;
778
31005
              ++i;
779
31005
              repSet->erase(i2);
780
            }
781
            else
782
            {
783
210950
              if (normalized != rep)
784
              {
785
7053
                assertedReps[*i] = normalized;
786
7053
                changed = true;
787
              }
788
210950
              ++i;
789
            }
790
          }
791
        }
792
      }
793
    } while (changed);
794
795
34656
    if (!unassignedAssignable)
796
    {
797
24989
      break;
798
    }
799
800
    // 3. Assign unassigned assignable EC's using type enumeration - assign a
801
    // value *different* from all other EC's if the type is infinite
802
    // Assign first value from type enumerator otherwise - for finite types, we
803
    // rely on polite framework to ensure that EC's that have to be
804
    // different are different.
805
806
    // Only make assignments on a type if:
807
    // 1. there are no terms that share the same base type with un-normalized
808
    // representatives
809
    // 2. there are no terms that share teh same base type that are unevaluated
810
    // evaluable terms
811
    // Alternatively, if 2 or 3 don't hold but we are in a special
812
    // deadlock-breaking mode where assignOne is true, go ahead and make one
813
    // assignment
814
9667
    changed = false;
815
    // must iterate over the ordered type list to ensure that we do not
816
    // enumerate values with subterms
817
    //  having types that we are currently enumerating (when possible)
818
    //  for example, this ensures we enumerate uninterpreted sort U before (List
819
    //  of U) and (Array U U)
820
    //  however, it does not break cyclic type dependencies for mutually
821
    //  recursive datatypes, but this is handled
822
    //  by recording all subterms of enumerated values in TypeSet::addSubTerms.
823
75523
    for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
824
    {
825
73419
      TypeNode t = *type_it;
826
      // continue if there are no more equivalence classes of this type to
827
      // assign
828
65856
      std::set<Node>* noRepSetPtr = typeNoRepSet.getSet(t);
829
65856
      if (noRepSetPtr == NULL)
830
      {
831
10702
        continue;
832
      }
833
55154
      set<Node>& noRepSet = *noRepSetPtr;
834
55154
      if (noRepSet.empty())
835
      {
836
40851
        continue;
837
      }
838
839
      // get properties of this type
840
14303
      bool isCorecursive = false;
841
14303
      if (t.isDatatype())
842
      {
843
10391
        const DType& dt = t.getDType();
844
10391
        isCorecursive =
845
10391
            dt.isCodatatype()
846
31173
            && (!d_env.isFiniteType(t) || dt.isRecursiveSingleton(t));
847
      }
848
#ifdef CVC5_ASSERTIONS
849
14303
      bool isUSortFiniteRestricted = false;
850
14303
      if (options().quantifiers.finiteModelFind)
851
      {
852
12095
        isUSortFiniteRestricted = !t.isSort() && involvesUSort(t);
853
      }
854
#endif
855
856
21866
      TypeNode tb = t.getBaseType();
857
14303
      if (!assignOne)
858
      {
859
10586
        set<Node>* repSet = typeRepSet.getSet(tb);
860
10586
        if (repSet != NULL && !repSet->empty())
861
        {
862
6456
          continue;
863
        }
864
4130
        if (evaluableSet.find(tb) != evaluableSet.end())
865
        {
866
284
          continue;
867
        }
868
      }
869
15126
      Trace("model-builder") << "  Assign phase, working on type: " << t
870
7563
                             << endl;
871
      bool assignable, evaluable CVC5_UNUSED;
872
7563
      std::map<Node, Assigner>::iterator itAssigner;
873
7563
      std::map<Node, Node>::iterator itAssignerM;
874
7563
      set<Node>* repSet = typeRepSet.getSet(t);
875
17137
      for (i = noRepSet.begin(); i != noRepSet.end();)
876
      {
877
13291
        i2 = i;
878
13291
        ++i;
879
        // check whether it has an assigner object
880
13291
        itAssignerM = eqcToAssignerMaster.find(*i2);
881
13291
        if (itAssignerM != eqcToAssignerMaster.end())
882
        {
883
          // Take the master's assigner. Notice we don't care which order
884
          // equivalence classes are assigned. For instance, the master can
885
          // be assigned after one of its slaves.
886
35
          itAssigner = eqcToAssigner.find(itAssignerM->second);
887
        }
888
        else
889
        {
890
13256
          itAssigner = eqcToAssigner.find(*i2);
891
        }
892
13291
        if (itAssigner != eqcToAssigner.end())
893
        {
894
45
          assignable = isAssignerActive(tm, itAssigner->second);
895
        }
896
        else
897
        {
898
13246
          assignable = assignableEqc.find(*i2) != assignableEqc.end();
899
        }
900
13291
        evaluable = evaluableEqc.find(*i2) != evaluableEqc.end();
901
26582
        Trace("model-builder-debug")
902
13291
            << "    eqc " << *i2 << " is assignable=" << assignable
903
13291
            << ", evaluable=" << evaluable << std::endl;
904
13291
        if (assignable)
905
        {
906
13217
          Assert(!evaluable || assignOne);
907
          // this assertion ensures that if we are assigning to a term of
908
          // Boolean type, then the term must be assignable.
909
          // Note we only assign to terms of Boolean type if the term occurs in
910
          // a singleton equivalence class; otherwise the term would have been
911
          // in the equivalence class of true or false and would not need
912
          // assigning.
913
13217
          Assert(!t.isBoolean() || isAssignable(*i2));
914
22717
          Node n;
915
13217
          if (itAssigner != eqcToAssigner.end())
916
          {
917
90
            Trace("model-builder-debug")
918
45
                << "Get value from assigner for finite type..." << std::endl;
919
            // if it has an assigner, get the value from the assigner.
920
45
            n = itAssigner->second.getNextAssignment();
921
45
            Assert(!n.isNull());
922
          }
923
13172
          else if (t.isSort() || !d_env.isFiniteType(t))
924
          {
925
            // If its interpreted as infinite, we get a fresh value that does
926
            // not occur in the model.
927
            // Note we also consider uninterpreted sorts to be infinite here
928
            // regardless of whether the cardinality class of t is
929
            // CardinalityClass::INTERPRETED_FINITE.
930
            // This is required because the UF solver does not explicitly
931
            // assign uninterpreted constants to equivalence classes in its
932
            // collectModelValues method. Doing so would have the same effect
933
            // as running the code in this case.
934
            bool success;
935
15
            do
936
            {
937
26062
              Trace("model-builder-debug") << "Enumerate term of type " << t
938
13031
                                           << std::endl;
939
13031
              n = typeConstSet.nextTypeEnum(t, true);
940
              //--- AJR: this code checks whether n is a legal value
941
13031
              Assert(!n.isNull());
942
13031
              success = true;
943
26062
              Trace("model-builder-debug") << "Check if excluded : " << n
944
13031
                                           << std::endl;
945
#ifdef CVC5_ASSERTIONS
946
13031
              if (isUSortFiniteRestricted)
947
              {
948
                // must not involve uninterpreted constants beyond cardinality
949
                // bound (which assumed to coincide with #eqc)
950
                // this is just an assertion now, since TypeEnumeratorProperties
951
                // should ensure that only legal values are enumerated wrt this
952
                // constraint.
953
11034
                std::map<Node, bool> visited;
954
5517
                success = !isExcludedUSortValue(eqc_usort_count, n, visited);
955
5517
                if (!success)
956
                {
957
                  Trace("model-builder")
958
                      << "Excluded value for " << t << " : " << n
959
                      << " due to out of range uninterpreted constant."
960
                      << std::endl;
961
                }
962
5517
                Assert(success);
963
              }
964
#endif
965
13031
              if (success && isCorecursive)
966
              {
967
62
                if (repSet != NULL && !repSet->empty())
968
                {
969
                  // in the case of codatatypes, check if it is in the set of
970
                  // values that we cannot assign
971
54
                  success = !isExcludedCdtValue(n, repSet, assertedReps, *i2);
972
54
                  if (!success)
973
                  {
974
30
                    Trace("model-builder")
975
15
                        << "Excluded value : " << n
976
15
                        << " due to alpha-equivalent codatatype expression."
977
15
                        << std::endl;
978
                  }
979
                }
980
              }
981
              //---
982
13031
            } while (!success);
983
13016
            Assert(!n.isNull());
984
          }
985
          else
986
          {
987
312
            Trace("model-builder-debug")
988
156
                << "Get first value from finite type..." << std::endl;
989
            // Otherwise, we get the first value from the type enumerator.
990
312
            TypeEnumerator te(t);
991
156
            n = *te;
992
          }
993
13217
          Trace("model-builder-debug") << "...got " << n << std::endl;
994
13217
          assignConstantRep(tm, *i2, n);
995
13217
          changed = true;
996
13217
          noRepSet.erase(i2);
997
13217
          if (assignOne)
998
          {
999
3717
            assignOne = false;
1000
3717
            break;
1001
          }
1002
        }
1003
      }
1004
    }
1005
1006
    // Corner case - I'm not sure this can even happen - but it's theoretically
1007
    // possible to have a cyclical dependency
1008
    // in EC assignment/evaluation, e.g. EC1 = {a, b + 1}; EC2 = {b, a - 1}.  In
1009
    // this case, neither one will get assigned because we are waiting
1010
    // to be able to evaluate.  But we will never be able to evaluate because
1011
    // the variables that need to be assigned are in
1012
    // these same EC's.  In this case, repeat the whole fixed-point computation
1013
    // with the difference that the first EC
1014
    // that has both assignable and evaluable expressions will get assigned.
1015
9667
    if (!changed)
1016
    {
1017
3717
      Assert(!assignOne);  // check for infinite loop!
1018
3717
      assignOne = true;
1019
    }
1020
9667
  }
1021
1022
#ifdef CVC5_ASSERTIONS
1023
  // Assert that all representatives have been converted to constants
1024
43440
  for (it = typeRepSet.begin(); it != typeRepSet.end(); ++it)
1025
  {
1026
18451
    set<Node>& repSet = TypeSet::getSet(it);
1027
18451
    if (!repSet.empty())
1028
    {
1029
      Trace("model-builder") << "***Non-empty repSet, size = " << repSet.size()
1030
                             << ", first = " << *(repSet.begin()) << endl;
1031
      Assert(false);
1032
    }
1033
  }
1034
#endif /* CVC5_ASSERTIONS */
1035
1036
24989
  Trace("model-builder") << "Copy representatives to model..." << std::endl;
1037
24989
  tm->d_reps.clear();
1038
24989
  std::map<Node, Node>::iterator itMap;
1039
877643
  for (itMap = d_constantReps.begin(); itMap != d_constantReps.end(); ++itMap)
1040
  {
1041
852654
    tm->d_reps[itMap->first] = itMap->second;
1042
852654
    tm->d_rep_set.add(itMap->second.getType(), itMap->second);
1043
  }
1044
1045
24989
  Trace("model-builder") << "Make sure ECs have reps..." << std::endl;
1046
  // Make sure every EC has a rep
1047
24989
  for (itMap = assertedReps.begin(); itMap != assertedReps.end(); ++itMap)
1048
  {
1049
    tm->d_reps[itMap->first] = itMap->second;
1050
    tm->d_rep_set.add(itMap->second.getType(), itMap->second);
1051
  }
1052
45217
  for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it)
1053
  {
1054
20228
    set<Node>& noRepSet = TypeSet::getSet(it);
1055
20623
    for (const Node& node : noRepSet)
1056
    {
1057
395
      tm->d_reps[node] = node;
1058
395
      tm->d_rep_set.add(node.getType(), node);
1059
    }
1060
  }
1061
1062
  // modelBuilder-specific initialization
1063
24989
  if (!processBuildModel(tm))
1064
  {
1065
    Trace("model-builder")
1066
        << "TheoryEngineModelBuilder: fail process build model." << std::endl;
1067
    return false;
1068
  }
1069
24989
  Trace("model-builder") << "TheoryEngineModelBuilder: success" << std::endl;
1070
24989
  return true;
1071
}
1072
1073
811
void TheoryEngineModelBuilder::postProcessModel(bool incomplete, TheoryModel* m)
1074
{
1075
  // if we are incomplete, there is no guarantee on the model.
1076
  // thus, we do not check the model here.
1077
811
  if (incomplete)
1078
  {
1079
35
    return;
1080
  }
1081
776
  Assert(m != nullptr);
1082
  // debug-check the model if the checkModels() is enabled.
1083
776
  if (options().smt.debugCheckModels)
1084
  {
1085
269
    debugCheckModel(m);
1086
  }
1087
}
1088
1089
269
void TheoryEngineModelBuilder::debugCheckModel(TheoryModel* tm)
1090
{
1091
269
  if (tm->hasApproximations())
1092
  {
1093
    // models with approximations may fail the assertions below
1094
    return;
1095
  }
1096
269
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
1097
269
  std::map<Node, Node>::iterator itMap;
1098
  // Check that every term evaluates to its representative in the model
1099
4945
  for (eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
1100
4945
       !eqcs_i.isFinished();
1101
       ++eqcs_i)
1102
  {
1103
    // eqc is the equivalence class representative
1104
9352
    Node eqc = (*eqcs_i);
1105
    // get the representative
1106
9352
    Node rep = tm->getRepresentative(eqc);
1107
4676
    if (!rep.isConst() && eqc.getType().isBoolean())
1108
    {
1109
      // if Boolean, it does not necessarily have a constant representative, use
1110
      // get value instead
1111
      rep = tm->getValue(eqc);
1112
      AlwaysAssert(rep.isConst());
1113
    }
1114
4676
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, tm->d_equalityEngine);
1115
41424
    for (; !eqc_i.isFinished(); ++eqc_i)
1116
    {
1117
36748
      Node n = *eqc_i;
1118
      static int repCheckInstance = 0;
1119
18374
      ++repCheckInstance;
1120
36748
      AlwaysAssert(rep.getType().isSubtypeOf(n.getType()))
1121
18374
          << "Representative " << rep << " of " << n
1122
18374
          << " violates type constraints (" << rep.getType() << " and "
1123
18374
          << n.getType() << ")";
1124
      // non-linear mult is not necessarily accurate wrt getValue
1125
18374
      if (n.getKind() != kind::NONLINEAR_MULT)
1126
      {
1127
18368
        if (tm->getValue(*eqc_i) != rep)
1128
        {
1129
          std::stringstream err;
1130
          err << "Failed representative check:" << std::endl
1131
              << "( " << repCheckInstance << ") "
1132
              << "n: " << n << endl
1133
              << "getValue(n): " << tm->getValue(n) << std::endl
1134
              << "rep: " << rep << std::endl;
1135
          AlwaysAssert(tm->getValue(*eqc_i) == rep) << err.str();
1136
        }
1137
      }
1138
    }
1139
  }
1140
1141
  // builder-specific debugging
1142
269
  debugModel(tm);
1143
}
1144
1145
654321
Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, bool evalOnly)
1146
{
1147
654321
  std::map<Node, Node>::iterator itMap = d_constantReps.find(r);
1148
654321
  if (itMap != d_constantReps.end())
1149
  {
1150
    return (*itMap).second;
1151
  }
1152
654321
  NodeMap::iterator it = d_normalizedCache.find(r);
1153
654321
  if (it != d_normalizedCache.end())
1154
  {
1155
25931
    return (*it).second;
1156
  }
1157
628390
  Trace("model-builder-debug") << "do normalize on " << r << std::endl;
1158
1256780
  Node retNode = r;
1159
628390
  if (r.getNumChildren() > 0)
1160
  {
1161
1253286
    std::vector<Node> children;
1162
626643
    if (r.getMetaKind() == kind::metakind::PARAMETERIZED)
1163
    {
1164
267353
      children.push_back(r.getOperator());
1165
    }
1166
626643
    bool childrenConst = true;
1167
2036599
    for (size_t i = 0; i < r.getNumChildren(); ++i)
1168
    {
1169
2819912
      Node ri = r[i];
1170
1409956
      bool recurse = true;
1171
1409956
      if (!ri.isConst())
1172
      {
1173
1018239
        if (m->d_equalityEngine->hasTerm(ri))
1174
        {
1175
990895
          itMap =
1176
1981790
              d_constantReps.find(m->d_equalityEngine->getRepresentative(ri));
1177
990895
          if (itMap != d_constantReps.end())
1178
          {
1179
654437
            ri = (*itMap).second;
1180
654437
            Trace("model-builder-debug") << i << ": const child " << ri << std::endl;
1181
654437
            recurse = false;
1182
          }
1183
336458
          else if (!evalOnly)
1184
          {
1185
273763
            recurse = false;
1186
273763
            Trace("model-builder-debug") << i << ": keep " << ri << std::endl;
1187
          }
1188
        }
1189
        else
1190
        {
1191
27344
          Trace("model-builder-debug") << i << ": no hasTerm " << ri << std::endl;
1192
        }
1193
1018239
        if (recurse)
1194
        {
1195
90039
          ri = normalize(m, ri, evalOnly);
1196
        }
1197
1018239
        if (!ri.isConst())
1198
        {
1199
279005
          childrenConst = false;
1200
        }
1201
      }
1202
1409956
      children.push_back(ri);
1203
    }
1204
626643
    retNode = NodeManager::currentNM()->mkNode(r.getKind(), children);
1205
626643
    if (childrenConst)
1206
    {
1207
410740
      retNode = rewrite(retNode);
1208
    }
1209
  }
1210
628390
  d_normalizedCache[r] = retNode;
1211
628390
  return retNode;
1212
}
1213
1214
3562
bool TheoryEngineModelBuilder::preProcessBuildModel(TheoryModel* m)
1215
{
1216
3562
  return true;
1217
}
1218
1219
24989
bool TheoryEngineModelBuilder::processBuildModel(TheoryModel* m)
1220
{
1221
24989
  if (m->areFunctionValuesEnabled())
1222
  {
1223
24989
    assignFunctions(m);
1224
  }
1225
24989
  return true;
1226
}
1227
1228
4896
void TheoryEngineModelBuilder::assignFunction(TheoryModel* m, Node f)
1229
{
1230
4896
  Assert(!logicInfo().isHigherOrder());
1231
9792
  uf::UfModelTree ufmt(f);
1232
9792
  Node default_v;
1233
25695
  for (size_t i = 0; i < m->d_uf_terms[f].size(); i++)
1234
  {
1235
41598
    Node un = m->d_uf_terms[f][i];
1236
41598
    vector<TNode> children;
1237
20799
    children.push_back(f);
1238
20799
    Trace("model-builder-debug") << "  process term : " << un << std::endl;
1239
104716
    for (size_t j = 0; j < un.getNumChildren(); ++j)
1240
    {
1241
167834
      Node rc = m->getRepresentative(un[j]);
1242
167834
      Trace("model-builder-debug2") << "    get rep : " << un[j] << " returned "
1243
83917
                                    << rc << std::endl;
1244
83917
      Assert(rc.isConst());
1245
83917
      children.push_back(rc);
1246
    }
1247
41598
    Node simp = NodeManager::currentNM()->mkNode(un.getKind(), children);
1248
41598
    Node v = m->getRepresentative(un);
1249
41598
    Trace("model-builder") << "  Setting (" << simp << ") to (" << v << ")"
1250
20799
                           << endl;
1251
20799
    ufmt.setValue(m, simp, v);
1252
20799
    default_v = v;
1253
  }
1254
4896
  if (default_v.isNull())
1255
  {
1256
    // choose default value from model if none exists
1257
    TypeEnumerator te(f.getType().getRangeType());
1258
    default_v = (*te);
1259
  }
1260
4896
  ufmt.setDefaultValue(m, default_v);
1261
4896
  bool condenseFuncValues = options().theory.condenseFunctionValues;
1262
4896
  if (condenseFuncValues)
1263
  {
1264
4896
    ufmt.simplify();
1265
  }
1266
9792
  std::stringstream ss;
1267
4896
  ss << "_arg_";
1268
9792
  Node val = ufmt.getFunctionValue(ss.str().c_str(), condenseFuncValues);
1269
4896
  m->assignFunctionDefinition(f, val);
1270
  // ufmt.debugPrint( std::cout, m );
1271
4896
}
1272
1273
366
void TheoryEngineModelBuilder::assignHoFunction(TheoryModel* m, Node f)
1274
{
1275
366
  Assert(logicInfo().isHigherOrder());
1276
732
  TypeNode type = f.getType();
1277
732
  std::vector<TypeNode> argTypes = type.getArgTypes();
1278
732
  std::vector<Node> args;
1279
732
  std::vector<TNode> apply_args;
1280
839
  for (unsigned i = 0; i < argTypes.size(); i++)
1281
  {
1282
946
    Node v = NodeManager::currentNM()->mkBoundVar(argTypes[i]);
1283
473
    args.push_back(v);
1284
473
    if (i > 0)
1285
    {
1286
107
      apply_args.push_back(v);
1287
    }
1288
  }
1289
  // start with the base return value (currently we use the same default value
1290
  // for all functions)
1291
732
  TypeEnumerator te(type.getRangeType());
1292
732
  Node curr = (*te);
1293
366
  std::map<Node, std::vector<Node> >::iterator itht = m->d_ho_uf_terms.find(f);
1294
366
  if (itht != m->d_ho_uf_terms.end())
1295
  {
1296
1573
    for (size_t i = 0; i < itht->second.size(); i++)
1297
    {
1298
2414
      Node hn = itht->second[i];
1299
1207
      Trace("model-builder-debug") << "    process : " << hn << std::endl;
1300
1207
      Assert(hn.getKind() == kind::HO_APPLY);
1301
1207
      Assert(m->areEqual(hn[0], f));
1302
2414
      Node hni = m->getRepresentative(hn[1]);
1303
2414
      Trace("model-builder-debug2") << "      get rep : " << hn[0]
1304
1207
                                    << " returned " << hni << std::endl;
1305
1207
      Assert(hni.isConst());
1306
1207
      Assert(hni.getType().isSubtypeOf(args[0].getType()));
1307
1207
      hni = rewrite(args[0].eqNode(hni));
1308
2414
      Node hnv = m->getRepresentative(hn);
1309
2414
      Trace("model-builder-debug2") << "      get rep val : " << hn
1310
1207
                                    << " returned " << hnv << std::endl;
1311
1207
      Assert(hnv.isConst());
1312
1207
      if (!apply_args.empty())
1313
      {
1314
244
        Assert(hnv.getKind() == kind::LAMBDA
1315
               && hnv[0].getNumChildren() + 1 == args.size());
1316
488
        std::vector<TNode> largs;
1317
528
        for (unsigned j = 0; j < hnv[0].getNumChildren(); j++)
1318
        {
1319
284
          largs.push_back(hnv[0][j]);
1320
        }
1321
244
        Assert(largs.size() == apply_args.size());
1322
244
        hnv = hnv[1].substitute(
1323
            largs.begin(), largs.end(), apply_args.begin(), apply_args.end());
1324
244
        hnv = rewrite(hnv);
1325
      }
1326
1207
      Assert(!TypeNode::leastCommonTypeNode(hnv.getType(), curr.getType())
1327
                  .isNull());
1328
1207
      curr = NodeManager::currentNM()->mkNode(kind::ITE, hni, hnv, curr);
1329
    }
1330
  }
1331
  Node val = NodeManager::currentNM()->mkNode(
1332
      kind::LAMBDA,
1333
732
      NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args),
1334
1464
      curr);
1335
366
  m->assignFunctionDefinition(f, val);
1336
366
}
1337
1338
// This struct is used to sort terms by the "size" of their type
1339
//   The size of the type is the number of nodes in the type, for example
1340
//  size of Int is 1
1341
//  size of Function( Int, Int ) is 3
1342
//  size of Function( Function( Bool, Int ), Int ) is 5
1343
5220
struct sortTypeSize
1344
{
1345
  // stores the size of the type
1346
  std::map<TypeNode, unsigned> d_type_size;
1347
  // get the size of type tn
1348
3704
  unsigned getTypeSize(TypeNode tn)
1349
  {
1350
3704
    std::map<TypeNode, unsigned>::iterator it = d_type_size.find(tn);
1351
3704
    if (it != d_type_size.end())
1352
    {
1353
2817
      return it->second;
1354
    }
1355
    else
1356
    {
1357
887
      unsigned sum = 1;
1358
2141
      for (unsigned i = 0; i < tn.getNumChildren(); i++)
1359
      {
1360
1254
        sum += getTypeSize(tn[i]);
1361
      }
1362
887
      d_type_size[tn] = sum;
1363
887
      return sum;
1364
    }
1365
  }
1366
1367
 public:
1368
  // compares the type size of i and j
1369
  // returns true iff the size of i is less than that of j
1370
  // tiebreaks are determined by node value
1371
1225
  bool operator()(Node i, Node j)
1372
  {
1373
1225
    int si = getTypeSize(i.getType());
1374
1225
    int sj = getTypeSize(j.getType());
1375
1225
    if (si < sj)
1376
    {
1377
255
      return true;
1378
    }
1379
970
    else if (si == sj)
1380
    {
1381
859
      return i < j;
1382
    }
1383
    else
1384
    {
1385
111
      return false;
1386
    }
1387
  }
1388
};
1389
1390
24989
void TheoryEngineModelBuilder::assignFunctions(TheoryModel* m)
1391
{
1392
24989
  if (!options().theory.assignFunctionValues)
1393
  {
1394
    return;
1395
  }
1396
24989
  Trace("model-builder") << "Assigning function values..." << std::endl;
1397
49978
  std::vector<Node> funcs_to_assign = m->getFunctionsToAssign();
1398
1399
24989
  if (logicInfo().isHigherOrder())
1400
  {
1401
    // sort based on type size if higher-order
1402
365
    Trace("model-builder") << "Sort functions by type..." << std::endl;
1403
730
    sortTypeSize sts;
1404
365
    std::sort(funcs_to_assign.begin(), funcs_to_assign.end(), sts);
1405
  }
1406
1407
24989
  if (Trace.isOn("model-builder"))
1408
  {
1409
    Trace("model-builder") << "...have " << funcs_to_assign.size()
1410
                           << " functions to assign:" << std::endl;
1411
    for (unsigned k = 0; k < funcs_to_assign.size(); k++)
1412
    {
1413
      Node f = funcs_to_assign[k];
1414
      Trace("model-builder") << "  [" << k << "] : " << f << " : "
1415
                             << f.getType() << std::endl;
1416
    }
1417
  }
1418
1419
  // construct function values
1420
30251
  for (unsigned k = 0; k < funcs_to_assign.size(); k++)
1421
  {
1422
10524
    Node f = funcs_to_assign[k];
1423
5262
    Trace("model-builder") << "  Function #" << k << " is " << f << std::endl;
1424
    // std::map< Node, std::vector< Node > >::iterator itht =
1425
    // m->d_ho_uf_terms.find( f );
1426
5262
    if (!logicInfo().isHigherOrder())
1427
    {
1428
9792
      Trace("model-builder") << "  Assign function value for " << f
1429
4896
                             << " based on APPLY_UF" << std::endl;
1430
4896
      assignFunction(m, f);
1431
    }
1432
    else
1433
    {
1434
732
      Trace("model-builder") << "  Assign function value for " << f
1435
366
                             << " based on curried HO_APPLY" << std::endl;
1436
366
      assignHoFunction(m, f);
1437
    }
1438
  }
1439
24989
  Trace("model-builder") << "Finished assigning function values." << std::endl;
1440
}
1441
1442
}  // namespace theory
1443
31137
}  // namespace cvc5