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