GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/theory_model_builder.cpp Lines: 628 672 93.5 %
Date: 2021-08-14 Branches: 1211 2851 42.5 %

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