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;
precond postcond
i.e., the precond mathematically implies the post cond when
the mathematical rules of the function are obeyed.
precond {function body} 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
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.