1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli, Yoni Zohar |
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 |
|
* A cache of skolems for theory of strings. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__STRINGS__SKOLEM_CACHE_H |
19 |
|
#define CVC5__THEORY__STRINGS__SKOLEM_CACHE_H |
20 |
|
|
21 |
|
#include <map> |
22 |
|
#include <tuple> |
23 |
|
#include <unordered_set> |
24 |
|
|
25 |
|
#include "expr/node.h" |
26 |
|
#include "expr/skolem_manager.h" |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
namespace theory { |
30 |
|
|
31 |
|
class Rewriter; |
32 |
|
|
33 |
|
namespace strings { |
34 |
|
|
35 |
|
/** |
36 |
|
* A cache of all string skolems generated by the TheoryStrings class. This |
37 |
|
* cache is used to ensure that duplicate skolems are not generated when |
38 |
|
* possible, and helps identify what skolems were allocated in the current run. |
39 |
|
*/ |
40 |
16420 |
class SkolemCache |
41 |
|
{ |
42 |
|
public: |
43 |
|
/** |
44 |
|
* Constructor. |
45 |
|
* |
46 |
|
* @param rr determines if we aggressively share Skolems based on rewriting or |
47 |
|
* return the constants they are entailed to be equal to. This argument is |
48 |
|
* optional. |
49 |
|
*/ |
50 |
|
SkolemCache(Rewriter* rr); |
51 |
|
/** Identifiers for skolem types |
52 |
|
* |
53 |
|
* The comments below document the properties of each skolem introduced by |
54 |
|
* inference in the strings solver, where by skolem we mean the fresh |
55 |
|
* string variable that witnesses each of "exists k". |
56 |
|
* |
57 |
|
* The skolems with _REV suffixes are used for the reverse version of the |
58 |
|
* preconditions below, e.g. where we are considering a' ++ a = b' ++ b. |
59 |
|
* |
60 |
|
* All skolems assume a and b are strings unless otherwise stated. |
61 |
|
* |
62 |
|
* Notice that these identifiers are each syntax sugar for constructing a |
63 |
|
* purification skolem. It is required for the purposes of proof checking |
64 |
|
* that this only results in calls to SkolemManager::mkPurifySkolem. |
65 |
|
*/ |
66 |
|
enum SkolemId |
67 |
|
{ |
68 |
|
// exists k. k = a |
69 |
|
SK_PURIFY, |
70 |
|
// a != "" ^ b = "ccccd" ^ a ++ "d" ++ a' = b ++ b' => |
71 |
|
// exists k. a = "cccc" ++ k |
72 |
|
SK_ID_C_SPT, |
73 |
|
SK_ID_C_SPT_REV, |
74 |
|
// a != "" ^ b = "c" ^ len(a)!=len(b) ^ a ++ a' = b ++ b' => |
75 |
|
// exists k. a = "c" ++ k |
76 |
|
SK_ID_VC_SPT, |
77 |
|
SK_ID_VC_SPT_REV, |
78 |
|
// a != "" ^ b != "" ^ len(a)!=len(b) ^ a ++ a' = b ++ b' => |
79 |
|
// exists k1 k2. len( k1 )>0 ^ len( k2 )>0 ^ |
80 |
|
// ( a ++ k1 = b OR a = b ++ k2 ) |
81 |
|
// k1 is the variable for (a,b) and k2 is the skolem for (b,a). |
82 |
|
SK_ID_V_SPT, |
83 |
|
SK_ID_V_SPT_REV, |
84 |
|
// a != "" ^ b != "" ^ len(a)!=len(b) ^ a ++ a' = b ++ b' => |
85 |
|
// exists k. len( k )>0 ^ ( a ++ k = b OR a = b ++ k ) |
86 |
|
SK_ID_V_UNIFIED_SPT, |
87 |
|
SK_ID_V_UNIFIED_SPT_REV, |
88 |
|
// a != "" ^ b = "c" ^ a ++ a' != b ++ b' => |
89 |
|
// exists k, k_rem. |
90 |
|
// len( k ) = 1 ^ |
91 |
|
// ( ( a = k ++ k_rem ^ k != "c" ) OR ( a = "c" ++ k_rem ) ) |
92 |
|
SK_ID_DC_SPT, |
93 |
|
SK_ID_DC_SPT_REM, |
94 |
|
// a != "" ^ b != "" ^ len( a ) != len( b ) ^ a ++ a' != b ++ b' => |
95 |
|
// exists k_x k_y k_z. |
96 |
|
// ( len( k_y ) = len( a ) ^ len( k_x ) = len( b ) ^ len( k_z) > 0 |
97 |
|
// ( a = k_x ++ k_z OR b = k_y ++ k_z ) ) |
98 |
|
SK_ID_DEQ_X, |
99 |
|
SK_ID_DEQ_Y, |
100 |
|
// contains( a, b ) => |
101 |
|
// exists k_pre, k_post. a = k_pre ++ b ++ k_post ^ |
102 |
|
// ~contains(k_pre ++ substr( b, 0, len(b)-1 ), b) |
103 |
|
// |
104 |
|
// As an optimization, these skolems are reused for positive occurrences of |
105 |
|
// contains, where they have the semantics: |
106 |
|
// |
107 |
|
// contains( a, b ) => |
108 |
|
// exists k_pre, k_post. a = k_pre ++ b ++ k_post |
109 |
|
// |
110 |
|
// We reuse them since it is sound to consider w.l.o.g. the first occurrence |
111 |
|
// of b in a as the witness for contains( a, b ). |
112 |
|
SK_FIRST_CTN_PRE, |
113 |
|
SK_FIRST_CTN_POST, |
114 |
|
// For integer b, |
115 |
|
// len( a ) > b => |
116 |
|
// exists k. a = k ++ a' ^ len( k ) = b |
117 |
|
SK_PREFIX, |
118 |
|
// For integer b, |
119 |
|
// b > 0 => |
120 |
|
// exists k. a = a' ++ k ^ len( k ) = ite( len(a)>b, len(a)-b, 0 ) |
121 |
|
SK_SUFFIX_REM |
122 |
|
}; |
123 |
|
/** |
124 |
|
* Returns a skolem of type string that is cached for (a,b,id) and has |
125 |
|
* name c. |
126 |
|
*/ |
127 |
|
Node mkSkolemCached(Node a, Node b, SkolemId id, const char* c); |
128 |
|
/** |
129 |
|
* Returns a skolem of type string that is cached for (a,[null],id) and has |
130 |
|
* name c. |
131 |
|
*/ |
132 |
|
Node mkSkolemCached(Node a, SkolemId id, const char* c); |
133 |
|
/** Same as above, but the skolem to construct has a custom type tn */ |
134 |
|
Node mkTypedSkolemCached( |
135 |
|
TypeNode tn, Node a, Node b, SkolemId id, const char* c); |
136 |
|
/** Same as mkTypedSkolemCached above for (a,[null],id) */ |
137 |
|
Node mkTypedSkolemCached(TypeNode tn, Node a, SkolemId id, const char* c); |
138 |
|
/** |
139 |
|
* Specific version for seq.nth, used for cases where the index is out of |
140 |
|
* range for sequence type seqType. |
141 |
|
*/ |
142 |
|
static Node mkSkolemSeqNth(TypeNode seqType, const char* c); |
143 |
|
/** Returns a (uncached) skolem of type string with name c */ |
144 |
|
Node mkSkolem(const char* c); |
145 |
|
/** Returns true if n is a skolem allocated by this class */ |
146 |
|
bool isSkolem(Node n) const; |
147 |
|
/** Make index variable |
148 |
|
* |
149 |
|
* This returns an integer variable of kind BOUND_VARIABLE that is used |
150 |
|
* for axiomatizing the behavior of a term or predicate t. Notice that this |
151 |
|
* index variable does *not* necessarily refer to indices in the term t |
152 |
|
* itself. Instead, it refers to indices in the relevant string in the |
153 |
|
* reduction of t. For example, the index variable for the term str.to_int(s) |
154 |
|
* is used to quantify over the positions in string term s. |
155 |
|
*/ |
156 |
|
static Node mkIndexVar(Node t); |
157 |
|
|
158 |
|
/** Make length variable |
159 |
|
* |
160 |
|
* This returns an integer variable of kind BOUND_VARIABLE that is used for |
161 |
|
* axiomatizing the behavior of a term or predicate t. It refers to lengths |
162 |
|
* of strings in the reduction of t. For example, the length variable for the |
163 |
|
* term str.indexof(s, r, n) is used to quantify over the lengths of strings |
164 |
|
* that could be matched by r. |
165 |
|
*/ |
166 |
|
static Node mkLengthVar(Node t); |
167 |
|
/** |
168 |
|
* Make skolem function, possibly normalizing based on the rewriter of this |
169 |
|
* class. This method should be used whenever it is not possible to define |
170 |
|
* a Skolem identifier that amounts to purification of a term. |
171 |
|
* |
172 |
|
* Notice that this method is not static or constant since it tracks the |
173 |
|
* Skolem we construct (in d_allSkolems), which is used for finite model |
174 |
|
* finding. |
175 |
|
*/ |
176 |
|
Node mkSkolemFun(SkolemFunId id, |
177 |
|
TypeNode tn, |
178 |
|
Node a = Node::null(), |
179 |
|
Node b = Node::null()); |
180 |
|
|
181 |
|
private: |
182 |
|
/** |
183 |
|
* Simplifies the arguments for a string skolem used for indexing into the |
184 |
|
* cache. In certain cases, we can share skolems with similar arguments e.g. |
185 |
|
* SK_FIRST_CTN(a, c) can be used instead of SK_FIRST_CTN((str.substr a 0 n), |
186 |
|
* c) because the first occurrence of "c" in "(str.substr a 0 n)" is also the |
187 |
|
* first occurrence of "c" in "a" (assuming that "c" appears in both and |
188 |
|
* otherwise the value of SK_FIRST_CTN does not matter). |
189 |
|
* |
190 |
|
* @param id The type of skolem |
191 |
|
* @param a The first argument used for indexing |
192 |
|
* @param b The second argument used for indexing |
193 |
|
* @return A tuple with the new skolem id, the new first, and the new second |
194 |
|
* argument |
195 |
|
*/ |
196 |
|
std::tuple<SkolemId, Node, Node> normalizeStringSkolem(SkolemId id, |
197 |
|
Node a, |
198 |
|
Node b); |
199 |
|
/** the optional rewriter */ |
200 |
|
Rewriter* d_rr; |
201 |
|
/** string type */ |
202 |
|
TypeNode d_strType; |
203 |
|
/** Constant node zero */ |
204 |
|
Node d_zero; |
205 |
|
/** map from node pairs and identifiers to skolems */ |
206 |
|
std::map<Node, std::map<Node, std::map<SkolemId, Node> > > d_skolemCache; |
207 |
|
/** the set of all skolems we have generated */ |
208 |
|
std::unordered_set<Node> d_allSkolems; |
209 |
|
}; |
210 |
|
|
211 |
|
} // namespace strings |
212 |
|
} // namespace theory |
213 |
|
} // namespace cvc5 |
214 |
|
|
215 |
|
#endif /* CVC5__THEORY__STRINGS__SKOLEM_CACHE_H */ |