CS 326 Formal Reasoning: Loops Program Verification Example In

CS 326 Formal Reasoning: Loops Program Verification Example In

Program Verification • Weakest Preconditions – most permissive assumptions to ensure postcondition is CS 326 satisfied. Formal Reasoning: Loops • Verifying functional correctness Stephen Freund // requires P // ensures Q Prove: method test(...) { P => wp(S, Q) S } 1 Example in Dafny Loops method Test(x : int, y : int) returns (c :Point?) { n ≥ 0 } requires P; i = 0; ensures c != null; { y = 0; ∧ ∧ c := null; { P: n ≥ 0 i = 0 y = 0 } var z; while(i != n) { if y < 0 { i = i+1; z := -2 * y; Prove: P => wp(..., c != null) y = y+i; } else { } z := x; { Q: y = sum(1,n) } } if z > 10 { c := new Point(z,y); } } 1 {P} Loops Loops in Hoare Logic while(B) { { n ≥ 0 } S { n ≥ 0 } i = 0; } i = 0; y = 0; {Q} y = 0; { P: n ≥ 0 ∧ i = 0 ∧ y = 0 } { P: n ≥0 ∧ i = 0 ∧ y = 0 } { invariant: y = sum(1,i) } Pick invariant I such that: { invariant I : ... } while(i != n) { while(i != n) { { y = sum(1,i) ∧ i != n } 1. P => I i = i+1; i = i+1; 2. {I ∧ B}S{I} { y = sum(1,i-1) } y = y+i; 3. (I ∧ !B) => Q y = y+i; } { y = sum(1,i-1) + i = sum(1,i) } { Q: y = sum(1,n) } } { y = sum(1,i) ∧ i = n } => { Q: y = sum(1,n) } {P} {P} Version 2 while(B) { Version 2 while(B) { { n ≥ 0 } S { n ≥ 0 } S i = 1; } i = 1; } y = 0; {Q} y = 0; {Q} { P: n ≥ 0 ∧ i = 1 ∧ y = 0 } { P: n ≥ 0 ∧ i = 1 ∧ y = 0 } { invariant: y = sum(1,i) } { invariant: y = sum(1,i-1) } while(i != n) { Pick invariant I such that: while(i != n) { Pick invariant I such that: { y = sum(1,i) ∧ i != n } 1. P => I { y = sum(1,i-1) ∧ i != n } 1. P => I i = i+1; 2. {I ∧ B}S{I} i = i+1; 2. {I ∧ B}S{I} { y = sum(1,i-1) } { y = sum(1,i-2) } 3. (I ∧ !B) => Q 3. (I ∧ !B) => Q y = y+i; y = y+i; { y = sum(1,i-1) + i = sum(1,i) } { y = sum(1,i-2) + i = sum(1,i-1) } } } { y = sum(1,i) ∧ i = n } => { y = sum(1,i-1) ∧ i = n } => { Q: y = sum(1,n) } { Q: y = sum(1,n) } 2 {P} {P} Version 3 while(B) { Version 4: Self Check while(B) { { n ≥ 0 } S { n ≥ 0 } S i = 1; } i = 1; } y = 0; {Q} y = 0; {Q} { P: n ≥ 0 ∧ i = 1 ∧ y = 0 } { P: n ≥ 0 ∧ i = 1 ∧ y = 0 } { invariant: y = sum(1,i-1) } { invariant: y = sum(1,i-1) } while(i != n + 1) { Pick invariant I such that: while(i != n + 1) { Pick invariant I such that: { y = sum(1,i-1) ∧ i != n + 1 } 1. P => I { y = sum(1,i-1) ∧ i != n } 1. P => I i = i+1; 2. {I ∧ B}S{I} y = y+i; 2. {I ∧ B}S{I} { y = sum(1,i-2) } { y = sum(1,i-2) } 3. (I ∧ !B) => Q 3. (I ∧ !B) => Q y = y+i; i = i+1; { y = sum(1,i-2) + i = sum(1,i-1) } This line is wr ong! { y = sum(1,i-2) + i = sum(1,i-1) } } To f ix , we need to flip the two } { y = sum(1,i-1) ∧ i = n + 1 } => statements in the loop –see { y = sum(1,i-1) ∧ i = n } => { Q: y = sum(1,n) } Version 4 next. { Q: y = sum(1,n) } Too Strong? Too Weak? Just Right? Methodology • Loop invariant is too strong: 1. Decide on the invariant first – may not hold on entry. – What describes the milestone of each iteration? – may not be preserved by body 2. Write a loop body to maintain the invariant • Loop invariant is too weak: 3. Write the loop test so "false implies – can't prove what you want after the loop postcondition" • No automatic procedure for conjuring a loop- 4. Write initialization code to establish invariant invariant... – Think about invariant while writing the code – If proof doesn’t work, invariant or code or both may need work 3 Methodology Example Set max to hold the largest value in array items Set max to hold the largest value in array items 1. Decide loop invariant first: 2. Write a loop body to maintain the invariant // I: max holds largest value in items[0..k-1] max holds largest value in range 0..k-1 of items while( ) { // I holds if(max < items[k]) { max = items[k]; // breaks I temporarily } // max holds largest value in items[0..k] k = k+1; // I holds again } Example Example Set max to hold the largest value in array items Set max to hold the largest value in array items 3. Write the loop test so false-implies-postcondition 4. Write initialization code to establish invariant // I: max holds largest value in items[0..k-1] k = 1; max = items[0]; while(k != items.count) { // I: max holds largest value in items[0..k-1] // I holds while(k != items.count) { if(max < items[k]) { // I holds max = items[k]; // breaks I temporarily if(max < items[k]) { } max = items[k]; // breaks I temporarily // max holds largest value in items[0..k] } k = k+1; // I holds again // max holds largest value in items[0..k] } k = k+1; // I holds again // max holds largest value in items[0..items.count-1] } // max holds largest value in items[0..items.count-1] 4 Example Quotient and Remainder Set q to be the quotient of x/y and r to be the remainder Edge case! // pre: items.count > 0 {Pre: x > 0 ∧ y > 0} k = 1; max = items[0]; q = 0; r = x; // I: max holds largest value in items[0..k-1] ∧ while(k != items.count) { {Invariant: q*y + r = x 0 ≤ r } // I holds while (y <= r) { if(max < items[k]) { q = q + 1; max = items[k]; // breaks I temporarily } r = r – y; // max holds largest value in items[0..k] } k = k+1; // I holds again ∧ } {Post: x = q*y + r 0 ≤ r < y } // max holds largest value in items[0..items.count-1] Dutch National Flag (classic) Pre- and Post-conditions Given an array of red, white, and blue pebbles, Precondition: Any miX of red, white, and blue sort the array so the red pebbles are at the front, MiXed colors: red, white, blue white are in the middle, and blue are at the end – [Can only swap pebbles, not count them...] Postcondition: – Red, then white, then blue – Number of each color same as in original array Red White Blue Edsgar Dijkstra 5 Red White MiXed Blue Some Potential Invariants More Precise i j k • Precondition: a contains red,white,blue • Postcondition: Red White Blue MiXed 0 <= i <= j < a.count ∧ a[0..i-1] is red Red White MiXed Blue ∧ a[i..j-1] is white ∧ a[j..a.count-1] is blue Red MiXed White Blue • Invariant: 0 <= i <= j <= k <= a.count MiXed Red White Blue ∧ a[0..i-1] is red ∧ a[i..j-1] is white ∧ a[k..a.count-1] is blue The Code Termination i = 0; Red White MiXed Blue j = 0; k = a.count; i j k • Quotient-and-remainder while (j!=k) { – r (starts positive, gets strictly smaller) if(a[j] == White) { j = j+1; • Binary search } else if (a[j] == Blue) { – size of range still considered swap(a,j,k-1); k = k-1; • Dutch-national-flag } else { // a[j] == Red – size of range not yet partitioned (k-j) swap(a,i,j) i = i+1; • Search in a linked list j = j+1; – length of list not yet considered } } 6 From last time: Recap • weakest == most { P } permissive Point c = null; • strongest == most int z; restrictive if (y < 0) { z = -2*y; } else { What is the weakest z = x; precondition P that ensures postcondition Q? } if (z > 10) { c = new Point(z,y); } { Q: c != null } When to use proofs for loops Termination • Overkill for “obvious” loops: • Two kinds of loops – for (name in friends) {…} – Those we want to always terminate (normal case) – Those that may conceptually run forever (e.g., web-server) • Use logical reasoning: • – So, proving a loop correct usually also requires proving When intermediate state (invariant) is unclear or edge cases termination are tricky or you need inspiration, etc. – We haven’t been proving this: might just preserve invariant – As an intellectual debugging tool forever without test ever becoming false • What exactly is the invariant? – Our Hoare triples say if loop terminates, postcondition holds • Is it satisfied on every iteration? • How to prove termination (variants eXist): • Are you sure? Write code to check? – Map state to a natural number somehow (just “in the proof”) • Did you check all the edge cases? – Prove the natural number goes down on every iteration • Are there preconditions you did not make eXplicit? – Prove test is false by the time natural number gets to 0 7 Why Reason About Programs? Our Approach • Essential complement to testing • Hoare Logic, an approach developed in the 70’s – Testing shows specific result for a specific input • Rarely use Hoare logic explicitly – often overkill for simple code • Proof shows general result for all inputs – shines for developing code with subtle invariants – Can only prove correct code, proving uncovers bugs – Provides deeper understanding of why code is correct • Ideal for introducing program reasoning foundations • Precisely stating assumptions is essence of spec – How does logic “talk about” program states? – “Callers must not pass null as an argument” – – “Callee will always return an unaliased object” How can program eXecution “change what’s true”? – What do “weaker” and “stronger” mean in logic? Weakest Precondition wp(X = e, Q) Q[X := e] wp(S1;S2, Q) wp(S1,wp(S2,Q)) wp(if b S1 else S2, Q) (b ∧ wp(S1,Q)) ∨ (!b ∧ wp(S2,Q)) 8.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    8 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us