GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_enumerator.cpp Lines: 627 645 97.2 %
Date: 2021-11-05 Branches: 991 2260 43.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Aina Niemetz
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 sygus_enumerator.
14
 */
15
16
#include "theory/quantifiers/sygus/sygus_enumerator.h"
17
18
#include "expr/dtype_cons.h"
19
#include "expr/node_algorithm.h"
20
#include "options/datatypes_options.h"
21
#include "options/quantifiers_options.h"
22
#include "smt/logic_exception.h"
23
#include "theory/datatypes/sygus_datatype_utils.h"
24
#include "theory/datatypes/theory_datatypes_utils.h"
25
#include "theory/quantifiers/sygus/synth_engine.h"
26
#include "theory/quantifiers/sygus/type_node_id_trie.h"
27
#include "theory/rewriter.h"
28
#include "util/rational.h"
29
30
using namespace cvc5::kind;
31
32
namespace cvc5 {
33
namespace theory {
34
namespace quantifiers {
35
36
261
SygusEnumerator::SygusEnumerator(TermDbSygus* tds,
37
                                 SygusEnumeratorCallback* sec,
38
                                 SygusStatistics* s,
39
                                 bool enumShapes,
40
261
                                 bool enumAnyConstHoles)
41
    : d_tds(tds),
42
      d_sec(sec),
43
      d_stats(s),
44
      d_enumShapes(enumShapes),
45
      d_enumAnyConstHoles(enumAnyConstHoles),
46
      d_tlEnum(nullptr),
47
261
      d_abortSize(-1)
48
{
49
261
}
50
51
261
void SygusEnumerator::initialize(Node e)
52
{
53
261
  Trace("sygus-enum") << "SygusEnumerator::initialize " << e << std::endl;
54
261
  d_enum = e;
55
  // allocate the default callback
56
261
  if (d_sec == nullptr && options::sygusSymBreakDynamic())
57
  {
58
57
    d_secd.reset(new SygusEnumeratorCallbackDefault(e, d_stats));
59
57
    d_sec = d_secd.get();
60
  }
61
261
  d_etype = d_enum.getType();
62
261
  Assert(d_etype.isDatatype());
63
261
  Assert(d_etype.getDType().isSygus());
64
261
  d_tlEnum = getMasterEnumForType(d_etype);
65
261
  d_abortSize = options::sygusAbortSize();
66
67
  // if we don't have a term database, we don't register symmetry breaking
68
  // lemmas
69
261
  if (d_tds == nullptr)
70
  {
71
    return;
72
  }
73
  // Get the statically registered symmetry breaking clauses for e, see if they
74
  // can be used for speeding up the enumeration.
75
261
  NodeManager* nm = NodeManager::currentNM();
76
522
  std::vector<Node> sbl;
77
261
  d_tds->getSymBreakLemmas(e, sbl);
78
522
  Node ag = d_tds->getActiveGuardForEnumerator(e);
79
522
  Node truen = nm->mkConst(true);
80
  // use TNode for substitute below
81
522
  TNode agt = ag;
82
522
  TNode truent = truen;
83
261
  Assert(d_tcache.find(d_etype) != d_tcache.end());
84
261
  const DType& dt = d_etype.getDType();
85
371
  for (const Node& lem : sbl)
86
  {
87
110
    if (!d_tds->isSymBreakLemmaTemplate(lem))
88
    {
89
      // substitute its active guard by true and rewrite
90
126
      Node slem = lem.substitute(agt, truent);
91
63
      slem = Rewriter::rewrite(slem);
92
      // break into conjuncts
93
126
      std::vector<Node> sblc;
94
63
      if (slem.getKind() == AND)
95
      {
96
18
        for (const Node& slemc : slem)
97
        {
98
12
          sblc.push_back(slemc);
99
        }
100
      }
101
      else
102
      {
103
57
        sblc.push_back(slem);
104
      }
105
132
      for (const Node& sblemma : sblc)
106
      {
107
138
        Trace("sygus-enum")
108
69
            << "  symmetry breaking lemma : " << sblemma << std::endl;
109
        // if its a negation of a unit top-level tester, then this specifies
110
        // that we should not enumerate terms whose top symbol is that
111
        // constructor
112
69
        if (sblemma.getKind() == NOT)
113
        {
114
130
          Node a;
115
65
          int tst = datatypes::utils::isTester(sblemma[0], a);
116
65
          if (tst >= 0)
117
          {
118
65
            if (a == e)
119
            {
120
130
              Node cons = dt[tst].getConstructor();
121
130
              Trace("sygus-enum") << "  ...unit exclude constructor #" << tst
122
65
                                  << ", constructor " << cons << std::endl;
123
65
              d_sbExcTlCons.insert(cons);
124
            }
125
          }
126
        }
127
        // other symmetry breaking lemmas such as disjunctions are not used
128
      }
129
    }
130
  }
131
}
132
133
204
void SygusEnumerator::addValue(Node v)
134
{
135
  // do nothing
136
204
}
137
138
62116
bool SygusEnumerator::increment() { return d_tlEnum->increment(); }
139
61655
Node SygusEnumerator::getCurrent()
140
{
141
61655
  if (d_abortSize >= 0)
142
  {
143
10043
    int cs = static_cast<int>(d_tlEnum->getCurrentSize());
144
10043
    if (cs > d_abortSize)
145
    {
146
28
      std::stringstream ss;
147
14
      ss << "Maximum term size (" << options::sygusAbortSize()
148
14
         << ") for enumerative SyGuS exceeded.";
149
14
      throw LogicException(ss.str());
150
    }
151
  }
152
61641
  Node ret = d_tlEnum->getCurrent();
153
61641
  if (!ret.isNull() && !d_sbExcTlCons.empty())
154
  {
155
708
    Assert(ret.hasOperator());
156
    // might be excluded by an externally provided symmetry breaking clause
157
708
    if (d_sbExcTlCons.find(ret.getOperator()) != d_sbExcTlCons.end())
158
    {
159
76
      Trace("sygus-enum-exc")
160
76
          << "Exclude (external) : " << datatypes::utils::sygusToBuiltin(ret)
161
38
          << std::endl;
162
38
      ret = Node::null();
163
    }
164
  }
165
61641
  if (Trace.isOn("sygus-enum"))
166
  {
167
    Trace("sygus-enum") << "Enumerate : ";
168
    TermDbSygus::toStreamSygus("sygus-enum", ret);
169
    Trace("sygus-enum") << std::endl;
170
  }
171
61641
  return ret;
172
}
173
174
454
bool SygusEnumerator::isEnumShapes() const { return d_enumShapes; }
175
176
475
SygusEnumerator::TermCache::TermCache()
177
    : d_sec(nullptr),
178
      d_isSygusType(false),
179
      d_numConClasses(0),
180
      d_sizeEnum(0),
181
475
      d_isComplete(false)
182
{
183
475
}
184
185
475
void SygusEnumerator::TermCache::initialize(SygusStatistics* s,
186
                                            Node e,
187
                                            TypeNode tn,
188
                                            SygusEnumeratorCallback* sec)
189
{
190
475
  Trace("sygus-enum-debug") << "Init term cache " << tn << "..." << std::endl;
191
475
  d_stats = s;
192
475
  d_enum = e;
193
475
  d_tn = tn;
194
475
  d_sec = sec;
195
475
  d_sizeStartIndex[0] = 0;
196
475
  d_isSygusType = false;
197
198
  // compute static information about tn
199
475
  if (!d_tn.isDatatype())
200
  {
201
    // not a datatype, finish
202
42
    return;
203
  }
204
454
  const DType& dt = tn.getDType();
205
454
  if (!dt.isSygus())
206
  {
207
    // not a sygus datatype, finish
208
    return;
209
  }
210
211
454
  d_isSygusType = true;
212
213
  // get argument types for all constructors
214
908
  std::map<unsigned, std::vector<TypeNode>> argTypes;
215
  // map weights to constructors
216
908
  std::map<unsigned, std::vector<unsigned>> weightsToIndices;
217
218
  // constructor class 0 is reserved for nullary operators with 0 weight
219
  // this is an optimization so that we always skip them for sizes >= 1
220
454
  ConstructorClass& ccZero = d_cclass[0];
221
454
  ccZero.d_weight = 0;
222
454
  d_numConClasses = 1;
223
  // we must indicate that we should process zero weight constructor classes
224
454
  weightsToIndices[0].clear();
225
2687
  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
226
  {
227
    // record weight information
228
2233
    unsigned w = dt[i].getWeight();
229
4466
    Trace("sygus-enum-debug") << "Weight " << dt[i].getSygusOp() << ": " << w
230
2233
                              << std::endl;
231
2233
    weightsToIndices[w].push_back(i);
232
    // record type information
233
4556
    for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++)
234
    {
235
4646
      TypeNode type = dt[i].getArgType(j);
236
2323
      argTypes[i].push_back(type);
237
    }
238
  }
239
454
  NodeManager* nm = NodeManager::currentNM();
240
1259
  for (std::pair<const unsigned, std::vector<unsigned>>& wp : weightsToIndices)
241
  {
242
805
    unsigned w = wp.first;
243
244
    // assign constructors to constructor classes
245
1610
    TypeNodeIdTrie tnit;
246
1610
    std::map<Node, unsigned> nToC;
247
3038
    for (unsigned i : wp.second)
248
    {
249
2233
      if (argTypes[i].empty() && w == 0)
250
      {
251
956
        ccZero.d_cons.push_back(i);
252
      }
253
      else
254
      {
255
        // we merge those whose argument types are the same
256
        // We could, but choose not to, order these types, which would lead to
257
        // more aggressive merging of constructor classes. On the negative side,
258
        // this adds another level of indirection to remember which argument
259
        // positions the argument types occur in, for each constructor.
260
2554
        Node n = nm->mkConst(Rational(i));
261
1277
        nToC[n] = i;
262
1277
        tnit.add(n, argTypes[i]);
263
      }
264
    }
265
1610
    std::map<Node, unsigned> assign;
266
805
    tnit.assignIds(assign, d_numConClasses);
267
2082
    for (std::pair<const Node, unsigned>& cp : assign)
268
    {
269
      // determine which constructor class this goes into using tnit
270
1277
      unsigned cclassi = cp.second;
271
1277
      unsigned i = nToC[cp.first];
272
2554
      Trace("sygus-enum-debug") << "Constructor class for "
273
2554
                                << dt[i].getSygusOp() << " is " << cclassi
274
1277
                                << std::endl;
275
      // initialize the constructor class
276
1277
      if (d_cclass.find(cclassi) == d_cclass.end())
277
      {
278
765
        d_cclass[cclassi].d_weight = w;
279
3060
        d_cclass[cclassi].d_types.insert(d_cclass[cclassi].d_types.end(),
280
765
                                         argTypes[i].begin(),
281
3060
                                         argTypes[i].end());
282
      }
283
      // add to constructor class
284
1277
      d_cclass[cclassi].d_cons.push_back(i);
285
    }
286
1610
    Trace("sygus-enum-debug") << "#cons classes for weight <= " << w << " : "
287
805
                              << d_numConClasses << std::endl;
288
805
    d_weightToCcIndex[w] = d_numConClasses;
289
  }
290
454
  Trace("sygus-enum-debug") << "...finish" << std::endl;
291
}
292
293
77601
unsigned SygusEnumerator::TermCache::getLastConstructorClassIndexForWeight(
294
    unsigned w) const
295
{
296
77601
  std::map<unsigned, unsigned>::const_iterator it = d_weightToCcIndex.find(w);
297
77601
  if (it == d_weightToCcIndex.end())
298
  {
299
64904
    return d_numConClasses;
300
  }
301
12697
  return it->second;
302
}
303
111
unsigned SygusEnumerator::TermCache::getNumConstructorClasses() const
304
{
305
111
  return d_numConClasses;
306
}
307
1376
void SygusEnumerator::TermCache::getConstructorClass(
308
    unsigned i, std::vector<unsigned>& cclass) const
309
{
310
1376
  std::map<unsigned, ConstructorClass>::const_iterator it = d_cclass.find(i);
311
1376
  Assert(it != d_cclass.end());
312
1376
  cclass.insert(
313
2752
      cclass.end(), it->second.d_cons.begin(), it->second.d_cons.end());
314
1376
}
315
1301
void SygusEnumerator::TermCache::getTypesForConstructorClass(
316
    unsigned i, std::vector<TypeNode>& types) const
317
{
318
1301
  std::map<unsigned, ConstructorClass>::const_iterator it = d_cclass.find(i);
319
1301
  Assert(it != d_cclass.end());
320
1301
  types.insert(
321
2602
      types.end(), it->second.d_types.begin(), it->second.d_types.end());
322
1301
}
323
324
1301
unsigned SygusEnumerator::TermCache::getWeightForConstructorClass(
325
    unsigned i) const
326
{
327
1301
  std::map<unsigned, ConstructorClass>::const_iterator it = d_cclass.find(i);
328
1301
  Assert(it != d_cclass.end());
329
1301
  return it->second.d_weight;
330
}
331
332
76218
bool SygusEnumerator::TermCache::addTerm(Node n)
333
{
334
76218
  if (!d_isSygusType)
335
  {
336
    // non-sygus terms generated by TermEnumMasterInterp/TermEnumMasterFv
337
    // enumeration are unique by construction
338
250
    Trace("sygus-enum-terms") << "tc(" << d_tn << "): term (builtin): " << n
339
125
                              << std::endl;
340
125
    d_terms.push_back(n);
341
125
    return true;
342
  }
343
76093
  Assert(!n.isNull());
344
76093
  if (d_sec != nullptr)
345
  {
346
76093
    if (!d_sec->addTerm(n, d_bterms))
347
    {
348
92626
      Trace("sygus-enum-exc")
349
92626
          << "Exclude: " << datatypes::utils::sygusToBuiltin(n)
350
46313
          << " due to callback" << std::endl;
351
46313
      return false;
352
    }
353
  }
354
29780
  if (d_stats != nullptr)
355
  {
356
29780
    ++(d_stats->d_enumTerms);
357
  }
358
29780
  d_terms.push_back(n);
359
29780
  return true;
360
}
361
653
void SygusEnumerator::TermCache::pushEnumSizeIndex()
362
{
363
653
  d_sizeEnum++;
364
653
  d_sizeStartIndex[d_sizeEnum] = d_terms.size();
365
1306
  Trace("sygus-enum-debug") << "tc(" << d_tn << "): size " << d_sizeEnum
366
1306
                            << " terms start at index " << d_terms.size()
367
653
                            << std::endl;
368
653
}
369
57232
unsigned SygusEnumerator::TermCache::getEnumSize() const { return d_sizeEnum; }
370
48798
unsigned SygusEnumerator::TermCache::getIndexForSize(unsigned s) const
371
{
372
48798
  Assert(s <= d_sizeEnum);
373
48798
  std::map<unsigned, unsigned>::const_iterator it = d_sizeStartIndex.find(s);
374
48798
  Assert(it != d_sizeStartIndex.end());
375
48798
  return it->second;
376
}
377
294382
Node SygusEnumerator::TermCache::getTerm(unsigned index) const
378
{
379
294382
  Assert(index < d_terms.size());
380
294382
  return d_terms[index];
381
}
382
383
78355
unsigned SygusEnumerator::TermCache::getNumTerms() const
384
{
385
78355
  return d_terms.size();
386
}
387
388
78441
bool SygusEnumerator::TermCache::isComplete() const { return d_isComplete; }
389
60
void SygusEnumerator::TermCache::setComplete() { d_isComplete = true; }
390
301235
unsigned SygusEnumerator::TermEnum::getCurrentSize() { return d_currSize; }
391
5549
SygusEnumerator::TermEnum::TermEnum() : d_se(nullptr), d_currSize(0) {}
392
5074
SygusEnumerator::TermEnumSlave::TermEnumSlave()
393
    : TermEnum(),
394
      d_sizeLim(0),
395
      d_index(0),
396
      d_indexNextEnd(0),
397
      d_hasIndexNextEnd(false),
398
5074
      d_master(nullptr)
399
{
400
5074
}
401
402
5074
bool SygusEnumerator::TermEnumSlave::initialize(SygusEnumerator* se,
403
                                                TypeNode tn,
404
                                                unsigned sizeMin,
405
                                                unsigned sizeMax)
406
{
407
5074
  d_se = se;
408
5074
  d_tn = tn;
409
5074
  d_sizeLim = sizeMax;
410
10148
  Trace("sygus-enum-debug2") << "slave(" << d_tn
411
5074
                             << "): init, min/max=" << sizeMin << "/" << sizeMax
412
5074
                             << "...\n";
413
414
  // must have pointer to the master
415
5074
  d_master = d_se->getMasterEnumForType(d_tn);
416
417
5074
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
418
  // if the size is exact, we start at the limit
419
5074
  d_currSize = sizeMin;
420
  // initialize the index
421
5082
  while (d_currSize > tc.getEnumSize())
422
  {
423
132
    Trace("sygus-enum-debug2") << "slave(" << d_tn
424
66
                               << "): init force increment master...\n";
425
    // increment the master until we have enough terms
426
66
    if (!d_master->increment())
427
    {
428
124
      Trace("sygus-enum-debug2") << "slave(" << d_tn
429
62
                                 << "): ...fail init force master\n";
430
62
      return false;
431
    }
432
8
    Trace("sygus-enum-debug2") << "slave(" << d_tn
433
4
                               << "): ...success init force master\n";
434
  }
435
5012
  d_index = tc.getIndexForSize(d_currSize);
436
5012
  Trace("sygus-enum-debug2") << "slave(" << d_tn << "): validate indices...\n";
437
  // initialize the next end index (marks where size increments)
438
5012
  validateIndexNextEnd();
439
10024
  Trace("sygus-enum-debug2")
440
5012
      << "slave(" << d_tn << "): validate init end: " << d_hasIndexNextEnd
441
5012
      << " " << d_indexNextEnd << " " << d_index << " " << d_currSize << "\n";
442
  // ensure that indexNextEnd is valid (it must be greater than d_index)
443
5012
  bool ret = validateIndex();
444
10024
  Trace("sygus-enum-debug2")
445
10024
      << "slave(" << d_tn << "): ..." << (ret ? "success" : "fail")
446
5012
      << " init, now: " << d_hasIndexNextEnd << " " << d_indexNextEnd << " "
447
5012
      << d_index << " " << d_currSize << "\n";
448
5012
  return ret;
449
}
450
451
147191
Node SygusEnumerator::TermEnumSlave::getCurrent()
452
{
453
147191
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
454
294382
  Node curr = tc.getTerm(d_index);
455
294382
  Trace("sygus-enum-debug2")
456
147191
      << "slave(" << d_tn
457
294382
      << "): current : " << datatypes::utils::sygusToBuiltin(curr)
458
294382
      << ", sizes = " << datatypes::utils::getSygusTermSize(curr) << " "
459
147191
      << getCurrentSize() << std::endl;
460
294382
  Trace("sygus-enum-debug2") << "slave(" << d_tn
461
147191
                             << "): indices : " << d_hasIndexNextEnd << " "
462
147191
                             << d_indexNextEnd << " " << d_index << std::endl;
463
  // lookup in the cache
464
294382
  return tc.getTerm(d_index);
465
}
466
467
42553
bool SygusEnumerator::TermEnumSlave::increment()
468
{
469
  // increment index
470
42553
  d_index++;
471
  // ensure that index is valid
472
42553
  return validateIndex();
473
}
474
475
47565
bool SygusEnumerator::TermEnumSlave::validateIndex()
476
{
477
47565
  Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : validate index...\n";
478
47565
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
479
  // ensure that index is in the range
480
77417
  while (d_index >= tc.getNumTerms())
481
  {
482
15755
    Assert(d_index == tc.getNumTerms());
483
15755
    Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : force master...\n";
484
    // if the size of the master is larger than the size limit, then
485
    // there is no use continuing, since there are no more terms that this
486
    // slave enumerator can return.
487
15755
    if (d_master->getCurrentSize() > d_sizeLim)
488
    {
489
689
      return false;
490
    }
491
    // must push the master index
492
15066
    if (!d_master->increment())
493
    {
494
280
      Trace("sygus-enum-debug2") << "slave(" << d_tn
495
140
                                 << ") : ...fail force master\n";
496
140
      return false;
497
    }
498
29852
    Trace("sygus-enum-debug2") << "slave(" << d_tn
499
14926
                               << ") : ...success force master\n";
500
  }
501
  // always validate the next index end here
502
46736
  validateIndexNextEnd();
503
93472
  Trace("sygus-enum-debug2") << "slave(" << d_tn
504
46736
                             << ") : validate index end...\n";
505
  // if we are at the beginning of the next size, increment current size
506
47520
  while (d_hasIndexNextEnd && d_index == d_indexNextEnd)
507
  {
508
4094
    d_currSize++;
509
8188
    Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : size++ ("
510
4094
                               << d_currSize << "/" << d_sizeLim << ")\n";
511
    // if we've hit the size limit, return false
512
4094
    if (d_currSize > d_sizeLim)
513
    {
514
3702
      Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : fail size\n";
515
3702
      return false;
516
    }
517
392
    validateIndexNextEnd();
518
  }
519
43034
  Trace("sygus-enum-debug2") << "slave(" << d_tn << ") : finished\n";
520
43034
  return true;
521
}
522
523
52140
void SygusEnumerator::TermEnumSlave::validateIndexNextEnd()
524
{
525
52140
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
526
  // update the next end index
527
52140
  d_hasIndexNextEnd = d_currSize < tc.getEnumSize();
528
52140
  if (d_hasIndexNextEnd)
529
  {
530
43786
    d_indexNextEnd = tc.getIndexForSize(d_currSize + 1);
531
  }
532
52140
}
533
534
475
void SygusEnumerator::initializeTermCache(TypeNode tn)
535
{
536
  // initialize the term cache
537
475
  d_tcache[tn].initialize(d_stats, d_enum, tn, d_sec);
538
475
}
539
540
5335
SygusEnumerator::TermEnum* SygusEnumerator::getMasterEnumForType(TypeNode tn)
541
{
542
5335
  if (tn.isDatatype() && tn.getDType().isSygus())
543
  {
544
5300
    std::map<TypeNode, TermEnumMaster>::iterator it = d_masterEnum.find(tn);
545
5300
    if (it != d_masterEnum.end())
546
    {
547
4846
      return &it->second;
548
    }
549
454
    initializeTermCache(tn);
550
    // initialize the master enumerator
551
454
    bool ret = d_masterEnum[tn].initialize(this, tn);
552
454
    AlwaysAssert(ret);
553
454
    return &d_masterEnum[tn];
554
  }
555
35
  if (d_enumAnyConstHoles)
556
  {
557
8
    std::map<TypeNode, TermEnumMasterFv>::iterator it = d_masterEnumFv.find(tn);
558
8
    if (it != d_masterEnumFv.end())
559
    {
560
      return &it->second;
561
    }
562
8
    initializeTermCache(tn);
563
    // initialize the master enumerator
564
8
    bool ret = d_masterEnumFv[tn].initialize(this, tn);
565
8
    AlwaysAssert(ret);
566
8
    return &d_masterEnumFv[tn];
567
  }
568
  std::map<TypeNode, std::unique_ptr<TermEnumMasterInterp>>::iterator it =
569
27
      d_masterEnumInt.find(tn);
570
27
  if (it != d_masterEnumInt.end())
571
  {
572
14
    return it->second.get();
573
  }
574
13
  initializeTermCache(tn);
575
  // create the master enumerator
576
13
  d_masterEnumInt[tn].reset(new TermEnumMasterInterp(tn));
577
  // initialize the master enumerator
578
13
  TermEnumMasterInterp* temi = d_masterEnumInt[tn].get();
579
13
  bool ret = temi->initialize(this, tn);
580
13
  AlwaysAssert(ret);
581
13
  return temi;
582
}
583
584
454
SygusEnumerator::TermEnumMaster::TermEnumMaster()
585
    : TermEnum(),
586
      d_enumShapes(false),
587
      d_enumShapesInit(false),
588
      d_isIncrementing(false),
589
      d_currTermSet(false),
590
      d_consClassNum(0),
591
      d_ccWeight(0),
592
      d_consNum(0),
593
      d_currChildSize(0),
594
454
      d_childrenValid(0)
595
{
596
454
}
597
598
454
bool SygusEnumerator::TermEnumMaster::initialize(SygusEnumerator* se,
599
                                                 TypeNode tn)
600
{
601
454
  Trace("sygus-enum-debug") << "master(" << tn << "): init...\n";
602
454
  d_tds = se->d_tds;
603
454
  d_se = se;
604
454
  d_tn = tn;
605
606
454
  d_currSize = 0;
607
  // we will start with constructor class zero
608
454
  d_consClassNum = 0;
609
454
  d_currChildSize = 0;
610
454
  d_ccCons.clear();
611
454
  d_enumShapes = se->isEnumShapes();
612
454
  d_enumShapesInit = false;
613
454
  d_isIncrementing = false;
614
454
  d_currTermSet = false;
615
454
  bool ret = increment();
616
908
  Trace("sygus-enum-debug") << "master(" << tn
617
454
                            << "): finish init, ret = " << ret << "\n";
618
454
  return ret;
619
}
620
621
137664
Node SygusEnumerator::TermEnumMaster::getCurrent()
622
{
623
137664
  if (d_currTermSet)
624
  {
625
61641
    return d_currTerm;
626
  }
627
76023
  d_currTermSet = true;
628
  // construct based on the children
629
152046
  std::vector<Node> children;
630
76023
  const DType& dt = d_tn.getDType();
631
76023
  Assert(d_consNum > 0 && d_consNum <= d_ccCons.size());
632
  // get the current constructor number
633
76023
  unsigned cnum = d_ccCons[d_consNum - 1];
634
76023
  children.push_back(dt[cnum].getConstructor());
635
  // add the current of each child to children
636
223214
  for (unsigned i = 0, nargs = dt[cnum].getNumArgs(); i < nargs; i++)
637
  {
638
147191
    Assert(d_children.find(i) != d_children.end());
639
294382
    Node cc = d_children[i].getCurrent();
640
147191
    if (cc.isNull())
641
    {
642
      d_currTerm = cc;
643
      return cc;
644
    }
645
147191
    children.push_back(cc);
646
  }
647
76023
  if (d_enumShapes)
648
  {
649
    // ensure all variables are unique
650
11151
    childrenToShape(children);
651
  }
652
76023
  d_currTerm = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children);
653
76023
  return d_currTerm;
654
}
655
656
77583
bool SygusEnumerator::TermEnumMaster::increment()
657
{
658
  // Am I already incrementing? If so, fail.
659
  // This is to break infinite loops for slave enumerators who request an
660
  // increment() from the master enumerator of their type that is also their
661
  // parent. This ensures we do not loop on a grammar like:
662
  //   A -> -( A ) | B+B
663
  //   B -> x | y
664
  // where we require the first term enumerated to be over B+B.
665
  // Set that we are incrementing
666
77583
  if (d_isIncrementing)
667
  {
668
    return false;
669
  }
670
155166
  Trace("sygus-enum-summary") << "SygusEnumerator::TermEnumMaster: increment "
671
77583
                              << d_tn << "..." << std::endl;
672
77583
  d_isIncrementing = true;
673
77583
  bool ret = incrementInternal();
674
77583
  d_isIncrementing = false;
675
155166
  Trace("sygus-enum-summary")
676
77583
      << "SygusEnumerator::TermEnumMaster: finished increment " << d_tn
677
77583
      << std::endl;
678
77583
  return ret;
679
}
680
681
78404
bool SygusEnumerator::TermEnumMaster::incrementInternal()
682
{
683
78404
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
684
78404
  if (tc.isComplete())
685
  {
686
803
    return false;
687
  }
688
155202
  Trace("sygus-enum-debug2") << "master(" << d_tn
689
77601
                             << "): get last constructor class..." << std::endl;
690
  // the maximum index of a constructor class to consider
691
77601
  unsigned ncc = tc.getLastConstructorClassIndexForWeight(d_currSize);
692
155202
  Trace("sygus-enum-debug2") << "Last constructor class " << d_currSize << ": "
693
77601
                             << ncc << std::endl;
694
  // If we are enumerating shapes, the first enumerated term is a free variable.
695
77601
  if (d_enumShapes && !d_enumShapesInit)
696
  {
697
70
    Assert(d_tds != nullptr);
698
140
    Node fv = d_tds->getFreeVar(d_tn, 0);
699
70
    d_enumShapesInit = true;
700
70
    d_currTermSet = true;
701
70
    d_currTerm = fv;
702
    // must add to term cache
703
70
    tc.addTerm(fv);
704
70
    return true;
705
  }
706
707
  // have we initialized the current constructor class?
708
80283
  while (d_ccCons.empty() && d_consClassNum < ncc)
709
  {
710
1376
    Assert(d_ccTypes.empty());
711
2752
    Trace("sygus-enum-debug2") << "master(" << d_tn
712
1376
                               << "): try constructor class " << d_consClassNum
713
1376
                               << std::endl;
714
    // get the list of constructors in the constructor class
715
1376
    tc.getConstructorClass(d_consClassNum, d_ccCons);
716
    // if there are any...
717
1376
    if (!d_ccCons.empty())
718
    {
719
      // successfully initialized the constructor class
720
1269
      d_consNum = 0;
721
      // we will populate the children
722
1269
      Assert(d_children.empty());
723
1269
      Assert(d_ccTypes.empty());
724
1269
      tc.getTypesForConstructorClass(d_consClassNum, d_ccTypes);
725
1269
      d_ccWeight = tc.getWeightForConstructorClass(d_consClassNum);
726
1269
      d_childrenValid = 0;
727
      // initialize the children into their initial state
728
1269
      if (!initializeChildren())
729
      {
730
        // didn't work (due to size), we will try the next class
731
174
        d_ccCons.clear();
732
174
        d_ccTypes.clear();
733
348
        Trace("sygus-enum-debug2") << "master(" << d_tn
734
174
                                   << "): failed due to init size\n";
735
      }
736
    }
737
    else
738
    {
739
      // No constructors in constructor class. This can happen for class 0 if a
740
      // type has no nullary constructors with weight 0.
741
214
      Trace("sygus-enum-debug2") << "master(" << d_tn
742
107
                                 << "): failed due to no cons\n";
743
    }
744
    // increment the next constructor class we will try
745
1376
    d_consClassNum++;
746
  }
747
748
  // have we run out of constructor classes for this size?
749
77531
  if (d_ccCons.empty())
750
  {
751
    // check whether we should terminate, which notice always treats
752
    // uninterpreted sorts as infinite, since we do not put bounds on them
753
    // in our enumeration.
754
687
    if (isCardinalityClassFinite(d_tn.getCardinalityClass(), false))
755
    {
756
111
      if (ncc == tc.getNumConstructorClasses())
757
      {
758
83
        bool doTerminate = true;
759
92
        for (unsigned i = 1; i < ncc; i++)
760
        {
761
          // The maximum size of terms from a constructor class can be
762
          // determined if all of its argument types are finished enumerating.
763
          // If this maximum size is less than or equal to d_currSize for
764
          // each constructor class, we are done.
765
32
          unsigned sum = tc.getWeightForConstructorClass(i);
766
41
          std::vector<TypeNode> cctns;
767
32
          tc.getTypesForConstructorClass(i, cctns);
768
46
          for (unsigned j = 0, ntypes = cctns.size(); j < ntypes; j++)
769
          {
770
51
            TypeNode tnc = cctns[j];
771
37
            SygusEnumerator::TermCache& tcc = d_se->d_tcache[tnc];
772
37
            if (!tcc.isComplete())
773
            {
774
              // maximum size of this constructor class cannot be determined
775
23
              doTerminate = false;
776
23
              break;
777
            }
778
            else
779
            {
780
14
              sum += tcc.getEnumSize();
781
14
              if (sum > d_currSize)
782
              {
783
                // maximum size of this constructor class is greater than size
784
                doTerminate = false;
785
                break;
786
              }
787
            }
788
          }
789
32
          if (!doTerminate)
790
          {
791
23
            break;
792
          }
793
        }
794
83
        if (doTerminate)
795
        {
796
120
          Trace("sygus-engine") << "master(" << d_tn << "): complete at size "
797
60
                                << d_currSize << std::endl;
798
60
          tc.setComplete();
799
60
          return false;
800
        }
801
      }
802
    }
803
804
    // increment the size bound
805
627
    d_currSize++;
806
1254
    Trace("sygus-enum-debug2") << "master(" << d_tn
807
627
                               << "): size++ : " << d_currSize << "\n";
808
627
    if (Trace.isOn("sygus-engine"))
809
    {
810
      // am i the master enumerator? if so, print
811
      if (d_se->d_tlEnum == this)
812
      {
813
        Trace("sygus-engine") << "SygusEnumerator::size = " << d_currSize
814
                              << std::endl;
815
      }
816
    }
817
818
    // push the bound
819
627
    tc.pushEnumSizeIndex();
820
821
    // restart with constructor class one (skip nullary constructors)
822
627
    d_consClassNum = 1;
823
824
    // We break for a round: return the null term when we cross a size
825
    // boundary. This ensures that the necessary breaks are taken, e.g.
826
    // in slave enumerators who may instead want to abandon this call to
827
    // increment master when the size of the master makes their increment
828
    // infeasible.
829
627
    d_currTermSet = true;
830
627
    d_currTerm = Node::null();
831
627
    return true;
832
  }
833
834
76844
  bool incSuccess = false;
835
39007
  do
836
  {
837
230060
    Trace("sygus-enum-debug2") << "master(" << d_tn << "): check return "
838
230060
                               << d_childrenValid << "/" << d_ccTypes.size()
839
115030
                               << std::endl;
840
    // the children should be initialized by here
841
115030
    Assert(d_childrenValid == d_ccTypes.size());
842
843
    // do we have more constructors for the given children?
844
115030
    if (d_consNum < d_ccCons.size())
845
    {
846
152046
      Trace("sygus-enum-debug2") << "master(" << d_tn << "): try constructor "
847
76023
                                 << d_consNum << std::endl;
848
      // increment constructor index
849
      // we will build for the current constructor and the given children
850
76023
      d_consNum++;
851
76023
      d_currTermSet = false;
852
76023
      d_currTerm = Node::null();
853
152046
      Node c = getCurrent();
854
76023
      if (!c.isNull())
855
      {
856
76023
        if (!tc.addTerm(c))
857
        {
858
          // the term was not unique based on rewriting
859
92626
          Trace("sygus-enum-debug2") << "master(" << d_tn
860
46313
                                     << "): failed addTerm\n";
861
          // we will return null (d_currTermSet is true at this point)
862
46313
          Assert(d_currTermSet);
863
46313
          d_currTerm = Node::null();
864
        }
865
      }
866
76023
      return true;
867
    }
868
869
    // finished constructors for this set of children, must increment children
870
871
    // reset the constructor number
872
39007
    d_consNum = 0;
873
874
    // try incrementing the last child until we find one that works
875
39007
    incSuccess = false;
876
124113
    while (!incSuccess && d_childrenValid > 0)
877
    {
878
85106
      Trace("sygus-enum-debug2") << "master(" << d_tn << "): try incrementing "
879
42553
                                 << d_childrenValid << std::endl;
880
42553
      unsigned i = d_childrenValid - 1;
881
42553
      Assert(d_children[i].getCurrentSize() <= d_currChildSize);
882
      // track the size
883
42553
      d_currChildSize -= d_children[i].getCurrentSize();
884
42553
      if (d_children[i].increment())
885
      {
886
76390
        Trace("sygus-enum-debug2") << "master(" << d_tn
887
38195
                                   << "): increment success...\n";
888
38195
        d_currChildSize += d_children[i].getCurrentSize();
889
        // must see if we can initialize the remaining children here
890
        // if not, there is no use continuing.
891
38195
        if (initializeChildren())
892
        {
893
76372
          Trace("sygus-enum-debug2")
894
38186
              << "master(" << d_tn << "): success init children\n";
895
38186
          Assert(d_currChildSize + d_ccWeight <= d_currSize);
896
38186
          incSuccess = true;
897
        }
898
        else
899
        {
900
          // failed to initialize the remaining children (likely due to a
901
          // child having a non-zero minimum size bound).
902
18
          Trace("sygus-enum-debug2")
903
9
              << "master(" << d_tn << "): fail init children\n";
904
9
          d_currChildSize -= d_children[i].getCurrentSize();
905
        }
906
      }
907
42553
      if (!incSuccess)
908
      {
909
8734
        Trace("sygus-enum-debug2") << "master(" << d_tn
910
4367
                                   << "): fail, backtrack...\n";
911
        // current child is out of values
912
4367
        d_children.erase(i);
913
4367
        d_childrenValid--;
914
      }
915
    }
916
  } while (incSuccess);
917
1642
  Trace("sygus-enum-debug2") << "master(" << d_tn
918
821
                             << "): failed increment children\n";
919
  // restart with the next constructor class
920
821
  d_ccCons.clear();
921
821
  d_ccTypes.clear();
922
821
  return incrementInternal();
923
}
924
925
39464
bool SygusEnumerator::TermEnumMaster::initializeChildren()
926
{
927
78928
  Trace("sygus-enum-debug2")
928
39464
      << "master(" << d_tn << "): init children, start = " << d_childrenValid
929
78928
      << ", #types=" << d_ccTypes.size() << ", sizes=" << d_currChildSize << "/"
930
39464
      << d_currSize << std::endl;
931
39464
  unsigned currChildren = d_childrenValid;
932
39464
  unsigned sizeMin = 0;
933
  // while we need to initialize the current child
934
49336
  while (d_childrenValid < d_ccTypes.size())
935
  {
936
5119
    if (!initializeChild(d_childrenValid, sizeMin))
937
    {
938
280
      if (d_childrenValid == currChildren)
939
      {
940
        // we are back to the child we started with, we terminate now.
941
366
        Trace("sygus-enum-debug2") << "master(" << d_tn
942
183
                                   << "): init children : failed, finished"
943
183
                                   << std::endl;
944
183
        return false;
945
      }
946
194
      Trace("sygus-enum-debug2") << "master(" << d_tn
947
97
                                 << "): init children : failed" << std::endl;
948
      // we failed in this size configuration
949
      // reinitialize with the next size up
950
97
      unsigned currSize = d_children[d_childrenValid - 1].getCurrentSize();
951
97
      d_currChildSize -= currSize;
952
97
      sizeMin = currSize + 1;
953
97
      d_children.erase(d_childrenValid - 1);
954
97
      d_childrenValid--;
955
    }
956
    else
957
    {
958
4839
      sizeMin = 0;
959
4839
      d_childrenValid++;
960
    }
961
  }
962
78562
  Trace("sygus-enum-debug2") << "master(" << d_tn
963
39281
                             << "): init children : success" << std::endl;
964
  // initialized all children
965
39281
  return true;
966
}
967
968
5119
bool SygusEnumerator::TermEnumMaster::initializeChild(unsigned i,
969
                                                      unsigned sizeMin)
970
{
971
5119
  Assert(d_ccWeight <= d_currSize);
972
5119
  Assert(d_currChildSize + d_ccWeight <= d_currSize);
973
5119
  unsigned sizeMax = (d_currSize - d_ccWeight) - d_currChildSize;
974
10238
  Trace("sygus-enum-debug2") << "master(" << d_tn << "): initializeChild " << i
975
5119
                             << " (" << d_currSize << ", " << d_ccWeight << ", "
976
5119
                             << d_currChildSize << ")\n";
977
5119
  if (sizeMin > sizeMax)
978
  {
979
90
    Trace("sygus-enum-debug2") << "master(" << d_tn << "): failed due to size "
980
45
                               << sizeMin << "/" << sizeMax << "\n";
981
45
    return false;
982
  }
983
  // initialize the child to enumerate exactly the terms that sum to size
984
5074
  sizeMin = (i + 1 == d_ccTypes.size()) ? sizeMax : sizeMin;
985
5074
  TermEnumSlave& te = d_children[i];
986
5074
  bool init = te.initialize(d_se, d_ccTypes[i], sizeMin, sizeMax);
987
5074
  if (!init)
988
  {
989
    // failed to initialize
990
235
    d_children.erase(i);
991
470
    Trace("sygus-enum-debug2") << "master(" << d_tn
992
235
                               << "): failed due to child init\n";
993
235
    return false;
994
  }
995
4839
  unsigned teSize = te.getCurrentSize();
996
  // fail if the initial children size does not fit d_currSize-d_ccWeight
997
4839
  if (teSize + d_currChildSize + d_ccWeight > d_currSize)
998
  {
999
    d_children.erase(i);
1000
    Trace("sygus-enum-debug2") << "master(" << d_tn
1001
                               << "): failed due to child size\n";
1002
    return false;
1003
  }
1004
4839
  d_currChildSize += teSize;
1005
9678
  Trace("sygus-enum-debug2") << "master(" << d_tn
1006
4839
                             << "): success initializeChild " << i << "\n";
1007
4839
  return true;
1008
}
1009
1010
11151
void SygusEnumerator::TermEnumMaster::childrenToShape(
1011
    std::vector<Node>& children)
1012
{
1013
11151
  if (children.size() <= 2)
1014
  {
1015
    // don't need to convert constants and unary applications
1016
971
    return;
1017
  }
1018
20360
  std::map<TypeNode, int> vcounter;
1019
  // Buffered child, so that we only compute vcounter if there are more than
1020
  // one children with free variables, since otherwise there is no change.
1021
  // For example, if we are given { C, (+ x1 x2), 1 }, we buffer child (+ x1 x2)
1022
  // noting that it has free variables. We proceed with processing the remaining
1023
  // children, and note that no other child contains free variables, and hence
1024
  // no change is necessary (since by construction, all children have the
1025
  // property of having unique variable subterms). On the other hand if the
1026
  // last child above was x1, then this would trigger us to convert (+ x1 x2)
1027
  // while computing vcounter, and subsequently update x1 to x3 to obtain
1028
  // { C, (+ x1 x2), x3 }.
1029
  // Have we set the buffer child index
1030
10180
  bool bufferChildSet = false;
1031
  // Have we processed the buffer child index
1032
10180
  bool bufferChildProcessed = false;
1033
  // The buffer child index
1034
10180
  size_t bufferChild = 0;
1035
32777
  for (size_t i = 1, nchildren = children.size(); i < nchildren; i++)
1036
  {
1037
22597
    if (!expr::hasBoundVar(children[i]))
1038
    {
1039
      // don't need to care about expressions with no bound variables
1040
10433
      continue;
1041
    }
1042
21129
    else if (!bufferChildSet)
1043
    {
1044
8965
      bufferChild = i;
1045
8965
      bufferChildSet = true;
1046
8965
      continue;
1047
    }
1048
3199
    else if (!bufferChildProcessed)
1049
    {
1050
      // process the buffer child
1051
2966
      children[bufferChild] = convertShape(children[bufferChild], vcounter);
1052
2966
      bufferChildProcessed = true;
1053
    }
1054
3199
    children[i] = convertShape(children[i], vcounter);
1055
  }
1056
}
1057
1058
6165
Node SygusEnumerator::TermEnumMaster::convertShape(
1059
    Node n, std::map<TypeNode, int>& vcounter)
1060
{
1061
6165
  Assert(d_tds != nullptr);
1062
6165
  NodeManager* nm = NodeManager::currentNM();
1063
12330
  std::unordered_map<TNode, Node> visited;
1064
6165
  std::unordered_map<TNode, Node>::iterator it;
1065
12330
  std::vector<TNode> visit;
1066
12330
  TNode cur;
1067
6165
  visit.push_back(n);
1068
15997
  do
1069
  {
1070
22162
    cur = visit.back();
1071
22162
    visit.pop_back();
1072
22162
    it = visited.find(cur);
1073
1074
22162
    if (it == visited.end())
1075
    {
1076
16741
      if (cur.isVar())
1077
      {
1078
        // do the conversion
1079
8304
        visited[cur] = d_tds->getFreeVarInc(cur.getType(), vcounter);
1080
      }
1081
8437
      else if (!expr::hasBoundVar(cur))
1082
      {
1083
        // no bound variables, no change
1084
3074
        visited[cur] = cur;
1085
      }
1086
      else
1087
      {
1088
5363
        visited[cur] = Node::null();
1089
5363
        visit.push_back(cur);
1090
5363
        visit.insert(visit.end(), cur.begin(), cur.end());
1091
      }
1092
    }
1093
5421
    else if (it->second.isNull())
1094
    {
1095
10726
      Node ret = cur;
1096
5363
      bool childChanged = false;
1097
10726
      std::vector<Node> children;
1098
5363
      if (cur.getMetaKind() == metakind::PARAMETERIZED)
1099
      {
1100
5363
        children.push_back(cur.getOperator());
1101
      }
1102
15997
      for (const Node& cn : cur)
1103
      {
1104
10634
        it = visited.find(cn);
1105
10634
        Assert(it != visited.end());
1106
10634
        Assert(!it->second.isNull());
1107
10634
        childChanged = childChanged || cn != it->second;
1108
10634
        children.push_back(it->second);
1109
      }
1110
5363
      if (childChanged)
1111
      {
1112
3757
        ret = nm->mkNode(cur.getKind(), children);
1113
      }
1114
5363
      visited[cur] = ret;
1115
    }
1116
22162
  } while (!visit.empty());
1117
6165
  Assert(visited.find(n) != visited.end());
1118
6165
  Assert(!visited.find(n)->second.isNull());
1119
12330
  return visited[n];
1120
}
1121
1122
13
SygusEnumerator::TermEnumMasterInterp::TermEnumMasterInterp(TypeNode tn)
1123
13
    : TermEnum(), d_te(tn), d_currNumConsts(0), d_nextIndexEnd(0)
1124
{
1125
13
}
1126
1127
13
bool SygusEnumerator::TermEnumMasterInterp::initialize(SygusEnumerator* se,
1128
                                                       TypeNode tn)
1129
{
1130
13
  d_se = se;
1131
13
  d_tn = tn;
1132
13
  d_currSize = 0;
1133
13
  d_currNumConsts = 1;
1134
13
  d_nextIndexEnd = 1;
1135
13
  return true;
1136
}
1137
1138
109
Node SygusEnumerator::TermEnumMasterInterp::getCurrent() { return *d_te; }
1139
111
bool SygusEnumerator::TermEnumMasterInterp::increment()
1140
{
1141
111
  if (d_te.isFinished())
1142
  {
1143
2
    return false;
1144
  }
1145
109
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
1146
218
  Node curr = getCurrent();
1147
109
  tc.addTerm(curr);
1148
109
  if (tc.getNumTerms() == d_nextIndexEnd)
1149
  {
1150
18
    tc.pushEnumSizeIndex();
1151
18
    d_currSize++;
1152
18
    d_currNumConsts = d_currNumConsts * options::sygusActiveGenEnumConsts();
1153
18
    d_nextIndexEnd = d_nextIndexEnd + d_currNumConsts;
1154
  }
1155
109
  ++d_te;
1156
109
  return !d_te.isFinished();
1157
}
1158
8
SygusEnumerator::TermEnumMasterFv::TermEnumMasterFv() : TermEnum() {}
1159
8
bool SygusEnumerator::TermEnumMasterFv::initialize(SygusEnumerator* se,
1160
                                                   TypeNode tn)
1161
{
1162
8
  d_se = se;
1163
8
  d_tn = tn;
1164
8
  d_currSize = 0;
1165
16
  Node ret = getCurrent();
1166
8
  AlwaysAssert(!ret.isNull());
1167
8
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
1168
8
  tc.addTerm(ret);
1169
16
  return true;
1170
}
1171
1172
16
Node SygusEnumerator::TermEnumMasterFv::getCurrent()
1173
{
1174
16
  Assert(d_se->d_tds != nullptr);
1175
16
  Node ret = d_se->d_tds->getFreeVar(d_tn, d_currSize);
1176
32
  Trace("sygus-enum-debug2") << "master_fv(" << d_tn << "): mk " << ret
1177
16
                             << std::endl;
1178
16
  return ret;
1179
}
1180
1181
8
bool SygusEnumerator::TermEnumMasterFv::increment()
1182
{
1183
8
  SygusEnumerator::TermCache& tc = d_se->d_tcache[d_tn];
1184
  // size increments at a constant rate
1185
8
  d_currSize++;
1186
8
  tc.pushEnumSizeIndex();
1187
16
  Node curr = getCurrent();
1188
16
  Trace("sygus-enum-debug2") << "master_fv(" << d_tn << "): increment, add "
1189
8
                             << curr << std::endl;
1190
8
  bool ret = tc.addTerm(curr);
1191
8
  AlwaysAssert(ret);
1192
16
  return true;
1193
}
1194
1195
}  // namespace quantifiers
1196
}  // namespace theory
1197
31125
}  // namespace cvc5