GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/instantiate.h Lines: 5 5 100.0 %
Date: 2021-09-15 Branches: 2 4 50.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Morgan Deters
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
 * instantiate
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef CVC5__THEORY__QUANTIFIERS__INSTANTIATE_H
19
#define CVC5__THEORY__QUANTIFIERS__INSTANTIATE_H
20
21
#include <map>
22
23
#include "context/cdhashset.h"
24
#include "expr/node.h"
25
#include "proof/proof.h"
26
#include "theory/inference_id.h"
27
#include "theory/quantifiers/inst_match_trie.h"
28
#include "theory/quantifiers/quant_util.h"
29
#include "util/statistics_stats.h"
30
31
namespace cvc5 {
32
33
class LazyCDProof;
34
35
namespace theory {
36
namespace quantifiers {
37
38
class TermRegistry;
39
class QuantifiersState;
40
class QuantifiersInferenceManager;
41
class QuantifiersRegistry;
42
class FirstOrderModel;
43
44
/** Instantiation rewriter
45
 *
46
 * This class is used for cases where instantiation lemmas can be rewritten by
47
 * external utilities. Examples of this include virtual term substitution and
48
 * nested quantifier elimination techniques.
49
 */
50
class InstantiationRewriter
51
{
52
 public:
53
6723
  InstantiationRewriter() {}
54
6720
  virtual ~InstantiationRewriter() {}
55
56
  /** rewrite instantiation
57
   *
58
   * The node inst is the instantiation of quantified formula q for terms.
59
   * This method returns the rewritten form of the instantiation.
60
   *
61
   * The flag doVts is whether we must apply virtual term substitution to the
62
   * instantiation.
63
   *
64
   * Returns a TrustNode of kind REWRITE, corresponding to the rewrite of inst
65
   * and its proof generator.
66
   */
67
  virtual TrustNode rewriteInstantiation(Node q,
68
                                         std::vector<Node>& terms,
69
                                         Node inst,
70
                                         bool doVts) = 0;
71
};
72
73
/** Context-dependent list of nodes */
74
6177
class InstLemmaList
75
{
76
 public:
77
6177
  InstLemmaList(context::Context* c) : d_list(c) {}
78
  /** The list */
79
  context::CDList<Node> d_list;
80
};
81
82
/** Instantiate
83
 *
84
 * This class is used for generating instantiation lemmas.  It maintains an
85
 * instantiation trie, which is represented by a different data structure
86
 * depending on whether incremental solving is enabled (see d_inst_match_trie
87
 * and d_c_inst_match_trie).
88
 *
89
 * Below, we say an instantiation lemma for q = forall x. F under substitution
90
 * { x -> t } is the formula:
91
 *   ( ~forall x. F V F * { x -> t } )
92
 * where * is application of substitution.
93
 *
94
 * Its main interface is ::addInstantiation(...), which is called by many of
95
 * the quantifiers modules, which enqueues instantiation lemmas in quantifiers
96
 * engine via calls to QuantifiersInferenceManager::addPendingLemma.
97
 *
98
 * It also has utilities for constructing instantiations, and interfaces for
99
 * getting the results of the instantiations produced during check-sat calls.
100
 */
101
class Instantiate : public QuantifiersUtil
102
{
103
  using NodeInstListMap =
104
      context::CDHashMap<Node, std::shared_ptr<InstLemmaList>>;
105
106
 public:
107
  Instantiate(Env& env,
108
              QuantifiersState& qs,
109
              QuantifiersInferenceManager& qim,
110
              QuantifiersRegistry& qr,
111
              TermRegistry& tr,
112
              ProofNodeManager* pnm = nullptr);
113
  ~Instantiate();
114
  /** reset */
115
  bool reset(Theory::Effort e) override;
116
  /** register quantifier */
117
  void registerQuantifier(Node q) override;
118
  /** identify */
119
28079
  std::string identify() const override { return "Instantiate"; }
120
  /** check incomplete */
121
  bool checkComplete(IncompleteId& incId) override;
122
123
  //--------------------------------------rewrite objects
124
  /** add instantiation rewriter */
125
  void addRewriter(InstantiationRewriter* ir);
126
  /** notify flush lemmas
127
   *
128
   * This is called just before the quantifiers engine flushes its lemmas to
129
   * the output channel.
130
   */
131
  void notifyFlushLemmas();
132
  //--------------------------------------end rewrite objects
133
134
  /** do instantiation specified by m
135
   *
136
   * This function returns true if the instantiation lemma for quantified
137
   * formula q for the substitution specified by terms is successfully enqueued
138
   * via a call to QuantifiersInferenceManager::addPendingLemma.
139
   * @param q the quantified formula to instantiate
140
   * @param terms the terms to instantiate with
141
   * @param id the identifier of the instantiation lemma sent via the inference
142
   * manager
143
   * @param pfArg an additional node to add to the arguments of the INSTANTIATE
144
   * step
145
   * @param mkRep whether to take the representatives of the terms in the
146
   * range of the substitution m,
147
   * @param doVts whether we must apply virtual term substitution to the
148
   * instantiation lemma.
149
   *
150
   * This call may fail if it can be determined that the instantiation is not
151
   * relevant or legal in the current context. This happens if:
152
   * (1) The substitution is not well-typed,
153
   * (2) The substitution involves terms whose instantiation level is above the
154
   *     allowed limit,
155
   * (3) The resulting instantiation is entailed in the current context using a
156
   *     fast entailment check (see TermDb::isEntailed),
157
   * (4) The range of the substitution is a duplicate of that of a previously
158
   *     added instantiation,
159
   * (5) The instantiation lemma is a duplicate of previously added lemma.
160
   *
161
   */
162
  bool addInstantiation(Node q,
163
                        std::vector<Node>& terms,
164
                        InferenceId id,
165
                        Node pfArg = Node::null(),
166
                        bool mkRep = false,
167
                        bool doVts = false);
168
  /**
169
   * Same as above, but we also compute a vector failMask indicating which
170
   * values in terms led to the instantiation not being added when this method
171
   * returns false.  For example, if q is the formula
172
   *   forall xy. x>5 => P(x,y)
173
   * If terms = { 4, 0 }, then this method will return false since
174
   *   4>5 => P(4,0)
175
   * is entailed true based on rewriting. This method may additionally set
176
   * failMask to "10", indicating that x's value was critical, but y's value
177
   * was not. In other words, all instantiations including { x -> 4 } will also
178
   * lead to this method returning false.
179
   *
180
   * The bits of failMask are computed in a greedy fashion, in reverse order.
181
   * That is, we check whether each variable is critical one at a time, starting
182
   * from the end.
183
   *
184
   * The parameter expFull is whether try to set all bits of the fail mask to
185
   * 0. If this argument is true, then we only try to set a suffix of the
186
   * bits in failMask to false. The motivation for expFull=false is for callers
187
   * of this method that are enumerating tuples in lexiocographic order. The
188
   * number of false bits in the suffix of failMask tells the caller how many
189
   * "decimal" places to increment their iterator.
190
   */
191
  bool addInstantiationExpFail(Node q,
192
                               std::vector<Node>& terms,
193
                               std::vector<bool>& failMask,
194
                               InferenceId id,
195
                               Node pfArg = Node::null(),
196
                               bool mkRep = false,
197
                               bool doVts = false,
198
                               bool expFull = true);
199
  /** record instantiation
200
   *
201
   * Explicitly record that q has been instantiated with terms, with virtual
202
   * term substitution if doVts is true. This is the same as addInstantiation,
203
   * but does not enqueue an instantiation lemma.
204
   */
205
  void recordInstantiation(Node q,
206
                           std::vector<Node>& terms,
207
                           bool doVts = false);
208
  /** exists instantiation
209
   *
210
   * Returns true if and only if the instantiation already was added or
211
   * recorded by this class.
212
   *   modEq : whether to check for duplication modulo equality
213
   */
214
  bool existsInstantiation(Node q,
215
                           std::vector<Node>& terms,
216
                           bool modEq = false);
217
  //--------------------------------------general utilities
218
  /** get instantiation
219
   *
220
   * Returns the instantiation lemma for q under substitution { vars -> terms }.
221
   * doVts is whether to apply virtual term substitution to its body.
222
   *
223
   * If provided, pf is a lazy proof for which we store a proof of the
224
   * returned formula with free assumption q. This typically stores a
225
   * single INSTANTIATE step concluding the instantiated body of q from q.
226
   */
227
  Node getInstantiation(Node q,
228
                        std::vector<Node>& vars,
229
                        std::vector<Node>& terms,
230
                        InferenceId id = InferenceId::UNKNOWN,
231
                        Node pfArg = Node::null(),
232
                        bool doVts = false,
233
                        LazyCDProof* pf = nullptr);
234
  /** get instantiation
235
   *
236
   * Same as above but with vars equal to the bound variables of q.
237
   */
238
  Node getInstantiation(Node q, std::vector<Node>& terms, bool doVts = false);
239
  //--------------------------------------end general utilities
240
241
  /**
242
   * Called once at the end of each instantiation round. This prints
243
   * instantiations added this round to trace inst-per-quant-round, if
244
   * applicable, and prints to out if the option debug-inst is enabled.
245
   */
246
  void notifyEndRound();
247
  /** debug print model, called once, before we terminate with sat/unknown. */
248
  void debugPrintModel();
249
250
  //--------------------------------------user-level interface utilities
251
  /** get instantiated quantified formulas
252
   *
253
   * Get the list of quantified formulas that were instantiated in the current
254
   * user context, store them in qs.
255
   */
256
  void getInstantiatedQuantifiedFormulas(std::vector<Node>& qs) const;
257
  /** get instantiation term vectors
258
   *
259
   * Get term vectors corresponding to for all instantiations lemmas added in
260
   * the current user context for quantified formula q, store them in tvecs.
261
   */
262
  void getInstantiationTermVectors(Node q,
263
                                   std::vector<std::vector<Node> >& tvecs);
264
  /** get instantiation term vectors
265
   *
266
   * Get term vectors for all instantiations lemmas added in the current user
267
   * context for quantified formula q, store them in tvecs.
268
   */
269
  void getInstantiationTermVectors(
270
      std::map<Node, std::vector<std::vector<Node> > >& insts);
271
  /**
272
   * Get instantiations for quantified formula q. If q is (forall ((x T)) (P
273
   * x)), this is a list of the form (P t1) ... (P tn) for ground terms ti.
274
   */
275
  void getInstantiations(Node q, std::vector<Node>& insts);
276
  //--------------------------------------end user-level interface utilities
277
278
  /** Are proofs enabled for this object? */
279
  bool isProofEnabled() const;
280
281
  /** statistics class
282
   *
283
   * This tracks statistics on the number of instantiations successfully
284
   * enqueued on the quantifiers output channel, and the number of redundant
285
   * instantiations encountered by various criteria.
286
   */
287
  class Statistics
288
  {
289
   public:
290
    IntStat d_instantiations;
291
    IntStat d_inst_duplicate;
292
    IntStat d_inst_duplicate_eq;
293
    IntStat d_inst_duplicate_ent;
294
    Statistics();
295
  }; /* class Instantiate::Statistics */
296
  Statistics d_statistics;
297
298
 private:
299
  /** record instantiation, return true if it was not a duplicate */
300
  bool recordInstantiationInternal(Node q, std::vector<Node>& terms);
301
  /** remove instantiation from the cache */
302
  bool removeInstantiationInternal(Node q, std::vector<Node>& terms);
303
  /**
304
   * Ensure that n has type tn, return a term equivalent to it for that type
305
   * if possible.
306
   */
307
  static Node ensureType(Node n, TypeNode tn);
308
  /** Get or make the instantiation list for quantified formula q */
309
  InstLemmaList* getOrMkInstLemmaList(TNode q);
310
311
  /** Reference to the quantifiers state */
312
  QuantifiersState& d_qstate;
313
  /** Reference to the quantifiers inference manager */
314
  QuantifiersInferenceManager& d_qim;
315
  /** The quantifiers registry */
316
  QuantifiersRegistry& d_qreg;
317
  /** Reference to the term registry */
318
  TermRegistry& d_treg;
319
  /** pointer to the proof node manager */
320
  ProofNodeManager* d_pnm;
321
  /** instantiation rewriter classes */
322
  std::vector<InstantiationRewriter*> d_instRewrite;
323
324
  /**
325
   * The list of all instantiation lemma bodies per quantifier. This is used
326
   * for debugging and for quantifier elimination.
327
   */
328
  NodeInstListMap d_insts;
329
  /** explicitly recorded instantiations
330
   *
331
   * Sometimes an instantiation is recorded internally but not sent out as a
332
   * lemma, for instance, for partial quantifier elimination. This is a map
333
   * of these instantiations, for each quantified formula. This map is cleared
334
   * on presolve, e.g. it is local to a check-sat call.
335
   */
336
  std::map<Node, std::vector<Node> > d_recordedInst;
337
  /** statistics for debugging total instantiations per quantifier per round */
338
  std::map<Node, uint32_t> d_instDebugTemp;
339
340
  /** list of all instantiations produced for each quantifier
341
   *
342
   * We store context (dependent, independent) versions. If incremental solving
343
   * is disabled, we use d_inst_match_trie for performance reasons.
344
   */
345
  std::map<Node, InstMatchTrie> d_inst_match_trie;
346
  std::map<Node, CDInstMatchTrie*> d_c_inst_match_trie;
347
  /**
348
   * The list of quantified formulas for which the domain of d_c_inst_match_trie
349
   * is valid.
350
   */
351
  context::CDHashSet<Node> d_c_inst_match_trie_dom;
352
  /**
353
   * A CDProof storing instantiation steps.
354
   */
355
  std::unique_ptr<CDProof> d_pfInst;
356
};
357
358
}  // namespace quantifiers
359
}  // namespace theory
360
}  // namespace cvc5
361
362
#endif /* CVC5__THEORY__QUANTIFIERS__INSTANTIATE_H */