GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model_builder.cpp Lines: 628 672 93.5 %
Date: 2021-09-17 Branches: 1217 2859 42.6 %

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