GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/enum_stream_substitution.h Lines: 6 6 100.0 %
Date: 2021-05-22 Branches: 2 4 50.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Haniel Barbosa, 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
 * Class for streaming concrete values (through substitutions) from
14
 * enumerated abstract ones.
15
 */
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__QUANTIFIERS__SYGUS__ENUM_STREAM_SUBSTITUTION_H
19
#define CVC5__THEORY__QUANTIFIERS__SYGUS__ENUM_STREAM_SUBSTITUTION_H
20
21
#include "expr/node.h"
22
#include "theory/quantifiers/sygus/synth_conjecture.h"
23
24
namespace cvc5 {
25
namespace theory {
26
namespace quantifiers {
27
28
/** Streamer of different values according to variable permutations
29
 *
30
 * Generates a new value (modulo rewriting) when queried in which its variables
31
 * are permuted (see EnumStreamSubstitution for more details).
32
 */
33
class EnumStreamPermutation
34
{
35
 public:
36
  EnumStreamPermutation(quantifiers::TermDbSygus* tds);
37
1
  ~EnumStreamPermutation() {}
38
  /** resets utility
39
   *
40
   * for each subset of the variables in value (according to their
41
   * subclasses_classes), a permutation utility is initialized
42
   */
43
  void reset(Node value);
44
  /** computes next permutation, if any, of value
45
   *
46
   * a "next" permutation is determined by having at least one new permutation
47
   * in one of the variable subclasses in the value.
48
   *
49
   * For example, if the variables of value (OP x1 x2 x3 x4) are partioned into
50
   * {{x1, x4}, {x2, x3}} then the sequence of getNext() is
51
   *
52
   * (OP x4 x2 x3 x1)
53
   * (OP x1 x3 x2 x4)
54
   * (OP x4 x3 x2 x1)
55
   *
56
   * Moreover, new values are only considered if they are unique modulo
57
   * rewriting. If for example OP were "+", then no next value would exist,
58
   * while if OP were "-" the only next value would be: (- x4 x2 x3 x1)
59
   *
60
   * Since the same variable can occur in different subfield types (and
61
   * therefore their datatype equivalents would have different types) a map from
62
   * variables to sets of constructors (see var_cons) is used to build
63
   * substitutions in a proper way when generating different combinations.
64
   */
65
  Node getNext();
66
  /** retrieve variables in class with given id */
67
  const std::vector<Node>& getVarsClass(unsigned id) const;
68
  /** retrieve number of variables being permuted from subclass with given id */
69
  unsigned getVarClassSize(unsigned id) const;
70
71
 private:
72
  /** sygus term database of current quantifiers engine */
73
  quantifiers::TermDbSygus* d_tds;
74
  /** maps subclass ids to subset of d_vars with that subclass id */
75
  std::map<unsigned, std::vector<Node>> d_var_classes;
76
  /** maps variables to subfield types with constructors for
77
   * the that variable, which are themselves associated with the respective
78
   * constructors */
79
  std::map<Node, std::map<TypeNode, Node>> d_var_tn_cons;
80
  /** whether first query */
81
  bool d_first;
82
  /** value to which we are generating permutations */
83
  Node d_value;
84
  /** generated permutations (modulo rewriting) */
85
  std::unordered_set<Node> d_perm_values;
86
  /** retrieves variables occurring in value */
87
  void collectVars(Node n,
88
                   std::vector<Node>& vars,
89
                   std::unordered_set<Node>& visited);
90
  /** Utility for stepwise application of Heap's algorithm for permutation
91
   *
92
   * see https://en.wikipedia.org/wiki/Heap%27s_algorithm
93
   */
94
3
  class PermutationState
95
  {
96
   public:
97
    PermutationState(const std::vector<Node>& vars);
98
    /** computes next permutation, i.e. execute one step of Heap's algorithm
99
     *
100
     * returns true if one exists, false otherwise
101
     *
102
     * when a new permutation is generated the the new variable arrangement is
103
     * stored in d_last_perm (in terms of d_vars' indices)
104
     */
105
    bool getNextPermutation();
106
    /** resets permutation state to initial variable ordering */
107
    void reset();
108
    /** retrieves last variable permutation
109
     *
110
     * vars is populated with the new variable arrangement
111
     */
112
    void getLastPerm(std::vector<Node>& vars);
113
    /** retrieve variables being permuted */
114
    const std::vector<Node>& getVars() const;
115
116
   private:
117
    /** variables being permuted */
118
    std::vector<Node> d_vars;
119
    /** last computed permutation of variables */
120
    std::vector<unsigned> d_last_perm;
121
    /** auxiliary position list for generating permutations */
122
    std::vector<unsigned> d_seq;
123
    /** current index being permuted */
124
    unsigned d_curr_ind;
125
  };
126
  /** permutation state of each variable subclass */
127
  std::vector<PermutationState> d_perm_state_class;
128
  /** current variable subclass being permuted */
129
  unsigned d_curr_ind;
130
};
131
132
/** Streamer of concrete values for enumerator
133
 *
134
 * When a given enumerator is "variable agnostic", only values in which
135
 * variables are ordered are chosen for it (see
136
 * TermDbSygus::registerEnumerator). If such values are seen as "abstract", in
137
 * the sense that each represent a set of values, this class can be used to
138
 * stream all the concrete values that correspond to them.
139
 *
140
 * For example a variable agnostic enumerator that contains three variables, x1,
141
 * x2, x3, in which x1 < x2 < x3, for which an "abstract" value (OP x1 x2) is
142
 * derived, will lead to the stream of "concrete" values
143
 *
144
 * (OP x1 x2)
145
 * (OP x1 x3)
146
 * (OP x2 x3)
147
 *
148
 * (OP x2 x1)
149
 * (OP x3 x1)
150
 * (OP x3 x2)
151
 *
152
 * in which for each permutation of the variables in the abstract value ([x1,
153
 * x2] and [x2, x1] in the above) we generate all the substitutions through
154
 * ordered combinations of the variables of the enumerator ([x1, x2], [x1, x3],
155
 * and [x2, x3] in the above).
156
 *
157
 * Moreover the permutations are generated modulo rewriting, s.t. if two
158
 * permutations are equivalent, only one is used.
159
 *
160
 * It should be noted that the variables of a variable agnostic enumerator are
161
 * kept in independent "subclasses" (see TermDbSygus::getSubclassForVar).
162
 * Therefore when streaming concrete values, permutations and combinations are
163
 * generated by the product of the permutations and combinations of each class.
164
 */
165
class EnumStreamSubstitution
166
{
167
 public:
168
  EnumStreamSubstitution(quantifiers::TermDbSygus* tds);
169
1
  ~EnumStreamSubstitution() {}
170
  /** initializes utility
171
   *
172
   * the combinations are generated from a initial set of variables (for now all
173
   * variables in given type).
174
   */
175
  void initialize(TypeNode tn);
176
  /** resets value for which substitutions will be generated through
177
   * combinations
178
   *
179
   * For each variable subclass in this utility, a subset is chosen with as
180
   * many variables as in the same variable subclass of value's variables.
181
   *
182
   * The combinations are performed modulo subclasses. For each subclass of the
183
   * given variables, a combination utility is initialized.
184
   *
185
   * For example, if the initial variable set is partioned into
186
   *
187
   * {1 -> {x1, x4}, 2 -> {x2, x3, x6}, 3 -> {x5}}
188
   *
189
   * and value's variables into
190
   *
191
   * {1 -> {x1, x4}, 2 -> {x2}, 3 -> {}}
192
   *
193
   * then the combination utilities are initialized such that for class 1 all
194
   * ordered subsets with two variables are chosen; for class 2 all ordered
195
   * subsets with one variable; and for class 3 no combination can be chosen.
196
   */
197
  void resetValue(Node value);
198
  /** computes next combination, if any, of value
199
   *
200
   * a "next" combination is determined by having at least one new combination
201
   * in one of the variable subclasses in the initial set of variables. If no
202
   * new combination exists, the cycle restarts with a new base value generated
203
   * by EnumStreamPermutation::getNext() (see above).
204
   *
205
   * This layered approach (of deriving all combinations for each permutation)
206
   * allows to consider only ordered combinations to generate all possible
207
   * variations of the base value. See the example in EnumStreamSubstitution for
208
   * further details.
209
   */
210
  Node getNext();
211
212
 private:
213
  /** sygus term database of current quantifiers engine */
214
  quantifiers::TermDbSygus* d_tds;
215
  /** type this utility has been initialized for */
216
  TypeNode d_tn;
217
  /** current value */
218
  Node d_value;
219
  /** maps subclass ids to d_tn's variables with that subclass id */
220
  std::map<unsigned, std::vector<Node>> d_var_classes;
221
  /** maps variables to subfield types with constructors for
222
   * the that variable, which are themselves associated with the respective
223
   * constructors */
224
  std::map<Node, std::map<TypeNode, Node>> d_var_tn_cons;
225
  /** last value generated after a combination
226
   *
227
   * If getNext() has been called, this is the return value of the most recent
228
   * call to getNext(). Otherwise, this value is null.
229
   */
230
  Node d_last;
231
  /** generated combinations */
232
  std::unordered_set<Node> d_comb_values;
233
  /** permutation utility */
234
  EnumStreamPermutation d_stream_permutations;
235
  /** Utility for stepwise generation of ordered subsets of size k from n
236
   * variables */
237
3
  class CombinationState
238
  {
239
   public:
240
    CombinationState(unsigned n,
241
                     unsigned k,
242
                     unsigned subclass_id,
243
                     const std::vector<Node>& vars);
244
    /** computes next combination
245
     *
246
     * returns true if one exists, false otherwise
247
     */
248
    bool getNextCombination();
249
    /** resets combination state to first k variables in vars */
250
    void reset();
251
    /** retrieves last variable combination
252
     *
253
     * variables in new combination are stored in argument vars
254
     */
255
    void getLastComb(std::vector<Node>& vars);
256
    /** retrieve subclass id */
257
    const unsigned getSubclassId() const;
258
259
   private:
260
    /** subclass id of variables being combined */
261
    unsigned d_subclass_id;
262
    /** number of variables */
263
    unsigned d_n;
264
    /** size of subset */
265
    unsigned d_k;
266
    /** last combination state */
267
    std::vector<unsigned> d_last_comb;
268
    /** variables from which combination is extracted */
269
    std::vector<Node> d_vars;
270
  };
271
  /** combination state for each variable subclass */
272
  std::vector<CombinationState> d_comb_state_class;
273
  /** current class being combined */
274
  unsigned d_curr_ind;
275
};
276
277
/**
278
 * An enumerated value generator based on the above class. This is
279
 * SynthConjecture's interface to using the above utility.
280
 */
281
2
class EnumStreamConcrete : public EnumValGenerator
282
{
283
 public:
284
1
  EnumStreamConcrete(quantifiers::TermDbSygus* tds) : d_ess(tds) {}
285
  /** initialize this class with enumerator e */
286
  void initialize(Node e) override;
287
  /** get that value v was enumerated */
288
  void addValue(Node v) override;
289
  /** increment */
290
  bool increment() override;
291
  /** get the current value enumerated by this class */
292
  Node getCurrent() override;
293
294
 private:
295
  /** stream substitution utility */
296
  EnumStreamSubstitution d_ess;
297
  /** the current term generated by this class */
298
  Node d_currTerm;
299
};
300
301
}  // namespace quantifiers
302
}  // namespace theory
303
}  // namespace cvc5
304
305
#endif