GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_enumerator.cpp Lines: 649 667 97.3 %
Date: 2021-08-20 Branches: 1040 2342 44.4 %

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