Skip to content

Commit 38fd81a

Browse files
committed
Add constraints for bounded quantification
These can only be omitted when the instantiations trivially make them true. This surfaced further misinterpretations in the regression tests of the "==>" operator: bounded existential quantification should generally use &&.
1 parent f40d479 commit 38fd81a

File tree

9 files changed

+50
-39
lines changed

9 files changed

+50
-39
lines changed

regression/cbmc/Quantifiers-not-exists/main.c renamed to regression/cbmc-cover/Quantifiers-not-exists/main.c

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
int main()
22
{
3-
43
int a[2][2];
54
int b[2][2];
65
int c[2][2];
@@ -25,16 +24,15 @@ int main()
2524

2625
assert(0);
2726

28-
assert(a[0][0]>10);
29-
30-
assert( (b[0][0]<1||b[0][0]>10) && (b[0][1]<1||b[0][1]>10));
31-
assert( (b[1][0]<1||b[1][0]>10) && (b[1][1]<1||b[1][1]>10));
27+
assert(a[0][0] > 10);
3228

33-
assert(c[0][0]==0 || c[0][1]==0 || c[1][0]<=10 || c[1][1]<=10);
29+
assert((b[0][0] < 1 || b[0][0] > 10) && (b[0][1] < 1 || b[0][1] > 10));
30+
assert((b[1][0] < 1 || b[1][0] > 10) && (b[1][1] < 1 || b[1][1] > 10));
3431

35-
assert( ((d[0][0]<1||d[0][0]>10) || (d[0][1]<1||d[0][1]>10)) );
36-
assert( ((d[1][0]<1||d[1][0]>10) || (d[1][1]<1||d[1][1]>10)) );
32+
assert(c[0][0] == 0 || c[0][1] == 0 || c[1][0] <= 10 || c[1][1] <= 10);
3733

34+
assert(((d[0][0] < 1 || d[0][0] > 10) || (d[0][1] < 1 || d[0][1] > 10)));
35+
assert(((d[1][0] < 1 || d[1][0] > 10) || (d[1][1] < 1 || d[1][1] > 10)));
3836

3937
return 0;
4038
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--cover location
4+
^\*\* 1 of 46 covered \(2.2%\)
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
--
10+
All assertions are unreachable as each of the __CPROVER_assume evaluate to false
11+
(!exists i. i>=0 && i<2 ==> ... is equivalent to forall i. i>=0 && i<2 && ...,
12+
where neither i>=0 nor i<2 is actually true for all values of i).

regression/cbmc/Quantifiers-assertion/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^\*\* Results:$

regression/cbmc/Quantifiers-if/main.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ int main()
99
if(__CPROVER_forall { int i; (i>=0 && i<2) ==> a[i]>=1 && a[i]<=10 })
1010
__CPROVER_assert(0, "failure 1");
1111

12-
if(__CPROVER_exists { int i; (i>=0 && i<2) ==> a[i]>=1 && a[i]<=10 })
12+
if(__CPROVER_exists { int i; (i>=0 && i<2) && a[i]>=1 && a[i]<=10 })
1313
__CPROVER_assert(0, "failure 2");
1414

1515
if(__CPROVER_forall { int i; (i>=0 && i<2) ==> a[i]>=2 && a[i]<=10 })
1616
__CPROVER_assert(0, "success 1");
1717

18-
if(__CPROVER_exists { int i; (i>=0 && i<2) ==> a[i]>=2 && a[i]<=10 })
18+
if(__CPROVER_exists { int i; (i>=0 && i<2) && a[i]>=2 && a[i]<=10 })
1919
__CPROVER_assert(0, "failure 3");
2020

21-
if(__CPROVER_exists { int i; (i>=0 && i<2) ==> a[i]>=5 && a[i]<=10 })
21+
if(__CPROVER_exists { int i; (i>=0 && i<2) && a[i]>=5 && a[i]<=10 })
2222
__CPROVER_assert(0, "success 2");
2323
// clang-format on
2424

regression/cbmc/Quantifiers-invalid-var-range/main.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ int main()
44
int a[3][3];
55
// clang-format off
66
// clang-format would rewrite the "==>" as "== >"
7-
__CPROVER_assume(__CPROVER_forall { int i; (i>=0 && i<5) ==> __CPROVER_exists{int j; (j>=i && j<3) ==> a[i][j]==10} });
7+
// NOLINTNEXTLINE(whitespace/line_length)
8+
__CPROVER_assume(__CPROVER_forall { int i; (i>=0 && i<5) ==> __CPROVER_exists{int j; (j>=i && j<3) && a[i][j]==10} });
89
// clang-format on
910

1011
assert(a[0][0]==10||a[0][1]==10||a[0][2]==10);

regression/cbmc/Quantifiers-not-exists/test.desc

-20
This file was deleted.

regression/cbmc/Quantifiers-not/main.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ int main()
99
if(!__CPROVER_forall { int i; (i>=0 && i<2) ==> a[i]>=1 && a[i]<=10 })
1010
__CPROVER_assert(0, "success 1");
1111

12-
if(!__CPROVER_exists { int i; (i>=0 && i<2) ==> a[i]>=1 && a[i]<=10 })
12+
if(!__CPROVER_exists { int i; (i>=0 && i<2) && a[i]>=1 && a[i]<=10 })
1313
__CPROVER_assert(0, "success 2");
1414

1515
if(!__CPROVER_forall { int i; (i>=0 && i<2) ==> a[i]>=2 && a[i]<=10 })
1616
__CPROVER_assert(0, "failure 1");
1717

18-
if(!__CPROVER_exists { int i; (i>=0 && i<2) ==> a[i]>=2 && a[i]<=10 })
18+
if(!__CPROVER_exists { int i; (i>=0 && i<2) && a[i]>=2 && a[i]<=10 })
1919
__CPROVER_assert(0, "success 3");
2020

21-
if(!__CPROVER_exists { int i; (i>=0 && i<2) ==> a[i]>=5 && a[i]<=10 })
21+
if(!__CPROVER_exists { int i; (i>=0 && i<2) && a[i]>=5 && a[i]<=10 })
2222
__CPROVER_assert(0, "failure 2");
2323
// clang-format on
2424

regression/cbmc/Quantifiers-two-dimension-array/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^\*\* Results:$

src/solvers/flattening/boolbv_quantifier.cpp

+22-2
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,31 @@ instantiate_quantifier(const quantifier_exprt &expr, const namespacet &ns)
167167

168168
if(expr.id()==ID_forall)
169169
{
170-
return conjunction(expr_insts);
170+
// maintain the domain constraint if it isn't guaranteed by the
171+
// instantiations (for a disjunction the domain constraint is implied by the
172+
// instantiations)
173+
if(re.id() == ID_and)
174+
{
175+
expr_insts.push_back(binary_predicate_exprt(
176+
var_expr, ID_gt, from_integer(lb, var_expr.type())));
177+
expr_insts.push_back(binary_predicate_exprt(
178+
var_expr, ID_le, from_integer(ub, var_expr.type())));
179+
}
180+
return simplify_expr(conjunction(expr_insts), ns);
171181
}
172182
else if(expr.id() == ID_exists)
173183
{
174-
return disjunction(expr_insts);
184+
// maintain the domain constraint if it isn't trivially satisfied by the
185+
// instantiations (for a conjunction the instantiations are stronger
186+
// constraints)
187+
if(re.id() == ID_or)
188+
{
189+
expr_insts.push_back(binary_predicate_exprt(
190+
var_expr, ID_gt, from_integer(lb, var_expr.type())));
191+
expr_insts.push_back(binary_predicate_exprt(
192+
var_expr, ID_le, from_integer(ub, var_expr.type())));
193+
}
194+
return simplify_expr(disjunction(expr_insts), ns);
175195
}
176196

177197
UNREACHABLE;

0 commit comments

Comments
 (0)