{loop invariant I : ... } {bound function t : ... } do B1 ⟶ S1 [] B2 ⟶ S2 [] ... [] Bm ⟶ Sm od |
Consider a Hoare Triple {P} Sinit; LOOP {Q} in which Sinit is an assignment command (used for initialization) and LOOP is a repetition command annotated with a loop invariant and bound function, as in the template to the right.
To prove the Hoare Triple, you show each of the five items on the loop checklist:
Items (i) and (ii) together show that I is, as claimed, an invariant of the loop. Item (iii) shows that, if and when the loop terminates, the postcondition Q holds. Items (iv) and (v) together show that the loop eventually terminates.
Note that any precondition regarding only constants (e.g., N ≥ 0) can be considered to be an implicit conjunct of the loop invariant.
1. Prove that the following program is correct. Notice that the loop guard and the main conjunct of the loop invariant were derived (using the "delete a conjunct" heuristic) from the strengthened version Q' of the postcondition, which was obtained from the original postcondition Q using the "replace a constant by a fresh variable" heuristic.
|[ con N : int;
var k,m : int;
{P: N ≥ 0}
k,m := 0,0;
{loop invariant I: m = k2 ∧ 0≤k≤N}
{bound function t: N - k}
do k ≠ N ⟶ k,m := k+1,m+k+k+1
od
{Q': m = k2 ∧ k=N }
{Q: m = N2 }
]|
2. Prove this program's correctness:
|[ con X, Y : int;
var x,y,z : int;
{P: X ≥ 0 ∧ Y ≥ 0}
x,y,z := X,Y,0;
{loop invariant I: z = 2(Y-y) + (X-x) ∧ x ≥ 0 ∧ y ≥ 0 }
{bound function t: 2y + x}
do x > y ⟶ x,z := x-1,z+1
[] y > 0 ⟶ x,y := x+1,y-1; z := z+1
od
{Q: z = 2Y + X }
]|
In completing the proof, you may appeal to "obvious" theorems of number theory. For example:
You may also find that Contrapositive (3.61) is useful in showing item (iii) on the loop checklist.
3. (List Reversal)
Prove the correctness of the following program, which reverses a list.
Regarding notation,
You may make use of the following axioms and theorems.
For all b:elem and x,y,z : list of elem :
|
Here is the program:
|[ var x, y : list of elem {x = X};
y := empty;
{invariant I: rev.y | x = X}
{bound t: length.x}
do x != empty ⟶ x,y := tail.x, [head.x] | y
od
{rev.y = X}
]|
4. Apply the replace a constant by a variable heurisic to rewrite the postcondition Q in the program below, which computes the product of the elements of an array of integers. Specifically, replace 0 by the fresh variable k and add the new conjunct k=0 to obtain a stronger postcondition Q'. (Repeating: Replace 0 by k; do not replace #B by k.)
Then take one of the conjuncts of Q' to be a loop invariant and the negation of the other conjunct to be the loop guard. (That is, apply the "delete a conjunct" heuristic.)
Complete the pre-loop assignment command so that k and prod are initialized in such a way as to truthify the loop invariant. Then complete the assignment command forming the loop body so that its execution preserves the truth of the invariant and "makes progress towards termination". (Derive the right-hand side of the assignment to prod via calculation.) To show the latter will require you to describe a bound function, and to show that this function cannot go below zero without falsifying the loop guard may require you to include in the loop invariant a conjunct that imposes lower and upper bounds upon k.
Show your completed program and a proof of its correctness.
|[ con B : array of int;
var prod : int;
var k : int;
k,prod := ?,?;
{loop invariant I: ?}
{bound function t: ?}
do ? ⟶
k,prod := ?,?;
od
{ Q: prod = (×j | 0≤j<#B : B.j) }
]|