500 likes | 665 Views
Program Proving Notes. Ellen L. Walker. Formal Specification & Proof of Programs (Verification). Formally proving that a program satisfies a formal specification Alternative to testing to determine whether a program works as specified. One means of specifying program semantics. Definitions.
E N D
Program Proving Notes Ellen L. Walker
Formal Specification & Proof of Programs (Verification) • Formally proving that a program satisfies a formal specification • Alternative to testing to determine whether a program works as specified. • One means of specifying program semantics
Definitions • Specification— description of what a program should do, usually in English. • Formal specification— a specification using formal mathematical notation. Mathematical notation makes the specification more concise & more precise. • Proving (verifying) a program— given a program and a formal specification, use formal proof techniques (e.g. induction) to prove that the program behavior fits the specification. • Specification of a programming language (semantics)— formal specification for each statement in the language.
Formally Proving a Program • Given: • formal specification of program • specification of programming language • a program in the language • Prove: • the program executes according to specifications
Conditions in Specification • Preconditions • Must hold before the program executes • Postconditions • Must hold after the program executes A formal specification always has both preconditions and postconditions
Notation • P { S } Q • P is the precondition • S is the program (or statement) • Q is the postcondition • P and Q are written in logic • S is written in the programming language (or pseudocode)
Specification as Logic • (P and execution of S) -> Q • If this expression is always true we say the specification is valid
Example • x > 0 { x = -x } x < 0 • Precondition: x>0 • Postcondition: x<0 • Program: x = -x • This specification is valid • When the precondition holds before the program, the postcondition will always hold after the program.
Special Cases • P { S } true • Valid for all programs and preconditions • false { S } Q • Valid for all programs and postconditions • When the precondition is false before program runs, the specification is valid no matter what!
Many Choices for P and Q • true { y = x + 1} y > x • x > 0 { y = x + 1} y > x • x = 1 { y = x + 1} y > x • x = 1 { y = x + 1} true • x = 1 {y = x + 1} y > x • x = 1 {y = x + 1} y > 1 • x = 1 {y = x + 1} y = 2
Logical Implication • P->W (“P implies W” or “If P then W”)
Mathematical examples • (a>b) -> (b < a) true • (a≥b) -> (a > b) false • (a>b) -> (a ≥ b) true • (a>b) -> (a > b+1) false • (a>b) -> (a ≥ b+1) false • (a>b) and a and b are integers -> (a≥b+1) true
Rules of Implication • Shorthand: “a->b” means “a->b is true” • (A and B) -> A • (A and B) -> B • A -> (A or B) • B -> (A or B) • (A->B) is equivalent to (not B -> not A)
Strength of Conditions • If P1 and P2 are conditions, and P1 -> P2, • Then P1 is stronger than P2and P2 is weaker than P1 • Intuition: stronger conditions are more specific, have fewer “possibilities”
Strength of Conditions (continued) • The strongest possible condition is false • False -> Q for all Q • The weakest possible condition is true • P -> True for all P • Not all conditions are comparable • (y > 1) is not comparable to (x > 0) • (y > 5) is not comparable to (y < 8) • No implication either way
Weakest Precondition • Many choices for Precondition • true { y = x + 1} y > x • x > 0 { y = x + 1} y > x • x = 1 { y = x + 1} y > x • Choose the weakest for best specification • Avoids “unnecessary” specification
Why Weakest Precondition? • Suppose P and W are preconditions and P->W (W is weaker) • Given W { S } Q and P true before the program begins • Because P->W, W is also true before the program begins • Therefore P { S } Q • “W is the precondition that implies all other preconditions that allow S to run and guarantee Q as a postcondition” • Notation: W = wp(S, Q)
Proving a Program Specification Goal: prove P { S } Q • Find wp(S,Q) • Prove that P -> wp(S, Q) Work backwards from postcondition to precondition
Example • Prove k>0 {x = 1/k } xk=1 • wp(x=1/k,xk=1) is k≠0 • (k>0) -> (k≠0) for all k • Therefore, our specification is true.
More Examples • Prove x = 1 {x = 1/x} x > 0 • wp (x = 1/x, x > 0) is 1/x > 0, or x > 0 • Since 1>0, x=1 implies x > 0 • Therefore, the specification x =1 {x = 1/x} x > 0 is true. • Prove x ≠ 0 {x = x + 1} x > 0 • wp (x= x + 1, x > 0) is x' + 1 > 0 or x' > –1 • x ≠ 0 doesn't necessarily imply x > –1 (consider x = –5) • Therefore, the specification x ≠ 0 {x = x + 1} x > 0 is false
Programming Language Semantics • Language consists of Statements • Complex statements derived from simpler statements and control structures • Conditionals (IF) • Loops (WHILE)
A Small Language • Empty statement (skip) • Assignment statement (x=y) • Sequence of statements ( { S1 S2 } ) • Conditional ( if (C) S1 else S2 ) • Loop ( while (C) S )
Specifying Language Semantics • For each statement, determine the wp of the statement • Statement wp depends on its parts • Using conditions (C) directly • Using wp of subordinate statements (S)
Semantics of skip • The empty statement has no effect • Therefore wp(skip, Q) is Q • Example: wp(skip, x<0) is x<0
Semantics of Assignment • Given x = E (where E is an expression) • Two cases: • Postcondition does not contain x • Wp(x=E,Q) = Q because Q is unaffected • Postcondition does contain x • Consider Q as a function of x • Wp(x=E, Q(x)) = Q(E) • To be careful, we must add “and E is defined” to avoid cases such as x = 1/0
Assignment Examples • Wp (x=y, y>5) is y>5 • Q does not contain x • Wp (x=y, x<2) is y<2 • Q does contain x, so substitute y for x • Wp (x = x+1, x>4) is x’>3 • Use x’ as the “before” value of x
Assignment vs. Equality Test • Be careful • x=0 {x=1} x=1
Semantics of a Sequence • Given P {S1} R and R {S2} Q, we can write P { {S1 S2} } Q • Therefore • Wp({S1 S2}, Q) = wp(S1, wp(S2, Q)) • Find wp of the second statement and the postcondition (R, above) • Then find wp of the first statement with that wp (R) as the postcondition
Examples • wp ({x=y; x= 1/x;}, x>0) is wp(x=y, wp(x=1/x, x>0)) iswp(x=y, 1/x > 0) is wp(x=y, x>0) isy > 0 • wp({x = 2*t; skip;}. x>5) iswp(x=2*t; wp(skip, x>5)) iswp(x=2*t, x>5) is2t > 5 is t > 2.5
One More Example • true {x = 5; y = 2; x = x*y} x=10
Semantics of IF • The conditional with test T and statements S1 and S2 is • if (T) S1 else S2 • When there is no “else, write: if (T) S1 else skip • Wp(if (T) S1 else S2) is (T and wp(S1,Q)) or ((not T) and wp(S2,Q)) • If T is true, use S1’s precondition • If T is false, use S2’s precondition • Equivalently,(T-> wp(S1,Q)) and ((not T)-> wp(S2,Q))
Proving a Loop • Two things to prove • If the loop terminates, the postcondition is true • The loop terminates • Proving only the postcondition is called weak correctness
Weak Correctness Example • True {while true x=1} x=1 • Weakly correct • If the loop ever terminated, x would be 1 • Not strongly correct • But the loop will never terminate
Semantics of WHILE • Treat as a “repeated if”, where B must be true the last time • Define Pk = wp(loop executes k times, Q) • wp(while (B) S, Q) • P0 = Not B and Q • P1 = B and wp(S, P0) • P2 = B and wp(S, P1) • Pk = B and wp(S, Pk-1) • wp(while (B) S, Q) = P0 or P1 or P2 or… Pk
How to Solve the Infinite OR • Direct approach • Use mathematics to solve the infinite series • Nice if it works, but you have to see the pattern • Indirect approach • Prove weak correctness and termination separately • Use “loop invariant”
Example: Direct Proof • What is wp(while (i<n) i=i+1, i=n) ? • H0 : not B and Q • not(i<n) and i=n • i=n • H1: B and wp(S, H0) • i<n and wp(i=i+1,i=n) • i<n and i+1=n • i+1=n
Direct Proof, continued • H2: B and wp(S,H1) • i<n and wp(i=i+1,i+1=n) • i+2=n • Hk: B and wp(S,Hk-1) • i<n and wp(i=i+1,i+k-1=n) • i+k=n • H0 or H1 or H2 or H3 or … • i=n or i+1=n or i+2=n or … i+k=n … • The above is equivalent to writing i≤n
Loop Invariants (Indirect method) • A loop invariant is any statement that is true every time a loop executes. • For example, consider the fragment: i = 1; x = 1; while(i < n ) { x = x * i; i = i + 1; } • One invariants is: i<n (or the loop ends)
A Loop has Many Invariants • 3 different invariants for the example loop: • i < n (because the loop will terminate if i ≥ n) • true (an invariant of every loop) • x = (i – 1)! (because x started at 1 and has been multiplied by 1, 2, 3 ... i • This last invariant is most useful: it tells what the loop does.
Using Loop Invariants to Prove Weak Correctness • Prove P { while B S} Q 1. Invariant is true after each time S runs B and inv {S} inv • When the loop ends, Q is true (Not B and inv) -> Q • Invariant is true before the loop P -> inv
Example Loop i = 1 and x = 1 and n > 0 //pre { while( i < n ) { x = x * i; i = i + 1; } } x = (n – 1)! //post • Prove, using inv: 0< i ≤ n and x = (i –1)!
Step 1 • B and inv {S} inv • B and inv is: (i<n) and 0< i ≤ n and x = (i –1)! , or 0<i<n and x=(i-1)! • Wp(S, inv) is: Wp((x=x*i, i=i+1), 0<i≤n and x=(i-1)!) = Wp(x=x*i, wp(i=i+1, 0<i ≤ n and x=(i-1)!)) = Wp(x=x*i, 0<i+1 ≤ n and x=(i!)) 0<i+1 ≤ n and x*i = i! -1<i ≤ n-1 and x = (i-1)! (since i is integer, we know that -1< i < n) • B and inv -> wp(s, inv), so step 1 is complete
Step 2 • Not B and inv -> Q (i>= n) and (0< i ≤ n and x = (i –1)! ) is i = n and x = (i-1)! x = n-1! • The above expression is Q, so Step 2 is complete
Step 3 • P -> inv • P is: i=1 and x=1 and n>0 • Since n>0 and i=1, 0<I ≤ n • We define 0! = 1. Since x=1 and i=1, x=(i-1)! • Both parts of the invariant are proven, so Step 3 is complete
Finding the Invariant • Invariant is an approximation to the weakest precondition • Find it by working the loop body backwards, treating inv as a function with loop variables as parameters • Wp(inv(params), S) = B and inv(params) • Your first guess is often too weak (it’s an invariant but won’t prove the loop)
Example Find an invariant for the loop while (i < n) { i = i + 1; x = x * i; } Note: the invariant also “explains” the loop
Proving Termination • Somehow, we need to make an argument that: • The loop ends when B becomes false • Each iteration gets us “closer” to B becoming false • Formally, this is done using a “well-founded set”
Well-Founded Set • An ordered set with a “bottom element” • Any decreasing sequence in the set must reach the “bottom element” with a finite number of elements • Examples: • [0-99] • Non-negative integers • Letters of the alphabet (bottom is “a”)
Proving Termination using WFS • Find a well-founded set such that: • Every loop execution generates an element of the set (e.g. value of n-I) • If the bottom element is reached, the loop terminates (e.g. n-I becomes 0 when I=n) • The sequence of values generated through multiple iterations of the loop is decreasing (e.g. since I gets bigger, n-I gets smaller)
Summary • Axiomatic semantics allows any program in the language to be proven correct • In the specification of a language, the weakest precondition for each statement type must be defined • Loops can be proven directly using an OR of weakest preconditions, or indirectly using an invariant and a separate proof of termination