Skip to content

Commit f9199a0

Browse files
Make index_of precise diffblue/test-gen#77
Adding constraints to make sure the index_of primitive of the string solver is precise. Also add specific constraints for constant argument in indexOf to improve performances in that case.
1 parent f4f4c44 commit f9199a0

File tree

1 file changed

+89
-11
lines changed

1 file changed

+89
-11
lines changed

src/solvers/refinement/string_constraint_generator_indexof.cpp

+89-11
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,17 @@ exprt string_constraint_generatort::add_axioms_for_index_of(
7373
7474
Function: string_constraint_generatort::add_axioms_for_index_of_string
7575
76-
Inputs: two string expressions and an integer expression
76+
Inputs:
77+
str - a string expression
78+
substring - a string expression
79+
from_index - an expression representing an index in strings
7780
7881
Outputs: a integer expression
7982
80-
Purpose: add axioms stating that the returned value is either -1 or greater
81-
than from_index and the string beggining there has prefix substring
83+
Purpose: add axioms stating that the returned value is an index greater than
84+
from_index such that str at that index starts with substring and is
85+
the first occurence of substring in str, or -1 if str does not contain
86+
substring.
8287
8388
\*******************************************************************/
8489

@@ -92,20 +97,24 @@ exprt string_constraint_generatort::add_axioms_for_index_of_string(
9297
symbol_exprt contains=fresh_boolean("contains_substring");
9398

9499
// We add axioms:
95-
// a1 : contains => |str|-|substring|>=offset>=from_index
96-
// a2 : !contains => offset=-1
97-
// a3 : forall 0<=witness<|substring|.
98-
// contains => str[witness+offset]=substring[witness]
100+
// a1 : contains => from_index <= offset <= |str|-|substring|
101+
// a2 : !contains <=> offset=-1
102+
// a3 : forall n:[0,|substring|[.
103+
// contains => str[n+offset]=substring[n]
104+
// a4 : forall n:[from_index,offset[.
105+
// contains => (exists m:[0,|substring|[. str[m+n]!=substring[m]])
106+
// a5: forall n:[from_index,|str|-|substring|[.
107+
// !contains => (exists m:[0,|substring|[. str[m+n]!=substring[m])
99108

100109
implies_exprt a1(
101110
contains,
102111
and_exprt(
103-
str.axiom_for_is_longer_than(plus_exprt_with_overflow_check(
104-
substring.length(), offset)),
105-
binary_relation_exprt(offset, ID_ge, from_index)));
112+
binary_relation_exprt(from_index, ID_le, offset),
113+
binary_relation_exprt(
114+
offset, ID_le, minus_exprt(str.length(), substring.length()))));
106115
axioms.push_back(a1);
107116

108-
implies_exprt a2(
117+
equal_exprt a2(
109118
not_exprt(contains),
110119
equal_exprt(offset, from_integer(-1, index_type)));
111120
axioms.push_back(a2);
@@ -118,9 +127,78 @@ exprt string_constraint_generatort::add_axioms_for_index_of_string(
118127
equal_exprt(str[plus_exprt(qvar, offset)], substring[qvar]));
119128
axioms.push_back(a3);
120129

130+
if(!is_constant_string(substring))
131+
{
132+
// string_not contains_constraintt are formula of the form:
133+
// forall x in [lb,ub[. p(x) => exists y in [lb,ub[. s1[x+y] != s2[y]
134+
string_not_contains_constraintt a4(
135+
from_index,
136+
offset,
137+
contains,
138+
from_integer(0, index_type),
139+
substring.length(),
140+
str,
141+
substring);
142+
axioms.push_back(a4);
143+
144+
string_not_contains_constraintt a5(
145+
from_index,
146+
minus_exprt(str.length(), substring.length()),
147+
not_exprt(contains),
148+
from_integer(0, index_type),
149+
substring.length(),
150+
str,
151+
substring);
152+
axioms.push_back(a5);
153+
}
154+
else
155+
{
156+
// Unfold the existential quantifier as a disjunction in case of a constant
157+
// a4 && a5 <=> a6:
158+
// forall n:[from_index,|str|-|substring|].
159+
// !contains || n < offset =>
160+
// str[n]!=substring[0] || ... ||
161+
// str[n+|substring|-1]!=substring[|substring|-1]
162+
symbol_exprt qvar2=fresh_univ_index("QA_index_of_string_2", index_type);
163+
mp_integer sub_length;
164+
assert(!to_integer(substring.length(), sub_length));
165+
exprt::operandst disjuncts;
166+
for(mp_integer offset=0; offset<sub_length; ++offset)
167+
{
168+
exprt expr_offset=from_integer(offset, index_type);
169+
plus_exprt shifted(expr_offset, qvar2);
170+
disjuncts.push_back(
171+
not_exprt(equal_exprt(str[shifted], substring[expr_offset])));
172+
}
173+
174+
or_exprt premise(
175+
not_exprt(contains), binary_relation_exprt(qvar, ID_lt, offset));
176+
minus_exprt length_diff(str.length(), substring.length());
177+
string_constraintt a6(
178+
qvar2,
179+
from_index,
180+
plus_exprt(from_integer(1, index_type), length_diff),
181+
premise,
182+
disjunction(disjuncts));
183+
axioms.push_back(a6);
184+
}
185+
121186
return offset;
122187
}
123188

189+
/*******************************************************************\
190+
191+
Function: string_constraint_generatort::add_axioms_for_last_index_of_string
192+
193+
Inputs: two string expressions and an integer expression
194+
195+
Outputs: a integer expression
196+
197+
Purpose: add axioms stating that the returned value is either -1 or less
198+
than from_index and the string beggining there has prefix substring
199+
200+
\*******************************************************************/
201+
124202
exprt string_constraint_generatort::add_axioms_for_last_index_of_string(
125203
const string_exprt &str,
126204
const string_exprt &substring,

0 commit comments

Comments
 (0)