CSC 509 Lecture Notes Week 10
Introduction to Formal Program Verification
/* * Compute factorial of x, for positive x, using an iterative technique. * * Precond: x >= 0 * * Postcond: return == x! * */ int Factorial(int x) { int y; y = 1; while (x > 0) { x = x - 1; y = y * x; } return y; }
Test No. | Input | Expected |
Results | ||
1 | x = -1 | ERROR (precondition violation) |
2 | x = 0 | return = 1 |
3 | x = 1 | return = 1 |
4 | x = 4 | return = 24 |
5 | x = 6 | return = 120 |
6 | x = 70 | return > 10**100 (possible numeric overflow) |
Table 1: Unit testing Factorial.
results in y having the symbolic value of 1 * x which simplifies to just x.y := 1; y := y * x;
x := x - 1; y := y * x;
results in y's symbolic value of x * (x - 1) * ((x - 1) - 1) which simplifies to x * (x - 1) * (x - 2)x := x - 1; y := y * x;
i.e., the precond mathematically implies the post cond when the mathematical rules of the function are obeyed.precond postcond
which means that if the precond is true before the function body is (mathematically) executed, then the postcond must be true after the execution is complete.precond {function body} postcond
precond {function body} postcond
int Duh() { /* * Add 2 to 2 and return the result. * * precondition: ; * postcondition: return == 4; * */ int x,y; x = 2; y = x + 2; return y; }
int ReallyDuh() { /* * Add 2 to 3 and return the result. * precondition: ; * postcondition: return == 4; */ int x,y; x = 2; y = x + 3; return = y; }
which is false.true 4 == 2 + 3 ==> true false
p q p q 0 0 1 0 1 1 1 0 0 1 1 1
int Factorial(int N) { /* * Compute factorial of x, for positive x, using an iterative technique. * * Precond: N >= 0 * * Postcond: return == N! * */ int x,y; /* Temporary computation vars */ x = N; y = 1; while (x > 0) { y = y * x; x = x - 1; } return y; }
Figure 1: Factorial proof outline.
y R f(x) = N!for some relation R. And it looks like R is multiplication, i.e.,
y * f(X) = N!
y = x * (x-1) * (x-2) * ... * (x-k) * (x-k-1) * ... * 1 = N!
y * x! = N!
if (y*x! == N! and x>=0) then if (x>0) then y*x*(x-1)! == N! and (x-1)>=0 => if (y*x! == N! and x>=0) then if (x>0) y*x! == N! and x>=1 => if (y*x! == N! and x>=0) then if (x>0) y*x! == N! => if (y*x! == N! and x>=0) then y*x! == N! and x>0 => true
if (y*x! == N and x>=0) then if (x<=0) then y==N! => if (y*x! == N! and x==0) then y==N! => if (y*0! == N!) then y==N! => if (y*1 == N!) then y==N! => true
y * x! = N! and xt;=0 and x>0 y * (x-1) * (x-1)! = N! and x-1 t;= 0 ==>
y * x! = N! and x>0 y * (x-1) * (x-1)! = N! (oops)
y * x! = N! and xt;=0 and (xt;=0) y = N! ==>
y * x! = N! and xt;=0 and x<0 y = N!
y = N! y * x = N! y * x * (x-1) = N! y * x * (x-1) * (x-2) = N! y * x * (x-1) * (x-2) * (x-3) = N! . . . y * x * (x-1) * ... * (x-N) = N!
y = N! y * (x-1) = N! y * (x-1) * (x-2) = N! y * (x-1) * (x-2) * (x-3) = N! . . . y * (x-1) * (x-2) * ... * (x-N) = N!
Figure 2: Factorial call proof outline.
Label Predicate Proof Step
VC: true => forall (x: integer) Rule of verification if (x>=0) then x!==x! else x==x condition generation => true Induction on x Pre: true Given P5: forall (x: integer) Rule of readint if (x>=0) then x!==x! else x==x P4: if (x>=0) then Rule of if-then-else if (x>=0) then x!==x! else x!==x P2 else if (x>=0) then y==x! else x==x P3 => if (x>=0) then x!==x! else x==x Simplification P3: if (x>=0) then y==x! else x==x Rule of assignment P2: if (x>=0) then x!==x! else x!==x Rule of function call P1: if (x>=0) then y==x! else y==x Rule of assignment Post: if (x>=0) then return==x! else return==x Given
Table 2: Proof that Factorial call does not violate precondition.