GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_enumerator.h Lines: 9 9 100.0 %
Date: 2021-08-16 Branches: 0 0 0.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner
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
 * sygus_enumerator
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__QUANTIFIERS__SYGUS_ENUMERATOR_H
19
#define CVC5__THEORY__QUANTIFIERS__SYGUS_ENUMERATOR_H
20
21
#include <map>
22
#include <unordered_set>
23
#include "expr/node.h"
24
#include "expr/type_node.h"
25
#include "theory/quantifiers/sygus/enum_val_generator.h"
26
#include "theory/quantifiers/sygus/synth_conjecture.h"
27
#include "theory/quantifiers/sygus/term_database_sygus.h"
28
29
namespace cvc5 {
30
namespace theory {
31
namespace quantifiers {
32
33
class SynthConjecture;
34
class SygusPbe;
35
36
/** SygusEnumerator
37
 *
38
 * This class is used for enumerating all terms of a sygus datatype type. At
39
 * a high level, it is used as an alternative approach to sygus datatypes
40
 * solver as a candidate generator in a synthesis loop. It filters terms based
41
 * on redundancy criteria, for instance, it does not generate two terms whose
42
 * builtin terms (TermDb::sygusToBuiltin) can be shown to be equivalent via
43
 * rewriting. It enumerates terms in order of sygus term size
44
 * (TermDb::getSygusTermSize).
45
 *
46
 * It also can be configured to enumerates sygus terms with free variables,
47
 * (as opposed to variables bound in the formal arguments list of the
48
 * function-to-synthesize), where each free variable appears in exactly one
49
 * subterm. For grammar:
50
 *   S -> 0 | 1 | x | S+S
51
 * this enumerator will generate the stream:
52
 *   z1, C_0, C_1, C_x, C_+(z1, z2), C_+(z1, C_1), C_+(C_1, C_1) ...
53
 * and so on, where z1 and z2 are variables of sygus datatype type S. We call
54
 * these "shapes". This feature can be enabled by setting enumShapes to true
55
 * in the constructor below.
56
 */
57
class SygusEnumerator : public EnumValGenerator
58
{
59
 public:
60
  /**
61
   * @param tds Pointer to the term database, required if enumShapes or
62
   * enumAnyConstHoles is true, or if we want to include symmetry breaking from
63
   * lemmas stored in the sygus term database,
64
   * @param p Pointer to the conjecture, required if we wish to do
65
   * conjecture-specific symmetry breaking
66
   * @param s Pointer to the statistics
67
   * @param enumShapes If true, this enumerator will generate terms having any
68
   * number of free variables
69
   * @param enumAnyConstHoles If true, this enumerator will generate terms where
70
   * free variables are the arguments to any-constant constructors.
71
   */
72
  SygusEnumerator(TermDbSygus* tds = nullptr,
73
                  SynthConjecture* p = nullptr,
74
                  SygusStatistics* s = nullptr,
75
                  bool enumShapes = false,
76
                  bool enumAnyConstHoles = false);
77
334
  ~SygusEnumerator() {}
78
  /** initialize this class with enumerator e */
79
  void initialize(Node e) override;
80
  /** Inform this generator that abstract value v was enumerated. */
81
  void addValue(Node v) override;
82
  /** increment */
83
  bool increment() override;
84
  /** Get the next concrete value generated by this class. */
85
  Node getCurrent() override;
86
  /** Are we enumerating shapes? */
87
  bool isEnumShapes() const;
88
89
 private:
90
  /** pointer to term database sygus */
91
  TermDbSygus* d_tds;
92
  /** pointer to the synth conjecture that owns this enumerator */
93
  SynthConjecture* d_parent;
94
  /** pointer to the statistics */
95
  SygusStatistics* d_stats;
96
  /** Whether we are enumerating shapes */
97
  bool d_enumShapes;
98
  /** Whether we are enumerating free variables as arguments to any-constant
99
   * constructors */
100
  bool d_enumAnyConstHoles;
101
  /** Term cache
102
   *
103
   * This stores a list of terms for a given sygus type. The key features of
104
   * this data structure are that terms are stored in order of size,
105
   * indices can be recorded that indicate where terms of size n begin for each
106
   * natural number n, and redundancy criteria are used for discarding terms
107
   * that are not relevant. This includes discarding terms whose builtin version
108
   * is the same up to T-rewriting with another, or is equivalent under
109
   * examples, if the conjecture in question is in examples form and
110
   * sygusSymBreakPbe is enabled.
111
   *
112
   * This class also computes static information about sygus types that is
113
   * relevant for enumeration. Primarily, this includes mapping constructors
114
   * to "constructor classes". Two sygus constructors can be placed in the same
115
   * constructor class if their constructor weight is equal, and the tuple
116
   * of their argument types are the same. For example, for:
117
   *   A -> A+B | A-B | A*B | A+A | A | x
118
   * The first three constructors above can be placed in the same constructor
119
   * class, assuming they have identical weights. Constructor classes are used
120
   * as an optimization when enumerating terms, since they expect the same
121
   * tuple of argument terms for constructing a term of a fixed size.
122
   *
123
   * Constructor classes are allocated such that the constructor weights are
124
   * in ascending order. This allows us to avoid constructors whose weight
125
   * is greater than n while we are trying to enumerate terms of sizes strictly
126
   * less than n.
127
   *
128
   * Constructor class 0 is reserved for nullary operators with weight 0. This
129
   * is an optimization so that such constructors can be skipped for sizes
130
   * greater than 0, since we know all terms generated by these constructors
131
   * have size 0.
132
   */
133
312
  class TermCache
134
  {
135
   public:
136
    TermCache();
137
    /** initialize this cache */
138
    void initialize(SygusStatistics* s,
139
                    Node e,
140
                    TypeNode tn,
141
                    TermDbSygus* tds,
142
                    ExampleEvalCache* ece = nullptr);
143
    /** get last constructor class index for weight
144
     *
145
     * This returns a minimal index n such that all constructor classes at
146
     * index < n have weight at most w.
147
     */
148
    unsigned getLastConstructorClassIndexForWeight(unsigned w) const;
149
    /** get num constructor classes */
150
    unsigned getNumConstructorClasses() const;
151
    /** get the constructor indices for constructor class i */
152
    void getConstructorClass(unsigned i, std::vector<unsigned>& cclass) const;
153
    /** get argument types for constructor class i */
154
    void getTypesForConstructorClass(unsigned i,
155
                                     std::vector<TypeNode>& types) const;
156
    /** get constructor weight for constructor class i */
157
    unsigned getWeightForConstructorClass(unsigned i) const;
158
159
    /**
160
     * Add sygus term n to this cache, return true if the term was unique based
161
     * on the redundancy criteria used by this class.
162
     */
163
    bool addTerm(Node n);
164
    /**
165
     * Indicate to this cache that we are finished enumerating terms of the
166
     * current size.
167
     */
168
    void pushEnumSizeIndex();
169
    /** Get the current size of terms that we are enumerating */
170
    unsigned getEnumSize() const;
171
    /** get the index at which size s terms start, where s <= getEnumSize() */
172
    unsigned getIndexForSize(unsigned s) const;
173
    /** get the index^th term successfully added to this cache */
174
    Node getTerm(unsigned index) const;
175
    /** get the number of terms successfully added to this cache */
176
    unsigned getNumTerms() const;
177
    /** are we finished enumerating terms? */
178
    bool isComplete() const;
179
    /** set that we are finished enumerating terms */
180
    void setComplete();
181
182
   private:
183
    /** reference to the statistics of parent */
184
    SygusStatistics* d_stats;
185
    /** the enumerator this cache is for */
186
    Node d_enum;
187
    /** the sygus type of terms in this cache */
188
    TypeNode d_tn;
189
    /** pointer to term database sygus */
190
    TermDbSygus* d_tds;
191
    /** extended rewriter */
192
    ExtendedRewriter d_extr;
193
    /**
194
     * Pointer to the example evaluation cache utility (used for symmetry
195
     * breaking).
196
     */
197
    ExampleEvalCache* d_eec;
198
    //-------------------------static information about type
199
    /** is d_tn a sygus type? */
200
    bool d_isSygusType;
201
    /** number of constructor classes */
202
    unsigned d_numConClasses;
203
    /** Map from weights to the starting constructor class for that weight. */
204
    std::map<unsigned, unsigned> d_weightToCcIndex;
205
    /** Information for each constructor class */
206
    class ConstructorClass
207
    {
208
     public:
209
812
      ConstructorClass() : d_weight(0) {}
210
812
      ~ConstructorClass() {}
211
      /** The indices of the constructors in this constructor class */
212
      std::vector<unsigned> d_cons;
213
      /** The argument types of the constructor class */
214
      std::vector<TypeNode> d_types;
215
      /** Constructor weight */
216
      unsigned d_weight;
217
    };
218
    std::map<unsigned, ConstructorClass> d_cclass;
219
    /** constructor to indices */
220
    std::map<unsigned, std::vector<unsigned>> d_cToCIndices;
221
    //-------------------------end static information about type
222
223
    /** the list of sygus terms we have enumerated */
224
    std::vector<Node> d_terms;
225
    /** the set of builtin terms corresponding to the above list */
226
    std::unordered_set<Node> d_bterms;
227
    /**
228
     * The index of first term whose size is greater than or equal to that size,
229
     * if it exists.
230
     */
231
    std::map<unsigned, unsigned> d_sizeStartIndex;
232
    /** the maximum size of terms we have stored in this cache so far */
233
    unsigned d_sizeEnum;
234
    /** whether this term cache is complete */
235
    bool d_isComplete;
236
    /** sampler (for --sygus-rr-verify) */
237
    quantifiers::SygusSampler d_samplerRrV;
238
    /** is the above sampler initialized? */
239
    bool d_sampleRrVInit;
240
  };
241
  /** above cache for each sygus type */
242
  std::map<TypeNode, TermCache> d_tcache;
243
  /** initialize term cache for type tn */
244
  void initializeTermCache(TypeNode tn);
245
246
  /** virtual class for term enumerators */
247
  class TermEnum
248
  {
249
   public:
250
    TermEnum();
251
3577
    virtual ~TermEnum() {}
252
    /** get the current size of terms we are enumerating */
253
    unsigned getCurrentSize();
254
    /** get the current term of the enumerator */
255
    virtual Node getCurrent() = 0;
256
    /** increment the enumerator, return false if the enumerator is finished */
257
    virtual bool increment() = 0;
258
259
   protected:
260
    /** pointer to the sygus enumerator class */
261
    SygusEnumerator* d_se;
262
    /** the (sygus) type of terms we are enumerating */
263
    TypeNode d_tn;
264
    /** the current size of terms we are enumerating */
265
    unsigned d_currSize;
266
  };
267
  class TermEnumMaster;
268
  /** A "slave" enumerator
269
   *
270
   * A slave enumerator simply iterates over an index in a given term cache,
271
   * and relies on a pointer to a "master" enumerator to generate new terms
272
   * whenever necessary.
273
   *
274
   * This class maintains the following invariants, for tc=d_se->d_tcache[d_tn]:
275
   * (1) d_index < tc.getNumTerms(),
276
   * (2) d_currSize is the term size of tc.getTerm( d_index ),
277
   * (3) d_hasIndexNextEnd is (d_currSize < tc.getEnumSize()),
278
   * (4) If d_hasIndexNextEnd is true, then
279
   *       d_indexNextEnd = tc.getIndexForSize(d_currSize+1), and
280
   *       d_indexNextEnd > d_index.
281
   *
282
   * Intuitively, these invariants say (1) d_index is a valid index in the
283
   * term cache, (2) d_currSize is the sygus term size of getCurrent(), (3)
284
   * d_hasIndexNextEnd indicates whether d_indexNextEnd is valid, and (4)
285
   * d_indexNextEnd is the index in the term cache where terms of the current
286
   * size end, if such an index exists.
287
   */
288
3265
  class TermEnumSlave : public TermEnum
289
  {
290
   public:
291
    TermEnumSlave();
292
    /**
293
     * Initialize this enumerator to enumerate terms of type tn whose size is in
294
     * the range [sizeMin, sizeMax], inclusive. If this function returns true,
295
     * then getCurrent() will return the first term in the stream, which is
296
     * non-empty. Further terms are generated by increment()/getCurrent().
297
     */
298
    bool initialize(SygusEnumerator* se,
299
                    TypeNode tn,
300
                    unsigned sizeMin,
301
                    unsigned sizeMax);
302
    /** get the current term of the enumerator */
303
    Node getCurrent() override;
304
    /** increment the enumerator */
305
    bool increment() override;
306
307
   private:
308
    /** the maximum size of terms this enumerator should enumerate */
309
    unsigned d_sizeLim;
310
    /** the current index in the term cache we are considering */
311
    unsigned d_index;
312
    /** the index in the term cache where terms of the current size end */
313
    unsigned d_indexNextEnd;
314
    /** whether d_indexNextEnd refers to a valid index */
315
    bool d_hasIndexNextEnd;
316
    /** pointer to the master enumerator of type d_tn */
317
    TermEnum* d_master;
318
    /** validate invariants on d_index, d_indexNextEnd, d_hasIndexNextEnd */
319
    bool validateIndex();
320
    /** validate invariants on  d_indexNextEnd, d_hasIndexNextEnd  */
321
    void validateIndexNextEnd();
322
  };
323
  /** Class for "master" enumerators
324
   *
325
   * This enumerator is used to generate new terms of a given type d_tn. It
326
   * generates all terms of type d_tn that are not redundant based on the
327
   * current criteria.
328
   *
329
   * To enumerate terms, this class performs the following steps as necessary
330
   * during a call to increment():
331
   * - Fix the size of terms "d_currSize" we are currently enumerating,
332
   * - Set the constructor class "d_consClassNum" whose constructors are the top
333
   * symbol of the current term we are constructing. All constructors from this
334
   * class have the same weight, which we store in d_ccWeight,
335
   * - Initialize the current children "d_children" so that the sum of their
336
   * current sizes is exactly (d_currSize - d_ccWeight),
337
   * - Increment the current set of children until a new tuple of terms is
338
   * considered,
339
   * - Set the constructor "d_consNum" from within the constructor class,
340
   * - Build the current term and check whether it is not redundant according
341
   * to the term cache of its type.
342
   *
343
   * We say this enumerator is active if initialize(...) returns true, and the
344
   * last call (if any) to increment returned true.
345
   *
346
   * This class maintains the following invariants, for tc=d_se->d_tcache[d_tn],
347
   * if it is active:
348
   * (1) getCurrent() is tc.getTerm(tc.getNumTerms()-1),
349
   * (2) tc.pushEnumSizeIndex() has been called by this class exactly
350
   * getCurrentSize() times.
351
   * In other words, (1) getCurrent() is always the last term in the term cache
352
   * of the type of this enumerator tc, and (2) the size counter of tc is in
353
   * sync with the current size of this enumerator, that is, the master
354
   * enumerator is responsible for communicating size boundaries to its term
355
   * cache.
356
   */
357
296
  class TermEnumMaster : public TermEnum
358
  {
359
   public:
360
    TermEnumMaster();
361
    /**
362
     * Initialize this enumerator to enumerate (all) terms of type tn, modulo
363
     * the redundancy criteria used by this class.
364
     */
365
    bool initialize(SygusEnumerator* se, TypeNode tn);
366
    /** get the current term of the enumerator */
367
    Node getCurrent() override;
368
    /** increment the enumerator
369
     *
370
     * Returns true if there are more terms to enumerate, in which case a
371
     * subsequent call to getCurrent() returns the next enumerated term. This
372
     * method returns false if the last call to increment() has yet to
373
     * terminate. This can happen for recursive datatypes where a slave
374
     * enumerator may request that this class increment the next term. We avoid
375
     * an infinite loop by guarding this with the d_isIncrementing flag and
376
     * return false.
377
     */
378
    bool increment() override;
379
380
   private:
381
    /** pointer to term database sygus */
382
    TermDbSygus* d_tds;
383
    /** are we enumerating shapes? */
384
    bool d_enumShapes;
385
    /** have we initialized the shape enumeration? */
386
    bool d_enumShapesInit;
387
    /** are we currently inside a increment() call? */
388
    bool d_isIncrementing;
389
    /** cache for getCurrent() */
390
    Node d_currTerm;
391
    /** is d_currTerm set */
392
    bool d_currTermSet;
393
    //----------------------------- current constructor class information
394
    /** the next constructor class we are using */
395
    unsigned d_consClassNum;
396
    /** the constructors in the current constructor class */
397
    std::vector<unsigned> d_ccCons;
398
    /** the types of the current constructor class */
399
    std::vector<TypeNode> d_ccTypes;
400
    /** the operator weight for the constructor class */
401
    unsigned d_ccWeight;
402
    //----------------------------- end current constructor class information
403
    /** If >0, 1 + the index in d_ccCons we are considering */
404
    unsigned d_consNum;
405
    /** the child enumerators for this enumerator */
406
    std::map<unsigned, TermEnumSlave> d_children;
407
    /** the current sum of current sizes of the enumerators in d_children */
408
    unsigned d_currChildSize;
409
    /**
410
     * The number of indices, starting from zero, in d_children that point to
411
     * initialized slave enumerators.
412
     */
413
    unsigned d_childrenValid;
414
    /** initialize children
415
     *
416
     * Initialize all the remaining uninitialized children of this enumerator.
417
     * If this method returns true, then each of d_children are
418
     * initialized to be slave enumerators of the argument types indicated by
419
     * d_ccTypes, and the sum of their current sizes (d_currChildSize) is
420
     * exactly (d_currSize - d_ccWeight). If this method returns false, then
421
     * it was not possible to initialize the children such that they meet the
422
     * size requirements, and such that the assignments from children to size
423
     * has not already been considered. In this case, all updates to d_children
424
     * are reverted and d_currChildSize and d_childrenValid are reset to their
425
     * values prior to this call.
426
     */
427
    bool initializeChildren();
428
    /** initialize child
429
     *
430
     * Initialize child i to enumerate terms whose size is at least sizeMin,
431
     * and whose maximum size is the largest size such that we can still
432
     * construct terms for the given constructor class and the current children
433
     * whose size is not more than the current size d_currSize. Additionally,
434
     * if i is the last child, we modify sizeMin such that it is exactly the
435
     * size of terms needed for the children to sum up to size d_currSize.
436
     */
437
    bool initializeChild(unsigned i, unsigned sizeMin);
438
    /** increment internal, helper for increment() */
439
    bool incrementInternal();
440
    /**
441
     * The vector children is a set of terms given to
442
     *    NodeManager::mkNode(APPLY_CONSTRUCTOR, children)
443
     * This converts children so that all sygus free variables are unique. Note
444
     * that the first child is a constructor operator and should be skipped.
445
     */
446
    void childrenToShape(std::vector<Node>& children);
447
    /**
448
     * Convert n into shape based on the variable counters. For example if
449
     * vcounter is { Int -> 7 }, then (+ x1 x2) is converted to (+ x7 x8) and
450
     * vouncter is updated to { Int -> 9 }.
451
     */
452
    Node convertShape(Node n, std::map<TypeNode, int>& vcounter);
453
  };
454
  /** an interpreted value enumerator
455
   *
456
   * This enumerator uses the builtin type enumerator for a given type. It
457
   * is used to fill in concrete holes into "any constant" constructors
458
   * when sygus-repair-const is not enabled. The number of terms of size n
459
   * is m^n, where m is configurable via --sygus-active-gen-enum-cfactor=m.
460
   */
461
22
  class TermEnumMasterInterp : public TermEnum
462
  {
463
   public:
464
    TermEnumMasterInterp(TypeNode tn);
465
    /** initialize this enumerator */
466
    bool initialize(SygusEnumerator* se, TypeNode tn);
467
    /** get the current term of the enumerator */
468
    Node getCurrent() override;
469
    /** increment the enumerator */
470
    bool increment() override;
471
472
   private:
473
    /** the type enumerator */
474
    TypeEnumerator d_te;
475
    /** the current number of terms we are enumerating for the given size */
476
    unsigned d_currNumConsts;
477
    /** the next end threshold */
478
    unsigned d_nextIndexEnd;
479
  };
480
  /** a free variable enumerator
481
   *
482
   * This enumerator enumerates canonical free variables for a given type.
483
   * The n^th variable in this stream is assigned size n. This enumerator is
484
   * used in conjunction with sygus-repair-const to generate solutions with
485
   * constant holes. In this approach, free variables are arguments to
486
   * any-constant constructors. This is required so that terms with holes are
487
   * unique up to rewriting when appropriate.
488
   */
489
5
  class TermEnumMasterFv : public TermEnum
490
  {
491
   public:
492
    TermEnumMasterFv();
493
    /** initialize this enumerator */
494
    bool initialize(SygusEnumerator* se, TypeNode tn);
495
    /** get the current term of the enumerator */
496
    Node getCurrent() override;
497
    /** increment the enumerator */
498
    bool increment() override;
499
  };
500
  /** the master enumerator for each sygus type */
501
  std::map<TypeNode, TermEnumMaster> d_masterEnum;
502
  /** the master enumerator for each non-sygus type */
503
  std::map<TypeNode, TermEnumMasterFv> d_masterEnumFv;
504
  /** the master enumerator for each non-sygus type */
505
  std::map<TypeNode, std::unique_ptr<TermEnumMasterInterp>> d_masterEnumInt;
506
  /** the sygus enumerator this class is for */
507
  Node d_enum;
508
  /** the type of d_enum */
509
  TypeNode d_etype;
510
  /** pointer to the master enumerator of type d_etype */
511
  TermEnum* d_tlEnum;
512
  /** the abort size, caches the value of --sygus-abort-size */
513
  int d_abortSize;
514
  /** get master enumerator for type tn */
515
  TermEnum* getMasterEnumForType(TypeNode tn);
516
  //-------------------------------- externally specified symmetry breaking
517
  /** set of constructors we disallow at top level
518
   *
519
   * A constructor C is disallowed at the top level if a symmetry breaking
520
   * lemma that entails ~is-C( d_enum ) was registered to
521
   * TermDbSygus::registerSymBreakLemma.
522
   */
523
  std::unordered_set<Node> d_sbExcTlCons;
524
  //-------------------------------- end externally specified symmetry breaking
525
};
526
527
}  // namespace quantifiers
528
}  // namespace theory
529
}  // namespace cvc5
530
531
#endif /* CVC5__THEORY__QUANTIFIERS__SYGUS_ENUMERATOR_H */