@@ -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
110+ // is `!(var_expr >= constant)` - identified by the first if branch - and
111+ // the second is `var_expr == constant` - identified by the second else-if
112+ // branch. The second form could be met if previous simplification has
113+ // identified a singleton 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
142+ // changes to the simplifier (as an example), you would need to add an
143+ // else-if branch that handles that type above.
144+ continue ;
127145 }
128146 }
129147 }
0 commit comments