GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/expr/skolem_manager.h Lines: 1 1 100.0 %
Date: 2021-11-07 Branches: 0 0 0.0 %

Line Exec Source
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 */