1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, Andres Noetzli |
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 |
|
* Skolem manager utility. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__EXPR__SKOLEM_MANAGER_H |
19 |
|
#define CVC5__EXPR__SKOLEM_MANAGER_H |
20 |
|
|
21 |
|
#include <string> |
22 |
|
|
23 |
|
#include "expr/node.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
|
27 |
|
class ProofGenerator; |
28 |
|
|
29 |
|
/** Skolem function identifier */ |
30 |
|
enum class SkolemFunId |
31 |
|
{ |
32 |
|
NONE, |
33 |
|
/** an uninterpreted function f s.t. f(x) = x / 0.0 (real division) */ |
34 |
|
DIV_BY_ZERO, |
35 |
|
/** an uninterpreted function f s.t. f(x) = x / 0 (integer division) */ |
36 |
|
INT_DIV_BY_ZERO, |
37 |
|
/** an uninterpreted function f s.t. f(x) = x mod 0 */ |
38 |
|
MOD_BY_ZERO, |
39 |
|
/** an uninterpreted function f s.t. f(x) = sqrt(x) */ |
40 |
|
SQRT, |
41 |
|
/** a wrongly applied selector */ |
42 |
|
SELECTOR_WRONG, |
43 |
|
/** a shared selector */ |
44 |
|
SHARED_SELECTOR, |
45 |
|
/** an application of seq.nth that is out of bounds */ |
46 |
|
SEQ_NTH_OOB, |
47 |
|
//----- string skolems are cached based on two strings (a, b) |
48 |
|
/** exists k. ( b occurs k times in a ) */ |
49 |
|
STRINGS_NUM_OCCUR, |
50 |
|
/** For function k: Int -> Int |
51 |
|
* exists k. |
52 |
|
* forall 0 <= x <= n, |
53 |
|
* k(x) is the end index of the x^th occurrence of b in a |
54 |
|
* where n is the number of occurrences of b in a, and k(0)=0. |
55 |
|
*/ |
56 |
|
STRINGS_OCCUR_INDEX, |
57 |
|
/** |
58 |
|
* For function k: Int -> Int |
59 |
|
* exists k. |
60 |
|
* forall 0 <= x < n, |
61 |
|
* k(x) is the length of the x^th occurrence of b in a (excluding |
62 |
|
* matches of empty strings) |
63 |
|
* where b is a regular expression, n is the number of occurrences of b |
64 |
|
* in a, and k(0)=0. |
65 |
|
*/ |
66 |
|
STRINGS_OCCUR_LEN, |
67 |
|
/** |
68 |
|
* Diff index for disequalities a != b => substr(a,k,1) != substr(b,k,1) |
69 |
|
*/ |
70 |
|
STRINGS_DEQ_DIFF, |
71 |
|
//----- |
72 |
|
/** |
73 |
|
* A function used to define intermediate results of str.replace_all and |
74 |
|
* str.replace_re_all applications. |
75 |
|
*/ |
76 |
|
STRINGS_REPLACE_ALL_RESULT, |
77 |
|
/** |
78 |
|
* A function used to define intermediate results of str.from_int |
79 |
|
* applications. |
80 |
|
*/ |
81 |
|
STRINGS_ITOS_RESULT, |
82 |
|
/** |
83 |
|
* A function used to define intermediate results of str.to_int |
84 |
|
* applications. |
85 |
|
*/ |
86 |
|
STRINGS_STOI_RESULT, |
87 |
|
/** |
88 |
|
* An index containing a non-digit in a string, used when (str.to_int a) = -1. |
89 |
|
*/ |
90 |
|
STRINGS_STOI_NON_DIGIT, |
91 |
|
/** |
92 |
|
* For sequence a and regular expression b, |
93 |
|
* in_re(a, re.++(_*, b, _*)) => |
94 |
|
* exists k_pre, k_match, k_post. |
95 |
|
* a = k_pre ++ k_match ++ k_post ^ |
96 |
|
* len(k_pre) = indexof_re(x, y, 0) ^ |
97 |
|
* (forall l. 0 < l < len(k_match) => |
98 |
|
* ~in_re(substr(k_match, 0, l), r)) ^ |
99 |
|
* in_re(k_match, b) |
100 |
|
* |
101 |
|
* k_pre is the prefix before the first, shortest match of b in a. k_match |
102 |
|
* is the substring of a matched by b. It is either empty or there is no |
103 |
|
* shorter string that matches b. |
104 |
|
*/ |
105 |
|
SK_FIRST_MATCH_PRE, |
106 |
|
SK_FIRST_MATCH, |
107 |
|
SK_FIRST_MATCH_POST, |
108 |
|
/** |
109 |
|
* Regular expression unfold component: if (str.in_re t R), where R is |
110 |
|
* (re.++ r0 ... rn), then the RE_UNFOLD_POS_COMPONENT{t,R,i} is a string |
111 |
|
* skolem ki such that t = (str.++ k0 ... kn) and (str.in_re k0 r0) for |
112 |
|
* i = 0, ..., n. |
113 |
|
*/ |
114 |
|
RE_UNFOLD_POS_COMPONENT, |
115 |
|
/** An uninterpreted function for bag.map operator: |
116 |
|
* To compute (bag.count y (map f A)), we need to find the distinct |
117 |
|
* elements in A that are mapped to y by function f (i.e., preimage of {y}). |
118 |
|
* If n is the cardinality of this preimage, then |
119 |
|
* the preimage is the set {uf(1), ..., uf(n)} |
120 |
|
* where uf: Int -> E is a skolem function, and E is the type of elements of A |
121 |
|
*/ |
122 |
|
BAGS_MAP_PREIMAGE, |
123 |
|
/** An uninterpreted function for bag.map operator: |
124 |
|
* If the preimage of {y} in A is {uf(1), ..., uf(n)} (see BAGS_MAP_PREIMAGE}, |
125 |
|
* then the multiplicity of an element y in a bag (map f A) is sum(n), |
126 |
|
* where sum: Int -> Int is a skolem function such that: |
127 |
|
* sum(0) = 0 |
128 |
|
* sum(i) = sum (i-1) + (bag.count (uf i) A) |
129 |
|
*/ |
130 |
|
BAGS_MAP_SUM, |
131 |
|
/** Higher-order type match predicate, see HoTermDb */ |
132 |
|
HO_TYPE_MATCH_PRED, |
133 |
|
}; |
134 |
|
/** Converts a skolem function name to a string. */ |
135 |
|
const char* toString(SkolemFunId id); |
136 |
|
/** Writes a skolem function name to a stream. */ |
137 |
|
std::ostream& operator<<(std::ostream& out, SkolemFunId id); |
138 |
|
|
139 |
|
/** |
140 |
|
* A manager for skolems that can be used in proofs. This is designed to be |
141 |
|
* a trusted interface to NodeManager::mkSkolem, where one |
142 |
|
* must provide a definition for the skolem they create in terms of a |
143 |
|
* predicate that the introduced variable is intended to witness. |
144 |
|
* |
145 |
|
* It is implemented by mapping terms to an attribute corresponding to their |
146 |
|
* "original form" and "witness form" as described below. Hence, this class does |
147 |
|
* not impact the reference counting of skolem variables which may be deleted if |
148 |
|
* they are not used. |
149 |
|
* |
150 |
|
* We distinguish two kinds of mappings between terms and skolems: |
151 |
|
* |
152 |
|
* (1) "Original form", which associates skolems with the terms they purify. |
153 |
|
* This is used in mkPurifySkolem below. |
154 |
|
* |
155 |
|
* (2) "Witness form", which associates skolems with their formal definition |
156 |
|
* as a witness term. This is used in mkSkolem below. |
157 |
|
* |
158 |
|
* It is possible to unify these so that purification skolems for t are skolems |
159 |
|
* whose witness form is (witness ((x T)) (= x t)). However, there are |
160 |
|
* motivations not to do so. In particular, witness terms in most contexts |
161 |
|
* should be seen as black boxes, converting something to witness form may have |
162 |
|
* unintended consequences e.g. variable shadowing. In contrast, converting to |
163 |
|
* original form does not have these complications. Furthermore, having original |
164 |
|
* form greatly simplifies reasoning in the proof, in particular, it avoids the |
165 |
|
* need to reason about identifiers for introduced variables x. |
166 |
|
* |
167 |
|
* Furthermore, note that original form and witness form may share skolems |
168 |
|
* in the rare case that a witness term is purified. This is currently only the |
169 |
|
* case for algorithms that introduce witness, e.g. BV/set instantiation. |
170 |
|
* |
171 |
|
* Additionally, we consider a third class of skolems (mkSkolemFunction) which |
172 |
|
* are for convenience associated with an identifier, and not a witness term. |
173 |
|
*/ |
174 |
|
class SkolemManager |
175 |
|
{ |
176 |
|
public: |
177 |
|
SkolemManager(); |
178 |
10379 |
~SkolemManager() {} |
179 |
|
|
180 |
|
/** |
181 |
|
* Optional flags used to control behavior of skolem creation. |
182 |
|
* They should be composed with a bitwise OR (e.g., |
183 |
|
* "SKOLEM_BOOL_TERM_VAR | SKOLEM_EXACT_NAME"). Of course, SKOLEM_DEFAULT |
184 |
|
* cannot be composed in such a manner. |
185 |
|
*/ |
186 |
|
enum SkolemFlags |
187 |
|
{ |
188 |
|
SKOLEM_DEFAULT = 0, /**< default behavior */ |
189 |
|
SKOLEM_EXACT_NAME = 1, /**< do not make the name unique by adding the id */ |
190 |
|
SKOLEM_BOOL_TERM_VAR = 2 /**< vars requiring kind BOOLEAN_TERM_VARIABLE */ |
191 |
|
}; |
192 |
|
/** |
193 |
|
* This makes a skolem of same type as bound variable v, (say its type is T), |
194 |
|
* whose definition is (witness ((v T)) pred). This definition is maintained |
195 |
|
* by this class. |
196 |
|
* |
197 |
|
* Notice that (exists ((v T)) pred) should be a valid formula. This fact |
198 |
|
* captures the reason for why the returned Skolem was introduced. |
199 |
|
* |
200 |
|
* Take as an example extensionality in arrays: |
201 |
|
* |
202 |
|
* (declare-fun a () (Array Int Int)) |
203 |
|
* (declare-fun b () (Array Int Int)) |
204 |
|
* (assert (not (= a b))) |
205 |
|
* |
206 |
|
* To witness the index where the arrays a and b are disequal, it is intended |
207 |
|
* we call this method on: |
208 |
|
* Node k = mkSkolem( x, F ) |
209 |
|
* where F is: |
210 |
|
* (=> (not (= a b)) (not (= (select a x) (select b x)))) |
211 |
|
* and x is a fresh bound variable of integer type. Internally, this will map |
212 |
|
* k to the term: |
213 |
|
* (witness ((x Int)) (=> (not (= a b)) |
214 |
|
* (not (= (select a x) (select b x))))) |
215 |
|
* A lemma generated by the array solver for extensionality may safely use |
216 |
|
* the skolem k in the standard way: |
217 |
|
* (=> (not (= a b)) (not (= (select a k) (select b k)))) |
218 |
|
* Furthermore, notice that the following lemma does not involve fresh |
219 |
|
* skolem variables and is valid according to the theory of arrays extended |
220 |
|
* with support for witness: |
221 |
|
* (let ((w (witness ((x Int)) (=> (not (= a b)) |
222 |
|
* (not (= (select a x) (select b x))))))) |
223 |
|
* (=> (not (= a b)) (not (= (select a w) (select b w))))) |
224 |
|
* This version of the lemma, which requires no explicit tracking of free |
225 |
|
* Skolem variables, can be obtained by a call to getWitnessForm(...) |
226 |
|
* below. We call this the "witness form" of the lemma above. |
227 |
|
* |
228 |
|
* @param v The bound variable of the same type of the Skolem to create. |
229 |
|
* @param pred The desired property of the Skolem to create, in terms of bound |
230 |
|
* variable v. |
231 |
|
* @param prefix The prefix of the name of the Skolem |
232 |
|
* @param comment Debug information about the Skolem |
233 |
|
* @param flags The flags for the Skolem (see SkolemFlags) |
234 |
|
* @param pg The proof generator for this skolem. If non-null, this proof |
235 |
|
* generator must respond to a call to getProofFor(exists v. pred) during |
236 |
|
* the lifetime of the current node manager. |
237 |
|
* @return The skolem whose witness form is registered by this class. |
238 |
|
*/ |
239 |
|
Node mkSkolem(Node v, |
240 |
|
Node pred, |
241 |
|
const std::string& prefix, |
242 |
|
const std::string& comment = "", |
243 |
|
int flags = SKOLEM_DEFAULT, |
244 |
|
ProofGenerator* pg = nullptr); |
245 |
|
/** |
246 |
|
* Make skolemized form of existentially quantified formula q, and store its |
247 |
|
* Skolems into the argument skolems. |
248 |
|
* |
249 |
|
* For example, calling this method on: |
250 |
|
* (exists ((x Int) (y Int)) (P x y)) |
251 |
|
* returns: |
252 |
|
* (P w1 w2) |
253 |
|
* where w1 and w2 are skolems with witness forms: |
254 |
|
* (witness ((x Int)) (exists ((y Int)) (P x y))) |
255 |
|
* (witness ((y Int)) (P w1 y)) |
256 |
|
* respectively. Additionally, this method will add { w1, w2 } to skolems. |
257 |
|
* Notice that y is *not* renamed in the witness form of w1. This is not |
258 |
|
* necessary since w1 is skolem. Although its witness form contains |
259 |
|
* quantification on y, we never construct a term where the witness form |
260 |
|
* of w1 is expanded in the witness form of w2. This avoids variable |
261 |
|
* shadowing. |
262 |
|
* |
263 |
|
* In contrast to mkSkolem, the proof generator is for the *entire* |
264 |
|
* existentially quantified formula q, which may have multiple variables in |
265 |
|
* its prefix. |
266 |
|
* |
267 |
|
* @param q The existentially quantified formula to skolemize, |
268 |
|
* @param skolems Vector to add Skolems of q to, |
269 |
|
* @param prefix The prefix of the name of each of the Skolems |
270 |
|
* @param comment Debug information about each of the Skolems |
271 |
|
* @param flags The flags for the Skolem (see SkolemFlags) |
272 |
|
* @param pg The proof generator for this skolem. If non-null, this proof |
273 |
|
* generator must respond to a call to getProofFor(q) during |
274 |
|
* the lifetime of the current node manager. |
275 |
|
* @return The skolemized form of q. |
276 |
|
*/ |
277 |
|
Node mkSkolemize(Node q, |
278 |
|
std::vector<Node>& skolems, |
279 |
|
const std::string& prefix, |
280 |
|
const std::string& comment = "", |
281 |
|
int flags = SKOLEM_DEFAULT, |
282 |
|
ProofGenerator* pg = nullptr); |
283 |
|
/** |
284 |
|
* Same as above, but for special case of (witness ((x T)) (= x t)) |
285 |
|
* where T is the type of t. This skolem is unique for each t, which we |
286 |
|
* implement via an attribute on t. This attribute is used to ensure to |
287 |
|
* associate a unique skolem for each t. |
288 |
|
* |
289 |
|
* Notice that a purification skolem is trivial to justify, and hence it |
290 |
|
* does not require a proof generator. |
291 |
|
* |
292 |
|
* Notice that in very rare cases, two different terms may have the |
293 |
|
* same purification skolem. For example, let k be the skolem introduced to |
294 |
|
* eliminate (ite A B C). Then, the pair of terms: |
295 |
|
* (ite (ite A B C) D E) and (ite k D E) |
296 |
|
* have the same purification skolem. In the implementation, this is a result |
297 |
|
* of the fact that the above terms have the same original form. It is sound |
298 |
|
* to use the same skolem to purify these two terms, since they are |
299 |
|
* definitionally equivalent. |
300 |
|
*/ |
301 |
|
Node mkPurifySkolem(Node t, |
302 |
|
const std::string& prefix, |
303 |
|
const std::string& comment = "", |
304 |
|
int flags = SKOLEM_DEFAULT); |
305 |
|
/** |
306 |
|
* Make skolem function. This method should be used for creating fixed |
307 |
|
* skolem functions of the forms described in SkolemFunId. The user of this |
308 |
|
* method is responsible for providing a proper type for the identifier that |
309 |
|
* matches the description of id. Skolem functions are useful for modelling |
310 |
|
* the behavior of partial functions, or for theory-specific inferences that |
311 |
|
* introduce fresh variables. |
312 |
|
* |
313 |
|
* A skolem function is not given a formal semantics in terms of a witness |
314 |
|
* term, nor is it a purification skolem, thus it does not fall into the two |
315 |
|
* categories of skolems above. This method is motivated by convenience, as |
316 |
|
* the user of this method does not require constructing canonical variables |
317 |
|
* for witness terms. |
318 |
|
* |
319 |
|
* The returned skolem is an ordinary skolem variable that can be used |
320 |
|
* e.g. in APPLY_UF terms when tn is a function type. |
321 |
|
* |
322 |
|
* Notice that we do not insist that tn is a function type. A user of this |
323 |
|
* method may construct a canonical (first-order) skolem using this method |
324 |
|
* as well. |
325 |
|
* |
326 |
|
* @param id The identifier of the skolem function |
327 |
|
* @param tn The type of the returned skolem function |
328 |
|
* @param cacheVal A cache value. The returned skolem function will be |
329 |
|
* unique to the pair (id, cacheVal). This value is required, for instance, |
330 |
|
* for skolem functions that are in fact families of skolem functions, |
331 |
|
* e.g. the wrongly applied case of selectors. |
332 |
|
* @return The skolem function. |
333 |
|
*/ |
334 |
|
Node mkSkolemFunction(SkolemFunId id, |
335 |
|
TypeNode tn, |
336 |
|
Node cacheVal = Node::null(), |
337 |
|
int flags = SKOLEM_DEFAULT); |
338 |
|
/** Same as above, with multiple cache values */ |
339 |
|
Node mkSkolemFunction(SkolemFunId id, |
340 |
|
TypeNode tn, |
341 |
|
const std::vector<Node>& cacheVals, |
342 |
|
int flags = SKOLEM_DEFAULT); |
343 |
|
/** |
344 |
|
* Is k a skolem function? Returns true if k was generated by the above call. |
345 |
|
* Updates the arguments to the values used when constructing it. |
346 |
|
*/ |
347 |
|
bool isSkolemFunction(Node k, SkolemFunId& id, Node& cacheVal) const; |
348 |
|
/** |
349 |
|
* Create a skolem constant with the given name, type, and comment. This |
350 |
|
* should only be used if the definition of the skolem does not matter. |
351 |
|
* The definition of a skolem matters e.g. when the skolem is used in a |
352 |
|
* proof. |
353 |
|
* |
354 |
|
* @param prefix the name of the new skolem variable is the prefix |
355 |
|
* appended with a unique ID. This way a family of skolem variables |
356 |
|
* can be made with unique identifiers, used in dump, tracing, and |
357 |
|
* debugging output. Use SKOLEM_EXACT_NAME flag if you don't want |
358 |
|
* a unique ID appended and use prefix as the name. |
359 |
|
* @param type the type of the skolem variable to create |
360 |
|
* @param comment a comment for dumping output; if declarations are |
361 |
|
* being dumped, this is included in a comment before the declaration |
362 |
|
* and can be quite useful for debugging |
363 |
|
* @param flags an optional mask of bits from SkolemFlags to control |
364 |
|
* skolem behavior |
365 |
|
*/ |
366 |
|
Node mkDummySkolem(const std::string& prefix, |
367 |
|
const TypeNode& type, |
368 |
|
const std::string& comment = "", |
369 |
|
int flags = SKOLEM_DEFAULT); |
370 |
|
/** |
371 |
|
* Get proof generator for existentially quantified formula q. This returns |
372 |
|
* the proof generator that was provided in a call to mkSkolem above. |
373 |
|
*/ |
374 |
|
ProofGenerator* getProofGenerator(Node q) const; |
375 |
|
/** |
376 |
|
* Convert to witness form, which gets the witness form of a skolem k. |
377 |
|
* Notice this method is *not* recursive, instead, it is a simple attribute |
378 |
|
* lookup. |
379 |
|
* |
380 |
|
* @param k The variable to convert to witness form described above |
381 |
|
* @return k in witness form. |
382 |
|
*/ |
383 |
|
static Node getWitnessForm(Node k); |
384 |
|
/** |
385 |
|
* Convert to original form, which recursively replaces all skolems terms in n |
386 |
|
* by the term they purify. |
387 |
|
* |
388 |
|
* @param n The term or formula to convert to original form described above |
389 |
|
* @return n in original form. |
390 |
|
*/ |
391 |
|
static Node getOriginalForm(Node n); |
392 |
|
|
393 |
|
private: |
394 |
|
/** Cache of skolem functions for mkSkolemFunction above. */ |
395 |
|
std::map<std::tuple<SkolemFunId, TypeNode, Node>, Node> d_skolemFuns; |
396 |
|
/** Backwards mapping of above */ |
397 |
|
std::map<Node, std::tuple<SkolemFunId, TypeNode, Node>> d_skolemFunMap; |
398 |
|
/** |
399 |
|
* Mapping from witness terms to proof generators. |
400 |
|
*/ |
401 |
|
std::map<Node, ProofGenerator*> d_gens; |
402 |
|
|
403 |
|
/** |
404 |
|
* A counter used to produce unique skolem names. |
405 |
|
* |
406 |
|
* Note that it is NOT incremented when skolems are created using |
407 |
|
* SKOLEM_EXACT_NAME, so it is NOT a count of the skolems produced |
408 |
|
* by this node manager. |
409 |
|
*/ |
410 |
|
size_t d_skolemCounter; |
411 |
|
/** Get or make skolem attribute for term w, which may be a witness term */ |
412 |
|
Node mkSkolemInternal(Node w, |
413 |
|
const std::string& prefix, |
414 |
|
const std::string& comment, |
415 |
|
int flags); |
416 |
|
/** |
417 |
|
* Skolemize the first variable of existentially quantified formula q. |
418 |
|
* For example, calling this method on: |
419 |
|
* (exists ((x Int) (y Int)) (P x y)) |
420 |
|
* will return: |
421 |
|
* (witness ((x Int)) (exists ((y Int)) (P x y))) |
422 |
|
* If q is not an existentially quantified formula, then null is |
423 |
|
* returned and an assertion failure is thrown. |
424 |
|
* |
425 |
|
* This method additionally updates qskolem to be the skolemized form of q. |
426 |
|
* In the above example, this is set to: |
427 |
|
* (exists ((y Int)) (P (witness ((x Int)) (exists ((y' Int)) (P x y'))) y)) |
428 |
|
*/ |
429 |
|
Node skolemize(Node q, |
430 |
|
Node& qskolem, |
431 |
|
const std::string& prefix, |
432 |
|
const std::string& comment = "", |
433 |
|
int flags = SKOLEM_DEFAULT); |
434 |
|
/** |
435 |
|
* Create a skolem constant with the given name, type, and comment. |
436 |
|
* |
437 |
|
* This method is intentionally private. To create skolems, one should |
438 |
|
* call a public method from SkolemManager for allocating a skolem in a |
439 |
|
* proper way, or otherwise use SkolemManager::mkDummySkolem. |
440 |
|
*/ |
441 |
|
Node mkSkolemNode(const std::string& prefix, |
442 |
|
const TypeNode& type, |
443 |
|
const std::string& comment = "", |
444 |
|
int flags = SKOLEM_DEFAULT); |
445 |
|
}; |
446 |
|
|
447 |
|
} // namespace cvc5 |
448 |
|
|
449 |
|
#endif /* CVC5__EXPR__PROOF_SKOLEM_CACHE_H */ |