GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model_builder.cpp Lines: 629 667 94.3 %
Date: 2021-05-22 Branches: 1227 2795 43.9 %

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 "options/quantifiers_options.h"
20
#include "options/smt_options.h"
21
#include "options/theory_options.h"
22
#include "options/uf_options.h"
23
#include "theory/rewriter.h"
24
#include "theory/uf/theory_uf_model.h"
25
26
using namespace std;
27
using namespace cvc5::kind;
28
using namespace cvc5::context;
29
30
namespace cvc5 {
31
namespace theory {
32
33
8
void TheoryEngineModelBuilder::Assigner::initialize(
34
    TypeNode tn, TypeEnumeratorProperties* tep, const std::vector<Node>& aes)
35
{
36
8
  d_te.reset(new TypeEnumerator(tn, tep));
37
8
  d_assignExcSet.insert(d_assignExcSet.end(), aes.begin(), aes.end());
38
8
}
39
40
43
Node TheoryEngineModelBuilder::Assigner::getNextAssignment()
41
{
42
43
  Assert(d_te != nullptr);
43
86
  Node n;
44
43
  bool success = false;
45
43
  TypeEnumerator& te = *d_te;
46
  // Check if we have run out of elements. This should never happen; if it
47
  // does we assert false and return null.
48
43
  if (te.isFinished())
49
  {
50
    Assert(false);
51
    return Node::null();
52
  }
53
  // must increment until we find one that is not in the assignment
54
  // exclusion set
55
17
  do
56
  {
57
60
    n = *te;
58
60
    success = std::find(d_assignExcSet.begin(), d_assignExcSet.end(), n)
59
120
              == d_assignExcSet.end();
60
    // increment regardless of fail or succeed, to set up the next value
61
60
    ++te;
62
60
  } while (!success);
63
43
  return n;
64
}
65
66
12506
TheoryEngineModelBuilder::TheoryEngineModelBuilder() {}
67
68
244427
Node TheoryEngineModelBuilder::evaluateEqc(TheoryModel* m, TNode r)
69
{
70
244427
  eq::EqClassIterator eqc_i = eq::EqClassIterator(r, m->d_equalityEngine);
71
258951
  for (; !eqc_i.isFinished(); ++eqc_i)
72
  {
73
253830
    Node n = *eqc_i;
74
246568
    Trace("model-builder-debug") << "Look at term : " << n << std::endl;
75
246568
    if (!isAssignable(n))
76
    {
77
245886
      Trace("model-builder-debug") << "...try to normalize" << std::endl;
78
252466
      Node normalized = normalize(m, n, true);
79
245886
      if (normalized.isConst())
80
      {
81
239306
        return normalized;
82
      }
83
    }
84
  }
85
5121
  return Node::null();
86
}
87
88
43
bool TheoryEngineModelBuilder::isAssignerActive(TheoryModel* tm, Assigner& a)
89
{
90
43
  if (a.d_isActive)
91
  {
92
35
    return true;
93
  }
94
8
  std::vector<Node>& eset = a.d_assignExcSet;
95
8
  std::map<Node, Node>::iterator it;
96
26
  for (unsigned i = 0, size = eset.size(); i < size; i++)
97
  {
98
    // Members of exclusion set must have values, otherwise we are not yet
99
    // assignable.
100
23
    Node er = eset[i];
101
18
    if (er.isConst())
102
    {
103
      // already processed
104
13
      continue;
105
    }
106
    // Assignable members of assignment exclusion set should be representatives
107
    // of their equivalence classes. This ensures we look up the constant
108
    // representatives for assignable members of assignment exclusion sets.
109
5
    Assert(er == tm->getRepresentative(er));
110
5
    it = d_constantReps.find(er);
111
5
    if (it == d_constantReps.end())
112
    {
113
      Trace("model-build-aes")
114
          << "isAssignerActive: not active due to " << er << std::endl;
115
      return false;
116
    }
117
    // update
118
5
    eset[i] = it->second;
119
  }
120
8
  Trace("model-build-aes") << "isAssignerActive: active!" << std::endl;
121
8
  a.d_isActive = true;
122
8
  return true;
123
}
124
125
2404675
bool TheoryEngineModelBuilder::isAssignable(TNode n)
126
{
127
2404675
  if (n.getKind() == kind::SELECT || n.getKind() == kind::APPLY_SELECTOR_TOTAL)
128
  {
129
    // selectors are always assignable (where we guarantee that they are not
130
    // evaluatable here)
131
222821
    if (!options::ufHo())
132
    {
133
204679
      Assert(!n.getType().isFunction());
134
204679
      return true;
135
    }
136
    else
137
    {
138
      // might be a function field
139
18142
      return !n.getType().isFunction();
140
    }
141
  }
142
2181854
  else if (n.getKind() == kind::FLOATINGPOINT_COMPONENT_SIGN)
143
  {
144
    // Extracting the sign of a floating-point number acts similar to a
145
    // selector on a datatype, i.e. if `(sign x)` wasn't assigned a value, we
146
    // can pick an arbitrary one. Note that the other components of a
147
    // floating-point number should always be assigned a value.
148
1220
    return true;
149
  }
150
  else
151
  {
152
    // non-function variables, and fully applied functions
153
2180634
    if (!options::ufHo())
154
    {
155
      // no functions exist, all functions are fully applied
156
2119297
      Assert(n.getKind() != kind::HO_APPLY);
157
2119297
      Assert(!n.getType().isFunction());
158
2119297
      return n.isVar() || n.getKind() == kind::APPLY_UF;
159
    }
160
    else
161
    {
162
      // Assert( n.getKind() != kind::APPLY_UF );
163
136637
      return (n.isVar() && !n.getType().isFunction())
164
54635
             || n.getKind() == kind::APPLY_UF
165
188433
             || (n.getKind() == kind::HO_APPLY
166
66621
                 && n[0].getType().getNumChildren() == 2);
167
    }
168
  }
169
}
170
171
2653318
void TheoryEngineModelBuilder::addAssignableSubterms(TNode n,
172
                                                     TheoryModel* tm,
173
                                                     NodeSet& cache)
174
{
175
2653318
  if (n.isClosure())
176
  {
177
31021
    return;
178
  }
179
2622297
  if (cache.find(n) != cache.end())
180
  {
181
1373855
    return;
182
  }
183
1248442
  if (isAssignable(n))
184
  {
185
377423
    tm->d_equalityEngine->addTerm(n);
186
  }
187
2680219
  for (TNode::iterator child_it = n.begin(); child_it != n.end(); ++child_it)
188
  {
189
1431777
    addAssignableSubterms(*child_it, tm, cache);
190
  }
191
1248442
  cache.insert(n);
192
}
193
194
592068
void TheoryEngineModelBuilder::assignConstantRep(TheoryModel* tm,
195
                                                 Node eqc,
196
                                                 Node constRep)
197
{
198
592068
  d_constantReps[eqc] = constRep;
199
1184136
  Trace("model-builder") << "    Assign: Setting constant rep of " << eqc
200
592068
                         << " to " << constRep << endl;
201
592068
  tm->d_rep_set.setTermForRepresentative(constRep, eqc);
202
592068
}
203
204
51
bool TheoryEngineModelBuilder::isExcludedCdtValue(
205
    Node val,
206
    std::set<Node>* repSet,
207
    std::map<Node, Node>& assertedReps,
208
    Node eqc)
209
{
210
102
  Trace("model-builder-debug")
211
51
      << "Is " << val << " and excluded codatatype value for " << eqc << "? "
212
51
      << std::endl;
213
111
  for (set<Node>::iterator i = repSet->begin(); i != repSet->end(); ++i)
214
  {
215
68
    Assert(assertedReps.find(*i) != assertedReps.end());
216
128
    Node rep = assertedReps[*i];
217
68
    Trace("model-builder-debug") << "  Rep : " << rep << std::endl;
218
    // check matching val to rep with eqc as a free variable
219
128
    Node eqc_m;
220
68
    if (isCdtValueMatch(val, rep, eqc, eqc_m))
221
    {
222
40
      Trace("model-builder-debug") << "  ...matches with " << eqc << " -> "
223
20
                                   << eqc_m << std::endl;
224
20
      if (eqc_m.getKind() == kind::UNINTERPRETED_CONSTANT)
225
      {
226
16
        Trace("model-builder-debug") << "*** " << val
227
8
                                     << " is excluded datatype for " << eqc
228
8
                                     << std::endl;
229
8
        return true;
230
      }
231
    }
232
  }
233
43
  return false;
234
}
235
236
184
bool TheoryEngineModelBuilder::isCdtValueMatch(Node v,
237
                                               Node r,
238
                                               Node eqc,
239
                                               Node& eqc_m)
240
{
241
184
  if (r == v)
242
  {
243
52
    return true;
244
  }
245
132
  else if (r == eqc)
246
  {
247
20
    if (eqc_m.isNull())
248
    {
249
      // only if an uninterpreted constant?
250
20
      eqc_m = v;
251
20
      return true;
252
    }
253
    else
254
    {
255
      return v == eqc_m;
256
    }
257
  }
258
224
  else if (v.getKind() == kind::APPLY_CONSTRUCTOR
259
112
           && r.getKind() == kind::APPLY_CONSTRUCTOR)
260
  {
261
74
    if (v.getOperator() == r.getOperator())
262
    {
263
136
      for (unsigned i = 0; i < v.getNumChildren(); i++)
264
      {
265
116
        if (!isCdtValueMatch(v[i], r[i], eqc, eqc_m))
266
        {
267
44
          return false;
268
        }
269
      }
270
20
      return true;
271
    }
272
  }
273
48
  return false;
274
}
275
276
17655
bool TheoryEngineModelBuilder::isFiniteType(TypeNode tn) const
277
{
278
17655
  return isCardinalityClassFinite(tn.getCardinalityClass(),
279
35310
                                  options::finiteModelFind());
280
}
281
282
21197
bool TheoryEngineModelBuilder::involvesUSort(TypeNode tn) const
283
{
284
21197
  if (tn.isSort())
285
  {
286
4
    return true;
287
  }
288
21193
  else if (tn.isArray())
289
  {
290
6
    return involvesUSort(tn.getArrayIndexType())
291
6
           || involvesUSort(tn.getArrayConstituentType());
292
  }
293
21191
  else if (tn.isSet())
294
  {
295
4
    return involvesUSort(tn.getSetElementType());
296
  }
297
21187
  else if (tn.isDatatype())
298
  {
299
21032
    const DType& dt = tn.getDType();
300
21032
    return dt.involvesUninterpretedType();
301
  }
302
  else
303
  {
304
155
    return false;
305
  }
306
}
307
308
88825
bool TheoryEngineModelBuilder::isExcludedUSortValue(
309
    std::map<TypeNode, unsigned>& eqc_usort_count,
310
    Node v,
311
    std::map<Node, bool>& visited)
312
{
313
88825
  Assert(v.isConst());
314
88825
  if (visited.find(v) == visited.end())
315
  {
316
65015
    visited[v] = true;
317
129844
    TypeNode tn = v.getType();
318
65015
    if (tn.isSort())
319
    {
320
372
      Trace("model-builder-debug") << "Is excluded usort value : " << v << " "
321
186
                                   << tn << std::endl;
322
186
      unsigned card = eqc_usort_count[tn];
323
186
      Trace("model-builder-debug") << "  Cardinality is " << card << std::endl;
324
      unsigned index =
325
186
          v.getConst<UninterpretedConstant>().getIndex().toUnsignedInt();
326
186
      Trace("model-builder-debug") << "  Index is " << index << std::endl;
327
186
      return index > 0 && index >= card;
328
    }
329
140414
    for (unsigned i = 0; i < v.getNumChildren(); i++)
330
    {
331
75585
      if (isExcludedUSortValue(eqc_usort_count, v[i], visited))
332
      {
333
        return true;
334
      }
335
    }
336
  }
337
88639
  return false;
338
}
339
340
353927
void TheoryEngineModelBuilder::addToTypeList(
341
    TypeNode tn,
342
    std::vector<TypeNode>& type_list,
343
    std::unordered_set<TypeNode>& visiting)
344
{
345
353927
  if (std::find(type_list.begin(), type_list.end(), tn) == type_list.end())
346
  {
347
77801
    if (visiting.find(tn) == visiting.end())
348
    {
349
29502
      visiting.insert(tn);
350
      /* This must make a recursive call on all types that are subterms of
351
       * values of the current type.
352
       * Note that recursive traversal here is over enumerated expressions
353
       * (very low expression depth). */
354
29502
      if (tn.isArray())
355
      {
356
409
        addToTypeList(tn.getArrayIndexType(), type_list, visiting);
357
409
        addToTypeList(tn.getArrayConstituentType(), type_list, visiting);
358
      }
359
29093
      else if (tn.isSet())
360
      {
361
334
        addToTypeList(tn.getSetElementType(), type_list, visiting);
362
      }
363
28759
      else if (tn.isDatatype())
364
      {
365
13780
        const DType& dt = tn.getDType();
366
93062
        for (unsigned i = 0; i < dt.getNumConstructors(); i++)
367
        {
368
150799
          for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
369
          {
370
143034
            TypeNode ctn = dt[i][j].getRangeType();
371
71517
            addToTypeList(ctn, type_list, visiting);
372
          }
373
        }
374
      }
375
29502
      Assert(std::find(type_list.begin(), type_list.end(), tn)
376
             == type_list.end());
377
29502
      type_list.push_back(tn);
378
    }
379
  }
380
353927
}
381
382
15249
bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm)
383
{
384
15249
  Trace("model-builder") << "TheoryEngineModelBuilder: buildModel" << std::endl;
385
386
30498
  Trace("model-builder")
387
15249
      << "TheoryEngineModelBuilder: Preprocess build model..." << std::endl;
388
  // model-builder specific initialization
389
15249
  if (!preProcessBuildModel(tm))
390
  {
391
    Trace("model-builder")
392
        << "TheoryEngineModelBuilder: fail preprocess build model."
393
        << std::endl;
394
    return false;
395
  }
396
397
30498
  Trace("model-builder")
398
      << "TheoryEngineModelBuilder: Add assignable subterms "
399
15249
         ", collect representatives and compute assignable information..."
400
15249
      << std::endl;
401
402
  // type enumerator properties
403
30498
  TypeEnumeratorProperties tep;
404
405
  // In the first step of model building, we do a traversal of the
406
  // equality engine and record the information in the following:
407
408
  // The constant representatives, per equivalence class
409
15249
  d_constantReps.clear();
410
  // The representatives that have been asserted by theories. This includes
411
  // non-constant "skeletons" that have been specified by parametric theories.
412
30498
  std::map<Node, Node> assertedReps;
413
  // A parition of the set of equivalence classes that have:
414
  // (1) constant representatives,
415
  // (2) an assigned representative specified by a theory in collectModelInfo,
416
  // (3) no assigned representative.
417
30498
  TypeSet typeConstSet, typeRepSet, typeNoRepSet;
418
  // An ordered list of types, such that T1 comes before T2 if T1 is a
419
  // "component type" of T2, e.g. U comes before (Set U). This is only strictly
420
  // necessary for finite model finding + parametric types instantiated with
421
  // uninterpreted sorts, but is probably a good idea to do in general since it
422
  // leads to models with smaller term sizes. -AJR
423
30498
  std::vector<TypeNode> type_list;
424
  // The count of equivalence classes per sort (for finite model finding).
425
30498
  std::map<TypeNode, unsigned> eqc_usort_count;
426
427
  // the set of equivalence classes that are "assignable", i.e. those that have
428
  // an assignable expression in them (see isAssignable), and have not already
429
  // been assigned a constant.
430
30498
  std::unordered_set<Node> assignableEqc;
431
  // The set of equivalence classes that are "evaluable", i.e. those that have
432
  // an expression in them that is not assignable, and have not already been
433
  // assigned a constant.
434
30498
  std::unordered_set<Node> evaluableEqc;
435
  // Assigner objects for relevant equivalence classes that require special
436
  // ways of assigning values, e.g. those that take into account assignment
437
  // exclusion sets.
438
30498
  std::map<Node, Assigner> eqcToAssigner;
439
  // A map from equivalence classes to the equivalence class that it shares an
440
  // assigner object with (all elements in the range of this map are in the
441
  // domain of eqcToAssigner).
442
30498
  std::map<Node, Node> eqcToAssignerMaster;
443
444
  // Loop through equivalence classes of the equality engine of the model.
445
15249
  eq::EqualityEngine* ee = tm->d_equalityEngine;
446
30498
  NodeSet assignableCache;
447
15249
  std::map<Node, Node>::iterator itm;
448
15249
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
449
  // should we compute assigner objects?
450
15249
  bool computeAssigners = tm->hasAssignmentExclusionSets();
451
  // the set of exclusion sets we have processed
452
30498
  std::unordered_set<Node> processedExcSet;
453
1201691
  for (; !eqcs_i.isFinished(); ++eqcs_i)
454
  {
455
874479
    Node eqc = *eqcs_i;
456
457
    // Information computed for each equivalence class
458
459
    // The assigned represenative and constant representative
460
874479
    Node rep, constRep;
461
    // A flag set to true if the current equivalence class is assignable (see
462
    // assignableEqc).
463
593221
    bool assignable = false;
464
    // Set to true if the current equivalence class is evaluatable (see
465
    // evaluableEqc).
466
593221
    bool evaluable = false;
467
    // Set to true if a term in the current equivalence class has been given an
468
    // assignment exclusion set.
469
593221
    bool hasESet CVC5_UNUSED = false;
470
    // Set to true if we found that a term in the current equivalence class has
471
    // been given an assignment exclusion set, and we have not seen this term
472
    // as part of a previous assignment exclusion group. In other words, when
473
    // this flag is true we construct a new assigner object with the current
474
    // equivalence class as its master.
475
593221
    bool foundESet = false;
476
    // The assignment exclusion set for the current equivalence class.
477
874479
    std::vector<Node> eset;
478
    // The group to which this equivalence class belongs when exclusion sets
479
    // were assigned (see the argument group of
480
    // TheoryModel::getAssignmentExclusionSet).
481
874479
    std::vector<Node> esetGroup;
482
483
    // Loop through terms in this EC
484
593221
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, ee);
485
3036303
    for (; !eqc_i.isFinished(); ++eqc_i)
486
    {
487
1221719
      Node n = *eqc_i;
488
1221541
      Trace("model-builder") << "  Processing Term: " << n << endl;
489
490
      // For each term n in this equivalence class, below we register its
491
      // assignable subterms, compute whether it is a constant or assigned
492
      // representative, then if we don't have a constant representative,
493
      // compute information regarding how we will assign values.
494
495
      // (1) Add assignable subterms, which ensures that e.g. models for
496
      // uninterpreted functions take into account all subterms in the
497
      // equality engine of the model
498
1221541
      addAssignableSubterms(n, tm, assignableCache);
499
      // model-specific processing of the term
500
1221541
      tm->addTermInternal(n);
501
502
      // (2) Record constant representative or assign representative, if
503
      // applicable
504
1533504
      if (n.isConst())
505
      {
506
311963
        Assert(constRep.isNull());
507
311963
        constRep = n;
508
623926
        Trace("model-builder")
509
311963
            << "  ConstRep( " << eqc << " ) = " << constRep << std::endl;
510
        // if we have a constant representative, nothing else matters
511
311963
        continue;
512
      }
513
514
      // If we don't have a constant rep, check if this is an assigned rep.
515
909578
      itm = tm->d_reps.find(n);
516
909578
      if (itm != tm->d_reps.end())
517
      {
518
        // Notice that this equivalence class may contain multiple terms that
519
        // were specified as being a representative, since e.g. datatypes may
520
        // assert representative for two constructor terms that are not in the
521
        // care graph and are merged during collectModeInfo due to equality
522
        // information from another theory. We overwrite the value of rep in
523
        // these cases here.
524
18040
        rep = itm->second;
525
36080
        Trace("model-builder")
526
18040
            << "  Rep( " << eqc << " ) = " << rep << std::endl;
527
      }
528
529
      // (3) Finally, process assignable information
530
1441733
      if (!isAssignable(n))
531
      {
532
532155
        evaluable = true;
533
        // expressions that are not assignable should not be given assignment
534
        // exclusion sets
535
532155
        Assert(!tm->getAssignmentExclusionSet(n, esetGroup, eset));
536
532155
        continue;
537
      }
538
377423
      assignable = true;
539
377423
      if (!computeAssigners)
540
      {
541
        // we don't compute assigners, skip
542
377210
        continue;
543
      }
544
      // process the assignment exclusion set for term n
545
      // was it processed based on a master exclusion group (see
546
      // eqcToAssignerMaster)?
547
248
      if (processedExcSet.find(n) != processedExcSet.end())
548
      {
549
        // Should not have two assignment exclusion sets for the same
550
        // equivalence class
551
35
        Assert(!hasESet);
552
35
        Assert(eqcToAssignerMaster.find(eqc) != eqcToAssignerMaster.end());
553
        // already processed as a slave term
554
35
        hasESet = true;
555
35
        continue;
556
      }
557
      // was it assigned one?
558
178
      if (tm->getAssignmentExclusionSet(n, esetGroup, eset))
559
      {
560
        // Should not have two assignment exclusion sets for the same
561
        // equivalence class
562
8
        Assert(!hasESet);
563
8
        foundESet = true;
564
8
        hasESet = true;
565
      }
566
    }
567
568
    // finished traversing the equality engine
569
874479
    TypeNode eqct = eqc.getType();
570
    // count the number of equivalence classes of sorts in finite model finding
571
593221
    if (options::finiteModelFind())
572
    {
573
33188
      if (eqct.isSort())
574
      {
575
4520
        eqc_usort_count[eqct]++;
576
      }
577
    }
578
    // Assign representative for this equivalence class
579
905184
    if (!constRep.isNull())
580
    {
581
      // Theories should not specify a rep if there is already a constant in the
582
      // equivalence class. However, it may be the case that the representative
583
      // specified by a theory may be merged with a constant based on equality
584
      // information from another class. Thus, rep may be non-null here.
585
      // Regardless, we assign constRep as the representative here.
586
311963
      assignConstantRep(tm, eqc, constRep);
587
311963
      typeConstSet.add(eqct.getBaseType(), constRep);
588
311963
      continue;
589
    }
590
281258
    else if (!rep.isNull())
591
    {
592
17991
      assertedReps[eqc] = rep;
593
17991
      typeRepSet.add(eqct.getBaseType(), eqc);
594
35982
      std::unordered_set<TypeNode> visiting;
595
17991
      addToTypeList(eqct.getBaseType(), type_list, visiting);
596
    }
597
    else
598
    {
599
263267
      typeNoRepSet.add(eqct, eqc);
600
526534
      std::unordered_set<TypeNode> visiting;
601
263267
      addToTypeList(eqct, type_list, visiting);
602
    }
603
604
281258
    if (assignable)
605
    {
606
37289
      assignableEqc.insert(eqc);
607
    }
608
281258
    if (evaluable)
609
    {
610
258467
      evaluableEqc.insert(eqc);
611
    }
612
    // If we found an assignment exclusion set, we construct a new assigner
613
    // object.
614
281258
    if (foundESet)
615
    {
616
      // we don't accept assignment exclusion sets for evaluable eqc
617
8
      Assert(!evaluable);
618
      // construct the assigner
619
8
      Assigner& a = eqcToAssigner[eqc];
620
      // Take the representatives of each term in the assignment exclusion
621
      // set, which ensures we can look up their value in d_constReps later.
622
16
      std::vector<Node> aes;
623
26
      for (const Node& e : eset)
624
      {
625
        // Should only supply terms that occur in the model or constants
626
        // in assignment exclusion sets.
627
18
        Assert(tm->hasTerm(e) || e.isConst());
628
36
        Node er = tm->hasTerm(e) ? tm->getRepresentative(e) : e;
629
18
        aes.push_back(er);
630
      }
631
      // initialize
632
8
      a.initialize(eqc.getType(), &tep, aes);
633
      // all others in the group are slaves of this
634
51
      for (const Node& g : esetGroup)
635
      {
636
43
        Assert(isAssignable(g));
637
43
        if (!tm->hasTerm(g))
638
        {
639
          // Ignore those that aren't in the model, in the case the user
640
          // has supplied an assignment exclusion set to a variable not in
641
          // the model.
642
          continue;
643
        }
644
86
        Node gr = tm->getRepresentative(g);
645
43
        if (gr != eqc)
646
        {
647
35
          eqcToAssignerMaster[gr] = eqc;
648
          // remember that this term has been processed
649
35
          processedExcSet.insert(g);
650
        }
651
      }
652
    }
653
  }
654
655
  // Now finished initialization
656
657
  // Compute type enumerator properties. This code ensures we do not
658
  // enumerate terms that have uninterpreted constants that violate the
659
  // bounds imposed by finite model finding. For example, if finite
660
  // model finding insists that there are only 2 values { U1, U2 } of type U,
661
  // then the type enumerator for list of U should enumerate:
662
  //   nil, (cons U1 nil), (cons U2 nil), (cons U1 (cons U1 nil)), ...
663
  // instead of enumerating (cons U3 nil).
664
15249
  if (options::finiteModelFind())
665
  {
666
1015
    tep.d_fixed_usort_card = true;
667
3385
    for (std::map<TypeNode, unsigned>::iterator it = eqc_usort_count.begin();
668
3385
         it != eqc_usort_count.end();
669
         ++it)
670
    {
671
4740
      Trace("model-builder") << "Fixed bound (#eqc) for " << it->first << " : "
672
2370
                             << it->second << std::endl;
673
2370
      tep.d_fixed_card[it->first] = Integer(it->second);
674
    }
675
1015
    typeConstSet.setTypeEnumeratorProperties(&tep);
676
  }
677
678
  // Need to ensure that each EC has a constant representative.
679
680
15249
  Trace("model-builder") << "Processing EC's..." << std::endl;
681
682
15249
  TypeSet::iterator it;
683
15249
  vector<TypeNode>::iterator type_it;
684
15249
  set<Node>::iterator i, i2;
685
15249
  bool changed, unassignedAssignable, assignOne = false;
686
30498
  set<TypeNode> evaluableSet;
687
688
  // Double-fixed-point loop
689
  // Outer loop handles a special corner case (see code at end of loop for
690
  // details)
691
  for (;;)
692
  {
693
    // Inner fixed-point loop: we are trying to learn constant values for every
694
    // EC.  Each time through this loop, we process all of the
695
    // types by type and may learn some new EC values.  EC's in one type may
696
    // depend on EC's in another type, so we need a fixed-point loop
697
    // to ensure that we learn as many EC values as possible
698
47553
    do
699
    {
700
47553
      changed = false;
701
47553
      unassignedAssignable = false;
702
47553
      evaluableSet.clear();
703
704
      // Iterate over all types we've seen
705
278137
      for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
706
      {
707
461168
        TypeNode t = *type_it;
708
461168
        TypeNode tb = t.getBaseType();
709
230584
        set<Node>* noRepSet = typeNoRepSet.getSet(t);
710
711
        // 1. Try to evaluate the EC's in this type
712
230584
        if (noRepSet != NULL && !noRepSet->empty())
713
        {
714
93016
          Trace("model-builder") << "  Eval phase, working on type: " << t
715
46508
                                 << endl;
716
          bool evaluable;
717
46508
          d_normalizedCache.clear();
718
1476536
          for (i = noRepSet->begin(); i != noRepSet->end();)
719
          {
720
1430028
            i2 = i;
721
1430028
            ++i;
722
2860056
            Trace("model-builder-debug") << "Look at eqc : " << (*i2)
723
1430028
                                         << std::endl;
724
2860056
            Node normalized;
725
            // only possible to normalize if we are evaluable
726
1430028
            evaluable = evaluableEqc.find(*i2) != evaluableEqc.end();
727
1430028
            if (evaluable)
728
            {
729
244427
              normalized = evaluateEqc(tm, *i2);
730
            }
731
1430028
            if (!normalized.isNull())
732
            {
733
239306
              Assert(normalized.isConst());
734
239306
              typeConstSet.add(tb, normalized);
735
239306
              assignConstantRep(tm, *i2, normalized);
736
478612
              Trace("model-builder") << "    Eval: Setting constant rep of "
737
239306
                                     << (*i2) << " to " << normalized << endl;
738
239306
              changed = true;
739
239306
              noRepSet->erase(i2);
740
            }
741
            else
742
            {
743
1190722
              if (evaluable)
744
              {
745
5121
                evaluableSet.insert(tb);
746
              }
747
              // If assignable, remember there is an equivalence class that is
748
              // not assigned and assignable.
749
1190722
              if (assignableEqc.find(*i2) != assignableEqc.end())
750
              {
751
1185694
                unassignedAssignable = true;
752
              }
753
            }
754
          }
755
        }
756
757
        // 2. Normalize any non-const representative terms for this type
758
230584
        set<Node>* repSet = typeRepSet.getSet(t);
759
230584
        if (repSet != NULL && !repSet->empty())
760
        {
761
102150
          Trace("model-builder")
762
51075
              << "  Normalization phase, working on type: " << t << endl;
763
51075
          d_normalizedCache.clear();
764
529561
          for (i = repSet->begin(); i != repSet->end();)
765
          {
766
478486
            Assert(assertedReps.find(*i) != assertedReps.end());
767
956972
            Node rep = assertedReps[*i];
768
956972
            Node normalized = normalize(tm, rep, false);
769
956972
            Trace("model-builder") << "    Normalizing rep (" << rep
770
478486
                                   << "), normalized to (" << normalized << ")"
771
478486
                                   << endl;
772
478486
            if (normalized.isConst())
773
            {
774
17991
              changed = true;
775
17991
              typeConstSet.add(tb, normalized);
776
17991
              assignConstantRep(tm, *i, normalized);
777
17991
              assertedReps.erase(*i);
778
17991
              i2 = i;
779
17991
              ++i;
780
17991
              repSet->erase(i2);
781
            }
782
            else
783
            {
784
460495
              if (normalized != rep)
785
              {
786
5716
                assertedReps[*i] = normalized;
787
5716
                changed = true;
788
              }
789
460495
              ++i;
790
            }
791
          }
792
        }
793
      }
794
    } while (changed);
795
796
33362
    if (!unassignedAssignable)
797
    {
798
15249
      break;
799
    }
800
801
    // 3. Assign unassigned assignable EC's using type enumeration - assign a
802
    // value *different* from all other EC's if the type is infinite
803
    // Assign first value from type enumerator otherwise - for finite types, we
804
    // rely on polite framework to ensure that EC's that have to be
805
    // different are different.
806
807
    // Only make assignments on a type if:
808
    // 1. there are no terms that share the same base type with un-normalized
809
    // representatives
810
    // 2. there are no terms that share teh same base type that are unevaluated
811
    // evaluable terms
812
    // Alternatively, if 2 or 3 don't hold but we are in a special
813
    // deadlock-breaking mode where assignOne is true, go ahead and make one
814
    // assignment
815
18113
    changed = false;
816
    // must iterate over the ordered type list to ensure that we do not
817
    // enumerate values with subterms
818
    //  having types that we are currently enumerating (when possible)
819
    //  for example, this ensures we enumerate uninterpreted sort U before (List
820
    //  of U) and (Array U U)
821
    //  however, it does not break cyclic type dependencies for mutually
822
    //  recursive datatypes, but this is handled
823
    //  by recording all subterms of enumerated values in TypeSet::addSubTerms.
824
152828
    for (type_it = type_list.begin(); type_it != type_list.end(); ++type_it)
825
    {
826
146933
      TypeNode t = *type_it;
827
      // continue if there are no more equivalence classes of this type to
828
      // assign
829
134715
      std::set<Node>* noRepSetPtr = typeNoRepSet.getSet(t);
830
134715
      if (noRepSetPtr == NULL)
831
      {
832
19788
        continue;
833
      }
834
114927
      set<Node>& noRepSet = *noRepSetPtr;
835
114927
      if (noRepSet.empty())
836
      {
837
88953
        continue;
838
      }
839
840
      // get properties of this type
841
25974
      bool isCorecursive = false;
842
25974
      if (t.isDatatype())
843
      {
844
21397
        const DType& dt = t.getDType();
845
42794
        isCorecursive = dt.isCodatatype()
846
64191
                        && (!isFiniteType(t) || dt.isRecursiveSingleton(t));
847
      }
848
#ifdef CVC5_ASSERTIONS
849
25974
      bool isUSortFiniteRestricted = false;
850
25974
      if (options::finiteModelFind())
851
      {
852
23565
        isUSortFiniteRestricted = !t.isSort() && involvesUSort(t);
853
      }
854
#endif
855
856
38192
      TypeNode tb = t.getBaseType();
857
25974
      if (!assignOne)
858
      {
859
18085
        set<Node>* repSet = typeRepSet.getSet(tb);
860
18085
        if (repSet != NULL && !repSet->empty())
861
        {
862
13159
          continue;
863
        }
864
4926
        if (evaluableSet.find(tb) != evaluableSet.end())
865
        {
866
597
          continue;
867
        }
868
      }
869
24436
      Trace("model-builder") << "  Assign phase, working on type: " << t
870
12218
                             << endl;
871
      bool assignable, evaluable CVC5_UNUSED;
872
12218
      std::map<Node, Assigner>::iterator itAssigner;
873
12218
      std::map<Node, Node>::iterator itAssignerM;
874
12218
      set<Node>* repSet = typeRepSet.getSet(t);
875
27255
      for (i = noRepSet.begin(); i != noRepSet.end();)
876
      {
877
22916
        i2 = i;
878
22916
        ++i;
879
        // check whether it has an assigner object
880
22916
        itAssignerM = eqcToAssignerMaster.find(*i2);
881
22916
        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
22881
          itAssigner = eqcToAssigner.find(*i2);
891
        }
892
22916
        if (itAssigner != eqcToAssigner.end())
893
        {
894
43
          assignable = isAssignerActive(tm, itAssigner->second);
895
        }
896
        else
897
        {
898
22873
          assignable = assignableEqc.find(*i2) != assignableEqc.end();
899
        }
900
22916
        evaluable = evaluableEqc.find(*i2) != evaluableEqc.end();
901
45832
        Trace("model-builder-debug")
902
22916
            << "    eqc " << *i2 << " is assignable=" << assignable
903
22916
            << ", evaluable=" << evaluable << std::endl;
904
22916
        if (assignable)
905
        {
906
22808
          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
22808
          Assert(!t.isBoolean() || isAssignable(*i2));
914
37737
          Node n;
915
22808
          if (itAssigner != eqcToAssigner.end())
916
          {
917
86
            Trace("model-builder-debug")
918
43
                << "Get value from assigner for finite type..." << std::endl;
919
            // if it has an assigner, get the value from the assigner.
920
43
            n = itAssigner->second.getNextAssignment();
921
43
            Assert(!n.isNull());
922
          }
923
22765
          else if (t.isSort() || !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
8
            do
936
            {
937
45346
              Trace("model-builder-debug") << "Enumerate term of type " << t
938
22673
                                           << std::endl;
939
22673
              n = typeConstSet.nextTypeEnum(t, true);
940
              //--- AJR: this code checks whether n is a legal value
941
22673
              Assert(!n.isNull());
942
22673
              success = true;
943
45346
              Trace("model-builder-debug") << "Check if excluded : " << n
944
22673
                                           << std::endl;
945
#ifdef CVC5_ASSERTIONS
946
22673
              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
26480
                std::map<Node, bool> visited;
954
13240
                success = !isExcludedUSortValue(eqc_usort_count, n, visited);
955
13240
                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
13240
                Assert(success);
963
              }
964
#endif
965
22673
              if (success && isCorecursive)
966
              {
967
59
                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
51
                  success = !isExcludedCdtValue(n, repSet, assertedReps, *i2);
972
51
                  if (!success)
973
                  {
974
16
                    Trace("model-builder")
975
8
                        << "Excluded value : " << n
976
8
                        << " due to alpha-equivalent codatatype expression."
977
8
                        << std::endl;
978
                  }
979
                }
980
              }
981
              //---
982
22673
            } while (!success);
983
22665
            Assert(!n.isNull());
984
          }
985
          else
986
          {
987
200
            Trace("model-builder-debug")
988
100
                << "Get first value from finite type..." << std::endl;
989
            // Otherwise, we get the first value from the type enumerator.
990
200
            TypeEnumerator te(t);
991
100
            n = *te;
992
          }
993
22808
          Trace("model-builder-debug") << "...got " << n << std::endl;
994
22808
          assignConstantRep(tm, *i2, n);
995
22808
          changed = true;
996
22808
          noRepSet.erase(i2);
997
22808
          if (assignOne)
998
          {
999
7879
            assignOne = false;
1000
7879
            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
18113
    if (!changed)
1016
    {
1017
7879
      Assert(!assignOne);  // check for infinite loop!
1018
7879
      assignOne = true;
1019
    }
1020
18113
  }
1021
1022
#ifdef CVC5_ASSERTIONS
1023
  // Assert that all representatives have been converted to constants
1024
24198
  for (it = typeRepSet.begin(); it != typeRepSet.end(); ++it)
1025
  {
1026
8949
    set<Node>& repSet = TypeSet::getSet(it);
1027
8949
    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
15249
  Trace("model-builder") << "Copy representatives to model..." << std::endl;
1037
15249
  tm->d_reps.clear();
1038
15249
  std::map<Node, Node>::iterator itMap;
1039
607317
  for (itMap = d_constantReps.begin(); itMap != d_constantReps.end(); ++itMap)
1040
  {
1041
592068
    tm->d_reps[itMap->first] = itMap->second;
1042
592068
    tm->d_rep_set.add(itMap->second.getType(), itMap->second);
1043
  }
1044
1045
15249
  Trace("model-builder") << "Make sure ECs have reps..." << std::endl;
1046
  // Make sure every EC has a rep
1047
15249
  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
30236
  for (it = typeNoRepSet.begin(); it != typeNoRepSet.end(); ++it)
1053
  {
1054
14987
    set<Node>& noRepSet = TypeSet::getSet(it);
1055
16140
    for (const Node& node : noRepSet)
1056
    {
1057
1153
      tm->d_reps[node] = node;
1058
1153
      tm->d_rep_set.add(node.getType(), node);
1059
    }
1060
  }
1061
1062
  // modelBuilder-specific initialization
1063
15249
  if (!processBuildModel(tm))
1064
  {
1065
    Trace("model-builder")
1066
        << "TheoryEngineModelBuilder: fail process build model." << std::endl;
1067
    return false;
1068
  }
1069
15249
  Trace("model-builder") << "TheoryEngineModelBuilder: success" << std::endl;
1070
15249
  return true;
1071
}
1072
1073
848
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
848
  if (incomplete)
1078
  {
1079
43
    return;
1080
  }
1081
805
  Assert(m != nullptr);
1082
  // debug-check the model if the checkModels() is enabled.
1083
805
  if (options::debugCheckModels())
1084
  {
1085
247
    debugCheckModel(m);
1086
  }
1087
}
1088
1089
247
void TheoryEngineModelBuilder::debugCheckModel(TheoryModel* tm)
1090
{
1091
#ifdef CVC5_ASSERTIONS
1092
247
  if (tm->hasApproximations())
1093
  {
1094
    // models with approximations may fail the assertions below
1095
    return;
1096
  }
1097
247
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
1098
247
  std::map<Node, Node>::iterator itMap;
1099
  // Check that every term evaluates to its representative in the model
1100
3748
  for (eqcs_i = eq::EqClassesIterator(tm->d_equalityEngine);
1101
3748
       !eqcs_i.isFinished();
1102
       ++eqcs_i)
1103
  {
1104
    // eqc is the equivalence class representative
1105
7002
    Node eqc = (*eqcs_i);
1106
    // get the representative
1107
7002
    Node rep = tm->getRepresentative(eqc);
1108
3501
    if (!rep.isConst() && eqc.getType().isBoolean())
1109
    {
1110
      // if Boolean, it does not necessarily have a constant representative, use
1111
      // get value instead
1112
      rep = tm->getValue(eqc);
1113
      Assert(rep.isConst());
1114
    }
1115
3501
    eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, tm->d_equalityEngine);
1116
31247
    for (; !eqc_i.isFinished(); ++eqc_i)
1117
    {
1118
27746
      Node n = *eqc_i;
1119
      static int repCheckInstance = 0;
1120
13873
      ++repCheckInstance;
1121
1122
      // non-linear mult is not necessarily accurate wrt getValue
1123
13873
      if (n.getKind() != kind::NONLINEAR_MULT)
1124
      {
1125
27718
        Debug("check-model::rep-checking") << "( " << repCheckInstance << ") "
1126
13859
                                           << "n: " << n << endl
1127
27718
                                           << "getValue(n): " << tm->getValue(n)
1128
13859
                                           << endl
1129
13859
                                           << "rep: " << rep << endl;
1130
13859
        Assert(tm->getValue(*eqc_i) == rep)
1131
            << "run with -d check-model::rep-checking for details";
1132
      }
1133
    }
1134
  }
1135
#endif /* CVC5_ASSERTIONS */
1136
1137
  // builder-specific debugging
1138
247
  debugModel(tm);
1139
}
1140
1141
807050
Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, bool evalOnly)
1142
{
1143
807050
  std::map<Node, Node>::iterator itMap = d_constantReps.find(r);
1144
807050
  if (itMap != d_constantReps.end())
1145
  {
1146
    return (*itMap).second;
1147
  }
1148
807050
  NodeMap::iterator it = d_normalizedCache.find(r);
1149
807050
  if (it != d_normalizedCache.end())
1150
  {
1151
21698
    return (*it).second;
1152
  }
1153
785352
  Trace("model-builder-debug") << "do normalize on " << r << std::endl;
1154
1570704
  Node retNode = r;
1155
785352
  if (r.getNumChildren() > 0)
1156
  {
1157
1559224
    std::vector<Node> children;
1158
779612
    if (r.getMetaKind() == kind::metakind::PARAMETERIZED)
1159
    {
1160
500955
      children.push_back(r.getOperator());
1161
    }
1162
779612
    bool childrenConst = true;
1163
2332665
    for (size_t i = 0; i < r.getNumChildren(); ++i)
1164
    {
1165
3106106
      Node ri = r[i];
1166
1553053
      bool recurse = true;
1167
1553053
      if (!ri.isConst())
1168
      {
1169
1087972
        if (m->d_equalityEngine->hasTerm(ri))
1170
        {
1171
1060535
          itMap =
1172
2121070
              d_constantReps.find(m->d_equalityEngine->getRepresentative(ri));
1173
1060535
          if (itMap != d_constantReps.end())
1174
          {
1175
401266
            ri = (*itMap).second;
1176
401266
            Trace("model-builder-debug") << i << ": const child " << ri << std::endl;
1177
401266
            recurse = false;
1178
          }
1179
659269
          else if (!evalOnly)
1180
          {
1181
604028
            recurse = false;
1182
604028
            Trace("model-builder-debug") << i << ": keep " << ri << std::endl;
1183
          }
1184
        }
1185
        else
1186
        {
1187
27437
          Trace("model-builder-debug") << i << ": no hasTerm " << ri << std::endl;
1188
        }
1189
1087972
        if (recurse)
1190
        {
1191
82678
          ri = normalize(m, ri, evalOnly);
1192
        }
1193
1087972
        if (!ri.isConst())
1194
        {
1195
610154
          childrenConst = false;
1196
        }
1197
      }
1198
1553053
      children.push_back(ri);
1199
    }
1200
779612
    retNode = NodeManager::currentNM()->mkNode(r.getKind(), children);
1201
779612
    if (childrenConst)
1202
    {
1203
313533
      retNode = Rewriter::rewrite(retNode);
1204
    }
1205
  }
1206
785352
  d_normalizedCache[r] = retNode;
1207
785352
  return retNode;
1208
}
1209
1210
3317
bool TheoryEngineModelBuilder::preProcessBuildModel(TheoryModel* m)
1211
{
1212
3317
  return true;
1213
}
1214
1215
15249
bool TheoryEngineModelBuilder::processBuildModel(TheoryModel* m)
1216
{
1217
15249
  if (m->areFunctionValuesEnabled())
1218
  {
1219
15249
    assignFunctions(m);
1220
  }
1221
15249
  return true;
1222
}
1223
1224
5015
void TheoryEngineModelBuilder::assignFunction(TheoryModel* m, Node f)
1225
{
1226
5015
  Assert(!options::ufHo());
1227
10030
  uf::UfModelTree ufmt(f);
1228
10030
  Node default_v;
1229
29597
  for (size_t i = 0; i < m->d_uf_terms[f].size(); i++)
1230
  {
1231
49164
    Node un = m->d_uf_terms[f][i];
1232
49164
    vector<TNode> children;
1233
24582
    children.push_back(f);
1234
24582
    Trace("model-builder-debug") << "  process term : " << un << std::endl;
1235
112287
    for (size_t j = 0; j < un.getNumChildren(); ++j)
1236
    {
1237
175410
      Node rc = m->getRepresentative(un[j]);
1238
175410
      Trace("model-builder-debug2") << "    get rep : " << un[j] << " returned "
1239
87705
                                    << rc << std::endl;
1240
87705
      Assert(rc.isConst());
1241
87705
      children.push_back(rc);
1242
    }
1243
49164
    Node simp = NodeManager::currentNM()->mkNode(un.getKind(), children);
1244
49164
    Node v = m->getRepresentative(un);
1245
49164
    Trace("model-builder") << "  Setting (" << simp << ") to (" << v << ")"
1246
24582
                           << endl;
1247
24582
    ufmt.setValue(m, simp, v);
1248
24582
    default_v = v;
1249
  }
1250
5015
  if (default_v.isNull())
1251
  {
1252
    // choose default value from model if none exists
1253
    TypeEnumerator te(f.getType().getRangeType());
1254
    default_v = (*te);
1255
  }
1256
5015
  ufmt.setDefaultValue(m, default_v);
1257
5015
  bool condenseFuncValues = options::condenseFunctionValues();
1258
5015
  if (condenseFuncValues)
1259
  {
1260
5015
    ufmt.simplify();
1261
  }
1262
10030
  std::stringstream ss;
1263
5015
  ss << "_arg_";
1264
10030
  Node val = ufmt.getFunctionValue(ss.str().c_str(), condenseFuncValues);
1265
5015
  m->assignFunctionDefinition(f, val);
1266
  // ufmt.debugPrint( std::cout, m );
1267
5015
}
1268
1269
1117
void TheoryEngineModelBuilder::assignHoFunction(TheoryModel* m, Node f)
1270
{
1271
1117
  Assert(options::ufHo());
1272
2234
  TypeNode type = f.getType();
1273
2234
  std::vector<TypeNode> argTypes = type.getArgTypes();
1274
2234
  std::vector<Node> args;
1275
2234
  std::vector<TNode> apply_args;
1276
2329
  for (unsigned i = 0; i < argTypes.size(); i++)
1277
  {
1278
2424
    Node v = NodeManager::currentNM()->mkBoundVar(argTypes[i]);
1279
1212
    args.push_back(v);
1280
1212
    if (i > 0)
1281
    {
1282
95
      apply_args.push_back(v);
1283
    }
1284
  }
1285
  // start with the base return value (currently we use the same default value
1286
  // for all functions)
1287
2234
  TypeEnumerator te(type.getRangeType());
1288
2234
  Node curr = (*te);
1289
1117
  std::map<Node, std::vector<Node> >::iterator itht = m->d_ho_uf_terms.find(f);
1290
1117
  if (itht != m->d_ho_uf_terms.end())
1291
  {
1292
3544
    for (size_t i = 0; i < itht->second.size(); i++)
1293
    {
1294
4854
      Node hn = itht->second[i];
1295
2427
      Trace("model-builder-debug") << "    process : " << hn << std::endl;
1296
2427
      Assert(hn.getKind() == kind::HO_APPLY);
1297
2427
      Assert(m->areEqual(hn[0], f));
1298
4854
      Node hni = m->getRepresentative(hn[1]);
1299
4854
      Trace("model-builder-debug2") << "      get rep : " << hn[0]
1300
2427
                                    << " returned " << hni << std::endl;
1301
2427
      Assert(hni.isConst());
1302
2427
      Assert(hni.getType().isSubtypeOf(args[0].getType()));
1303
2427
      hni = Rewriter::rewrite(args[0].eqNode(hni));
1304
4854
      Node hnv = m->getRepresentative(hn);
1305
4854
      Trace("model-builder-debug2") << "      get rep val : " << hn
1306
2427
                                    << " returned " << hnv << std::endl;
1307
2427
      Assert(hnv.isConst());
1308
2427
      if (!apply_args.empty())
1309
      {
1310
216
        Assert(hnv.getKind() == kind::LAMBDA
1311
               && hnv[0].getNumChildren() + 1 == args.size());
1312
432
        std::vector<TNode> largs;
1313
460
        for (unsigned j = 0; j < hnv[0].getNumChildren(); j++)
1314
        {
1315
244
          largs.push_back(hnv[0][j]);
1316
        }
1317
216
        Assert(largs.size() == apply_args.size());
1318
216
        hnv = hnv[1].substitute(
1319
            largs.begin(), largs.end(), apply_args.begin(), apply_args.end());
1320
216
        hnv = Rewriter::rewrite(hnv);
1321
      }
1322
2427
      Assert(!TypeNode::leastCommonTypeNode(hnv.getType(), curr.getType())
1323
                  .isNull());
1324
2427
      curr = NodeManager::currentNM()->mkNode(kind::ITE, hni, hnv, curr);
1325
    }
1326
  }
1327
  Node val = NodeManager::currentNM()->mkNode(
1328
      kind::LAMBDA,
1329
2234
      NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args),
1330
4468
      curr);
1331
1117
  m->assignFunctionDefinition(f, val);
1332
1117
}
1333
1334
// This struct is used to sort terms by the "size" of their type
1335
//   The size of the type is the number of nodes in the type, for example
1336
//  size of Int is 1
1337
//  size of Function( Int, Int ) is 3
1338
//  size of Function( Function( Bool, Int ), Int ) is 5
1339
9434
struct sortTypeSize
1340
{
1341
  // stores the size of the type
1342
  std::map<TypeNode, unsigned> d_type_size;
1343
  // get the size of type tn
1344
6107
  unsigned getTypeSize(TypeNode tn)
1345
  {
1346
6107
    std::map<TypeNode, unsigned>::iterator it = d_type_size.find(tn);
1347
6107
    if (it != d_type_size.end())
1348
    {
1349
4745
      return it->second;
1350
    }
1351
    else
1352
    {
1353
1362
      unsigned sum = 1;
1354
3079
      for (unsigned i = 0; i < tn.getNumChildren(); i++)
1355
      {
1356
1717
        sum += getTypeSize(tn[i]);
1357
      }
1358
1362
      d_type_size[tn] = sum;
1359
1362
      return sum;
1360
    }
1361
  }
1362
1363
 public:
1364
  // compares the type size of i and j
1365
  // returns true iff the size of i is less than that of j
1366
  // tiebreaks are determined by node value
1367
2195
  bool operator()(Node i, Node j)
1368
  {
1369
2195
    int si = getTypeSize(i.getType());
1370
2195
    int sj = getTypeSize(j.getType());
1371
2195
    if (si < sj)
1372
    {
1373
237
      return true;
1374
    }
1375
1958
    else if (si == sj)
1376
    {
1377
1842
      return i < j;
1378
    }
1379
    else
1380
    {
1381
116
      return false;
1382
    }
1383
  }
1384
};
1385
1386
15249
void TheoryEngineModelBuilder::assignFunctions(TheoryModel* m)
1387
{
1388
15249
  if (!options::assignFunctionValues())
1389
  {
1390
    return;
1391
  }
1392
15249
  Trace("model-builder") << "Assigning function values..." << std::endl;
1393
30498
  std::vector<Node> funcs_to_assign = m->getFunctionsToAssign();
1394
1395
15249
  if (options::ufHo())
1396
  {
1397
    // sort based on type size if higher-order
1398
431
    Trace("model-builder") << "Sort functions by type..." << std::endl;
1399
862
    sortTypeSize sts;
1400
431
    std::sort(funcs_to_assign.begin(), funcs_to_assign.end(), sts);
1401
  }
1402
1403
15249
  if (Trace.isOn("model-builder"))
1404
  {
1405
    Trace("model-builder") << "...have " << funcs_to_assign.size()
1406
                           << " functions to assign:" << std::endl;
1407
    for (unsigned k = 0; k < funcs_to_assign.size(); k++)
1408
    {
1409
      Node f = funcs_to_assign[k];
1410
      Trace("model-builder") << "  [" << k << "] : " << f << " : "
1411
                             << f.getType() << std::endl;
1412
    }
1413
  }
1414
1415
  // construct function values
1416
21381
  for (unsigned k = 0; k < funcs_to_assign.size(); k++)
1417
  {
1418
12264
    Node f = funcs_to_assign[k];
1419
6132
    Trace("model-builder") << "  Function #" << k << " is " << f << std::endl;
1420
    // std::map< Node, std::vector< Node > >::iterator itht =
1421
    // m->d_ho_uf_terms.find( f );
1422
6132
    if (!options::ufHo())
1423
    {
1424
10030
      Trace("model-builder") << "  Assign function value for " << f
1425
5015
                             << " based on APPLY_UF" << std::endl;
1426
5015
      assignFunction(m, f);
1427
    }
1428
    else
1429
    {
1430
2234
      Trace("model-builder") << "  Assign function value for " << f
1431
1117
                             << " based on curried HO_APPLY" << std::endl;
1432
1117
      assignHoFunction(m, f);
1433
    }
1434
  }
1435
15249
  Trace("model-builder") << "Finished assigning function values." << std::endl;
1436
}
1437
1438
}  // namespace theory
1439
28194
}  // namespace cvc5