@@ -194,9 +194,10 @@ exprt string_constraint_generatort::add_axioms_for_contains(
194
194
195
195
// We add axioms:
196
196
// a1 : contains ==> |s0| >= |s1|
197
- // a2 : 0 <= startpos <= |s0|-|s1|
198
- // a3 : forall qvar < |s1|. contains ==> s1[qvar] = s0[startpos + qvar]
199
- // a4 : !contains ==> |s1| > |s0| ||
197
+ // a2 : contains ==> 0 <= startpos <= |s0|-|s1|
198
+ // a3 : !contains ==> startpos = -1
199
+ // a4 : forall qvar < |s1|. contains ==> s1[qvar] = s0[startpos + qvar]
200
+ // a5 : !contains ==> |s1| > |s0| ||
200
201
// (forall startpos <= |s0| - |s1|.
201
202
// exists witness < |s1|. s1[witness] != s0[witness + startpos])
202
203
@@ -211,9 +212,14 @@ exprt string_constraint_generatort::add_axioms_for_contains(
211
212
implies_exprt a2 (contains, bounds);
212
213
axioms.push_back (a2);
213
214
215
+ implies_exprt a3 (
216
+ not_exprt (contains),
217
+ equal_exprt (startpos, from_integer (-1 , index_type)));
218
+ axioms.push_back (a3);
219
+
214
220
if (constant)
215
221
{
216
- // If the string is constant, we can use a more efficient axiom for a3 :
222
+ // If the string is constant, we can use a more efficient axiom for a4 :
217
223
// contains ==> AND_{i < |s1|} s1[i] = s0[startpos + i]
218
224
mp_integer s1_length;
219
225
assert (!to_integer (s1.length (), s1_length));
@@ -224,10 +230,10 @@ exprt string_constraint_generatort::add_axioms_for_contains(
224
230
plus_exprt shifted_i (expr_i, startpos);
225
231
conjuncts.push_back (equal_exprt (s1[expr_i], s0[shifted_i]));
226
232
}
227
- implies_exprt a3 (contains, conjunction (conjuncts));
228
- axioms.push_back (a3 );
233
+ implies_exprt a4 (contains, conjunction (conjuncts));
234
+ axioms.push_back (a4 );
229
235
230
- // The a4 constraint for constant strings translates to:
236
+ // The a5 constraint for constant strings translates to:
231
237
// !contains ==> |s1| > |s0| ||
232
238
// (forall qvar <= |s0| - |s1|.
233
239
// !(AND_{i < |s1|} s1[i] == s0[i + qvar])
@@ -244,30 +250,30 @@ exprt string_constraint_generatort::add_axioms_for_contains(
244
250
conjuncts1.push_back (equal_exprt (s1[expr_i], s0[shifted_i]));
245
251
}
246
252
247
- string_constraintt a4 (
253
+ string_constraintt a5 (
248
254
qvar,
249
255
plus_exprt (from_integer (1 , index_type), length_diff),
250
256
and_exprt (not_exprt (contains), s0.axiom_for_is_longer_than (s1)),
251
257
not_exprt (conjunction (conjuncts1)));
252
- axioms.push_back (a4 );
258
+ axioms.push_back (a5 );
253
259
}
254
260
else
255
261
{
256
262
symbol_exprt qvar=fresh_univ_index (" QA_contains" , index_type);
257
263
exprt qvar_shifted=plus_exprt (qvar, startpos);
258
- string_constraintt a3 (
264
+ string_constraintt a4 (
259
265
qvar, s1.length (), contains, equal_exprt (s1[qvar], s0[qvar_shifted]));
260
- axioms.push_back (a3 );
266
+ axioms.push_back (a4 );
261
267
262
268
// We rewrite axiom a4 as:
263
269
// forall startpos <= |s0|-|s1|. (!contains && |s0| >= |s1|)
264
270
// ==> exists witness < |s1|. s1[witness] != s0[startpos+witness]
265
- string_not_contains_constraintt a4 (
271
+ string_not_contains_constraintt a5 (
266
272
from_integer (0 , index_type),
267
273
plus_exprt (from_integer (1 , index_type), length_diff),
268
274
and_exprt (not_exprt (contains), s0.axiom_for_is_longer_than (s1)),
269
275
from_integer (0 , index_type), s1.length (), s0, s1);
270
- axioms.push_back (a4 );
276
+ axioms.push_back (a5 );
271
277
}
272
278
return typecast_exprt (contains, f.type ());
273
279
}
0 commit comments