GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_enumerator.cpp Lines: 642 659 97.4 %
Date: 2021-05-22 Branches: 1036 2302 45.0 %

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