GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/instantiate.h Lines: 5 5 100.0 %
Date: 2021-09-07 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
6719
  InstantiationRewriter() {}
54
6716
  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
6137
class InstLemmaList
75
{
76
 public:
77
6137
  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(QuantifiersState& qs,
108
              QuantifiersInferenceManager& qim,
109
              QuantifiersRegistry& qr,
110
              TermRegistry& tr,
111
              ProofNodeManager* pnm = nullptr);
112
  ~Instantiate();
113
  /** reset */
114
  bool reset(Theory::Effort e) override;
115
  /** register quantifier */
116
  void registerQuantifier(Node q) override;
117
  /** identify */
118
28465
  std::string identify() const override { return "Instantiate"; }
119
  /** check incomplete */
120
  bool checkComplete(IncompleteId& incId) override;
121
122
  //--------------------------------------rewrite objects
123
  /** add instantiation rewriter */
124
  void addRewriter(InstantiationRewriter* ir);
125
  /** notify flush lemmas
126
   *
127
   * This is called just before the quantifiers engine flushes its lemmas to
128
   * the output channel.
129
   */
130
  void notifyFlushLemmas();
131
  //--------------------------------------end rewrite objects
132
133
  /** do instantiation specified by m
134
   *
135
   * This function returns true if the instantiation lemma for quantified
136
   * formula q for the substitution specified by terms is successfully enqueued
137
   * via a call to QuantifiersInferenceManager::addPendingLemma.
138
   * @param q the quantified formula to instantiate
139
   * @param terms the terms to instantiate with
140
   * @param id the identifier of the instantiation lemma sent via the inference
141
   * manager
142
   * @param pfArg an additional node to add to the arguments of the INSTANTIATE
143
   * step
144
   * @param mkRep whether to take the representatives of the terms in the
145
   * range of the substitution m,
146
   * @param doVts whether we must apply virtual term substitution to the
147
   * instantiation lemma.
148
   *
149
   * This call may fail if it can be determined that the instantiation is not
150
   * relevant or legal in the current context. This happens if:
151
   * (1) The substitution is not well-typed,
152
   * (2) The substitution involves terms whose instantiation level is above the
153
   *     allowed limit,
154
   * (3) The resulting instantiation is entailed in the current context using a
155
   *     fast entailment check (see TermDb::isEntailed),
156
   * (4) The range of the substitution is a duplicate of that of a previously
157
   *     added instantiation,
158
   * (5) The instantiation lemma is a duplicate of previously added lemma.
159
   *
160
   */
161
  bool addInstantiation(Node q,
162
                        std::vector<Node>& terms,
163
                        InferenceId id,
164
                        Node pfArg = Node::null(),
165
                        bool mkRep = false,
166
                        bool doVts = false);
167
  /**
168
   * Same as above, but we also compute a vector failMask indicating which
169
   * values in terms led to the instantiation not being added when this method
170
   * returns false.  For example, if q is the formula
171
   *   forall xy. x>5 => P(x,y)
172
   * If terms = { 4, 0 }, then this method will return false since
173
   *   4>5 => P(4,0)
174
   * is entailed true based on rewriting. This method may additionally set
175
   * failMask to "10", indicating that x's value was critical, but y's value
176
   * was not. In other words, all instantiations including { x -> 4 } will also
177
   * lead to this method returning false.
178
   *
179
   * The bits of failMask are computed in a greedy fashion, in reverse order.
180
   * That is, we check whether each variable is critical one at a time, starting
181
   * from the end.
182
   *
183
   * The parameter expFull is whether try to set all bits of the fail mask to
184
   * 0. If this argument is true, then we only try to set a suffix of the
185
   * bits in failMask to false. The motivation for expFull=false is for callers
186
   * of this method that are enumerating tuples in lexiocographic order. The
187
   * number of false bits in the suffix of failMask tells the caller how many
188
   * "decimal" places to increment their iterator.
189
   */
190
  bool addInstantiationExpFail(Node q,
191
                               std::vector<Node>& terms,
192
                               std::vector<bool>& failMask,
193
                               InferenceId id,
194
                               Node pfArg = Node::null(),
195
                               bool mkRep = false,
196
                               bool doVts = false,
197
                               bool expFull = true);
198
  /** record instantiation
199
   *
200
   * Explicitly record that q has been instantiated with terms, with virtual
201
   * term substitution if doVts is true. This is the same as addInstantiation,
202
   * but does not enqueue an instantiation lemma.
203
   */
204
  void recordInstantiation(Node q,
205
                           std::vector<Node>& terms,
206
                           bool doVts = false);
207
  /** exists instantiation
208
   *
209
   * Returns true if and only if the instantiation already was added or
210
   * recorded by this class.
211
   *   modEq : whether to check for duplication modulo equality
212
   */
213
  bool existsInstantiation(Node q,
214
                           std::vector<Node>& terms,
215
                           bool modEq = false);
216
  //--------------------------------------general utilities
217
  /** get instantiation
218
   *
219
   * Returns the instantiation lemma for q under substitution { vars -> terms }.
220
   * doVts is whether to apply virtual term substitution to its body.
221
   *
222
   * If provided, pf is a lazy proof for which we store a proof of the
223
   * returned formula with free assumption q. This typically stores a
224
   * single INSTANTIATE step concluding the instantiated body of q from q.
225
   */
226
  Node getInstantiation(Node q,
227
                        std::vector<Node>& vars,
228
                        std::vector<Node>& terms,
229
                        InferenceId id = InferenceId::UNKNOWN,
230
                        Node pfArg = Node::null(),
231
                        bool doVts = false,
232
                        LazyCDProof* pf = nullptr);
233
  /** get instantiation
234
   *
235
   * Same as above but with vars equal to the bound variables of q.
236
   */
237
  Node getInstantiation(Node q, std::vector<Node>& terms, bool doVts = false);
238
  //--------------------------------------end general utilities
239
240
  /**
241
   * Called once at the end of each instantiation round. This prints
242
   * instantiations added this round to trace inst-per-quant-round, if
243
   * applicable, and prints to out if the option debug-inst is enabled.
244
   */
245
  void notifyEndRound();
246
  /** debug print model, called once, before we terminate with sat/unknown. */
247
  void debugPrintModel();
248
249
  //--------------------------------------user-level interface utilities
250
  /** get instantiated quantified formulas
251
   *
252
   * Get the list of quantified formulas that were instantiated in the current
253
   * user context, store them in qs.
254
   */
255
  void getInstantiatedQuantifiedFormulas(std::vector<Node>& qs) const;
256
  /** get instantiation term vectors
257
   *
258
   * Get term vectors corresponding to for all instantiations lemmas added in
259
   * the current user context for quantified formula q, store them in tvecs.
260
   */
261
  void getInstantiationTermVectors(Node q,
262
                                   std::vector<std::vector<Node> >& tvecs);
263
  /** get instantiation term vectors
264
   *
265
   * Get term vectors for all instantiations lemmas added in the current user
266
   * context for quantified formula q, store them in tvecs.
267
   */
268
  void getInstantiationTermVectors(
269
      std::map<Node, std::vector<std::vector<Node> > >& insts);
270
  /**
271
   * Get instantiations for quantified formula q. If q is (forall ((x T)) (P
272
   * x)), this is a list of the form (P t1) ... (P tn) for ground terms ti.
273
   */
274
  void getInstantiations(Node q, std::vector<Node>& insts);
275
  //--------------------------------------end user-level interface utilities
276
277
  /** Are proofs enabled for this object? */
278
  bool isProofEnabled() const;
279
280
  /** statistics class
281
   *
282
   * This tracks statistics on the number of instantiations successfully
283
   * enqueued on the quantifiers output channel, and the number of redundant
284
   * instantiations encountered by various criteria.
285
   */
286
  class Statistics
287
  {
288
   public:
289
    IntStat d_instantiations;
290
    IntStat d_inst_duplicate;
291
    IntStat d_inst_duplicate_eq;
292
    IntStat d_inst_duplicate_ent;
293
    Statistics();
294
  }; /* class Instantiate::Statistics */
295
  Statistics d_statistics;
296
297
 private:
298
  /** record instantiation, return true if it was not a duplicate */
299
  bool recordInstantiationInternal(Node q, std::vector<Node>& terms);
300
  /** remove instantiation from the cache */
301
  bool removeInstantiationInternal(Node q, std::vector<Node>& terms);
302
  /**
303
   * Ensure that n has type tn, return a term equivalent to it for that type
304
   * if possible.
305
   */
306
  static Node ensureType(Node n, TypeNode tn);
307
  /** Get or make the instantiation list for quantified formula q */
308
  InstLemmaList* getOrMkInstLemmaList(TNode q);
309
310
  /** Reference to the quantifiers state */
311
  QuantifiersState& d_qstate;
312
  /** Reference to the quantifiers inference manager */
313
  QuantifiersInferenceManager& d_qim;
314
  /** The quantifiers registry */
315
  QuantifiersRegistry& d_qreg;
316
  /** Reference to the term registry */
317
  TermRegistry& d_treg;
318
  /** pointer to the proof node manager */
319
  ProofNodeManager* d_pnm;
320
  /** instantiation rewriter classes */
321
  std::vector<InstantiationRewriter*> d_instRewrite;
322
323
  /**
324
   * The list of all instantiation lemma bodies per quantifier. This is used
325
   * for debugging and for quantifier elimination.
326
   */
327
  NodeInstListMap d_insts;
328
  /** explicitly recorded instantiations
329
   *
330
   * Sometimes an instantiation is recorded internally but not sent out as a
331
   * lemma, for instance, for partial quantifier elimination. This is a map
332
   * of these instantiations, for each quantified formula. This map is cleared
333
   * on presolve, e.g. it is local to a check-sat call.
334
   */
335
  std::map<Node, std::vector<Node> > d_recordedInst;
336
  /** statistics for debugging total instantiations per quantifier per round */
337
  std::map<Node, uint32_t> d_instDebugTemp;
338
339
  /** list of all instantiations produced for each quantifier
340
   *
341
   * We store context (dependent, independent) versions. If incremental solving
342
   * is disabled, we use d_inst_match_trie for performance reasons.
343
   */
344
  std::map<Node, InstMatchTrie> d_inst_match_trie;
345
  std::map<Node, CDInstMatchTrie*> d_c_inst_match_trie;
346
  /**
347
   * The list of quantified formulas for which the domain of d_c_inst_match_trie
348
   * is valid.
349
   */
350
  context::CDHashSet<Node> d_c_inst_match_trie_dom;
351
  /**
352
   * A CDProof storing instantiation steps.
353
   */
354
  std::unique_ptr<CDProof> d_pfInst;
355
};
356
357
}  // namespace quantifiers
358
}  // namespace theory
359
}  // namespace cvc5
360
361
#endif /* CVC5__THEORY__QUANTIFIERS__INSTANTIATE_H */