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