GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_reconstruct.h Lines: 1 1 100.0 %
Date: 2021-09-07 Branches: 0 0 0.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Abdalrhman Mohamed, Andrew Reynolds
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
 * Utility for reconstructing terms to match a grammar.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__QUANTIFIERS__SYGUS_RECONSTRUCT_H
19
#define CVC5__THEORY__QUANTIFIERS__SYGUS_RECONSTRUCT_H
20
21
#include <map>
22
#include <vector>
23
24
#include "expr/match_trie.h"
25
#include "theory/quantifiers/sygus/rcons_obligation.h"
26
#include "theory/quantifiers/sygus/rcons_type_info.h"
27
28
namespace cvc5 {
29
namespace theory {
30
namespace quantifiers {
31
32
using BuiltinSet = std::unordered_set<Node>;
33
using TypeBuiltinSetMap = std::unordered_map<TypeNode, BuiltinSet>;
34
using NodePairMap = std::unordered_map<Node, Node>;
35
36
/** SygusReconstruct
37
 *
38
 * This class implements an algorithm for reconstructing a given term such that
39
 * the reconstructed term is equivalent to the original term and its syntax
40
 * matches a specified grammar.
41
 *
42
 * Goal: find a term g in sygus type T0 that is equivalent to builtin term t0.
43
 *
44
 * rcons(t0, T0) returns g
45
 * {
46
 *   Obs: A set of pairs to reconstruct into T, where each pair is of the form
47
 *        (k, ts), where k is a skolem of a sygus type T and ts is a set of
48
 *        builtin terms of the type encoded by T.
49
 *
50
 *   Terms: A map from skolems k to a set of builtin terms in the pairs (k, ts).
51
 *          That is, Terms[k] = ts.
52
 *
53
 *   Sol: A map from skolems k to (possibly null) sygus terms of type T
54
 *        representing solutions to the obligations.
55
 *
56
 *   CandSols : A map from a skolem k to a set of possible solutions for its
57
 *              corresponding obligation. Whenever there is a successful match,
58
 *              it is added to this set.
59
 *
60
 *   Pool : A map from a sygus type T to a set of enumerated terms in T.
61
 *          The terms in this pool are patterns whose builtin analogs are used
62
 *          for matching against the terms to reconstruct ts in (k, ts).
63
 *
64
 *   let k0 be a fresh skolem of sygus type T0
65
 *   Obs[T0] += (k0, {t0})
66
 *
67
 *   TermsToRecons[T0] = {t0}
68
 *
69
 *   while Sol[k0] == null
70
 *     // map from T to terms pending addition to TermsToRecons
71
 *     TermsToRecons' = {}
72
 *     // enumeration phase
73
 *     for each subfield type T of T0
74
 *       // enumerated terms may contain variables zs ranging over all terms of
75
 *       // their type (subfield types of T0)
76
 *       s[zs] = nextEnum(T)
77
 *       if (s[zs] is ground)
78
 *         builtin = rewrite(toBuiltIn(s[zs]))
79
 *         // let X be the theory the solver is invoked with
80
 *         find (k, ts) in Obs s.t. |=_X ts[0] = builtin
81
 *         if no such pair exists
82
 *           k = newVar(T)
83
 *           ts = {builtin}
84
 *           Obs += (k, ts)
85
 *         markSolved((k, ts), s[zs])
86
 *       else if no s' in Pool[T] and matcher sigma s.t.
87
 *             rewrite(toBuiltIn(s')) * sigma = rewrite(toBuiltIn(s[zs]))
88
 *         Pool[T] += s[zs]
89
 *         for each t in TermsToRecons[T]
90
 *           TermsToRecons' += matchNewObs(t, s[zs])
91
 *     // match phase
92
 *     while TermsToRecons' != {}
93
 *       TermsToRecons'' = {}
94
 *       for each subfield type T of T0
95
 *         for each t in TermsToRecons'[T]
96
 *           TermsToRecons'[T] += t
97
 *           for each s[zs] in Pool[T]
98
 *             TermsToRecons'' += matchNewObs(t, s[zs])
99
 *         TermsToRecons' = TermsToRecons''
100
 *   g = Sol[k0]
101
 *   instantiate free variables of g with arbitrary sygus datatype values
102
 * }
103
 *
104
 * matchNewObs(t, s[zs]) returns TermsToRecons'
105
 * {
106
 *   u = rewrite(toBuiltIn(s[zs]))
107
 *   if match(u, t) == {toBuiltin(zs) -> sts}
108
 *     Sub = {} // substitution map from zs to corresponding new vars ks
109
 *     for each (z, st) in {zs -> sts}
110
 *       // let X be the theory the solver is invoked with
111
 *       if exists (k, ts) in Obs s.t. !=_X ts[0] = st
112
 *         ts += st
113
 *         Sub[z] = k
114
 *       else
115
 *         sk = newVar(typeOf(z))
116
 *         Sub[z] = sk
117
 *         TermsToRecons'[typeOf(z)] += st
118
 *     if Sol[sk] != null forall (z, sk) in Sub
119
 *       markSolved(k, s{Sub})
120
 *     else
121
 *       CandSol[k] += s{Sub}
122
 * }
123
 *
124
 * markSolved((k, ts), s)
125
 * {
126
 *   if Sol[k] != null
127
 *     return
128
 *   Sol[k] = s
129
 *   CandSols[k] += s
130
 *   Stack = {k}
131
 *   while Stack != {}
132
 *     k' = pop(Stack)
133
 *     for all k'' in CandSols keys
134
 *       for all s'[k'] in CandSols[k'']
135
 *         s'{k' -> Sol[k']}
136
 *         if s' does not contain free variables in Obs
137
 *           Sol[k''] = s'
138
 *           push(Stack, k'')
139
 * }
140
 */
141
2378
class SygusReconstruct : public expr::NotifyMatch
142
{
143
 public:
144
  /**
145
   * Constructor.
146
   *
147
   * @param env reference to the environment
148
   * @param tds database for sygus terms
149
   * @param s statistics managed for the synth engine
150
   */
151
  SygusReconstruct(Env& env, TermDbSygus* tds, SygusStatistics& s);
152
153
  /** Reconstruct solution.
154
   *
155
   * Return (if possible) a sygus encoding of a node that is equivalent to sol
156
   * and whose syntax matches the grammar corresponding to sygus datatype stn.
157
   *
158
   * For example, given:
159
   *   sol = (* 2 x)
160
   *   stn = A sygus datatype encoding the grammar
161
   *           Start -> (c_PLUS Start Start) | c_x | c_0 | c_1
162
   * This method may return (c_PLUS c_x c_x) and set reconstructed to 1.
163
   *
164
   * @param sol the target term
165
   * @param stn the sygus datatype type encoding the syntax restrictions
166
   * @param reconstructed the flag to update, set to 1 if we successfully return
167
   *                      a node, otherwise it is set to -1
168
   * @param enumLimit a value to limit the effort spent by this class (roughly
169
   *                  equal to the number of intermediate terms to try)
170
   * @return the reconstructed sygus term
171
   */
172
  Node reconstructSolution(Node sol,
173
                           TypeNode stn,
174
                           int8_t& reconstructed,
175
                           uint64_t enumLimit);
176
177
 private:
178
  /** Match builtin term `t` with pattern `sz`.
179
   *
180
   * This function matches the builtin term to reconstruct `t` with the builtin
181
   * analog of the pattern `sz`. If the match succeeds, `sz` is added to the set
182
   * of candidate solutions for the obligation `ob` corresponding to the builtin
183
   * term `t` and a set of new sub-terms to reconstruct is returned. If there
184
   * are no new sub-terms to reconstruct, then `sz` is considered a solution to
185
   * obligation `ob` and `markSolved(ob, sz)` is called. For example, given:
186
   *
187
   * Obs = [(k0, {(+ 1 1)})]
188
   * Pool[T0] = {(c_+ z1 z2)}
189
   * CandSols = {}
190
   *
191
   * Then calling `matchNewObs((+ 1 1), (c_+ z1 z2))` will result in:
192
   *
193
   * Obs = [(k0, {(+ 1 1)}), (k1, {1})]
194
   * Pool[T0] = {(c_+ z1 z2)}
195
   * CandSols = {k0 -> {(c_+ k1 k1)}}
196
   *
197
   * and will return `{T0 -> {1}}`.
198
   *
199
   * Notice that the patterns/shapes in pool are generic, and thus, contain vars
200
   * `z` as opposed to skolems `k`. Also, notice that `(c_+ z1 z2)` is
201
   * instantiated with only one skolem `k1`, which is then added to the set of
202
   * obligations. That's because the builtin analogs of `z1` and `z2` match with
203
   * the same builtin term `1`.
204
   *
205
   * @param t builtin term we need to reconstruct
206
   * @param sz a pattern to match against `t`
207
   * @return a set of new builtin terms to reconstruct if the match succeeds
208
   */
209
  TypeBuiltinSetMap matchNewObs(Node t, Node sz);
210
211
  /** mark obligation `ob` as solved.
212
   *
213
   * This function first marks `s` as the complete/constant solution for
214
   * `ob`. Then it substitutes all instances of `ob` in partial solutions to
215
   * other obligations with `s`. The function repeats those two steps for each
216
   * partial solution that gets completed because of the second step. For
217
   * example, given:
218
   *
219
   * CandSols = {
220
   *   k0 -> {(c_+ k1 c_1)},
221
   *   k1 -> {(c_* k2 c_x)},
222
   *   k2 -> {c_2}
223
   * }
224
   * Sol = {}
225
   *
226
   * Then calling `markSolved(k2, c_2)` will result in:
227
   *
228
   * CandSols = {
229
   *   k0 -> {(c_+ k1 c_1), (c_+ (c_* c_2 c_x) c_1)},
230
   *   k1 -> {(c_* k2 c_x), (c_* c_2 c_x)},
231
   *   k2 -> {c_2}
232
   * }
233
   * Sol = {
234
   *   k0 -> (c_+ (c_* c_2 c_x) c_1),
235
   *   k1 -> (c_* c_2 c_x),
236
   *   k2 -> c_2
237
   * }
238
   *
239
   * @param ob free var to mark as solved and substitute
240
   * @param sol solution to `ob`
241
   */
242
  void markSolved(RConsObligation* ob, Node s);
243
244
  /**
245
   * Initialize a sygus enumerator and a candidate rewrite database for each
246
   * sygus datatype type.
247
   *
248
   * @param stn The sygus datatype type encoding the syntax restrictions
249
   */
250
  void initialize(TypeNode stn);
251
252
  /**
253
   * Remove reconstructed terms from the given set of terms to reconstruct.
254
   *
255
   * @param termsToRecons a set of terms to reconstruct possibly containing
256
   *                      already reconstructed ones
257
   */
258
  void removeReconstructedTerms(TypeBuiltinSetMap& termsToRecons);
259
260
  /**
261
   * Replace all variables in `n` with ground values. Before, calling `match`,
262
   * `matchNewObs` rewrites the builtin analog of `n` which contains variables.
263
   * The rewritten term, however, may contain fewer variables:
264
   *
265
   * rewrite((ite true z1 z2)) = z1 // n = (c_ite c_true z1 z2)
266
   *
267
   * In such cases, `matchNewObs` replaces the remaining variables (`z1`) with
268
   * obligations and ignores the eliminated ones (`z2`). Since the values of the
269
   * eliminated variables do not matter, they are replaced with some ground
270
   * values by calling this method.
271
   *
272
   * @param n a term containing variables
273
   * @return `n` with all vars in `n` replaced with ground values
274
   */
275
  Node mkGround(Node n) const;
276
277
  /**
278
   * A notification that s is equal to n * { vars -> subs }. This function
279
   * should return false if we do not wish to be notified of further matches.
280
   */
281
  bool notify(Node s,
282
              Node n,
283
              std::vector<Node>& vars,
284
              std::vector<Node>& subs) override;
285
286
  /**
287
   * Reset the state of this SygusReconstruct object.
288
   */
289
  void clear();
290
291
  /**
292
   * Print the pool of patterns/shape used in the matching phase.
293
   *
294
   * \note requires enabling "sygus-rcons" trace
295
   *
296
   * @param pool a pool of patterns/shapes to print
297
   */
298
  void printPool(
299
      const std::unordered_map<TypeNode, std::vector<Node>>& pool) const;
300
301
  /** Reference to the env */
302
  Env& d_env;
303
  /** pointer to the sygus term database */
304
  TermDbSygus* d_tds;
305
  /** reference to the statistics of parent */
306
  SygusStatistics& d_stats;
307
308
  /** a list of obligations to solve */
309
  std::vector<std::unique_ptr<RConsObligation>> d_obs;
310
  /** a map from a sygus datatype type to its reconstruction info */
311
  std::unordered_map<TypeNode, RConsTypeInfo> d_stnInfo;
312
313
  /** a map from an obligation's skolem to its sygus solution (if it exists) */
314
  std::unordered_map<TNode, TNode> d_sol;
315
316
  /** a map from a candidate solution to its sub-obligations */
317
  std::unordered_map<Node, std::vector<RConsObligation*>> d_subObs;
318
  /** a map from a candidate solution to its parent obligation */
319
  std::unordered_map<Node, RConsObligation*> d_parentOb;
320
321
  /** a cache of sygus variables treated as ground terms by matching */
322
  std::unordered_map<Node, Node> d_sygusVars;
323
324
  /** A trie for filtering out redundant terms from the paterns pool */
325
  expr::MatchTrie d_poolTrie;
326
};
327
328
}  // namespace quantifiers
329
}  // namespace theory
330
}  // namespace cvc5
331
332
#endif  // CVC5__THEORY__QUANTIFIERS__SYGUS_RECONSTRUCT_H