Proofs of Program Correctness We can use the Hoare rules to prove the correctness of programs. For instance, consider a program that computes in variable y the factorial of a number initially stored in variable x: {x = n /\ n > 0} y:=1; while (x > 0) do (y:=y*x; x:=x-1) {y=n!} We can prove the correctness of this statement using Hoare logic. Since the overall proof tree is large, I will go through each piece of this tree in turn and show what rule I apply at each point. First, the program consists of a sequence of an assignment and a while loop. To be able to apply the rule for sequences, I need to find an assertion that holds after the assignment, but before the loop. Furthermore, if I look at the rule for while loops, I see that the assertion before the loop must be a loop invariant. So I must determine what the appropriate invariant is. Inspecting the execution of the loop, I see that the loop builds the factorial in y starting from n, then multiplying it with n-1, then n-2, etc. At each iteration, x is the next value that gets multiplied into y. In other words, at each iteration I have: y = n * (n-1) * ... * (x+1) I can multiply both sides of this equality by x! and re-write the equality as: x! * y = n! So this should be an invariant during the execution of the loop. Actually, I will use a slightly stronger invariant: I = ( x! * y = n! /\ x >= 0 ) So I want to prove two facts: (1) {x = n /\ n > 0} y:=1 {I} (2) {I} while (x > 0) do (y:=y*x; x:=x-1) {y=n!} If both (1) and (2) are true, I can use rule (seq) to get the desired result. To show (1) I look at the (assign) axiom and see that the following holds: {I[1/y]} y:=1 {I}. Expanding out I get: (3) {x! * 1 = n! /\ x >= 0} y:=1 { x! * y = n! /\ x >= 0} Furthermore, the following implication clearly holds: (x = n /\ n > 0) => (x! * 1 = n! /\ x >= 0) (because x = n implies x! = n!, and x = n /\ n > 0 implies x >=0). Then (1) follows from (3) using the rule of consequence. Let's turn and look at how we show (2) now. To be able to apply the (while), I need to show that I is truly a loop invariant: (4) {I /\ x > 0} y:=y*x; x:=x-1 {I} I will show this by going backwards through the sequence of assignments: The (assign) rule for x:=x-1 and y:=y*x show that: (5) {(x-1)! * y = n! /\ (x-1) >= 0} x:=x-1 {I} (6) {(x-1)! * y * x = n! /\ (x-1) >= 0} y:=y*x {(x-1)! * y = n! /\ (x-1) >= 0} Furthermore, the following implication holds: (I /\ x > 0) => {(x-1)! * y * x = n! /\ (x-1) >= 0} (because x > 0 implies (x-1) >= 0 and (x-1)! * y * x= x! * y). Then (4) follows from (5) and (6) using the rule of consequence. So I just showed that I is a loop invariant. Therefore I can apply the (while) rule and get: (7) {I} while (x > 0) do (y:=y*x; x:=x-1) {I /\ neg(x > 0)} The only piece left to complete the proof is the following implication: (I /\ neg(x > 0)) => (y = n!) which means: (x! * y = n! /\ x >= 0 /\ neg(x > 0)) => (y = n!) This is true because x >= 0 and neg(x > 0) means that x = 0, which means that x! = 0! = 1. By substituting 1 for x! in x! * y = n! we get that y = n!. Using this implication, (2) follows from (7) using the rule of consequence. And this completes the proof. So I was able to prove that program is correct -- it indeed meets its specification and computes the factorial. Note. For a more compact representation, one can write a sketch of the above proof by indicating the assertions necessary at each program point, along with the implications necessary for the rule of consequence. For instance: {x = n /\ n > 0} (x = n /\ n > 0) => (x! * 1 = n! /\ x >= 0) {x! * 1 = n! /\ x >= 0} y := 1 {x! * y = n! /\ x >= 0} while (x > 0) do {x! * y = n! /\ x >= 0 /\ x > 0} (x! * y = n! /\ x >= 0 /\ x > 0) => {(x-1)! * y * x = n! /\ (x-1) >= 0} {(x-1)! * y * x = n! /\ (x-1) >= 0} y := y * x; {(x-1)! * y = n! /\ (x-1) >= 0} x := x - 1 {x! * y = n! /\ x >= 0} {x! * y = n! /\ x >= 0 /\ neg(x > 0)} (x! * y = n! /\ x >= 0 /\ neg(x > 0)) => (y = n!) {y = n!}