Skip to content

Commit 9e73699

Browse files
Refactor negation of not contains constraints
This now uses get. Get is called on index_exprt which avoids concretizing array_string_exprt, which can potentially represent long strings. This makes string_refinement more efficient in programs with not_contains_constraints, when the underlying solver can come up with very long strings.
1 parent 85e8451 commit 9e73699

File tree

1 file changed

+28
-64
lines changed

1 file changed

+28
-64
lines changed

src/solvers/refinement/string_refinement.cpp

Lines changed: 28 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,51 +1202,38 @@ exprt substitute_array_access(
12021202
/// have been replaced by their valuation in the current model.
12031203
/// \pre Symbols other than the universal variable should have been replaced by
12041204
/// their valuation in the current model.
1205-
/// \param axiom: the not_contains constraint to add the negation of
1205+
/// \param constraint: the not_contains constraint to add the negation of
12061206
/// \param univ_var: the universal variable for the negation of the axiom
1207+
/// \param get: valuation function, the result should have been simplified
12071208
/// \return: the negation of the axiom under the current evaluation
12081209
static exprt negation_of_not_contains_constraint(
1209-
const string_not_contains_constraintt &axiom,
1210-
const symbol_exprt &univ_var)
1210+
const string_not_contains_constraintt &constraint,
1211+
const symbol_exprt &univ_var,
1212+
const std::function<exprt(const exprt &)> &get)
12111213
{
12121214
// If the for all is vacuously true, the negation is false.
1213-
const exprt &lbu=axiom.univ_lower_bound();
1214-
const exprt &ubu=axiom.univ_upper_bound();
1215-
if(lbu.id()==ID_constant && ubu.id()==ID_constant)
1216-
{
1217-
const auto lb_int = numeric_cast<mp_integer>(lbu);
1218-
const auto ub_int = numeric_cast<mp_integer>(ubu);
1219-
if(!lb_int || !ub_int || *ub_int<=*lb_int)
1220-
return false_exprt();
1221-
}
1222-
1223-
const auto lbe = numeric_cast_v<mp_integer>(axiom.exists_lower_bound());
1224-
const auto ube = numeric_cast_v<mp_integer>(axiom.exists_upper_bound());
1225-
1226-
// If the premise is false, the implication is trivially true, so the
1227-
// negation is false.
1228-
if(axiom.premise()==false_exprt())
1229-
return false_exprt();
1230-
1231-
and_exprt univ_bounds(
1232-
binary_relation_exprt(lbu, ID_le, univ_var),
1233-
binary_relation_exprt(ubu, ID_gt, univ_var));
1215+
const auto lbe =
1216+
numeric_cast_v<mp_integer>(get(constraint.exists_lower_bound()));
1217+
const auto ube =
1218+
numeric_cast_v<mp_integer>(get(constraint.exists_upper_bound()));
1219+
const auto univ_bounds = and_exprt(
1220+
binary_relation_exprt(get(constraint.univ_lower_bound()), ID_le, univ_var),
1221+
binary_relation_exprt(get(constraint.univ_upper_bound()), ID_gt, univ_var));
12341222

12351223
// The negated existential becomes an universal, and this is the unrolling of
12361224
// that universal quantifier.
12371225
std::vector<exprt> conjuncts;
1226+
conjuncts.reserve(numeric_cast_v<std::size_t>(ube - lbe));
12381227
for(mp_integer i=lbe; i<ube; ++i)
12391228
{
1240-
const constant_exprt i_exprt=from_integer(i, univ_var.type());
1241-
const equal_exprt equal_chars(
1242-
axiom.s0()[plus_exprt(univ_var, i_exprt)],
1243-
axiom.s1()[i_exprt]);
1244-
conjuncts.push_back(equal_chars);
1229+
const constant_exprt i_expr = from_integer(i, univ_var.type());
1230+
const exprt s0_char =
1231+
get(index_exprt(constraint.s0(), plus_exprt(univ_var, i_expr)));
1232+
const exprt s1_char = get(index_exprt(constraint.s1(), i_expr));
1233+
conjuncts.push_back(equal_exprt(s0_char, s1_char));
12451234
}
1246-
exprt equal_strings=conjunction(conjuncts);
1247-
and_exprt negaxiom(univ_bounds, axiom.premise(), equal_strings);
1248-
1249-
return negaxiom;
1235+
const exprt equal_strings = conjunction(conjuncts);
1236+
return and_exprt(univ_bounds, get(constraint.premise()), equal_strings);
12501237
}
12511238

12521239
/// Negates the constraint to be fed to a solver. The intended usage is to find
@@ -1406,42 +1393,19 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
14061393
for(std::size_t i = 0; i < axioms.not_contains.size(); i++)
14071394
{
14081395
const string_not_contains_constraintt &nc_axiom=axioms.not_contains[i];
1409-
const exprt &univ_bound_inf=nc_axiom.univ_lower_bound();
1410-
const exprt &univ_bound_sup=nc_axiom.univ_upper_bound();
1411-
const exprt &prem=nc_axiom.premise();
1412-
const exprt &exists_bound_inf=nc_axiom.exists_lower_bound();
1413-
const exprt &exists_bound_sup=nc_axiom.exists_upper_bound();
1414-
const array_string_exprt &s0 = nc_axiom.s0();
1415-
const array_string_exprt &s1 = nc_axiom.s1();
1416-
1417-
symbol_exprt univ_var=generator.fresh_univ_index(
1396+
const symbol_exprt univ_var = generator.fresh_univ_index(
14181397
"not_contains_univ_var", nc_axiom.s0().length().type());
1419-
string_not_contains_constraintt nc_axiom_in_model(
1420-
get(univ_bound_inf),
1421-
get(univ_bound_sup),
1422-
get(prem),
1423-
get(exists_bound_inf),
1424-
get(exists_bound_sup),
1425-
to_array_string_expr(get(s0)),
1426-
to_array_string_expr(get(s1)));
1427-
1428-
// necessary so that expressions such as `1 + (3 - (TRUE ? 0 : 0))` do not
1429-
// appear in bounds
1430-
nc_axiom_in_model =
1431-
to_string_not_contains_constraint(simplify_expr(nc_axiom_in_model, ns));
1432-
1433-
exprt negaxiom =
1434-
negation_of_not_contains_constraint(nc_axiom_in_model, univ_var);
1435-
1436-
negaxiom = simplify_expr(negaxiom, ns);
1437-
const exprt with_concrete_arrays =
1438-
substitute_array_access(negaxiom, gen_symbol, true);
1398+
const exprt negated_axiom = negation_of_not_contains_constraint(
1399+
nc_axiom, univ_var, [&](const exprt &expr) {
1400+
return simplify_expr(get(expr), ns); });
14391401

14401402
stream << indent << i << ".\n";
14411403
debug_check_axioms_step(
1442-
stream, ns, nc_axiom, nc_axiom_in_model, negaxiom, with_concrete_arrays);
1404+
stream, ns, nc_axiom, nc_axiom, negated_axiom, negated_axiom);
14431405

1444-
if(const auto witness = find_counter_example(ns, ui, negaxiom, univ_var))
1406+
if(
1407+
const auto witness =
1408+
find_counter_example(ns, ui, negated_axiom, univ_var))
14451409
{
14461410
stream << indent2 << "- violated_for: " << univ_var.get_identifier()
14471411
<< "=" << format(*witness) << eom;

0 commit comments

Comments
 (0)