Program Verification Program Verification 307/434
Outline Introduction: What and Why? Pre- and Postconditions Conditionals while-loops and Total Correctness Arrays Program Verification Introduction 308/434
Program Verification Reference: Huth & Ryan, Chapter 4 Program correctness: does a given program satisfy its specification does it do what it is supposed to do? Techniques for showing program correctness: inspection, code walk-throughs testing (white box, black box) formal verification Program Verification Introduction 309/434
Program Verification Testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence, never their absence [E Dijkstra, 1972] Program Verification Introduction 310/434
Program Verification Testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence, never their absence [E Dijkstra, 1972] Testing is not proof! Program Verification Introduction 310/434
Testing versus Formal Verification Testing: check a program for carefully chosen inputs (eg, 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 Program Verification Introduction 311/434
Why Formal Verification? Why formally specify and verify programs? Reduce bugs Safety-critical software or important components (eg, 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 common Program Verification Introduction 312/434
Framework for software verification The steps of formal verification: 1 Convert the informal description R of requirements for an application domain into an equivalent formula Φ R of some symbolic logic, 2 Write a program P which is meant to realise Φ R in some given programming environment, and 3 Prove that the program P satisfies the formula Φ R We shall consider only the third part in this course Program Verification Introduction 313/434
Programming Languages Broadly speaking, there are two kinds of programming languages in wide use: procedural and functional Procedural, or imperative, languages describe procedures to compute something They specify instructions (imperatives) to follow, in order to achieve the desired result Functional, or applicative, languages define the results of functions They specify which functions to apply, in order to obtain the desired result Program Verification Varieties of programming languages 314/434
Example Programs As examples, we will use the powering function given x and y, compute x y on unsigned integers Procedural (C++) unsigned power ( unsigned x, unsigned y ) { if ( y == 0 ) return 1 ; else return power( x, y-1 ) * x ; } Functional (Haskell) power :: Word -> Word -> Word power x y y == 0 = 1 otherwise = power x (y-1) * x Different syntax, but basically the same computation Program Verification Varieties of programming languages 315/434
Exponentiation in Peano Arithmetic Possible axioms for Peano Arithmetic (symbol ): Exp1: Exp2: x (x 0 = s(0)) x ( y (x s(y) = (x y) x)) Expressed in more algorithmic language, these give { 1 if y = 0 x y = { (x (y 1)) x otherwise (By convention, the free variables are implicitly universally quantified) This makes a third representation of the algorithm in the two programs Program Verification Varieties of programming languages 316/434
Handling of Variables Two different versions of power: With call by value: unsigned power ( unsigned x, unsigned y ) { if ( y == 0 ) return 1 ; else return power( x, y-1 ) * x ; } With call by reference: unsigned power ( unsigned & x, unsigned & y ) { if ( y == 0 ) return 1 ; else return power( x, y-1 ) * x ; } The call-by-reference version doesn t compile, since y-1 isn t a reference Program Verification Varieties of programming languages 317/434
A Re-write Change y-1 to y-- : With call by value: unsigned power ( unsigned x, unsigned y ) { if ( y == 0 ) return 1 ; else return power( x, y-- ) * x ; } With call by reference: unsigned power ( unsigned & x, unsigned & y ) { if ( y == 0 ) return 1 ; else return power( x, y-- ) * x ; } Now the call-by-reference version compiles but it s broken! Calling power( a, b ) by reference changes the value of b: a side effect Program Verification Varieties of programming languages 318/434
An Iterative Implementation The same effect occurs in iterative versions of the program: unsigned power ( unsigned x, unsigned y ) { unsigned result = 1 ; for ( ; y > 0 ; y-- ) result *= x ; unsigned power ( unsigned & x, unsigned & y ) { unsigned result = 1 ; unsigned z = y ; for ( ; z > 0 ; z-- ) result *= x ; } return result ; } return result ; In procedural code, the values of variables change! Program Verification Varieties of programming languages 319/434
Core programming language We shall use a subset of C[++], Java, etc It contains their core features: integer and Boolean expressions assignment sequence if-then-else (conditional statements) while-loops for-loops arrays Due to time constraings, we shall not include functions and procedures Program Verification Varieties of programming languages 320/434
Program States We are considering imperative or procedural programs The programs manipulate the values of variables The state of a program is the values of the variables at a particular time in the execution of the program Expressions evaluate relative to the current state of the program Executing a statement changes the state of the program Program Verification Program States and Correctness 321/434
Example We shall use the following code as an example Compute the factorial of input x and store in y y = 1; z = 0; while (z!= x) { z = z + 1; y = y z; } Program Verification Program States and Correctness 322/434
Example y = 1; z = 0; while (z!= x) { z = z + 1; y = y z; } State at the while test: Initial state s 0 : z=0, y=1 Next state s 1 : z=1, y=1 State s 2 : z=2, y=2 State s 3 : z=3, y=6 State s 4 : z=4, y=24 Program Verification Program States and Correctness 323/434
Example y = 1; z = 0; while (z!= x) { z = z + 1; y = y z; } State at the while test: Initial state s 0 : z=0, y=1 Next state s 1 : z=1, y=1 State s 2 : z=2, y=2 State s 3 : z=3, y=6 State s 4 : z=4, y=24 Note: the order of z = z + 1 and y = y * z matters! Program Verification Program States and Correctness 323/434
Specifications What does a specification specify? Example Compute a number y whose square is less than the input x Program Verification Program States and Correctness 324/434
Specifications What does a specification specify? Example Compute a number y whose square is less than the input x What if x = 4? Program Verification Program States and Correctness 324/434
Specifications What does a specification specify? Example Compute a number y whose square is less than the input x What if x = 4? Revised example If the input x is a positive number, compute a number whose square is less than x Program Verification Program States and Correctness 324/434
Specifications What does a specification specify? Example Compute a number y whose square is less than the input x What if x = 4? Revised example If the input x is a positive number, compute a number whose square is less than x For this, we need information not just about the state after the program executes, but also about the state before it executes Program Verification Program States and Correctness 324/434
Hoare Triples Our assertions about programs will have the form P precondition C program or code Q postcondition The meaning of the triple P C Q : If program C is run starting in a state that satisfies P, then the resulting state after the execution of C will satisfy Q An assertion P C Q is called a Hoare triple Program Verification Program States and Correctness 325/434
Specification of a Program A specification of a program C is a Hoare triple with C as the second component: P C Q Example The requirement If the input x is a positive number, compute a number whose square is less than x might be expressed as x > 0 C y y < x Program Verification Program States and Correctness 326/434
Specification Is Not Behaviour A triple, such as x > 0 C y y < x, specifies neither a unique program C nor a unique behaviour For example, both x > 0 C 1 y y < x and x > 0 C 2 y y < x hold: C 1 : C 2 : y = 0 ; y = 0 ; while (y * y < x) { y = y + 1 ; } y = y - 1 ; Program Verification Program States and Correctness 327/434
Hoare triples We want to develop a notion of proof that will allow us to prove that a program C satisfies the specification given by the precondition P and the postcondition Q The proof calculus is different from that for FOL, since Hoare triples have two features not present in logical formulas: program instructions (actions), rather than propositions, and a sense of time: before execution versus after execution Program Verification Program States and Correctness 328/434
Partial correctness A triple P C Q is satisfied under partial correctness, denoted par P C Q, if and only if for every state s that satisfies condition P, if execution of C starting from state s terminates in a state s, then state s satisfies condition Q Program Verification Program States and Correctness 329/434
Partial correctness For example, the program while true { x = 0; } satisfies all specifications! It is an endless loop and never terminates, but partial correctness only says what must happen if the program terminates Program Verification Program States and Correctness 330/434
Total correctness A triple P C Q is satisfied under total correctness, denoted tot P C Q, if and only if for every state s that satisfies P, execution of C starting from state s terminates, and the resulting state s satisfies Q Total Correctness = Partial Correctness + Termination Program Verification Program States and Correctness 331/434
Examples for Partial and Total Correctness Example 1 Total correctness satisfied: x = 1 y = x ; y = 1 Example 2 Neither total nor partial correctness: x = 1 y = x ; y = 2 Program Verification Program States and Correctness 332/434
Examples for Partial and Total Correctness Example 3 Infinite loop (partial correctness) x = 1 while (true) { x = 0 ; } x > 0 Program Verification Program States and Correctness 333/434
Partial and Total Correctness Example 4 Total correctness x 0 y = 1 ; z = 0 ; while (z! = x) { z = z + 1 ; y = y z ; } y = x! What happens if we remove the precondition? Program Verification Program States and Correctness 334/434
Examples for Partial and Total Correctness Example 5 No correctness, because input altered ( consumed ) x 0 y = 1 ; while (x! = 0) { y = y x ; x = x 1 ; } y = x! Program Verification Program States and Correctness 335/434
Logical variables Sometimes the pre- and postconditions require additional variables that do not appear in the program These are called logical variables Example x = x 0 x 0 0 y = 1; while (x!= 0) { y = y * x; x = x - 1; } y = x 0! Program Verification Program States and Correctness 336/434
Logical variables Sometimes the pre- and postconditions require additional variables that do not appear in the program These are called logical variables Example x = x 0 x 0 0 y = 1; while (x!= 0) { y = y * x; x = x - 1; } y = x 0! For a Hoare triple, its set of logical variables are those variables that are free in P or Q and do not occur in C Program Verification Program States and Correctness 336/434
Proving Correctness: Overview Total correctness is our goal We usually prove it by proving partial correctness and termination separately For partial correctness, we shall introduce sound inference rules For total correctness, we shall use ad hoc reasoning, which suffices for our examples (In general, total correctness is undecidable) Our focus on partial correctness may seem strange It s not the condition we want to justify But experience has shown it is useful to think about partial correctness separately from termination Program Verification Proving Correctness: Assignments 337/434
Proving Partial Correctness Recall the definition of Partial Correctness: For every starting state which satisfies P and for which C terminates, the final state satisfies Q How do we show this, if there are a large or infinite number of possible states? Answer: Inference rules (proof rules) Each construct in our programming language will have a rule Program Verification Proving Correctness: Assignments 338/434
Presentation of a Proof A full proof will have one or more conditions before and after each code statement Each statement makes a Hoare triple with the preceding and following conditions Each triple (postcondition) has a justification that explains its correctness program precondition y = 1; while (x!= 0) { y = y * x; x = x - 1; } program postcondition justification justification justification justification justification Program Verification Proving Correctness: Assignments 339/434
Inference Rule for Assignment Q[E/x] x = E Q (assignment) Intuition: Q(x) will hold after assigning (the value of) E to x if Q was true of that value beforehand Program Verification Proving Correctness: Assignments 340/434
Assignment: Example Example par y + 1 = 7 x = y + 1 x = 7 by one application of the assignment rule Program Verification Proving Correctness: Assignments 341/434
More Examples for Assignment Example 1 y = 2 x = y ; x = 2 Q[E/x] x = E; Q Example 2 0 < 2 x = 2 ; 0 < x Q[E/x] x = E; Q Program Verification Proving Correctness: Assignments 342/434
Examples of Assignment Example 3 x + 1 = 2 x = x + 1 ; x = 2 (x = 2)[(x + 1)/x] Example 4 x + 1 = n + 1 x = x + 1; x = n + 1 (equivalent to x = n ) Program Verification Proving Correctness: Assignments 343/434
Note about Examples In program correctness proofs, we usually work backwards from the postcondition:??? Q[E/x] x = y ; x = E; x > 0 Q Program Verification Proving Correctness: Assignments 344/434
Inference Rules with Implications Rule of Precondition strengthening : P P P C Q P C Q (implied) Rule of Postcondition weakening : P C Q Q Q P C Q (implied) Example of use: y = 6 y + 1 = 7 x = y + 1 x = 7 implied assignment Program Verification Proving Correctness: Assignments 345/434
Inference Rule for Sequences of Instructions P C 1 Q, Q C 2 R P C 1 ; C 2 R (composition) In order to prove P C 1 ; C 2 R, we need to find a midcondition Q for which we can prove P C 1 Q and Q C 2 R (In our examples, the midcondition will usually be determined by a rule, such as assignment But in general, a midcondition might be very difficult to determine) Program Verification Proving Correctness: Assignments 346/434
Proof Format: Annotated Programs Interleave program statements with assertions, each justified by an inference rule The composition rule is implicit Assertions should hold true whenever the program reaches that point in its execution Program Verification Proving Correctness: Assignments 347/434
Proof Format: Annotated Programs If implied inference rule is used, we must supply a proof of the implication We ll do these proofs after annotating the program Each assertion should be an instance of an inference rule Normally, Don t simplify the assertions in the annotated program Do the simplification while proving the implied conditions Program Verification Proving Correctness: Assignments 348/434
Example: Composition of Assignments To show: the following is satisfied under partial correctness We work bottom-up for assignments x = x 0 y = y 0 t = x ; x = y ; y = t ; x = y 0 y = x 0 Program Verification Proving Correctness: Assignments 349/434
Example: Composition of Assignments To show: the following is satisfied under partial correctness We work bottom-up for assignments x = x 0 y = y 0 t = x ; x = y ; x = y 0 t = x 0 y = t ; x = y 0 y = x 0 P 2 is P [t/y] assignment P Program Verification Proving Correctness: Assignments 349/434
Example: Composition of Assignments To show: the following is satisfied under partial correctness We work bottom-up for assignments x = x 0 y = y 0 t = x ; y = y 0 t = x 0 x = y ; x = y 0 t = x 0 y = t ; x = y 0 y = x 0 P 3 is P 2 [y/x] assignment assignment Program Verification Proving Correctness: Assignments 349/434
Example: Composition of Assignments To show: the following is satisfied under partial correctness We work bottom-up for assignments x = x 0 y = y 0 y = y 0 x = x 0 t = x ; y = y 0 t = x 0 x = y ; x = y 0 t = x 0 y = t ; x = y 0 y = x 0 P 3 [x/t] assignment assignment assignment Program Verification Proving Correctness: Assignments 349/434
Example: Composition of Assignments To show: the following is satisfied under partial correctness We work bottom-up for assignments x = x 0 y = y 0 y = y 0 x = x 0 t = x ; y = y 0 t = x 0 x = y ; x = y 0 t = x 0 y = t ; x = y 0 y = x 0 implied [proof required] assignment assignment assignment Finally, show x = x 0 y = y 0 implies y = y 0 x = x 0 Program Verification Proving Correctness: Assignments 349/434
Programs with Conditional Statements Program Verification Conditionals 350/434
Deduction Rules for Conditionals if-then-else: P B C 1 Q P B C 2 Q P if (B) C 1 else C 2 Q (if-then-else) if-then (without else): P B C Q (P B) Q P if (B) C Q (if-then) Program Verification Conditionals 351/434
Template for Conditionals With else Annotated program template for if-then-else: P if ( B ) { P B C 1 Q } else { P B C 2 Q } Q if-then-else (justify depending on C 1 a subproof ) if-then-else (justify depending on C 2 a subproof ) if-then-else [justifies this Q, given previous two] Program Verification Conditionals 352/434
Template for Conditionals Without else Annotated program template for if-then: P if ( B ) { P B C Q } Q if-then [add justification based on C] if-then Implied: Proof of P B Q Program Verification Conditionals 353/434
Example: Conditional Code Example: Prove the following is satisfied under partial correctness true P if ( max < x ) { if ( B ) { max = x ; C } } max x Q First, let s recall our proof method Program Verification Conditionals 354/434
The Steps of Creating a Proof Three steps in doing a proof of partial correctness: 1 First annotate using the appropriate inference rules 2 Then back up in the proof: add an assertion before each assignment statement, based on the assertion following the assignment 3 Finally prove any implieds : Annotations from (1) above containing implications Adjacent assertions created in step (2) Proofs here can use predicate logic, basic arithmetic, or other appropriate reasoning Program Verification Conditionals 355/434
Doing the Steps 1 Add annotations for the if-then statement 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 Program Verification Conditionals 356/434
Doing the Steps 1 Add annotations for the if-then statement 2 Push up for the assignments true if ( max < x ) { true max < x x x max = x ; max x } max x if-then if-then Implied: assignment (true (max < x)) max x Program Verification Conditionals 356/434
Doing the Steps 1 Add annotations for the if-then statement 2 Push up for the assignments 3 Identify implieds to be proven true if ( max < x ) { true max < x x x max = x ; max x } max x if-then Implied (a) assignment if-then Implied (b): (true (max < x)) max x Program Verification Conditionals 356/434
Proving Implied Conditions The auxiliary implied proofs can be done by Natural Deduction (and assuming the necessary arithmetic properties) We will use it informally Proof of Implied (a): ((true (max < x)) x x Clearly x x is a tautology and the implication holds Program Verification Conditionals 357/434
Implied (b) Proof of Implied (b): Show (P B) Q, which is (true (max < x)) (max x) 1 true (max < x) assumption 2 (max < x) e: 1 3 max x def of 4 (true (max < x)) (max x) i: 1 3 Program Verification Conditionals 358/434
Example 2 for Conditionals Prove the following is satisfied under partial correctness true if ( x > y ) { max = x; } else { max = y; } (x > y max = x) (x y max = y) Program Verification Conditionals 359/434
Example 2: Annotated Code true if ( x > y ) { x > y max = x ; (x > y max = x) (x y max = y) } else { (x > y) max = y ; (x > y max = x) (x y max = y) } (x > y max = x) (x y max = y) if-then-else if-then-else if-then-else Program Verification Conditionals 360/434
Example 2: Annotated Code true if ( x > y ) { x > y (x > y x = x) (x y x = y) max = x ; (x > y max = x) (x y max = y) } else { (x > y) (x > y y = x) (x y y = y) max = y ; (x > y max = x) (x y max = y) } (x > y max = x) (x y max = y) if-then-else assignment if-then-else assignment if-then-else Program Verification Conditionals 360/434
Example 2: Annotated Code true if ( x > y ) { x > y (x > y x = x) (x y x = y) max = x ; (x > y max = x) (x y max = y) } else { (x > y) (x > y y = x) (x y y = y) max = y ; (x > y max = x) (x y max = y) } (x > y max = x) (x y max = y) if-then-else implied (a) assignment if-then-else implied (b) assignment if-then-else Program Verification Conditionals 360/434
Example 2: Implied Conditions (a) Prove x > y ((x > y x = x) (x y x = y)) 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 y = 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 Program Verification Conditionals 361/434
While-Loops and Total Correctness Program Verification while-loops 362/434
Inference Rule: Partial-while Partial while : do not (yet) require termination I B C I I while (B) C I B (partial-while) In words: If the code C satisfies the triple I B C I, and I is true at the start of the while-loop, then no matter how many times we execute C, condition I will still be true Condition I is called a loop invariant After the while-loop terminates, B is also true Program Verification while-loops 363/434
Annotations for Partial-while P I while ( B ) { I B C I } I B Q Implied (a) partial-while to be justified, based on C partial-while Implied (b) (a) Prove P I (precondition P implies the loop invariant) (b) Prove (I B) Q (exit condition implies postcondition) We need to determine I!! Program Verification while-loops 364/434
Loop Invariants A loop invariant is an assertion (condition) that is true both before and after each execution of the body of a loop True before the while-loop begins True after the while-loop ends Expresses a relationship among the variables used within the body of the loop Some of these variables will have their values changed within the loop An invariant may or may not be useful in proving termination (to discuss later) Program Verification while-loops 365/434
Example: Finding a loop invariant x 0 y = 1 ; z = 0 ; while (z!= x) { z = z + 1 ; y = y * z ; } y = x! Program Verification while-loops 366/434
Example: Finding a loop invariant x 0 y = 1 ; z = 0 ; while (z!= x) { z = z + 1 ; y = y * z ; } y = x! At the while statement: x y z z x 5 1 0 true 5 1 1 true 5 2 2 true 5 6 3 true 5 24 4 true 5 120 5 false Program Verification while-loops 366/434
Example: Finding a loop invariant x 0 y = 1 ; z = 0 ; while (z!= x) { z = z + 1 ; y = y * z ; } y = x! At the while statement: x y z z x 5 1 0 true 5 1 1 true 5 2 2 true 5 6 3 true 5 24 4 true 5 120 5 false From the trace and the postcondition, a candidate loop invariant is y = z! Why are y z or x 0 not useful? These do not involve the loop-termination condition Program Verification while-loops 366/434
Annotations Inside a while-loop 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 Program Verification while-loops 367/434
Example: annotations for partial-while Annotate by partial-while, with chosen invariant (y = z!) x 0 y = 1 ; z = 0 ; y = z! while (z!= x) { (y = z!) (z = x) [justification required] partial-while ( I B ) z = z + 1 ; y = y * z ; y = z! } y = z! z = x) y = x! [justification required] partial-while ( I B ) Program Verification while-loops 368/434
Example: annotations for partial-while Annotate assignment statements (bottom-up) x 0 1 = 0! y = 1 ; y = 0! z = 0 ; y = z! while (z!= x) { (y = z!) (z = x) y(z + 1) = (z + 1)! z = z + 1 ; yz = z! y = y * z ; y = z! } y = z! z = x) y = x! assignment assignment partial-while assignment assignment partial-while Program Verification while-loops 368/434
Example: annotations for partial-while Note the required implied conditions x 0 1 = 0! y = 1 ; y = 0! z = 0 ; y = z! while (z!= x) { (y = z!) (z = x) y(z + 1) = (z + 1)! z = z + 1 ; yz = z! y = y * z ; y = z! } y = z! z = x) y = x! implied (a) assignment assignment partial-while implied (b) assignment assignment partial-while implied (c) Program Verification while-loops 368/434
Example: implied conditions (a) and (c) Proof of implied (a): (x 0) (1 = 0!) 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 Program Verification while-loops 369/434
Example: implied condition (b) Proof of implied (b): ((y = z!) (z = x)) (z + 1) y = (z + 1)! 1 y = z! z 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 5 (z + 1) y = (z + 1)! EqTrans: 3, 4 Program Verification while-loops 370/434
Example 2 (Partial-while) Prove the following is satisfied under partial correctness n 0 a 0 s = 1 ; i = 0 ; while (i < n) { s = s * a ; i = i + 1 ; } s = a n Program Verification while-loops 371/434
Example 2 (Partial-while) Prove the following is satisfied under partial correctness n 0 a 0 s = 1 ; i = 0 ; while (i < n) { s = s * a ; i = i + 1 ; } s = a n Trace of the loop: a n i s 2 3 0 1 2 3 1 1 2 2 3 2 1 2 2 2 3 3 1 2 2 2 Program Verification while-loops 371/434
Example 2 (Partial-while) Prove the following is satisfied under partial correctness n 0 a 0 s = 1 ; i = 0 ; while (i < n) { s = s * a ; i = i + 1 ; } s = a n Trace of the loop: a n i s 2 3 0 1 2 3 1 1 2 2 3 2 1 2 2 2 3 3 1 2 2 2 Candidate for the loop invariant: s = a i Program Verification while-loops 371/434
Example 2: Testing the invariant Using s = a i as an invariant yields the annotations shown at right Next, we want to Push up for assignments Prove the implications But: implied (c) is false! We must use a different invariant n 0 a 0 s = 1 ; i = 0 ; s = a i while (i < n) { s = a i i < n s = s * a ; i = i + 1 ; s = a i } s = a i i n s = a n Program Verification while-loops 372/434 partial-while partial-while implied (c)
Example 2: Adjusted invariant Try a new invariant: s = a i i n Now the implied conditions are actually true, and the proof can succeed n 0 a 0 1 = a 0 0 n s = 1 ; s = a 0 0 n i = 0 ; s = a i i n while (i < n) { s = a i i n i < n s a = a i+1 i + 1 n s = s * a ; s = a i+1 i + 1 n i = i + 1 ; s = a i i n } s = a i i n i n s = a n Program Verification while-loops 373/434 implied (a) assignment assignment partial-while implied (b) assignment assignment partial-while implied (c)
Total Correctness (Termination) Total Correctness = Partial Correctness + Termination Only while-loops can be responsible for non-termination in our programming language (In general, recursion can also cause it) Proving termination: For each while-loop in the program, Identify an integer expression which is always non-negative and whose value decreases every time through the while-loop Program Verification while-loops 374/434
Example For Total Correctness The code below has a loop guard of z x, which is equivalent to x z 0 What happens to the value of x z during execution? x 0 y = 1 ; z = 0 ; while ( z!= x ) { z = z + 1 ; y = y * z ; } y = x! At start of loop: x z = x 0 Program Verification while-loops 375/434
Example For Total Correctness The code below has a loop guard of z x, which is equivalent to x z 0 What happens to the value of x z during execution? x 0 y = 1 ; z = 0 ; At start of loop: x z = x 0 while ( z!= x ) { z = z + 1 ; x z decreases by 1 y = y * z ; } y = x! Program Verification while-loops 375/434
Example For Total Correctness The code below has a loop guard of z x, which is equivalent to x z 0 What happens to the value of x z during execution? x 0 y = 1 ; z = 0 ; At start of loop: x z = x 0 while ( z!= x ) { z = z + 1 ; x z decreases by 1 y = y * z ; x z unchanged } y = x! Program Verification while-loops 375/434
Example For Total Correctness The code below has a loop guard of z x, which is equivalent to x z 0 What happens to the value of x z during execution? x 0 y = 1 ; z = 0 ; At start of loop: x z = x 0 while ( z!= x ) { z = z + 1 ; x z decreases by 1 y = y * z ; x z unchanged } y = x! Thus the value of x z will eventually reach 0 The loop then exits and the program terminates Program Verification while-loops 375/434
Proof of Total Correctness We chose an expression x z (called the variant) At the start of the loop, x z 0: Precondition: x 0 Assignment z 0 Each time through the loop: x doesn t change: no assignment to it z increases by 1, by assignment Thus x z decreases by 1 Thus the value of x z will eventually reach 0 When x z = 0, the guard z! = x ends the loop Program Verification while-loops 376/434
Arrays Program Verification Arrays 377/434
Assignment of Values of an Array Let A be an array of n integers: A[1], A[2],, A[n] Assignment may work as before: P [A[x]/v] v = A[x] ; P assignment But a complication can occur: A[y] = 0 A[x] = 1; A[y] = 0??? The conclusion is not valid if x = y A correct rule must account for possible changes to A[y], A[z+3], etc, when A[x] changes Program Verification Arrays 378/434
Assignment to a Whole Array Our solution: Treat an assignment to an array value A[e 1 ] = e 2 as an assignment of the whole array: A = A{e 1 e 2 } ; where the term A{e 1 e 2 } denotes an array identical to A except that the e th 1 element is changed to have the value e 2 Program Verification Arrays 379/434
Array Assignment: Definition and Examples Definition: A{i e} denotes the array with entries given by { e, if j = i A{i e}[j] = { A[j], if j i Examples: A{1 7}{2 14}[2] =?? A{1 7}{2 14}{3 21}[2] =?? A{1 7}{2 14}{3 21}[i] =?? Program Verification Arrays 380/434
The Array-Assignment Rule Array assignment: Q[A{e 1 e 2 }/A] A[e 1 ] = e 2 (Array assignment) Q where { e, if j = i A{i e}[j] = { A[j], if j i Program Verification Arrays 381/434
Example Prove the following is satisfied under partial correctness A[x] = x 0 A[y] = y 0 t = A[x] ; A[x] = A[y] ; A[y] = t ; A[x] = y 0 A[y] = x 0 We do assignments bottom-up, as always Program Verification Arrays 382/434
Example: push up assertions for assignments A[x] = x 0 A[y] = y 0 t = A[x] ; A[x] = A[y] ; A{y t}[x] = y 0 A{y t}[y] = x 0 A[y] = t ; A[x] = y 0 A[y] = x 0 array assignment Program Verification Arrays 383/434
Example: push up assertions for assignments A[x] = x 0 A[y] = y 0 t = A[x] ; A{x A[y]}{y t}[x] = y 0 A{x A[y]}{y t}[y] = x 0 A[x] = A[y] ; A{y t}[x] = y 0 A{y t}[y] = x 0 array assignment A[y] = t ; A[x] = y 0 A[y] = x 0 array assignment Program Verification Arrays 383/434
Example: push up assertions for assignments A[x] = x 0 A[y] = y 0 A{x A[y]}{y A[x]}[x] = y 0 A{x A[y]}{y A[x]}[y] = x 0 t = A[x] ; A{x A[y]}{y t}[x] = y 0 A{x A[y]}{y t}[y] = x 0 assignment A[x] = A[y] ; A{y t}[x] = y 0 A{y t}[y] = x 0 array assignment A[y] = t ; A[x] = y 0 A[y] = x 0 array assignment Program Verification Arrays 383/434
Example: push up assertions for assignments A[x] = x 0 A[y] = y 0 A{x A[y]}{y A[x]}[x] = y 0 A{x A[y]}{y A[x]}[y] = x 0 t = A[x] ; A{x A[y]}{y t}[x] = y 0 A{x A[y]}{y t}[y] = x 0 implied (a) assignment A[x] = A[y] ; A{y t}[x] = y 0 A{y t}[y] = x 0 array assignment A[y] = t ; A[x] = y 0 A[y] = x 0 array assignment Program Verification Arrays 383/434
Example: Proof of implied As implied (a), we need to prove the following Lemma: and A{x A[y]}{y A[x]}[x] = A[y] A{x A[y]}{y A[x]}[y] = A[x] Proof In the second equation, the index element is the assigned element For the first equation, we consider two cases If y x, the {y } is irrelevant, and the claim holds If y = x, the result on the left is A[x], which is also A[y] Program Verification Arrays 384/434
Example: Alternative proof For an alternative proof, use the definition of M{i e}[j], with A{x A[y]} as M, i = y and e = A[x]: { A[x], if y = j A{x A[y]}{y A[x]}[j] = { A{x A[y]}[j], if y j At index j = y, this is just A[x], as required In the case j = x, we get the required value A[y] (Why?) And, finally, if j x and j y, then A{x A[y]}{y A[x]}[j] = A[j], as we should have required Program Verification Arrays 385/434
Example: reversing an array Example: Given an array R with n elements, reverse the elements Algorithm: exchange R[j] with R[n + 1 j], for each 1 j n/2 A possible program is j = 1 ; while ( 2*j <= n ) { t = R[j] ; R[j] = R[n+1-j] ; R[n+1-j] = t ; j = j + 1 ; } Needed: a postcondition, and a loop invariant Program Verification Arrays and Loops, Together 386/434
Reversal code: conditions and an invariant Precondition: ( x ((1 x n) (R[x] = r x )))) Postcondition: ( x ((1 x n) (R[x] = r n+1 x ))) Invariant? When exchanging at position j? If x < j or x > n + 1 j, then R[x] and R[n + 1 x] have already been exchanged If j x n + 1 j, then no exchange has happened yet Thus let Inv (j) be the formula ( x (((1 x < j) (R[x] = r n+1 x R[n + 1 x] = r x )) ((j x n/2) (R[x] = r x R[n + 1 x] = r n+1 x )))) and Inv(j) = Inv (j) (1 j n) Program Verification Arrays and Loops, Together 387/434
Reversal: Annotations around the loop The annotations surrounding the while-loop: ((n 0) ( x ((1 x n) (R[x] = r x ))))) Inv(1) j = 1 ; Inv(j) while ( 2*j <= n ) { (Inv(j) (2j n)) Inv(j) } (Inv(j) (2j > n)) ( x ((1 x n) (R[x] = r n+1 x ))) implied (a) assignment partial-while (TBA) partial-while implied (b) Program Verification Arrays and Loops, Together 388/434
Reversal code: annotations inside the loop We must now handle the code inside the loop (Inv(j) 2j n) Inv(j + 1)[R /R], where R is 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) partial-while implied (c) Lemma j = j + 1 ; Inv(j) assignment Program Verification Arrays and Loops, Together 389/434
Proof of Implied Condition (c) Recall Inv (j): ( x (((1 x < j) (R[x] = r n+1 x R[n + 1 x] = r x )) ((j x n/2) (R[x] = r x R[n + 1 x] = r n+1 x )))) We need this to imply Inv (j + 1)[R /R], which is ( x (((1 x < j + 1) (R [x] = r n+1 x R [n + 1 x] = r x )) ((j + 1 x n/2) (R [x] = r x R [n + 1 x] = r n+1 x )))), which by the construction of R is equivalent to ( x (((1 x < j) (R[x] = r n+1 x R[n + 1 x] = r x )) (R [j] = r n+1 j ) (R [n + 1 j] = r j ) ((j + 1 x n/2) (R[x] = r x R[n + 1 x] = r n+1 x )))) Program Verification Arrays and Loops, Together 390/434
Example: Binary Search Program Verification Example: Binary Search 391/434
Binary Search Binary search is a very common technique, to find whether a given item exists in a sorted array Although the algorithm is simple in principle, it is easy to get the details wrong Hence verification is in order Inputs: Array A indexed from 1 to n; integer x Precondition: A is sorted: i j ((1 i < j n) (A[i] A[j])) Output values: boolean found; integer m Postcondition: Either found is true and A[m] = x, or found is false and x does not occur at any location of A (Also, A and x are unchanged; We simply won t write to either) Program Verification Example: Binary Search 392/434
Code: The outer loop i j ((1 i < j n) (A[i] A[j])) l = 1; u = n; found = false; I while ( l <= u and!found ) { I (l u found) m = (l+u) div 2; J if (A[m] = x) { Body omitted } I } I (l u found) (found A[m] = x) ( found k (A[k] = x)) partial-while if-then-else partial-while Program Verification Example: Binary Search 393/434
Code: the if-statement J if ( A[m] = x ) { J (A[m] = x) found = true; I } else if ( A[m] < x ) { J (A[m] = x) (A[m] < x) l = m+1; I } else { J (A[m] = x) (A[m] < x) u = m - 1; I } I if-then-else if-then-else if-then-else if-then-else Program Verification Example: Binary Search 394/434
In the loop, there are two cases: Invariant for Binary Search We have found the target, at position m We have not yet found the target; if it is present, it must lie beween A[l] and A[u] (inclusive) Expressed as a formula: (found A[m] = x) ( found i ((A[i] = x) (l i u))) It turns out that the above is more specific than necessary As the actual invariant, we shall use the formula I = (found A[m] = x) ( i ((A[i] = x) (l i u))) (Exercise: As you go through the proof, check what would happen if we used the first formula instead) Program Verification Example: Binary Search 395/434
Annotations for while i j ((1 i < j n) (A[i] A[j])) l = 1; u = n; found = false; (found A[m] = x) ( i ((A[i] = x) (l i u))) while ( l <= u &&!found ) { (found A[m] = x) ( i ((A[i] = x) (l i u))) (l u) found partialwhile i ((A[i] = x) (l i u)) found (l (l + u)/2 u) implied m = (l+u) div 2 ; i ((A[i] = x) (l i u)) found (l m u) assignment The last condition is the formula J : the precondition for the if-statement Program Verification Example: Binary Search 396/434
First Branch of the if-statement i ((A[i] = x) (l i u)) found (l m u) if ( A[m] = x ) { i ((A[i] = x) (l i u)) found (l m u) (A[m] = x) if-then-else (true A[m] = x) ( i ((A[i] = x) (l i u))) implied found = true; (found A[m] = x) ( i ((A[i] = x) (l i u))) assignment } The implication is trivial Program Verification Example: Binary Search 397/434
Second Branch of the if-statement i ((A[i] = x) (l i u)) found (l m u) (A[m] = x) if ( A[m] < x ) { i ((A[i] = x) (l i u)) found (l m u) (A[m] = x) (A[m] < x) if-then-else (found A[m] = x) ( i ((A[i] = x) (m + 1 i u))) implied l = m + 1; (found A[m] = x) ( i ((A[i] = x) (l i u))) assignment } To justify the implication, show that A[j] < x whenever l j m This follows from the condition that A is sorted, together with A[m] < x Program Verification Example: Binary Search 398/434
An Extended Example: Sorting Program Verification Extended Example: Sorting 399/434
Postcondition for Sorting Suppose the code C sort is intended to sort n elements of array A Give pre- and postconditions for C sort, using a predicate sorted(a, n) which is true iff A[1] A[2] A[n] First Attempt n 1 C sort sorted(a, n) Program Verification Extended Example: Sorting 400/434
Postcondition for Sorting Suppose the code C sort is intended to sort n elements of array A Give pre- and postconditions for C sort, using a predicate sorted(a, n) which is true iff A[1] A[2] A[n] First Attempt n 1 C sort sorted(a, n) n 1 for i = 1 to n { A[i] = 0 ; } sorted(a, n) Program Verification Extended Example: Sorting 400/434
Postcondition for Sorting, II Let permutation(a, A, n) mean that array A[1], A[2],, A[n] is a permutation of array A [1], A [2],, A [n] (A will be a logical variable, not a program variable) Second Attempt n 1 A = A C sort sorted(a, n) permutation(a, A, n) Program Verification Extended Example: Sorting 401/434
Postcondition for Sorting, II Let permutation(a, A, n) mean that array A[1], A[2],, A[n] is a permutation of array A [1], A [2],, A [n] (A will be a logical variable, not a program variable) Second Attempt n 1 A = A n 1 A = A C sort some algorithm on A ; n = 1 ; sorted(a, n) permutation(a, A, n) sorted(a, n) permutation(a, A, n) Program Verification Extended Example: Sorting 401/434
Postcondition for Sorting, III Final Attempt (Correct) n 1 n = n 0 A = A C sort sorted(a, n 0 ) permutation(a, A, n 0 ) Program Verification Extended Example: Sorting 402/434
Algorithms for Sorting We shall briefly describe two algorithms for sorting Insertion Sort Quicksort Each has an inner loop which we will then consider Program Verification Extended Example: Sorting 403/434
Overview of Insertion Sort Input: Array A, with indices A[1] A[n] Plan: insert each element, in turn, into the array of previously sorted elements Algorithm: At the start, A[1] is sorted (as an array of length 1) For each k from 2 to n Assume the array is sorted up to position k 1 Insert A[k] into its correct place among A[1] A[k 1]: Compare it with A[k 1], A[k 2], etc, until its proper place is reached Program Verification Extended Example: Sorting 404/434
Insertion Sort: Inserting one element Possible code for the insertion loop: 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 ; } For correctness of this code, see the current assignment Program Verification Extended Example: Sorting 405/434
Overview of Quicksort Quicksort is an ingenious algorithm, with many variations Sometimes it works very well, sometimes not so well We shall ignore most of those issues, however, and just look at a central step of the algorithm Idea: Select one element of the array, called the pivot (Which one? A complicated issue YMMV) Separate the array into two parts: those less than or equal to the pivot, and those greater than the pivot Recursively sort each of the two parts Here, we shall focus on the middle step: partition the array according to the chosen pivot Program Verification Extended Example: Sorting 406/434
Partitioning an Array Given: Array X of length n, and a pivot p Goal: Put the small elements (those less than or equal to p) to the left part of the array, and the large elements (those greater than p) to the right Plan: Scan the array Upon finding a large element appearing before a small element, exchange the two Requisite: Do all exchanges in a single scan (Linear time!) Program Verification Extended Example: Sorting 407/434
Partition: The Algorithm Idea: keep the array elements in three sections of the array Those known to be small (less than or equal to the pivot) Those known to be large (larger than the pivot) Unknown elements (not yet examined) We mark the separations with pointers (indices) a and b, as shown small large unknown a b One step of the algorithm: If X[b] is small, swap it with X[a] and increment a Increment b Program Verification Extended Example: Sorting 408/434
Code and Pre- and Postconditions n 1 a = 1 ; while ( a < n && X[a] <= p ) { a = a + 1 ; } b = a + 1 ; while ( b <= n ) { if ( X[b] <= p ) { } t = X[b] ; X[b] = X[a] ; X[a] = t ; a = a + 1 ; } b = b + 1 ; // Initialize // Swap if needed z ((1 z n + 1) (X[1z) p) (X[zn] > p)) Notation: X[jk) means X[i], for each j i < k X[jk] means X[i], for each j i k Program Verification Extended Example: Sorting 409/434
Annotation: First loop Desired postcondition for the first loop: (X[1a) p) ((a n) (X[a] > p)) Annotation for the while, and pushing up, yields (X[11) p) a = 1 ; (X[1a) p) while ( a < n && X[a] <= p ) { (X[1a) p) ((a < n) (X[a] p)) (X[1a + 1) p) a = a + 1 ; (X[1a) p) } (X[1a) p) ((a n) (X[a] > p)) implied assignment partial-while implied assignment partial-while Program Verification Extended Example: Sorting 410/434
The Second while-loop For the second while-loop, a good candidate for the invariant is (X[1a) p) (X[ab) > p) Let s see if this works Colour key: Greenish: Blueish: Either, reddened: Reddish: lower part of the array upper part of the array result of a substitution condition from guards Program Verification Extended Example: Sorting 411/434
Inside the while-loop And the loop guard to the invariant at the start of the loop Then pushing up through the assignment and if yields (X[1a) p) (X[ab) > p) (b n) if (X[b] <= p ) { (X[1a) p) (X[ab) > p) (b n) X[b] p if-then } (X[1a) p) (X[ab + 1) > p) b = b + 1 (X[1a) p) (X[ab) > p) if-then + implied assignment Program Verification Extended Example: Sorting 412/434
Inside the if-statement Push up for the assignments inside the if: (X[1a) p) (X[ab) > p) (b n) X[b] p if-then ((X[1a) p)) (X[a] > p) (X[a + 1b) > p) X[b] p implied t = X[b] ; X[b] = X[a] ; X[a] = t ; ((X[1a) p)) (X[a] p) (X[a + 1b) > p) X[b] > p swap (X[1a + 1) p) (X[a + 1b + 1) > p) implied a = a + 1 ; (X[1a) p) (X[ab + 1) > p) assignment (The extra implied just makes the swap clearer) Program Verification Extended Example: Sorting 413/434
Putting It All Together The annotation thus far works fine But there is a glitch Between the loops, we have (X[1a) p) ((a n) (X[a] > p)) (X[1a) p) (X[aa + 1) > p) b = a + 1 ; (X[1a) p) (X[ab) > p) partial-while implied assignment But the implied fails in the case that the first loop ended with a = n we can t deduce X[a] > p Solution: either add an extra test to the code, or add 1 a n to the first invariant, and modify the second to (X[1a) p) ((a = n) (X[ab) > p)) Program Verification Extended Example: Sorting 414/434
Second while-loop: Full annotation (1 a n) (X[1a) p) ((a n) (X[a] > p)) (X[1a) p) ((a = n) (X[aa + 1) > p)) b = a + 1 ; (X[1a) p) ((a = n) (X[ab) > p)) while ( b <= n ) { (X[1a) p) ((a = n) (X[ab) > p)) (b n) (X[1a) p) (X[ab) > p) (b n) if (X[b] <= p ) { } (X[1a) p) (X[ab) > p) (X[1a) p) ((a = n) (X[ab) > p)) } (X[1a) p) ((a = n) (X[ab) > p)) (b > n) z ((1 z n + 1) (X[1z) p) (X[zn] > p)) partial-while implied assignment partial-while implied if-then implied partial-while implied Implied proofs left to you Program Verification Extended Example: Sorting 415/434