CSE 331: Hoare triples practice
Question 1: Hoare Triples
Each row is a Hoare triple about int variables x and y.
You may assume no arithmetic here ever overflows.
For each triple, write in its box:
- T if the triple is valid
- F if it is not
a.
{{ x = 2 or x = -2 }}
y = x * x;
{{ y = 4 }}
Answer
| Valid? |
|---|
| T |
Valid: reasoning forward and backward both close.
Forward, from the precondition:
{{ x = 2 or x = -2 }}
y = x * x;
{{ (x = 2 or x = -2) and y = x * x }}
{{ y = 4 }}
- The forward rule for
y = x * x. Neither the precondition norx * xmentionsy, so nothing is renamed, and the claim gainsy = x * x. - Whichever of 2 and -2
xis,x * xis 4. That is the postcondition, so the triple is valid.
Backward, from the postcondition:
{{ x = 2 or x = -2 }}
{{ x * x = 4 }}
y = x * x;
{{ y = 4 }}
- Before
y = x * x, putx * xfory: the weakest precondition,x * x = 4. - The precondition implies it, whichever of 2 and -2
xis, so the triple is valid.
The rule: Lecture 7's The rules for an assignment.
b.
{{ 0 <= x }}
x = x - 1;
{{ 0 <= x }}
Answer
| Valid? |
|---|
| F |
Not valid: one state is enough to show it.
A counterexample:
- Start from
x = 0, which the precondition0 <= xallows. - The line makes
xequal to -1. - Then
0 <= xis false.
The rule: Lecture 7's A triple.
c.
{{ x = y }}
x = x + 1;
{{ x = y + 2 }}
Answer
| Valid? |
|---|
| F |
Not valid: the postcondition fails in every state the precondition allows.
A counterexample:
- Start from
x = 0andy = 0, whichx = yallows. - The line makes
xequal to 1. - Then
x = y + 2is false:xis 1, andy + 2is 2.
Backward reasoning shows that every such state fails, not just this one:
{{ x = y }}
{{ x + 1 = y + 2 }}
x = x + 1;
{{ x = y + 2 }}
- Before
x = x + 1, putx + 1forx: the weakest precondition,x + 1 = y + 2, that is,x = y + 1. - The precondition, marked, does not imply the claim below it:
x = yandx = y + 1never hold together. The chain breaks here in every state the precondition allows, so the triple is not valid.
The rules: Lecture 7's A triple and The rules for an assignment.
d.
{{ x < y }}
x = x + 1;
{{ x <= y }}
Answer
| Valid? |
|---|
| T |
Valid, for integers: reasoning forward and backward both close.
Forward, from the precondition:
{{ x < y }}
x = x + 1;
{{ x0 < y and x = x0 + 1 }}
{{ x - 1 < y }}
{{ x <= y }}
- The forward rule for
x = x + 1.x0names the old value ofx, so the precondition becomesx0 < y, and the claim gainsx = x0 + 1. - The old value is
x - 1, so put that forx0. Thenx = x0 + 1says nothing, and drops. - For integers,
x - 1 < ymeansx <= y. That is the postcondition, so the triple is valid.
Backward, from the postcondition:
{{ x < y }}
{{ x + 1 <= y }}
x = x + 1;
{{ x <= y }}
- Before
x = x + 1, putx + 1forx: the weakest precondition,x + 1 <= y. - For integers, the precondition
x < yimplies it, so the triple is valid.
Over the real numbers it would not be valid:
- Start from
x = 0andy = 0.5, whichx < yallows. - The line makes
xequal to 1. - Then
x <= yis false.
The rule: Lecture 7's The rules for an assignment.
e.
{{ true }}
if (x < 0) {
x = -x;
}
{{ 0 < x }}
Answer
| Valid? |
|---|
| F |
Not valid: one state is enough to show it.
A counterexample:
- Start from
x = 0, which the preconditiontrueallows. - The condition
x < 0is false, so the branch is skipped, andxstays 0. - Then
0 < xis false.
The rule: Lecture 7's A triple.
f.
{{ y = 2 * x }}
y = y + 2;
x = x + 1;
{{ y = 2 * x }}
Answer
| Valid? |
|---|
| T |
Valid: reasoning forward and backward both close, one line at a time.
Forward, from the precondition, first line first:
{{ y = 2 * x }}
y = y + 2;
{{ y0 = 2 * x and y = y0 + 2 }}
{{ y = 2 * x + 2 }}
x = x + 1;
{{ y = 2 * x0 + 2 and x = x0 + 1 }}
{{ y = 2 * (x - 1) + 2 }}
{{ y = 2 * x }}
- The forward rule for
y = y + 2.y0names the old value ofy, so the precondition becomesy0 = 2 * x, and the claim gainsy = y0 + 2. - The old value is
y - 2, so put that fory0:y - 2 = 2 * x, that is,y = 2 * x + 2. - The forward rule for
x = x + 1.x0names the old value ofx, and the claim gainsx = x0 + 1. - The old value is
x - 1, so put that forx0. 2 * (x - 1) + 2is2 * x. That is the postcondition, so the triple is valid.
Backward, from the postcondition, last line first:
{{ y = 2 * x }}
{{ y + 2 = 2 * x + 2 }}
y = y + 2;
{{ y = 2 * x + 2 }}
{{ y = 2 * (x + 1) }}
x = x + 1;
{{ y = 2 * x }}
- Before
x = x + 1, putx + 1forx:y = 2 * (x + 1). - Multiplied out, the same claim:
y = 2 * x + 2. - Before
y = y + 2, puty + 2fory: the weakest precondition,y + 2 = 2 * x + 2. - The precondition
y = 2 * ximplies it: add 2 to both sides. So the triple is valid.
The rules: Lecture 7's The rules for an assignment and The rule for a sequence.
g.
{{ 0 < x and 0 < y }}
x = x - y;
{{ 0 < x }}
Answer
| Valid? |
|---|
| F |
Not valid: the postcondition fails whenever x <= y.
A counterexample:
- Start from
x = 1andy = 3, which the precondition allows. - The line makes
xequal to -2. - Then
0 < xis false.
Backward reasoning shows exactly which states fail:
{{ 0 < x and 0 < y }}
{{ 0 < x - y }}
x = x - y;
{{ 0 < x }}
- Before
x = x - y, putx - yforx: the weakest precondition,0 < x - y, that is,y < x. - The precondition, marked, does not imply the claim below it:
from
x = 1andy = 3, it holds andy < xdoes not. The chain breaks in just the states with0 < xandx <= y, so the triple is not valid.
The rules: Lecture 7's A triple and The rules for an assignment.
h.
{{ x < y and y < x }}
x = y;
{{ x = y + 1 }}
Answer
| Valid? |
|---|
| T |
Valid, vacuously: no state makes the precondition true.
Why vacuously:
- No state has
x < yandy < xat once, so the precondition isfalse. - A valid triple asks something only of runs from states where its precondition holds.
- There are none, so it asks nothing. Lecture 7's
{{ false }} x = 0; {{ x = 1 }}is the same case.
Forward, from the precondition:
{{ x < y and y < x }}
{{ false }}
x = y;
{{ false and x = y }}
{{ x = y + 1 }}
- No state has
x < yandy < xat once, so the precondition isfalse. - The forward rule for
x = ykeepsfalse, and the claim gainsx = y. falseimplies any claim, the postcondition included, so the triple is valid, vacuously.
Backward, from the postcondition:
{{ x < y and y < x }}
{{ false }}
{{ y = y + 1 }}
x = y;
{{ x = y + 1 }}
- Before
x = y, putyforx: the weakest precondition,y = y + 1, which no state satisfies. falseimplies it, as it implies any claim.- The precondition is
false, since no state hasx < yandy < xat once. So the triple is valid, vacuously.
The rules: Lecture 7's A triple and The rules for an assignment.
Question 2: Hoare Triples
Each row is a Hoare triple.
Variables done and visited have type boolean.
All other variables have type int.
You may assume no arithmetic here ever overflows.
For each triple, write in its box:
- T if the triple is valid
- F if it is not
a.
{{ 0 < y }}
x = x + y;
y = x - y;
{{ y < x }}
Answer
| Valid? |
|---|
| T |
Valid: the final x exceeds the final y by the original y.
Backward, from the postcondition:
{{ 0 < y }}
{{ (x + y) - y < x + y }}
x = x + y;
{{ x - y < x }}
y = x - y;
{{ y < x }}
- Before
y = x - y, putx - yforyin the postcondition. - Before
x = x + y, putx + yforxin the claim below it. - The claim simplifies to
x < x + y, which follows from0 < y, so the triple is valid.
The rules: Lecture 7's The rules for an assignment and The rule for a sequence.
b.
{{ true }}
if (x == 0) {
y = 0;
z = 1;
} else {
y = 1;
z = 0;
}
{{ y = 0 and z = 0 }}
Answer
| Valid? |
|---|
| F |
Not valid: neither branch makes both y = 0 and z = 0 true.
A counterexample:
- Start from
x = 0,y = 0, andz = 0. - The condition is true, so the true branch executes.
- That branch leaves
y = 0andz = 1. - The postcondition is false because
z = 0is false.
Why every run fails:
- The true branch makes
y = 0 and z = 1true. - The false branch makes
y = 1 and z = 0true. - The conditional rule joins these claims with
or, giving(y = 0 and z = 1) or (y = 1 and z = 0). - Either way, one of
yandzis 1, soy = 0 and z = 0is false.
The rule: Lecture 7's The rule for a conditional.
c.
{{ done = true or done = false }}
while (!done) {
done = true;
visited = true;
}
{{ done = true and visited = true }}
Answer
| Valid? |
|---|
| F |
Not valid: the body need not execute.
A counterexample:
- Start from
done = trueandvisited = false, which the precondition allows. - The condition
!doneis false, so the loop ends immediately. visited = trueis false in the final state.
The rules: Lecture 7's A triple and Lecture 8's The rule for a while loop.
d.
{{ 0 <= x }}
x = x + 1;
{{ 1 < x }}
Answer
| Valid? |
|---|
| F |
Not valid: the precondition allows x = 0.
A counterexample:
- Start from
x = 0, which the precondition allows. - The assignment makes
x = 1. - The postcondition requires
1 < x, which is false.
The rule: Lecture 7's The rules for an assignment.
e.
{{ lo <= hi }}
if (x < lo) {
x = lo;
}
if (hi < x) {
x = hi;
}
{{ lo <= x and x <= hi }}
Answer
| Valid? |
|---|
| T |
Valid: the two conditionals make both bounds true.
Forward, from the precondition:
{{ lo <= hi }}
if (x < lo) {
{{ lo <= hi and x < lo }}
x = lo;
{{ lo <= hi and x = lo }}
}
{{ lo <= hi and lo <= x }}
if (hi < x) {
{{ lo <= hi and lo <= x and hi < x }}
x = hi;
{{ lo <= hi and x = hi }}
}
{{ lo <= x and x <= hi }}
- The conditional rule adds
x < loin the true branch. - The assignment sets
x = loand preserveslo <= hi. - The conditional rule gives
lo <= xfrom either branch: the true branch setsx = lo, and the empty false branch starts withlo <= x. - The conditional rule adds
hi < xin the second true branch. - The assignment sets
x = hiand preserveslo <= hi. - The conditional rule gives both bounds from either branch:
the true branch has
lo <= hiandx = hi, and the empty false branch keepslo <= xwithx <= hi.
The rules: Lecture 7's The rule for a conditional, The rules for an assignment, and The rule for a sequence.
f.
{{ x = y and y = z and x != z }}
x = y;
{{ x != y }}
Answer
| Valid? |
|---|
| T |
Valid: no state makes the precondition true.
Forward, from the precondition:
{{ x = y and y = z and x != z }}
{{ false }}
x = y;
{{ false and x = y }}
{{ x != y }}
x = yandy = zimplyx = z, contradictingx != z.- The forward assignment rule keeps
falseand addsx = y. falseimplies any claim, includingx != y, so the triple is valid.
The rules: Lecture 7's A triple and The rules for an assignment.
g.
{{ x = 0 or y = 0 }}
if (x != 0) {
if (y == 0) {
x = 1;
y = 1;
}
}
{{ x = 0 or y = 0 }}
Answer
| Valid? |
|---|
| F |
Not valid: the inner true branch can execute.
A counterexample:
- Start from
x = 1andy = 0. - The precondition is true because
y = 0. - The outer condition
x != 0is true. - The inner condition
y == 0is also true. - Its assignments leave
x = 1andy = 1. - Neither
x = 0nory = 0is true in the final state.
The rule: Lecture 7's The rule for a conditional.
h.
{{ 0 <= x }}
while (0 < x) {
x = x;
}
{{ x = 0 }}
Answer
| Valid? |
|---|
| T |
Valid: every terminating run from the precondition ends with x = 0.
Forward, with invariant 0 <= x:
{{ 0 <= x }}
{{ Inv: 0 <= x }}
while (0 < x) {
{{ 0 <= x and 0 < x }}
x = x;
{{ 0 <= x }}
}
{{ 0 <= x and x <= 0 }}
{{ x = 0 }}
- The precondition is the invariant, so check (1) passes.
- The while rule adds the true condition
0 < xat body entry. x = xleavesxunchanged, preserving the invariant for check (2).- At exit, the while rule gives the invariant and the false
condition,
x <= 0. - The two bounds force
x = 0, so check (3) passes.
When the loop never ends:
- If
xstarts positive, the unchangedxkeeps the loop running. - A valid triple asks only about terminating runs.
The rules: Lecture 7's A triple and Lecture 8's The rule for a while loop.