Hoare-style program verification K. Rustan M. Leino Guest lecturer Rob DeLines CSE 503, Software Engineering University of Washington 28 Apr 2004
Review {P} skip {P} {P[w:=E]} w:=E {P} {PB} assert B {P} if {P} S {Q} and {Q} T {R}, then {P} S ; T {R} if {PB} S {R} and {PB} T {R}, then {P} if B then S else T end {R}
Loops To prove {P} while B do S end {Q} prove {P} {J} while B do {J B} {0 vf} {J B vf=VF} S {J vf<VF} end {J B} {Q}
Example: Array sum {0N} k := 0; s := 0; while k N do s:=s+a[k] ; k:=k+ 1 end {s = (Σi | 0i<N a[i])}
{0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} Example: Array sum {0N} k := 0; s := 0; while k N do s:=s+a[k] ; k:=k+ 1 end {s = (Σi | 0i<N a[i])}
Example: Array sum {0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])}
Example: Array sum {0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J k=N} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0 k N vf: N-k
{0N} {0 = (Σi | 0i<0 a[i]) 00N} k := 0; {0 = (Σi | 0i<k a[i]) 0kN} s := 0; {s = (Σi | 0i<k a[i]) 0kN} Example: Array sum Initialization
Example: Array sum Invariance {s = (Σi | 0i<k a[i]) 0kN kN N-k=VF} {s+a[k] = (Σi | 0i<k a[i])+a[k] 0k<N N-k- 1 <VF} s := s + a[k]; {s = (Σi | 0i<k a[i])+a[k] 0k<N N-k- 1 <VF} {s = (Σi | 0i<k+ 1 a[i]) 0k+ 1 N N-(k+ 1 )<VF} k := k+ 1 ; {s = (Σi | 0i<k a[i]) 0kN N-k<VF}
In-class exercise: computing cubes {0N} k := 0; r := 0; s := 1; t := 6; while kN do a[k] := r; r := r + s; s := s + t; t := t + 6; k := k + 1 end {(i | 0i<N a[i] = i 3 )}
Computing cubes Guessing the invariant From the postcondition (i | 0i<N a[i] = i 3 ) and the negation of the guard k=N guess the invariant (i | 0i<k a[i] = i 3 ) 0kN From this invariant and variant function N-k, it follows that the loop terminates
Computing cubes Maintaining the invariant while kN do {(i | 0i<k a[i] = i 3 ) 0kN kN} {(i | 0i<k a[i] = i 3 ) r=k 3 0k<N} a[k] := r; r := r + s; s := s + t; t := t + 6; {(i | 0i<k a[i] = i 3 ) a[k]=k 3 0k<N} {(i | 0i<k+ 1 a[i] = i 3 ) 0k+ 1 N} k := k + 1 {(i | 0i<k a[i] = i 3 ) 0kN} end Add this to the invariant, and then try to prove that it is maintained
Computing cubes Maintaining the invariant while kN do {r = k 3 …} {r + s = k 3 + 3*k 2 + 3*k + 1} a[k] := r; r := r + s; s := s + t; t := t + 6; {r = k 3 + 3*k 2 + 3*k + 1} {r = (k+ 1 ) 3 } k := k + 1 {r = k 3 } end Add s = 3*k 2 + 3*k + 1 to the invariant, and then try to prove that it is maintained
Computing cubes Maintaining the invariant while kN do {s = 3*k 2 + 3*k + 1 …} {s + t = 3*k 2 + 6*k *k } a[k] := r; r := r + s; s := s + t; t := t + 6; {s = 3*k 2 + 6*k *k } {s = 3*(k+1) 2 + 3*(k+1) + 1} k := k + 1 {s = 3*k 2 + 3*k + 1} end Add t = 6*k + 6 to the invariant, and then try to prove that it is maintained
Computing cubes Maintaining the invariant while kN do {t = 6*k + 6 …} {t + 6 = 6*k } a[k] := r; r := r + s; s := s + t; t := t + 6; {t = 6*k } {t = 6*(k+1) + 6} k := k + 1 {t = 6*k + 6} end
Computing cubes Establishing the invariant {0N} {(i | 0i<0 a[i] = i 3 ) 00N 0 = = 3* * = 6*0 + 6} k := 0; r := 0; s := 1; t := 6; {(i | 0i<k a[i] = i 3 ) 0kN r = k 3 s = 3*k 2 + 3*k + 1 t = 6*k + 6}
In-class exercise: computing cubes Answers Invariant: (i | 0i<k a[i] = i 3 ) 0 k N r = k 3 s = 3*k 2 + 3*k + 1 t = 6*k + 6 Variant function: N-k
Other common invariants k is the number of nodes traversed so far the current value of n does not exceed the initial value of n all array elements with an index less than j are smaller than x the number of processes whose program counter is inside the critical section is at most one the only principals that know the key K are A and B
Belgian chocolate How many breaks do you need to make 50 individual pieces from a 10x5 Belgian chocolate bar? Note: Belgian chocolate is so thick that you can't break two pieces at once. Invariant: #pieces = 1 + #breaks
Loop proof obligations a closer look To prove {P} while B do S end {Q} find invariant J and variant function vf such that: – invariant initially: P J – invariant maintained: {J B} S {J} – invariant sufficient: J B Q – vf well-founded – vf bounded: J B 0 vf – vf decreases: {J B vf=VF} S {vf<VF} Are all of these conditions needed?
{0N} k := N; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0kN vf: N-k Loop proof obligations invariant holds initially
{0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 2 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0kN vf: N-k Loop proof obligations invariant is maintained
Loop proof obligations invariant is sufficient {0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} k:=k+ 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: 0kN vf: N-k
Loop proof obligations variant function is well-founded {0N} k := 0; s := 0; r := 1.0 ; {J} while k N do {J kN} {0 vf} {J kN vf=VF} r := r / 2.0 ; {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s=(Σi | 0i<k a[i]) 0r vf: r
Loop proof obligations variant function is bounded {0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} k:=k- 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) kN vf: k
Loop proof obligations variant function decreases {0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} skip {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0kN vf: N-k
Ranges in invariants {0N} k := 0; s := 0; {J} while k N do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0kN vf: N-k Where are these used?
Ranges: lower bound {s = (Σi | 0i<k a[i]) 0kN kN N-k=VF} {s+a[k] = (Σi | 0i<k a[i])+a[k] 0k<N N-k- 1 <VF} s := s + a[k]; {s = (Σi | 0i<k a[i])+a[k] 0k<N N-k- 1 <VF} {s = (Σi | 0i<k+ 1 a[i]) 0k+ 1 N N-(k+ 1 )<VF} k := k+ 1 ; {s = (Σi | 0i<k a[i]) 0kN N-k<VF} This step uses 0k
Ranges: upper bound {0N} k := 0; s := 0; {J} while kN do {J kN} {0 vf} {J kN vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J (kN)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0kN vf: N-k This step uses kN
Ranges: upper bound {0N} k := 0; s := 0; {J} while k < N do {J k<N} {0 vf} {J k<N vf=VF} s:=s+a[k] ; k:=k+ 1 {J vf<VF} end {J (k<N)} {s = (Σi | 0i<N a[i])} J: s = (Σi | 0i<k a[i]) 0kN vf: N-k this step still needs kN Even with < instead of