Skip to content

Commit 7714d51

Browse files
committed
Fix recognisition of quantifier bounds in case of previous simplification of singleton interval
1 parent eeff129 commit 7714d51

File tree

2 files changed

+39
-21
lines changed

2 files changed

+39
-21
lines changed

regression/cbmc-primitives/alternating_quantifiers_6231/forall_in_exists.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ int main(int argc, char **argv)
88

99
__CPROVER_assert(
1010
__CPROVER_exists { int z; (0 < z && z < 2) &&
11-
__CPROVER_forall { int o; (10 < o && o < 20) ==> o > z && z == * i }},
11+
__CPROVER_forall { int o; (10 < o && o < 20) ==> o > z && z == *i }},
1212
"there exists a z between 0 and 2 so that for all o between 10 and 20, o > z and z = 1");
1313
}
1414
// clang-format on

src/solvers/flattening/boolbv_quantifier.cpp

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ get_quantifier_var_min(const exprt &var_expr, const exprt &quantifier_expr)
5050
}
5151
else if(quantifier_expr.id() == ID_and)
5252
{
53-
/**
54-
* The min variable
55-
* is in the form of "var_expr >= constant".
56-
*/
53+
// The minimum variable can be of the form `var_expr >= constant`, or
54+
// it can be of the form `var_expr == constant` (e.g. in the case where
55+
// the interval that bounds the variable is a singleton interval (set
56+
// with only one element)).
5757
for(auto &x : quantifier_expr.operands())
5858
{
59-
if(x.id()!=ID_ge)
59+
if(x.id() != ID_ge && x.id() != ID_equal)
6060
continue;
6161
const auto &x_binary = to_binary_relation_expr(x);
6262
if(expr_eq(var_expr, x_binary.lhs()) && x_binary.rhs().is_constant())
@@ -106,24 +106,42 @@ get_quantifier_var_max(const exprt &var_expr, const exprt &quantifier_expr)
106106
}
107107
else
108108
{
109-
/**
110-
* The max variable
111-
* is in the form of "!(var_expr >= constant)".
112-
*/
109+
// There are two potential forms we could come across here. The first one is
110+
// `!(var_expr >= constant)` - identified by the first if branch - and the second
111+
// is `var_expr == constant` - identified by the second else-if branch. The
112+
// second form could be met if previous simplification has identified a singleton
113+
// interval - see simplify_boolean_expr.cpp.
113114
for(auto &x : quantifier_expr.operands())
114115
{
115-
if(x.id()!=ID_not)
116-
continue;
117-
exprt y = to_not_expr(x).op();
118-
if(y.id()!=ID_ge)
119-
continue;
120-
const auto &y_binary = to_binary_relation_expr(y);
121-
if(expr_eq(var_expr, y_binary.lhs()) && y_binary.rhs().is_constant())
116+
if(x.id() == ID_not)
122117
{
123-
const constant_exprt &over_expr = to_constant_expr(y_binary.rhs());
124-
mp_integer over_i = numeric_cast_v<mp_integer>(over_expr);
125-
over_i-=1;
126-
return from_integer(over_i, y_binary.rhs().type());
118+
exprt y = to_not_expr(x).op();
119+
if(y.id() != ID_ge)
120+
continue;
121+
const auto &y_binary = to_binary_relation_expr(y);
122+
if(expr_eq(var_expr, y_binary.lhs()) && y_binary.rhs().is_constant())
123+
{
124+
const constant_exprt &over_expr = to_constant_expr(y_binary.rhs());
125+
mp_integer over_i = numeric_cast_v<mp_integer>(over_expr);
126+
over_i -= 1;
127+
return from_integer(over_i, y_binary.rhs().type());
128+
}
129+
}
130+
else if(x.id() == ID_equal)
131+
{
132+
const auto &y_binary = to_binary_relation_expr(x);
133+
if(expr_eq(var_expr, y_binary.lhs()) && y_binary.rhs().is_constant())
134+
{
135+
return to_constant_expr(y_binary.rhs());
136+
}
137+
}
138+
else
139+
{
140+
// If we are here, we came across a (simplified?) expression that was
141+
// not anticipated - normally this would be a bug, but if you made changes
142+
// to the simplifier (as an example), you would need to add an else-if
143+
// branch that handles that type above.
144+
continue;
127145
}
128146
}
129147
}

0 commit comments

Comments
 (0)