Skip to content

Commit 0976b08

Browse files
committed
Simplify when combining string-refinement result constraints
Due to the improvements in constant prop we increasingly have constraints that are trivially simplified, like: if 5 >= 2 do x else y Also because of the way these conditions are combined - the resulting merged if gets added to all subsequent conditions and values - we end up with expressions like this: if 5 >= 2 then (if 5 >= 2 do x ... else y ...) else (if 5 >= 2 do x ... else y ...) Where the size of the expression increases exponentially to the complexity of the original if statement even if the entire conditional is trivial to prove right/wrong. This could likely be worked out by the SAT solver happily enough but due to the size of the resulting expressions (I've seen ones 1.34 billion nodes deep) it never gets there within a reasonable time-frame.
1 parent 91ccdfb commit 0976b08

6 files changed

+79
-40
lines changed

src/solvers/strings/string_concatenation_builtin_function.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,13 @@ std::pair<exprt, string_constraintst> add_axioms_for_concat(
182182
/// \param fresh_symbol: generator of fresh symbols
183183
/// \param f: function application with two arguments: a string and a code point
184184
/// \param array_pool: pool of arrays representing strings
185+
/// \param ns: the namespace
185186
/// \return an expression
186187
std::pair<exprt, string_constraintst> add_axioms_for_concat_code_point(
187188
symbol_generatort &fresh_symbol,
188189
const function_application_exprt &f,
189-
array_poolt &array_pool)
190+
array_poolt &array_pool,
191+
const namespacet &ns)
190192
{
191193
PRECONDITION(f.arguments().size() == 4);
192194
const array_string_exprt res =
@@ -198,7 +200,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_concat_code_point(
198200
array_pool.fresh_string(index_type, char_type);
199201
return combine_results(
200202
add_axioms_for_code_point(code_point, f.arguments()[3], array_pool),
201-
add_axioms_for_concat(fresh_symbol, res, s1, code_point, array_pool));
203+
add_axioms_for_concat(fresh_symbol, res, s1, code_point, array_pool),
204+
ns);
202205
}
203206

204207
std::vector<mp_integer> string_concatenation_builtin_functiont::eval(

src/solvers/strings/string_constraint_generator.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_copy(
187187
std::pair<exprt, string_constraintst> add_axioms_for_concat_code_point(
188188
symbol_generatort &fresh_symbol,
189189
const function_application_exprt &f,
190-
array_poolt &array_pool);
190+
array_poolt &array_pool,
191+
const namespacet &ns);
191192
std::pair<exprt, string_constraintst> add_axioms_for_constant(
192193
const array_string_exprt &res,
193194
irep_idt sval,
@@ -200,20 +201,24 @@ std::pair<exprt, string_constraintst> add_axioms_for_delete(
200201
const array_string_exprt &str,
201202
const exprt &start,
202203
const exprt &end,
203-
array_poolt &array_pool);
204+
array_poolt &array_pool,
205+
const namespacet &ns);
204206
std::pair<exprt, string_constraintst> add_axioms_for_delete(
205207
symbol_generatort &fresh_symbol,
206208
const function_application_exprt &f,
207-
array_poolt &array_pool);
209+
array_poolt &array_pool,
210+
const namespacet &ns);
208211
std::pair<exprt, string_constraintst> add_axioms_for_delete_char_at(
209212
symbol_generatort &fresh_symbol,
210213
const function_application_exprt &expr,
211-
array_poolt &array_pool);
214+
array_poolt &array_pool,
215+
const namespacet &ns);
212216

213217
std::pair<exprt, string_constraintst> add_axioms_for_insert(
214218
symbol_generatort &fresh_symbol,
215219
const function_application_exprt &f,
216-
array_poolt &array_pool);
220+
array_poolt &array_pool,
221+
const namespacet &ns);
217222
std::pair<exprt, string_constraintst> add_axioms_for_insert_int(
218223
symbol_generatort &fresh_symbol,
219224
const function_application_exprt &f,
@@ -222,11 +227,13 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_int(
222227
std::pair<exprt, string_constraintst> add_axioms_for_insert_bool(
223228
symbol_generatort &fresh_symbol,
224229
const function_application_exprt &f,
225-
array_poolt &array_pool);
230+
array_poolt &array_pool,
231+
const namespacet &ns);
226232
std::pair<exprt, string_constraintst> add_axioms_for_insert_char(
227233
symbol_generatort &fresh_symbol,
228234
const function_application_exprt &f,
229-
array_poolt &array_pool);
235+
array_poolt &array_pool,
236+
const namespacet &ns);
230237
std::pair<exprt, string_constraintst> add_axioms_for_insert_float(
231238
symbol_generatort &fresh_symbol,
232239
const function_application_exprt &f,
@@ -243,11 +250,13 @@ std::pair<exprt, string_constraintst> add_axioms_for_cprover_string(
243250
const array_string_exprt &res,
244251
const exprt &arg,
245252
const exprt &guard,
246-
array_poolt &array_pool);
253+
array_poolt &array_pool,
254+
const namespacet &ns);
247255
std::pair<exprt, string_constraintst> add_axioms_from_literal(
248256
symbol_generatort &fresh_symbol,
249257
const function_application_exprt &f,
250-
array_poolt &array_pool);
258+
array_poolt &array_pool,
259+
const namespacet &ns);
251260

252261
std::pair<exprt, string_constraintst> add_axioms_for_string_of_int(
253262
const array_string_exprt &res,
@@ -490,5 +499,6 @@ exprt zero_if_negative(const exprt &expr);
490499

491500
std::pair<exprt, string_constraintst> combine_results(
492501
std::pair<exprt, string_constraintst> result1,
493-
std::pair<exprt, string_constraintst> result2);
502+
std::pair<exprt, string_constraintst> result2,
503+
const namespacet &ns);
494504
#endif

src/solvers/strings/string_constraint_generator_constants.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ add_axioms_for_empty_string(const function_application_exprt &f)
7878
/// \param arg: expression of type string typet
7979
/// \param guard: condition under which `res` should be equal to arg
8080
/// \param array_pool: pool of arrays representing strings
81+
/// \param ns: the namespace
8182
/// \return 0 if constraints were added, 1 if expression could not be handled
8283
/// and no constraint was added. Expression we can handle are of the form
8384
/// \f$ e := "<string constant>" | (expr)? e : e \f$
@@ -86,17 +87,19 @@ std::pair<exprt, string_constraintst> add_axioms_for_cprover_string(
8687
const array_string_exprt &res,
8788
const exprt &arg,
8889
const exprt &guard,
89-
array_poolt &array_pool)
90+
array_poolt &array_pool,
91+
const namespacet &ns)
9092
{
9193
if(const auto if_expr = expr_try_dynamic_cast<if_exprt>(arg))
9294
{
9395
const and_exprt guard_true(guard, if_expr->cond());
9496
const and_exprt guard_false(guard, not_exprt(if_expr->cond()));
9597
return combine_results(
9698
add_axioms_for_cprover_string(
97-
fresh_symbol, res, if_expr->true_case(), guard_true, array_pool),
99+
fresh_symbol, res, if_expr->true_case(), guard_true, array_pool, ns),
98100
add_axioms_for_cprover_string(
99-
fresh_symbol, res, if_expr->false_case(), guard_false, array_pool));
101+
fresh_symbol, res, if_expr->false_case(), guard_false, array_pool, ns),
102+
ns);
100103
}
101104
else if(const auto constant_expr = expr_try_dynamic_cast<constant_exprt>(arg))
102105
return add_axioms_for_constant(
@@ -114,15 +117,17 @@ std::pair<exprt, string_constraintst> add_axioms_for_cprover_string(
114117
/// \param f: function application with an argument which is a string literal
115118
/// that is a constant with a string value.
116119
/// \param array_pool: pool of arrays representing strings
120+
/// \param ns: the namespace
117121
/// \return string expression
118122
std::pair<exprt, string_constraintst> add_axioms_from_literal(
119123
symbol_generatort &fresh_symbol,
120124
const function_application_exprt &f,
121-
array_poolt &array_pool)
125+
array_poolt &array_pool,
126+
const namespacet &ns)
122127
{
123128
const function_application_exprt::argumentst &args = f.arguments();
124129
PRECONDITION(args.size() == 3); // Bad args to string literal?
125130
const array_string_exprt res = array_pool.find(args[1], args[0]);
126131
return add_axioms_for_cprover_string(
127-
fresh_symbol, res, args[2], true_exprt(), array_pool);
132+
fresh_symbol, res, args[2], true_exprt(), array_pool, ns);
128133
}

src/solvers/strings/string_constraint_generator_insert.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,14 @@ exprt length_constraint_for_insert(
111111
/// pointer `&res[0]`, refined_string `s1`, refined_string`s2`, integer
112112
/// `offset`, optional integer `start` and optional integer `end`
113113
/// \param array_pool: pool of arrays representing strings
114+
/// \param ns: the namespace
114115
/// \return an integer expression which is different from zero if there is an
115116
/// exception to signal
116117
std::pair<exprt, string_constraintst> add_axioms_for_insert(
117118
symbol_generatort &fresh_symbol,
118119
const function_application_exprt &f,
119-
array_poolt &array_pool)
120+
array_poolt &array_pool,
121+
const namespacet &ns)
120122
{
121123
PRECONDITION(f.arguments().size() == 5 || f.arguments().size() == 7);
122124
array_string_exprt s1 = get_string_expr(array_pool, f.arguments()[2]);
@@ -135,7 +137,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert(
135137
add_axioms_for_substring(
136138
fresh_symbol, substring, s2, start, end, array_pool),
137139
add_axioms_for_insert(
138-
fresh_symbol, res, s1, substring, offset, array_pool));
140+
fresh_symbol, res, s1, substring, offset, array_pool),
141+
ns);
139142
}
140143
else // 5 arguments
141144
{
@@ -168,7 +171,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_int(
168171
const array_string_exprt s2 = array_pool.fresh_string(index_type, char_type);
169172
return combine_results(
170173
add_axioms_for_string_of_int(s2, f.arguments()[4], 0, ns, array_pool),
171-
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool));
174+
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool),
175+
ns);
172176
}
173177

174178
/// add axioms corresponding to the StringBuilder.insert(Z) java function
@@ -177,12 +181,14 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_int(
177181
/// \param f: function application with three arguments: a string, an
178182
/// integer offset, and a Boolean
179183
/// \param array_pool: pool of arrays representing strings
184+
/// \param ns: the namespace
180185
/// \return a new string expression
181186
DEPRECATED(SINCE(2017, 10, 5, "convert the value to string and call insert"))
182187
std::pair<exprt, string_constraintst> add_axioms_for_insert_bool(
183188
symbol_generatort &fresh_symbol,
184189
const function_application_exprt &f,
185-
array_poolt &array_pool)
190+
array_poolt &array_pool,
191+
const namespacet &ns)
186192
{
187193
PRECONDITION(f.arguments().size() == 5);
188194
const array_string_exprt s1 = get_string_expr(array_pool, f.arguments()[0]);
@@ -194,7 +200,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_bool(
194200
const array_string_exprt s2 = array_pool.fresh_string(index_type, char_type);
195201
return combine_results(
196202
add_axioms_from_bool(s2, f.arguments()[4], array_pool),
197-
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool));
203+
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool),
204+
ns);
198205
}
199206

200207
/// Add axioms corresponding to the StringBuilder.insert(C) java function
@@ -203,11 +210,13 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_bool(
203210
/// \param f: function application with three arguments: a string, an
204211
/// integer offset, and a character
205212
/// \param array_pool: pool of arrays representing strings
213+
/// \param ns: the namespace
206214
/// \return an expression
207215
std::pair<exprt, string_constraintst> add_axioms_for_insert_char(
208216
symbol_generatort &fresh_symbol,
209217
const function_application_exprt &f,
210-
array_poolt &array_pool)
218+
array_poolt &array_pool,
219+
const namespacet &ns)
211220
{
212221
PRECONDITION(f.arguments().size() == 5);
213222
const array_string_exprt res =
@@ -219,7 +228,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_char(
219228
const array_string_exprt s2 = array_pool.fresh_string(index_type, char_type);
220229
return combine_results(
221230
add_axioms_from_char(s2, f.arguments()[4], array_pool),
222-
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool));
231+
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool),
232+
ns);
223233
}
224234

225235
/// add axioms corresponding to the StringBuilder.insert(D) java function
@@ -248,7 +258,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_insert_double(
248258
return combine_results(
249259
add_axioms_for_string_of_float(
250260
fresh_symbol, s2, f.arguments()[4], array_pool, ns),
251-
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool));
261+
add_axioms_for_insert(fresh_symbol, res, s1, s2, offset, array_pool),
262+
ns);
252263
}
253264

254265
/// Add axioms corresponding to the StringBuilder.insert(F) java function

src/solvers/strings/string_constraint_generator_main.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,19 +260,19 @@ string_constraint_generatort::add_axioms_for_function_application(
260260
else if(id == ID_cprover_string_compare_to_func)
261261
return add_axioms_for_compare_to(fresh_symbol, expr, array_pool);
262262
else if(id == ID_cprover_string_literal_func)
263-
return add_axioms_from_literal(fresh_symbol, expr, array_pool);
263+
return add_axioms_from_literal(fresh_symbol, expr, array_pool, ns);
264264
else if(id == ID_cprover_string_concat_code_point_func)
265-
return add_axioms_for_concat_code_point(fresh_symbol, expr, array_pool);
265+
return add_axioms_for_concat_code_point(fresh_symbol, expr, array_pool, ns);
266266
else if(id == ID_cprover_string_insert_func)
267-
return add_axioms_for_insert(fresh_symbol, expr, array_pool);
267+
return add_axioms_for_insert(fresh_symbol, expr, array_pool, ns);
268268
else if(id == ID_cprover_string_insert_int_func)
269269
return add_axioms_for_insert_int(fresh_symbol, expr, array_pool, ns);
270270
else if(id == ID_cprover_string_insert_long_func)
271271
return add_axioms_for_insert_int(fresh_symbol, expr, array_pool, ns);
272272
else if(id == ID_cprover_string_insert_bool_func)
273-
return add_axioms_for_insert_bool(fresh_symbol, expr, array_pool);
273+
return add_axioms_for_insert_bool(fresh_symbol, expr, array_pool, ns);
274274
else if(id == ID_cprover_string_insert_char_func)
275-
return add_axioms_for_insert_char(fresh_symbol, expr, array_pool);
275+
return add_axioms_for_insert_char(fresh_symbol, expr, array_pool, ns);
276276
else if(id == ID_cprover_string_insert_double_func)
277277
return add_axioms_for_insert_double(fresh_symbol, expr, array_pool, ns);
278278
else if(id == ID_cprover_string_insert_float_func)
@@ -303,9 +303,9 @@ string_constraint_generatort::add_axioms_for_function_application(
303303
else if(id == ID_cprover_string_set_length_func)
304304
return add_axioms_for_set_length(fresh_symbol, expr, array_pool);
305305
else if(id == ID_cprover_string_delete_func)
306-
return add_axioms_for_delete(fresh_symbol, expr, array_pool);
306+
return add_axioms_for_delete(fresh_symbol, expr, array_pool, ns);
307307
else if(id == ID_cprover_string_delete_char_at_func)
308-
return add_axioms_for_delete_char_at(fresh_symbol, expr, array_pool);
308+
return add_axioms_for_delete_char_at(fresh_symbol, expr, array_pool, ns);
309309
else if(id == ID_cprover_string_replace_func)
310310
return add_axioms_for_replace(fresh_symbol, expr, array_pool);
311311
else if(id == ID_cprover_string_constrain_characters_func)
@@ -441,9 +441,12 @@ exprt zero_if_negative(const exprt &expr)
441441
/// the return codes and merging the constraints.
442442
std::pair<exprt, string_constraintst> combine_results(
443443
std::pair<exprt, string_constraintst> result1,
444-
std::pair<exprt, string_constraintst> result2)
444+
std::pair<exprt, string_constraintst> result2,
445+
const namespacet &ns)
445446
{
446-
const exprt return_code = maximum(result1.first, result2.first);
447+
exprt return_code = maximum(result1.first, result2.first);
447448
merge(result2.second, std::move(result1.second));
449+
simplify(return_code, ns);
450+
448451
return {return_code, std::move(result2.second)};
449452
}

src/solvers/strings/string_constraint_generator_transformation.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,13 @@ std::pair<exprt, string_constraintst> add_axioms_for_replace(
358358
/// \param f: function application with two arguments, the first is a
359359
/// string and the second is an index
360360
/// \param array_pool: pool of arrays representing strings
361+
/// \param ns: the namespace
361362
/// \return an expression whose value is non null to signal an exception
362363
std::pair<exprt, string_constraintst> add_axioms_for_delete_char_at(
363364
symbol_generatort &fresh_symbol,
364365
const function_application_exprt &f,
365-
array_poolt &array_pool)
366+
array_poolt &array_pool,
367+
const namespacet &ns)
366368
{
367369
PRECONDITION(f.arguments().size() == 4);
368370
const array_string_exprt res =
@@ -375,7 +377,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_delete_char_at(
375377
str,
376378
f.arguments()[3],
377379
plus_exprt(f.arguments()[3], index_one),
378-
array_pool);
380+
array_pool,
381+
ns);
379382
}
380383

381384
/// Add axioms stating that `res` corresponds to the input `str`
@@ -400,7 +403,8 @@ std::pair<exprt, string_constraintst> add_axioms_for_delete(
400403
const array_string_exprt &str,
401404
const exprt &start,
402405
const exprt &end,
403-
array_poolt &array_pool)
406+
array_poolt &array_pool,
407+
const namespacet &ns)
404408
{
405409
PRECONDITION(start.type() == str.length_type());
406410
PRECONDITION(end.type() == str.length_type());
@@ -426,7 +430,9 @@ std::pair<exprt, string_constraintst> add_axioms_for_delete(
426430
end,
427431
array_pool.get_or_create_length(str),
428432
array_pool),
429-
add_axioms_for_concat(fresh_symbol, res, sub1, sub2, array_pool)));
433+
add_axioms_for_concat(fresh_symbol, res, sub1, sub2, array_pool),
434+
ns),
435+
ns);
430436
}
431437

432438
/// Remove a portion of a string
@@ -445,12 +451,13 @@ std::pair<exprt, string_constraintst> add_axioms_for_delete(
445451
std::pair<exprt, string_constraintst> add_axioms_for_delete(
446452
symbol_generatort &fresh_symbol,
447453
const function_application_exprt &f,
448-
array_poolt &array_pool)
454+
array_poolt &array_pool,
455+
const namespacet &ns)
449456
{
450457
PRECONDITION(f.arguments().size() == 5);
451458
const array_string_exprt res =
452459
array_pool.find(f.arguments()[1], f.arguments()[0]);
453460
const array_string_exprt arg = get_string_expr(array_pool, f.arguments()[2]);
454461
return add_axioms_for_delete(
455-
fresh_symbol, res, arg, f.arguments()[3], f.arguments()[4], array_pool);
462+
fresh_symbol, res, arg, f.arguments()[3], f.arguments()[4], array_pool, ns);
456463
}

0 commit comments

Comments
 (0)