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

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Abdalrhman Mohamed
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 that encapsulates techniques for a single (SyGuS) synthesis
14
 * conjecture.
15
 */
16
17
#include "cvc5_private.h"
18
19
#ifndef CVC5__THEORY__QUANTIFIERS__SYNTH_CONJECTURE_H
20
#define CVC5__THEORY__QUANTIFIERS__SYNTH_CONJECTURE_H
21
22
#include <memory>
23
24
#include "smt/env_obj.h"
25
#include "theory/quantifiers/expr_miner_manager.h"
26
#include "theory/quantifiers/sygus/ce_guided_single_inv.h"
27
#include "theory/quantifiers/sygus/cegis.h"
28
#include "theory/quantifiers/sygus/cegis_core_connective.h"
29
#include "theory/quantifiers/sygus/cegis_unif.h"
30
#include "theory/quantifiers/sygus/enum_val_generator.h"
31
#include "theory/quantifiers/sygus/example_eval_cache.h"
32
#include "theory/quantifiers/sygus/example_infer.h"
33
#include "theory/quantifiers/sygus/sygus_process_conj.h"
34
#include "theory/quantifiers/sygus/sygus_repair_const.h"
35
#include "theory/quantifiers/sygus/sygus_stats.h"
36
#include "theory/quantifiers/sygus/synth_verify.h"
37
#include "theory/quantifiers/sygus/template_infer.h"
38
39
namespace cvc5 {
40
namespace theory {
41
namespace quantifiers {
42
43
class CegGrammarConstructor;
44
class SygusPbe;
45
class SygusStatistics;
46
class EnumValueManager;
47
48
/** a synthesis conjecture
49
 * This class implements approaches for a synthesis conjecture, given by data
50
 * member d_quant.
51
 * This includes both approaches for synthesis in Reynolds et al CAV 2015. It
52
 * determines which approach and optimizations are applicable to the
53
 * conjecture, and has interfaces for implementing them.
54
 */
55
class SynthConjecture : protected EnvObj
56
{
57
 public:
58
  SynthConjecture(Env& env,
59
                  QuantifiersState& qs,
60
                  QuantifiersInferenceManager& qim,
61
                  QuantifiersRegistry& qr,
62
                  TermRegistry& tr,
63
                  SygusStatistics& s);
64
  ~SynthConjecture();
65
  /** presolve */
66
  void presolve();
67
  /** get original version of conjecture */
68
10615
  Node getConjecture() const { return d_quant; }
69
  /** get deep embedding version of conjecture */
70
  Node getEmbeddedConjecture() const { return d_embed_quant; }
71
  //-------------------------------for counterexample-guided check/refine
72
  /** whether the conjecture is waiting for a call to doCheck below */
73
  bool needsCheck();
74
  /** do syntax-guided enumerative check
75
   *
76
   * This is step 2(a) of Figure 3 of Reynolds et al CAV 2015.
77
   *
78
   * The method returns true if this conjecture is finished trying solutions
79
   * for the given call to SynthEngine::check.
80
   *
81
   * Notice that we make multiple calls to doCheck on one call to
82
   * SynthEngine::check. For example, if we are using an actively-generated
83
   * enumerator, one enumerated (abstract) term may correspond to multiple
84
   * concrete terms t1, ..., tn to check, where we make up to n calls to doCheck
85
   * when each of t1, ..., tn fails to satisfy the current refinement lemmas.
86
   */
87
  bool doCheck();
88
  //-------------------------------end for counterexample-guided check/refine
89
  /**
90
   * Prints the current synthesis solution to output stream out. This is
91
   * currently used for printing solutions for sygusStream only. We do not
92
   * enclose solutions in parentheses.
93
   */
94
  void printSynthSolutionInternal(std::ostream& out);
95
  /** get synth solutions
96
   *
97
   * This method returns true if this class has a solution available to the
98
   * conjecture that it was assigned.
99
   *
100
   * Let q be the synthesis conjecture assigned to this class.
101
   * This method adds entries to sol_map[q] that map functions-to-synthesize to
102
   * their builtin solution, which has the same type. For example, for synthesis
103
   * conjecture exists f. forall x. f( x )>x, this function will update
104
   * sol_map[q] to contain the entry:
105
   *   f -> (lambda x. x+1)
106
   */
107
  bool getSynthSolutions(std::map<Node, std::map<Node, Node> >& sol_map);
108
  /**
109
   * The feasible guard whose semantics are "this conjecture is feasiable".
110
   * This is "G" in Figure 3 of Reynolds et al CAV 2015.
111
   */
112
  Node getGuard() const;
113
  /** is ground */
114
  bool isGround() const { return d_innerVars.empty(); }
115
  /** are we using single invocation techniques */
116
  bool isSingleInvocation() const;
117
  /** preregister conjecture
118
   * This is used as a heuristic for solution reconstruction, so that we
119
   * remember expressions in the conjecture before preprocessing, since they
120
   * may be helpful during solution reconstruction (Figure 5 of Reynolds et al
121
   * CAV 2015)
122
   */
123
  void preregisterConjecture(Node q);
124
  /** assign conjecture q to this class */
125
  void assign(Node q);
126
  /** has a conjecture been assigned to this class */
127
830
  bool isAssigned() { return !d_embed_quant.isNull(); }
128
  /**
129
   * Get model value for term n.
130
   */
131
  Node getModelValue(Node n);
132
133
  /** get utility for static preprocessing and analysis of conjectures */
134
583
  SynthConjectureProcess* getProcess() { return d_ceg_proc.get(); }
135
  /** get constant repair utility */
136
241
  SygusRepairConst* getRepairConst() { return d_sygus_rconst.get(); }
137
  /** get example inference utility */
138
14699
  ExampleInfer* getExampleInfer() { return d_exampleInfer.get(); }
139
  /** get the example evaluation cache utility for enumerator e */
140
  ExampleEvalCache* getExampleEvalCache(Node e);
141
  /** get program by examples module */
142
  SygusPbe* getPbe() { return d_ceg_pbe.get(); }
143
  /** get the symmetry breaking predicate for type */
144
  Node getSymmetryBreakingPredicate(
145
      Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth);
146
  /** print out debug information about this conjecture */
147
  void debugPrint(const char* c);
148
  /** check side condition
149
   *
150
   * This returns false if the solution { d_candidates -> cvals } does not
151
   * satisfy the side condition of the conjecture maintained by this class,
152
   * if it exists, and true otherwise.
153
   */
154
  bool checkSideCondition(const std::vector<Node>& cvals) const;
155
156
  /** get a reference to the statistics of parent */
157
  SygusStatistics& getSygusStatistics() { return d_stats; };
158
159
 private:
160
  /** do refinement
161
   *
162
   * This is step 2(b) of Figure 3 of Reynolds et al CAV 2015.
163
   *
164
   * This method is run when skModel is corresponds to a counterexample to the
165
   * last candidate in the doCheck method.
166
   *
167
   * This method adds a refinement lemma on the output channel of quantifiers
168
   * engine. If the refinement lemma is a duplicate, then we manually
169
   * exclude the current candidate via excludeCurrentSolution. This should
170
   * only occur when the synthesis conjecture for the current candidate fails
171
   * to evaluate to false for a given counterexample point, but regardless its
172
   * negation is satisfiable for the current candidate and that point. This is
173
   * exclusive to theories with partial functions, e.g. (non-linear) division.
174
   *
175
   * This method returns true if a lemma was added on the output channel, and
176
   * false otherwise.
177
   */
178
  bool processCounterexample(const std::vector<Node>& skModel);
179
  /** Reference to the quantifiers state */
180
  QuantifiersState& d_qstate;
181
  /** Reference to the quantifiers inference manager */
182
  QuantifiersInferenceManager& d_qim;
183
  /** The quantifiers registry */
184
  QuantifiersRegistry& d_qreg;
185
  /** Reference to the term registry */
186
  TermRegistry& d_treg;
187
  /** reference to the statistics of parent */
188
  SygusStatistics& d_stats;
189
  /** term database sygus of d_qe */
190
  TermDbSygus* d_tds;
191
  /** The synthesis verify utility */
192
  SynthVerify d_verify;
193
  /** The feasible guard. */
194
  Node d_feasible_guard;
195
  /**
196
   * Do we have a solution in this solve context? This flag is reset to false
197
   * on every call to presolve.
198
   */
199
  bool d_hasSolution;
200
  /** the decision strategy for the feasible guard */
201
  std::unique_ptr<DecisionStrategy> d_feasible_strategy;
202
  /** single invocation utility */
203
  std::unique_ptr<CegSingleInv> d_ceg_si;
204
  /** template inference utility */
205
  std::unique_ptr<SygusTemplateInfer> d_templInfer;
206
  /** utility for static preprocessing and analysis of conjectures */
207
  std::unique_ptr<SynthConjectureProcess> d_ceg_proc;
208
  /** grammar utility */
209
  std::unique_ptr<CegGrammarConstructor> d_ceg_gc;
210
  /** repair constant utility */
211
  std::unique_ptr<SygusRepairConst> d_sygus_rconst;
212
  /** example inference utility */
213
  std::unique_ptr<ExampleInfer> d_exampleInfer;
214
  /** map from enumerators to their enumerator manager */
215
  std::map<Node, std::unique_ptr<EnumValueManager>> d_enumManager;
216
217
  //------------------------modules
218
  /** program by examples module */
219
  std::unique_ptr<SygusPbe> d_ceg_pbe;
220
  /** CEGIS module */
221
  std::unique_ptr<Cegis> d_ceg_cegis;
222
  /** CEGIS UNIF module */
223
  std::unique_ptr<CegisUnif> d_ceg_cegisUnif;
224
  /** connective core utility */
225
  std::unique_ptr<CegisCoreConnective> d_sygus_ccore;
226
  /** the set of active modules (subset of the above list) */
227
  std::vector<SygusModule*> d_modules;
228
  /** master module
229
   *
230
   * This is the module (one of those above) that takes sole responsibility
231
   * for this conjecture, determined during assign(...).
232
   */
233
  SygusModule* d_master;
234
  //------------------------end modules
235
236
  //------------------------enumerators
237
  /**
238
   * Get model values for terms n, store in vector v. This method returns true
239
   * if and only if all values added to v are non-null.
240
   *
241
   * The argument activeIncomplete indicates whether n contains an active
242
   * enumerator that is currently not finished enumerating values, but returned
243
   * null on a call to getEnumeratedValue. This value is used for determining
244
   * whether we should call getEnumeratedValues again within a call to
245
   * SynthConjecture::check.
246
   *
247
   * It removes terms from n that correspond to "inactive" enumerators, that
248
   * is, enumerators whose values have been exhausted.
249
   */
250
  bool getEnumeratedValues(std::vector<Node>& n,
251
                           std::vector<Node>& v,
252
                           bool& activeIncomplete);
253
  /**
254
   * Get or make enumerator manager for the enumerator e.
255
   */
256
  EnumValueManager* getEnumValueManagerFor(Node e);
257
  //------------------------end enumerators
258
259
  /** list of constants for quantified formula
260
   * The outer Skolems for the negation of d_embed_quant.
261
   */
262
  std::vector<Node> d_candidates;
263
  /** base instantiation
264
   * If d_embed_quant is forall d. exists y. P( d, y ), then
265
   * this is the formula  exists y. P( d_candidates, y ). Notice that
266
   * (exists y. F) is shorthand above for ~( forall y. ~F ).
267
   */
268
  Node d_base_inst;
269
  /** The skolemized form of the above formula. */
270
  Node d_checkBody;
271
  /** list of variables on inner quantification */
272
  std::vector<Node> d_innerVars;
273
  /** list of skolems on inner quantification */
274
  std::vector<Node> d_innerSks;
275
  /** the asserted (negated) conjecture */
276
  Node d_quant;
277
  /**
278
   * The side condition for solving the conjecture, after conversion to deep
279
   * embedding.
280
   */
281
  Node d_embedSideCondition;
282
  /** (negated) conjecture after simplification */
283
  Node d_simp_quant;
284
  /** (negated) conjecture after simplification, conversion to deep embedding */
285
  Node d_embed_quant;
286
  /** candidate information */
287
3304
  class CandidateInfo
288
  {
289
   public:
290
3304
    CandidateInfo() {}
291
    /** list of terms we have instantiated candidates with */
292
    std::vector<Node> d_inst;
293
  };
294
  std::map<Node, CandidateInfo> d_cinfo;
295
  /**
296
   * The first index of an instantiation in CandidateInfo::d_inst that we have
297
   * not yet tried to repair.
298
   */
299
  unsigned d_repair_index;
300
  /** record solution (this is used to construct solutions later) */
301
  void recordSolution(std::vector<Node>& vs);
302
  /** get synth solutions internal
303
   *
304
   * This function constructs the body of solutions for all
305
   * functions-to-synthesize in this conjecture and stores them in sols, in
306
   * order. For each solution added to sols, we add an integer indicating what
307
   * kind of solution n is, where if sols[i] = n, then
308
   *   if status[i] = 0: n is the (builtin term) corresponding to the solution,
309
   *   if status[i] = 1: n is the sygus representation of the solution.
310
   * We store builtin versions under some conditions (such as when the sygus
311
   * grammar is being ignored).
312
   *
313
   * This consults the single invocation module to get synthesis solutions if
314
   * isSingleInvocation() returns true.
315
   *
316
   * For example, for conjecture exists fg. forall x. f(x)>g(x), this function
317
   * may set ( sols, status ) to ( { x+1, d_x() }, { 1, 0 } ), where d_x() is
318
   * the sygus datatype constructor corresponding to variable x.
319
   */
320
  bool getSynthSolutionsInternal(std::vector<Node>& sols,
321
                                 std::vector<int8_t>& status);
322
  //-------------------------------- sygus stream
323
  /**
324
   * Prints the current synthesis solution to the output stream indicated by
325
   * the Options object, send a lemma blocking the current solution to the
326
   * output channel, which we refer to as a "stream exclusion lemma".
327
   *
328
   * The argument enums is the set of enumerators that comprise the current
329
   * solution, and values is their current values.
330
   */
331
  void printAndContinueStream(const std::vector<Node>& enums,
332
                              const std::vector<Node>& values);
333
  /** exclude the current solution { enums -> values } */
334
  void excludeCurrentSolution(const std::vector<Node>& enums,
335
                              const std::vector<Node>& values);
336
  /**
337
   * Whether we have guarded a stream exclusion lemma when using sygusStream.
338
   * This is an optimization that allows us to guard only the first stream
339
   * exclusion lemma.
340
   */
341
  bool d_guarded_stream_exc;
342
  //-------------------------------- end sygus stream
343
  /** expression miner managers for each function-to-synthesize
344
   *
345
   * Notice that for each function-to-synthesize, we enumerate a stream of
346
   * candidate solutions, where each of these streams is independent. Thus,
347
   * we maintain separate expression miner managers for each of them.
348
   *
349
   * This is used for the sygusRewSynth() option to synthesize new candidate
350
   * rewrite rules.
351
   */
352
  std::map<Node, std::unique_ptr<ExpressionMinerManager>> d_exprm;
353
};
354
355
}  // namespace quantifiers
356
}  // namespace theory
357
}  // namespace cvc5
358
359
#endif