Program A: LinearSearch with function specification CS156: The Calculus of @pre 0 ≤ ℓ ∧ u < | a | Computation @post rv ↔ ∃ i . ℓ ≤ i ≤ u ∧ a [ i ] = e bool LinearSearch( int [] a , int ℓ, int u , int e ) { Zohar Manna for @ ⊤ ( int i := ℓ ; i ≤ u ; i := i + 1) { Autumn 2008 if ( a [ i ] = e ) return true ; } return false ; } Chapter 5: Program Correctness: Mechanics Page 1 of 56 Page 2 of 56 Function LinearSearch searches subarray of array a of integers for Program B: BinarySearch with function specification specified value e . Function specifications @pre 0 ≤ ℓ ∧ u < | a | ∧ sorted( a , ℓ, u ) ◮ Function precondition (@ pre ) @post rv ↔ ∃ i . ℓ ≤ i ≤ u ∧ a [ i ] = e It behaves correctly only if 0 ≤ ℓ and u < | a | bool BinarySearch( int [] a , int ℓ, int u , int e ) { ◮ Function postcondition (@ post ) if ( ℓ > u ) return false ; It returns true iff a contains the value e in the range [ ℓ, u ] else { int m := ( ℓ + u ) div 2; for loop: initially set i to be ℓ , if ( a [ m ] = e ) return true ; execute the body and increment i by 1 else if ( a [ m ] < e ) return BinarySearch( a , m + 1 , u , e ); as long as i ≤ u else return BinarySearch( a , ℓ, m − 1 , e ); } @ - program annotation } Page 3 of 56 Page 4 of 56
The recursive function BinarySearch searches sorted subarray Program C: BubbleSort with function specification a of integers for specified value e . @pre ⊤ sorted: weakly increasing order, i.e. @post sorted( rv , 0 , | rv | − 1) int [] BubbleSort( int [] a 0 ) { sorted( a , ℓ, u ) ⇔ ∀ i , j . ℓ ≤ i ≤ j ≤ u → a [ i ] ≤ a [ j ] int [] a := a 0 ; for @ ⊤ Defined in the combined theory of integers and arrays, T Z ∪ A ( int i := | a | − 1; i > 0; i := i − 1) { for @ ⊤ Function specifications ( int j := 0; j < i ; j := j + 1) { ◮ Function precondition (@ pre ) if ( a [ j ] > a [ j + 1]) { It behaves correctly only if int t := a [ j ]; 0 ≤ ℓ and u < | a | and a [ j ] := a [ j + 1]; sorted( a , ℓ, u ). a [ j + 1] := t ; ◮ Function postcondition (@ post ) } } It returns true iff a contains the value e in the range [ ℓ, u ] } return a ; } Page 5 of 56 Page 6 of 56 Function BubbleSort sorts integer array a Sample execution of BubbleSort a: unsorted sorted 2 3 4 1 2 5 6 largest j i by “bubbling” the largest element of the left unsorted region of a 2 3 4 1 2 5 6 toward the sorted region on the right. j i Each iteration of the outer loop expands the sorted region by one 2 3 4 1 2 5 6 cell. 1 j i 2 3 1 4 2 5 6 Function specification j i ◮ Function postcondition (@post): 2 3 1 2 4 5 6 BubbleSort returns array rv sorted on the range [0 , | rv | − 1]. j , i 2 3 1 2 4 5 6 j i 1 Except the last iteration, which expands the sorted region by two cells, so that an entire array of length n is sorted in n − 1 iterations. Page 7 of 56 Page 8 of 56
Program Annotation Program A: LinearSearch with runtime assertions ◮ Function Specifications function precondition (@pre) @pre 0 ≤ ℓ ∧ u < | a | function postcondition (@post) @post rv ↔ ∃ i . ℓ ≤ i ≤ u ∧ a [ i ] = e ◮ Runtime Assertions bool LinearSearch( int [] a , int ℓ, int u , int e ) { e.g., @ 0 ≤ j < | a | ∧ 0 ≤ j + 1 < | a | for a [ j ] := a [ j + 1] @ L : ⊤ ◮ Loop Invariants ( int i := ℓ ; i ≤ u ; i := i + 1) { e.g., @ L : ℓ ≤ i ∧ ∀ j . ℓ ≤ j < i → a [ j ] � = e @ 0 ≤ i < | a | ; The L : gives a name to the formula, just like the F : we’ve used in other formulae. if ( a [ i ] = e ) return true ; } return false ; } Page 9 of 56 Page 10 of 56 Program B: BinarySearch with runtime assertions Program C: BubbleSort with runtime assertions @pre ⊤ @pre 0 ≤ ℓ ∧ u < | a | ∧ sorted( a , ℓ, u ) @post sorted( rv , 0 , | rv | − 1) @post rv ↔ ∃ i . ℓ ≤ i ≤ u ∧ a [ i ] = e int [] BubbleSort( int [] a 0 ) { bool BinarySearch( int [] a , int ℓ, int u , int e ) { int [] a := a 0 ; if ( ℓ > u ) return false ; for @ L 1 : ⊤ else { ( int i := | a | − 1; i > 0; i := i − 1) { @ 2 � = 0; for int m := ( ℓ + u ) div 2; @ L 2 : ⊤ @ 0 ≤ m < | a | ; ( int j := 0; j < i ; j := j + 1) { @ 0 ≤ j < | a | ∧ 0 ≤ j + 1 < | a | ; if ( a [ m ] = e ) return true ; if ( a [ j ] > a [ j + 1]) { else { int t := a [ j ]; @ 0 ≤ m < | a | ; a [ j ] := a [ j + 1]; if ( a [ m ] < e ) return BinarySearch( a , m + 1 , u , e ); a [ j + 1] := t ; } else return BinarySearch( a , ℓ, m − 1 , e ); } } } } return a ; } } Page 11 of 56 Page 12 of 56
Loop Invariants Program A: LinearSearch with loop invariants while @ F @pre 0 ≤ ℓ ∧ u < | a | � cond � { � body � } @post rv ↔ ∃ j . ℓ ≤ j ≤ u ∧ a [ j ] = e bool LinearSearch( int [] a , int ℓ, int u , int e ) { ◮ apply � body � as long as � cond � holds for ◮ assertion F holds at the beginning of every iteration @ L : ℓ ≤ i ∧ ( ∀ j . ℓ ≤ j < i → a [ j ] � = e ) evaluated before � cond � is checked ( int i := ℓ ; i ≤ u ; i := i + 1) { for � init � ; if ( a [ i ] = e ) return true ; @ F while } ( � init � ; � cond � ; � incr � ) @ F return false ; {� body �} � cond � { � body � ; � incr � } } Page 13 of 56 Page 14 of 56 Proving Partial Correctness Basic Paths: Loops To handle loops, we break the function into basic paths A function is partially correct if when the function’s precondition is satisfied on entry, @ ← precondition or loop invariant its postcondition is satisfied when the function halts/exits. sequence of instructions ◮ A function + annotation is reduced to finite set of (with no loop invariants) verification conditions (VCs), FOL formulae ◮ If all VCs are T -valid, then the function obeys its specification @ ← loop invariant, runtime assertion, or postcondition (partially correct) Page 15 of 56 Page 16 of 56
Program A: LinearSearch I Program A: LinearSearch II (3) Basic Paths of LinearSearch @ L : ℓ ≤ i ∧ ∀ j . ℓ ≤ j < i → a [ j ] � = e (1) assume i ≤ u ; @pre 0 ≤ ℓ ∧ u < | a | assume a [ i ] � = e ; i := ℓ ; i := i + 1; @ L : ℓ ≤ i ∧ ∀ j . ℓ ≤ j < i → a [ j ] � = e @ L : ℓ ≤ i ∧ ∀ j . ℓ ≤ j < i → a [ j ] � = e (2) (4) @ L : ℓ ≤ i ∧ ∀ j . ℓ ≤ j < i → a [ j ] � = e @ L : ℓ ≤ i ∧ ∀ j . ℓ ≤ j < i → a [ j ] � = e assume i ≤ u ; assume i > u ; assume a [ i ] = e ; rv := false ; rv := true ; @post rv ↔ ∃ j . ℓ ≤ j ≤ u ∧ a [ j ] = e @post rv ↔ ∃ j . ℓ ≤ j ≤ u ∧ a [ j ] = e Page 17 of 56 Page 18 of 56 Visualization of basic paths of LinearSearch Program C: BubbleSort with loop invariants @pre (1) @pre ⊤ (3) L @post sorted( rv , 0 , | rv | − 1) (2) , (4) int [] BubbleSort( int [] a 0 ) { @post int [] a := a 0 ; for − 1 ≤ i < | a | @ L 1 : ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) ∧ sorted( a , i , | a | − 1) ( int i := | a | − 1; i > 0; i := i − 1) { Page 19 of 56 Page 20 of 56
Partition partitioned( a , ℓ 1 , u 1 , ℓ 2 , u 2 ) for 1 ≤ i < | a | ∧ 0 ≤ j ≤ i ⇔ ∀ i , j . ℓ 1 ≤ i ≤ u 1 < ℓ 2 ≤ j ≤ u 2 → a [ i ] ≤ a [ j ] ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) @ L 2 : in T Z ∪ T A . ∧ partitioned( a , 0 , j − 1 , j , j ) That is, each element of a in the range [ ℓ 1 , u 1 ] is ≤ each element ∧ sorted( a , i , | a | − 1) in the range [ ℓ 2 , u 2 ]. ( int j := 0; j < i ; j := j + 1) { if ( a [ j ] > a [ j + 1]) { Basic Paths of BubbleSort int t := a [ j ]; (1) a [ j ] := a [ j + 1]; @pre ⊤ a [ j + 1] := t ; } a := a 0 ; } i := | a | − 1; } � � − 1 ≤ i < | a | ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) return a ; @ L 1 : } ∧ sorted( a , i , | a | − 1) Page 21 of 56 Page 22 of 56 (3) (2) � � � � 1 ≤ i < | a | ∧ 0 ≤ j ≤ i ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) − 1 ≤ i < | a | ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) @ L 2 : @ L 1 : ∧ partitioned( a , 0 , j − 1 , j , j ) ∧ sorted( a , i , | a | − 1) ∧ sorted( a , i , | a | − 1) assume j < i ; assume i > 0; assume a [ j ] > a [ j + 1]; j := 0; t := a [ j ]; � � 1 ≤ i < | a | ∧ 0 ≤ j ≤ i ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) @ L 2 : a [ j ] := a [ j + 1]; ∧ partitioned( a , 0 , j − 1 , j , j ) ∧ sorted( a , i , | a | − 1) a [ j + 1] := t ; j := j + 1; � � 1 ≤ i < | a | ∧ 0 ≤ j ≤ i ∧ partitioned( a , 0 , i , i + 1 , | a | − 1) @ L 2 : ∧ partitioned( a , 0 , j − 1 , j , j ) ∧ sorted( a , i , | a | − 1) Page 23 of 56 Page 24 of 56
Recommend
More recommend