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 |
6647 |
InstantiationRewriter() {} |
54 |
6647 |
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 |
6075 |
class InstLemmaList |
75 |
|
{ |
76 |
|
public: |
77 |
6075 |
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 |
28529 |
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 */ |