Professional Documents
Culture Documents
Verification
Verification
Verification
• Testing:
• check a program for carefully chosen inputs (e.g., boundary
conditions, etc.)
• in general: cannot be exhaustive
• Formal verification:
• formally state a specification (logic, set theory), and
• prove a program satisfies the specification for all inputs
• Reduce bugs
• Safety-critical software or important components
(e.g., brakes in cars, nuclear power plants)
• Documentation
• necessary for large multi-person, multi-year software projects
• good documentation facilitates code re-use
• Current Practice
• specifying software is widespread practice
• formally verifying software is less widespread
• hardware verification is commmon
y = 1;
z = 0;
while (z != x) {
z = z + 1;
y = y ∗ z;
}
Example.
Example.
Example.
Revised example.
Example.
Revised example.
For this, we need information not just about the state after the program
executes, but also about the state before it executes.
(| P |) — precondition
C — program or code
(| Q |) — postcondition
(| x > 0 |) C (| y · y < x |) .
C1 : y = 0 ;
C2 : y = 0 ;
while (y * y < x) {
y = y + 1 ;
}
y = y - 1 ;
|=par (| P |) C (| Q |) ,
if and only if
while true { x = 0; }
|=tot (| P |) C (| Q |) ,
if and only if
A full proof will have one or more Hoare triples before and after each
code statement. Each triple will have a justification.
(| precondition |)
y = 1;
(| . . . |) 〈justification〉
while (x != 0) {
(| . . . |) 〈justification〉
y = y * x;
(| . . . |) 〈justification〉
x = x - 1;
(| . . . |) 〈justification〉
}
(| postcondition |) 〈justification〉
(assignment)
(| Q[E/x] |) x = E (| Q |)
Intuition:
Example.
`par (| y + 1 = 7 |) x = y + 1 (| x = 7 |)
Example 1.
(| y = 2 |) (| P[E/x] |)
x = y ; x = E;
(| x = 2 |) (| P |)
Example 2.
(| 0 < 2 |) (| P[E/x] |)
x = 2 ; x = E;
(| 0 < x |) (| P |)
Example 3.
(| x + 1 = 2 |) (| (x = 2)[(x + 1)/x] |)
x = x + 1; x = x + 1;
(| x = 2 |) (| x = 2 |)
Example 4.
(| x + 1 = n + 1 |)
x = x + 1;
(| x = n + 1 |)
?? (| P[E/x] |)
x = y; x = E;
(| x > 0 |) (| P |)
Precondition strengthening:
P → P0 (| P 0 |) C (| Q |)
(implied)
(| P |) C (| Q |)
Postcondition weakening:
(| P |) C (| Q0 |) Q0 → Q
(implied)
(| P |) C (| Q |)
Example of use: (| y = 6 |)
(| y + 1 = 7 |) implied
x = y + 1
(| x = 7 |) assignment
(| P |) C1 (| Q |), (| Q |) C2 (| R |)
(composition)
(| P |) C1 ; C2 (| R |)
(In our examples, the mid-condition will usually be determined by a rule, such
as assignment. But in general, a mid-condition might be very difficult to
determine.)
Assertions should hold true whenever the program reaches that point in
its execution.
(| x = x 0 ∧ y = y0 |)
t = x ;
x = y ;
y = t ;
(| x = y0 ∧ y = x 0 |)
(| x = x 0 ∧ y = y0 |)
t = x ;
x = y ;
(| x = y0 ∧ t = x 0 |) P2 = (| P[t/ y] |)
y = t ;
(| x = y0 ∧ y = x 0 |) assignment (| P |)
(| x = x 0 ∧ y = y0 |)
t = x ;
(| y = y0 ∧ t = x 0 |) P3 = (| P2 [ y/x] |)
x = y ;
(| x = y0 ∧ t = x 0 |) assignment
y = t ;
(| x = y0 ∧ y = x 0 |) assignment
(| x = x 0 ∧ y = y0 |)
(| y = y0 ∧ x = x 0 |) (| P3 [x/t] |)
t = x ;
(| y = y0 ∧ t = x 0 |) assignment
x = y ;
(| x = y0 ∧ t = x 0 |) assignment
y = t ;
(| x = y0 ∧ y = x 0 |) assignment
(| x = x 0 ∧ y = y0 |)
(| y = y0 ∧ x = x 0 |) implied [proof required]
t = x ;
(| y = y0 ∧ t = x 0 |) assignment
x = y ;
(| x = y0 ∧ t = x 0 |) assignment
y = t ;
(| x = y0 ∧ y = x 0 |) assignment
if-then-else:
(| P ∧ B |) C1 (| Q |) (| P ∧ ¬B |) C2 (| Q |)
(if-then-else)
(| P |) if (B) C1 else C2 (| Q |)
(| P ∧ B |) C (| Q |) (P ∧ ¬B) → Q
(if-then)
(| P |) if (B) C (| Q |)
(| P |)
if ( B ) {
(| P ∧ B |) if-then-else
C1
(| Q |) (justify depending on C1 —a “subproof”)
} else {
(| P ∧ ¬B |) if-then-else
C2
(| Q |) (justify depending on C2 —a “subproof”)
}
(| Q |) if-then-else [justifies this Q, given previous two]
(| P |)
if ( B ) {
(| P ∧ B |) if-then
C
(| Q |) [add justification based on C ]
}
(| Q |) if-then
Implied: Proof of P ∧ ¬B → Q
(| true |) (| P |)
if ( max < x ) { if ( B ) {
max = x ; C
} }
(| max ≥ x |) (| Q |)
(| true |)
if ( max < x ) {
(| true ∧ max < x |) if-then
max = x ;
(| max ≥ x |) ←− to be shown
}
(| max ≥ x |) if-then
Implied: true ∧ ¬(max < x) → max ≥ x
(| true |)
if ( max < x ) {
(| true ∧ max < x |) if-then
(| x ≥ x |)
max = x ;
(| max ≥ x |) assignment
}
(| max ≥ x |) if-then
Implied: true ∧ ¬(max < x) → max ≥ x
(| true |)
if ( max < x ) {
(| true ∧ max < x |) if-then
(| x ≥ x |) Implied (a)
max = x ;
(| max ≥ x |) assignment
}
(| max ≥ x |) if-then
Implied (b): true ∧ ¬(max < x) → max ≥ x
(| true |)
if (x > y) {
max = x;
} else {
max = y;
}
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |)
(| true |)
if (x > y) {
(| x > y |) if-then-else
max = x ;
} else {
(| ¬(x > y) |) if-then-else
max = y ;
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |)
}
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) if-then-else
(| true |)
if (x > y) {
(| x > y |) if-then-else
(| (x > y ∧ x = x) ∨ (x ≤ y ∧ x = y) |)
max = x ;
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) assignment
} else {
(| ¬(x > y) |) if-then-else
(| (x > y ∧ y = x) ∨ (x ≤ y ∧ y = y) |)
max = y ;
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) assignment
}
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) if-then-else
(| true |)
if (x > y) {
(| x > y |) if-then-else
(| (x > y ∧ x = x) ∨ (x ≤ y ∧ x = y) |) implied (a)
max = x ;
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) assignment
} else {
(| ¬(x > y) |) if-then-else
(| (x > y ∧ y = x) ∨ (x ≤ y ∧ y = y) |) implied (b)
max = y ;
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) assignment
}
(| (x > y ∧ max = x) ∨ (x ≤ y ∧ max = y) |) if-then-else
1. x>y assumption
2. x=x EQ1
3. x>y∧x=x ∧i: 1, 2
4. (x > y ∧ x = x) ∨ (x ≤ y ∧ x = y) ∨i: 3
5. x > y → (x > y ∧ x = x) ∨ (x ≤ y ∧ x = y)
→i: 1–4
(b) Prove x ≤ y → (x > y ∧ x = x) ∨ (x ≤ y ∧ y = y) .
1. x≤y assumption
2. y=y EQ1
3. x≤y∧ y=y ∧i: 1,2
4. (x > y ∧ y = x) ∨ (x ≤ y ∧ y = y) ∨i: 3
5. x ≤ y → (x > y ∧ y = x) ∨ (x ≤ y ∧ y = y)
→i: 1–4
(| I ∧ B |) C (| I |)
(partial-while)
(| I |) while (B ) C (| I ∧ ¬B |)
In words:
(| P |)
(| I |) Implied (a)
while ( B ) {
(| I ∧ B |) partial-while
C
(| I |) ←− to be justified, based on C
}
(| I ∧ ¬B |) partial-while
(| Q |) Implied (b)
We need to determine I !!
Program Verification while-Loops 384/448
Loop Invariants
1. First annotate code using the while-loop inference rule, and any
other control rules, such as if-then.
2. Then work bottom-up (“push up”) through program code.
• Apply inference rule appropriate for the specific line of code, or
• Note a new assertion (“implied”) to be proven separately.
3. Prove the implied assertions using the inference rules of ordinary
logic.
(| x ≥ 0 |)
y = 1 ;
z = 0 ;
(| y = z! |) [justification required]
while (z != x) {
(| ( y = z!) ∧ ¬(z = x) |) partial-while ((| I ∧ B |))
z = z + 1 ;
y = y * z ;
(| y = z! |) [justification required]
}
(| y = z! ∧ z = x) |) partial-while ((| I ∧ ¬B |))
(| y = x! |)
(| x ≥ 0 |)
(| 1 = 0! |)
y = 1 ;
(| y = 0! |) assignment
z = 0 ;
(| y = z! |) assignment
while (z != x) {
(| ( y = z!) ∧ ¬(z = x) |) partial-while
(| y(z + 1) = (z + 1)! |)
z = z + 1 ;
(| yz = z! |) assignment
y = y * z ;
(| y = z! |) assignment
}
(| y = z! ∧ z = x) |) partial-while
(| y = x! |)
(| x ≥ 0 |)
(| 1 = 0! |) implied (a)
y = 1 ;
(| y = 0! |) assignment
z = 0 ;
(| y = z! |) assignment
while (z != x) {
(| ( y = z!) ∧ ¬(z = x) |) partial-while
(| y(z + 1) = (z + 1)! |) implied (b)
z = z + 1 ;
(| yz = z! |) assignment
y = y * z ;
(| y = z! |) assignment
}
(| y = z! ∧ z = x) |) partial-while
(| y = x! |) implied (c)
By definition of factorial.
Proof of implied (c): ( y = z!) ∧ (z = x) ` ( y = x!).
1. ( y = z!) ∧ (z = x) premise
2. y = z! ∧e: 1
3. z=x ∧e: 1
4. y = x! EqSubs: 2, 3
1. y = z! ∧ z 6= x premise
2. y = z! ∧e: 1
3. (z + 1) y = (z + 1) z! EqSubs: 2
4. (z + 1) z! = (z + 1)! def. of factorial: 3
5. (z + 1) y = (z + 1)! EqTrans: 3, 4
Proving termination:
For each while-loop in the program,
• Precondition: x ≥ 0.
• Assignment z ← 0.
For v = e1 to e2 { C }
(| P |)
(| I[e1 /v] ∧ (e1 ≤ e2 ) |) implied (a)
for v = e1 to e2 {
(| I ∧ (e1 ≤ v) ∧ (v ≤ e2 ) |) for-loop A
C
(| I[v + 1/v] |) [justification required]
}
(| I[e2 + 1/v] |) for-loop A
(| Q |) implied (b)
(| P |)
(| I ∧ (e1 > e2 ) |) implied (a)
for v = e1 to e2 {
C [Nothing happens]
}
(| I ∧ (e1 > e2 ) |) for-loop B
(| Q |) implied (b)
(| n ≥ 1 |) (| P |)
x = 0 ;
for i = 1 to n {
x = x + i; C
}
(| x = n(n + 1)/2 |) (| Q |)
(| n ≥ 1 |)
x = 0 ;
(| x = (1 − 1)1/2 ∧ 1 ≤ n |)
for i = 1 to n {
(| x = (i − 1)i/2 ∧ (1 ≤ i) ∧ (i ≤ n) |) for-loop
x = x + i ;
(| x = i(i + 1)/2 |)
}
(| x = n(n + 1)/2 |) for-loop
(| x = n(n + 1)/2 |)
(| n ≥ 1 |)
(| 0 = (1 − 1)1/2 ∧ 1 ≤ n |)
x = 0 ;
(| x = (1 − 1)1/2 ∧ 1 ≤ n |) assignment
for i = 1 to n {
(| x = (i − 1)i/2 ∧ (1 ≤ i) ∧ (i ≤ n) |) for-loop
(| x + i = i(i + 1)/2 |)
x = x + i ;
(| x = i(i + 1)/2 |) assignment
}
(| x = n(n + 1)/2 |) for-loop
(| x = n(n + 1)/2 |)
(| n ≥ 1 |)
(| 0 = (1 − 1)1/2 ∧ 1 ≤ n |) implied (a)
x = 0 ;
(| x = (1 − 1)1/2 ∧ 1 ≤ n |) assignment
for i = 1 to n {
(| x = (i − 1)i/2 ∧ (1 ≤ i) ∧ (i ≤ n) |) for-loop
(| x + i = i(i + 1)/2 |) implied (b)
x = x + i ;
(| x = i(i + 1)/2 |) assignment
}
(| x = n(n + 1)/2 |) for-loop
(| x = n(n + 1)/2 |)
1. n≥1 premise
2. 0 = (1 − 1)1/2 EQ2, algebra
3. (n ≥ 1) ∧ (0 = (1 − 1)1/2) ∧i: 1,2
4. n ≥ 1 → (n ≥ 1) ∧ (0 = (1 − 1)1/2) →i: 1–3
A correct rule must account for possible changes to A[y], A[z+3], etc.,
when A[x] changes.
A[e1 ] = e2 ;
A = A{e1 ← e2 } ;
Definition: ¨
e, if i = j
A{i ← e}[ j] =
A[ j], if i =
6 j .
Examples:
A{1 ← 7}{2 ← 14}[2] = ??
Array assignment:
(Array assignment)
(| P[A{e1 ← e2 }/A] |) A[e1 ] = e2 (| P |)
where ¨
e, if i = j
A{i ← e}[ j] =
A[ j], if i =
6 j .
(| A[x] = x 0 ∧ A[ y] = y0 |)
t = A[x] ;
A[x] = A[y] ;
A[y] = t ;
(| A[x] = y0 ∧ A[ y] = x 0 |)
(| A[x] = x 0 ∧ A[ y] = y0 |)
t = A[x] ;
A[x] = A[y] ;
(| A{ y ← t}[x] = y0 ∧ A{ y ← t}[ y] = x 0 |)
A[y] = t ;
(| A[x] = y0 ∧ A[ y] = x 0 |) array assignment
(| A[x] = x 0 ∧ A[ y] = y0 |)
t = A[x] ;
(| A{x ← A[ y]}{ y ← t}[x] = y0
∧ A{x ← A[ y]}{ y ← t}[ y] = x 0 |)
A[x] = A[y] ;
(| A{ y ← t}[x] = y0 ∧ A{ y ← t}[ y] = x 0 |) array assignment
A[y] = t ;
(| A[x] = y0 ∧ A[ y] = x 0 |) array assignment
(| A[x] = x 0 ∧ A[ y] = y0 |)
(| A{x ← A[ y]}{ y ← A[x]}[x] = y0
∧ A{x ← A[ y]}{ y ← A[x]}[ y] = x 0 |)
t = A[x] ;
(| A{x ← A[ y]}{ y ← t}[x] = y0
assignment
∧ A{x ← A[ y]}{ y ← t}[ y] = x 0 |)
A[x] = A[y] ;
(| A{ y ← t}[x] = y0 ∧ A{ y ← t}[ y] = x 0 |) array assignment
A[y] = t ;
(| A[x] = y0 ∧ A[ y] = x 0 |) array assignment
(| A[x] = x 0 ∧ A[ y] = y0 |)
(| A{x ← A[ y]}{ y ← A[x]}[x] = y0
implied (a)
∧ A{x ← A[ y]}{ y ← A[x]}[ y] = x 0 |)
t = A[x] ;
(| A{x ← A[ y]}{ y ← t}[x] = y0
assignment
∧ A{x ← A[ y]}{ y ← t}[ y] = x 0 |)
A[x] = A[y] ;
(| A{ y ← t}[x] = y0 ∧ A{ y ← t}[ y] = x 0 |) array assignment
A[y] = t ;
(| A[x] = y0 ∧ A[ y] = x 0 |) array assignment
Proof.
In the second equation, the index element is the assigned element.
For the first equation, we consider two cases.
j = 1 ;
while ( 2*j <= n ) {
t = R[j] ;
R[j] = R[n+1-j] ;
R[n+1-j] = t ;
j = j + 1 ;
}
(| Inv ( j) ∧ 2 j ≤ n |) partial-while
(| Inv ( j + 1)[R0 /R], where R0 is
implied (c)
R{ j ← R[n + 1 − j]}{(n + 1 − j) ← R[ j]} |)
t = R[j]; R[j] = R[n+1-j]; R[n+1-j] = t;
(| Inv ( j + 1) |) Lemma
j = j + 1 ;
(| Inv ( j) |) assignment
(| J |)
if ( A[m] = x ) {
(| J ∧ (A[m] = x) |) if-then-else
found = true;
(| Q |)
} else if ( A[m] < x ) {
(| J ∧ ¬(A[m] = x) ∧ (A[m] < x) |) if-then-else
l = m+1;
(| Q |)
} else {
(| J ∧ ¬(A[m] = x) ∧ ¬(A[m] < x) |) if-then-else
u = m - 1;
(| Q |)
}
(| Q |) if-then-else
(| n ≥ 1 |)
Csort
(| sorted (A, n) |)
(| n ≥ 1 |) (| n ≥ 1 |)
for i = 1 to n {
Csort A[i] = 0 ;
}
(| sorted (A, n) |) (| sorted (A, n) |)
Second Attempt
(| n ≥ 1 ∧ A = A0 |)
Csort
(| sorted(A, n) ∧
permutation(A, A0 , n) |)
Second Attempt
(| n ≥ 1 ∧ A = A0 |) (| n ≥ 1 ∧ A = A0 |)
Csort n = 1 ;
some algorithm on A ;
(| sorted(A, n) ∧
permutation(A, A0 , n) |) (| sorted (A, n) ∧ permutation(A, A0 , n) |)
(| n ≥ 1 ∧ n = n0 ∧ A = A0 |)
Csort
• Insertion Sort
• Quicksort
Plan: insert each element, in turn, into the array of previously sorted
elements.
Algorithm:
i = k ;
while ( i > 1 ) {
if ( A[i] < A[i-1] ) {
t = A[i] ;
A[i] = A[i-1] ;
A[i-1] = t ;
}
i = i - 1 ;
}
Here, we shall focus on the middle step: “partition” the array according
to the chosen pivot.