{Precondition: n > 0} i <- n fact <- 1 while i > 0 do {assert: ...} fact <- fact * i i <- i - 1 end while {Postcondition: fact = 1*2*...*n}The key is to find the loop invariant. Note that it will have to be strong enough to prove the postcondition. Let's try:
fact * i! = n! & i >= 0Recall that the correctness rule for while loops is:
if we can show {P & B} C {P}, then {P}while B do C {P & not-B}
Since B is "i > 0", we must show that:
{fact * i! = n! & i >= 0 & i > 0} fact <- fact * i i <- i - 1 {fact * i! = n! & i >= 0}Now we can use the assignment rule ({P[e/x]} x := e {P}) twice by working our way up the program:
{fact * (i-1)! = n! & i -1 >= 0} i <- i - 1 {fact * i! = n! & i >= 0}and then
{fact * i * (i-1)! = n! & i -1 >= 0} fact <- fact * i {fact * (i-1)! = n! & i -1 >= 0}Note that the precondition of the last statement can be rewritten as:
{fact * i! = n! & i >= 1}By Composition, we get:
{fact * i ! = n! & i >= 1} fact <- fact * i; i <- i - 1 {fact * i! = n! & i >= 0}
But clearly, fact * i! = n! & i >= 0 & i > 0 implies fact * i ! = n! & i >= 1. Therefore by the consequence rule we get:
{fact * i! = n! & i >= 0 & i > 0} fact <- fact * i; i <- i - 1 {fact * i! = n! & i >= 0}
Since this establishes that fact * i! = n! & i >= 0 is a loop invariant, the while rule implies:
{fact * i! = n! & i >= 0} while i > 0 do fact <- fact * i i <- i - 1 end while {fact * i! = n! & i >= 0 & not(i > 0)}
Now i >= 0 & not(i > 0) implies i = 0 and therefore fact * i! = fact * 0! = fact.
Thus fact * i! = n! & i >= 0 & not(i > 0) implies fact = n!.
Again by the consequence rule (and our earlier deduction on pre- and post-conditions on the while loop) we can now deduce:
{fact * i! = n! & i >= 0} while i > 0 do fact <- fact * i i <- i - 1 end while {fact = n!}
All we have to worry about now is taking care of the program before the while loop.
Thus if we can show:
{n > 0} i <- n fact <- 1 {fact * i! = n! & i >= 0}
then we can glue this together with the above correctness clause (using the composition rule) to show the entire program is correct.
We can prove this last part as before by pushing the postcondition up through the assignment statements using the assignment rule as follows:
{1 * i! = n! & i >= 0} fact <- 1 {fact * i! = n! & i >= 0}and
{1 * n! = n! & n >= 0} i <- n {1 * i! = n! & i >= 0}Since 1 * n! = n! is clearly true we can simplify this statement to:
{n >= 0} i <- n {1 * i! = n! & i >= 0}By sequencing we get:
{n >= 0} i <- n; fact <- 1 {fact * i! = n! & i >= 0}
We now notice that the precondition we were looking for was {n > 0}, but of
course,
n > 0 implies that n >= 0. Thus again by consequence, we get
{n > 0} i <- n; fact <- 1 {fact * i! = n! & i >= 0}(This should make intuitive sense - if we strengthen the precondition, the postcondition should still be true.)
Using sequence, we can put this partial correctness assertion together with that for the while loop and obtain:
{Precondition: n > 0} i <- n fact <- 1 while i > 0 do fact <- fact * i i <- i - 1 end while {Postcondition: fact = 1*2*...*n}
as desired!