Software Quality Assurance

Similar documents
Lecture 5 - Axiomatic semantics

Lectures 20, 21: Axiomatic Semantics

Hoare Logic. COMP2600 Formal Methods for Software Engineering. Rajeev Goré

Programming Languages Third Edition

6. Hoare Logic and Weakest Preconditions

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Symbolic Execution and Proof of Properties

Introduction to Axiomatic Semantics

Hoare Logic: Proving Programs Correct

The Rule of Constancy(Derived Frame Rule)

An Annotated Language

Lecture 1 Contracts : Principles of Imperative Computation (Fall 2018) Frank Pfenning

Chapter 3. Describing Syntax and Semantics ISBN

AXIOMS OF AN IMPERATIVE LANGUAGE PARTIAL CORRECTNESS WEAK AND STRONG CONDITIONS. THE AXIOM FOR nop

CMSC 330: Organization of Programming Languages

Propositional Logic Formal Syntax and Semantics. Computability and Logic

Formal Methods. CITS5501 Software Testing and Quality Assurance

Semantics. There is no single widely acceptable notation or formalism for describing semantics Operational Semantics

Lecture 1 Contracts. 1 A Mysterious Program : Principles of Imperative Computation (Spring 2018) Frank Pfenning

Hoare logic. A proof system for separation logic. Introduction. Separation logic

AXIOMS FOR THE INTEGERS

Hardware versus software

(a) (4 pts) Prove that if a and b are rational, then ab is rational. Since a and b are rational they can be written as the ratio of integers a 1

Program Verification. Program Verification 307/434

Lecture Notes on Contracts

Hoare triples. Floyd-Hoare Logic, Separation Logic

Reasoning about programs

Last time. Reasoning about programs. Coming up. Project Final Presentations. This Thursday, Nov 30: 4 th in-class exercise

Abstract Interpretation

Chapter 3 (part 3) Describing Syntax and Semantics

Chapter 3. Describing Syntax and Semantics

This is already grossly inconvenient in present formalisms. Why do we want to make this convenient? GENERAL GOALS

Outline. Introduction. 2 Proof of Correctness. 3 Final Notes. Precondition P 1 : Inputs include

3.7 Denotational Semantics

Note that in this definition, n + m denotes the syntactic expression with three symbols n, +, and m, not to the number that is the sum of n and m.

CS 125 Section #4 RAMs and TMs 9/27/16

Introduction to Axiomatic Semantics (1/2)

One of the most important areas where quantifier logic is used is formal specification of computer programs.

CS2104 Prog. Lang. Concepts

Reasoning About Imperative Programs. COS 441 Slides 10

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.

Part II. Hoare Logic and Program Verification. Why specify programs? Specification and Verification. Code Verification. Why verify programs?

! Use of formal notations. ! in software system descriptions. ! for a broad range of effects. ! and varying levels of use. !

Introduction to Axiomatic Semantics (1/2)

CITS5501 Software Testing and Quality Assurance Formal methods

Induction and Semantics in Dafny

p x i 1 i n x, y, z = 2 x 3 y 5 z

Theorem proving. PVS theorem prover. Hoare style verification PVS. More on embeddings. What if. Abhik Roychoudhury CS 6214

COMP 507: Computer-Aided Program Design

P1 Engineering Computation

Specification and Verification I

LECTURE 16. Functional Programming

Chapter 3. Semantics. Topics. Introduction. Introduction. Introduction. Introduction

Propositional Logic. Part I

Main Goal. Language-independent program verification framework. Derive program properties from operational semantics

The Formal Semantics of Programming Languages An Introduction. Glynn Winskel. The MIT Press Cambridge, Massachusetts London, England

Fall 2018 Lecture 1

Lecture Notes on Ints

CS 161 Computer Security

Overview. CS389L: Automated Logical Reasoning. Lecture 6: First Order Logic Syntax and Semantics. Constants in First-Order Logic.

Definition: A context-free grammar (CFG) is a 4- tuple. variables = nonterminals, terminals, rules = productions,,

15-819M: Data, Code, Decisions

Intermediate representations IR #1: CPS/L 3. Code example. Advanced Compiler Construction Michel Schinz

Fundamental Concepts. Chapter 1

COSC252: Programming Languages: Semantic Specification. Jeremy Bolton, PhD Adjunct Professor

Functional Programming Languages (FPL)

COS 320. Compiling Techniques

Contents. Chapter 1 SPECIFYING SYNTAX 1

Chapter 1. Introduction

Chapter 3. Describing Syntax and Semantics ISBN

Chapter 3. Describing Syntax and Semantics

Logic and Computation Lecture 20 CSU 290 Spring 2009 (Pucella) Thursday, Mar 12, 2009

Lecture Notes: Hoare Logic

Mathematical Induction

6.001 Notes: Section 6.1

Computation Club: Gödel s theorem

Diagonalization. The cardinality of a finite set is easy to grasp: {1,3,4} = 3. But what about infinite sets?

Denotational Semantics of a Simple Imperative Language Using Intensional Logic

Intro to semantics; Small-step semantics Lecture 1 Tuesday, January 29, 2013

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

Program Verification. Aarti Gupta

Recursion. Lars-Henrik Eriksson. Functional Programming 1. Based on a presentation by Tjark Weber and notes by Sven-Olof Nyström

Handout 9: Imperative Programs and State

Handout 10: Imperative programs and the Lambda Calculus

Summary of Course Coverage

SOFTWARE ENGINEERING DESIGN I

Formal Syntax and Semantics of Programming Languages

Recursively Enumerable Languages, Turing Machines, and Decidability

Deriving a Slicing Algorithm via FermaT Transformations

ELEMENTARY NUMBER THEORY AND METHODS OF PROOF

STABILITY AND PARADOX IN ALGORITHMIC LOGIC

axiomatic semantics involving logical rules for deriving relations between preconditions and postconditions.

The story so far. Elements of Programming Languages. Pairs in various languages. Pairs

A CRASH COURSE IN SEMANTICS

Lecture 6: Arithmetic and Threshold Circuits

ELEMENTARY NUMBER THEORY AND METHODS OF PROOF

Shared Variables and Interference

CS 242. Fundamentals. Reading: See last slide

Typing Control. Chapter Conditionals

Software Engineering Lecture Notes

Transcription:

Software Quality Assurance Every week we see new examples of: computer systems error/failure Here are some examples, taken from different industries

Airport chaos after computer crash By Vanessa Allen, PA News 17 May 2002 Air passengers faced travel chaos today after a software problem at Britain's air traffic system triggered mass delays and cancellations. British Airways cancelled 14 flights from Gatwick and Heathrow and all airports in Britain were likely to suffer delays. It was the third air traffic problem to have hit the part privatised service in the past two months.

These failures are spectacular since injury/loss of life and/or major financial loss are involved. Systems whose failure involves serious risk, including: loss of life, injury major financial loss are called safety critical systems.

Safety critical systems can be found in such industries as: Transport - automobile, rail, avionics, space Medical - monitoring, treatment Manufacturing- power especially nuclear, chemical, pharmaceutical Financial - banking, insurance, stock exchange

Of course, many non-safety critical systems e.g. Windows, Word etc can be expected to fail every few hours! In this chapter we consider technical aspects of software quality assurance. There are also managerial aspects to this issue that we have considered previously.

6.1. Debugging, Testing and Verification How can we engineer quality into software? Modern software engineering has three techniques: Debugging Testing Verification

These terms are often used with different meanings by different authors! Debugging: A process (usually interactive) of locating and identifying software errors using a debugging tool. Such a tool can automatically detect/identify untrapped exceptions, and locate their source.

e.g. array-out-of-bounds error null pointer division by zero stack/heap overflow runtime type error (dynamic type systems) A debugger is often supplied as part of a language development environment.

Observations: 1. The concept of a run-time exception can be precisely defined, so exception trapping can be automated. 2. The process of debugging is never obviously finished. 3. Not every error causes a run-time exception, e.g. infinite loops. Because of (3) we need other techniques.

Black-Box Testing: An interactive or batch process of executing a program using a specific set of inputs (the test set) and comparing results with predicted results usually based on some user requirement (the oracle step). Test failures are recorded and must be traced back to code errors.

Observations: 1. (Mostly) no finite number of tests establishes that a program is correct for all inputs. 2. The number of inputs we can test is very small as a percentage of the total number of inputs e.g. 32 bit integers, 100 int variables = 2 3200 possible inputs, 2 20 testable?

3. User requirements are often unclear about what the software should do. Makes it difficult to predict output/detect an error. 4. It can be difficult to trace an error to its source: no one-to-one relationship between error and lines of code. 5. Increasing use of GUIs/networks etc leads to unrepeatable errors!

Of these, problems (1) and (3) are the most problematic. Regarding (3), we can ask : Can all user requirements be made precise mathematically? (at least in theory)

Even if the answer is yes, testing still faces an unsolvable problem with issue (1). (1) Motivates a more powerful approach to software quality assurance, known variously as formal methods, program verification or simply verification.

Program Verification. A process that involves mathematically proving that a program correctly implements a set of user requirements (including termination), for all possible inputs (even if there are infinitely many).

For verification to work we need: 1. A mathematical model (a semantics) of the program to be checked 2. A mathematical model of the user requirements involved. 3. A mathematical procedure or technique to compare 1 with 2. Try to prove: program = requirements

6.2. Modeling Requirements with Logic Mathematics gives us a language to talk about different mathematical structures, e.g. integers, sets, rational numbers, real numbers, Booleans, Strings, etc. First-order predicate logic.

First-Order Logic Summary 1. Basic Syntactic Components (aka Data type) Variables: x, y, z, x, y, z, Constants: -2, -1, 0, 1, 2, Operations: +, -, *, /, mod, Relations: =,, is a data type for integer arithmetic

There are many non-numeric data types, e.g. Strings Variables: x, y, z, x, y, z, Constants: ε, a z, A Z, 0 9 + punctuation Operations: concat, head, tail, Relations: =, prefix, suffix, contains, We can obviously also combine data types.

Also structured or generic data types, e.g. Stack (of integers) Variables: x, y, z, x, y, z, (int) Variables: X, Y, Z, X, Y, Z, (stack) Constants: -2, -1, 0, 1, 2, (int) Constants: empty (stack) Operations: +, -, *, /, mod, (int) Operations: push, pop, top, (stack) Relations: =, (int) Relations: = (stack)

Remark In O-O design and programming many classes are used to introduce new data types.

2. Expressions Denote values in the data type when variables have been assigned values. e.g: (( x + y ) * ( -z) ) + 3 (integer) concat( a, tail( concat( b, x ) ) (string) ( false & ( true y ) ) (Boolean) Expressions are defined inductively, starting from components of a data type. Also occur as r.h.s of assignment statements.

3. Atomic Formulas Denote truth values (true or false) when variables have been assigned values. e.g.: (2 + y ) ( 3 * z ) (sometimes true) head( concat( a, x ) ) = a (always true) (true x) = false (always false) Atomic formulas always combine n expressions with a single n-ary relation symbol from the data type.

4. Formulas Denote truth values (true or false) when free variables have been assigned values. e.g.: ( 1 = 0 ) ( 1 0 ) (and) ( 1 = 0 ) ( 1 0 ) (or) (1 = 0 ) (not) x ( x = 0 ) (there exists quantifier) x( x 0 ) (for all quantifer) Formulas are defined inductively, starting from atomic formulas.

6.3. Programming Language Syntax & Semantics The question of what a program is allowed to look like (structurally) is called its syntax. The question of what a program actually does is called its semantics. Usually we describe its syntax formally using BNF (Backus Nauer Format) and semantics in words with reference to the program structure.

But to make a proof about the program, words alone are not precise enough. In this section we look at the formal syntax and semantics of a simple C -like imperative programming language While Programs

6.3.1. Syntax of While Programs While programs are built up from assignment statements, of the form <var> = <exp> Using sequencing (;), if_then_else, and the while loop (Pascal style).

We can make a formal BNF definition by: <WP> ::= <Ass> <WP> ; <WP> if <Bool_exp> then {<WP>} else {<WP>} while <Bool_exp> do { <WP> }

A typical small while program (notice semicolon (;) is a separator) x := m; y := n; while ( ~(y = 0) ) do { x := x + 1; y := y 1 }

6.3.2. State Transition Semantics of While Programs We can explain the semantics of a while program P in terms of state transition semantics what is the effect of successfully running P on the computers memory (state)?

In this approach we compare: the initial state of the computer (before running p) with the final state (after running p) assuming such a final state exists!

The initial state is called a precondition. The final state is called a postcondition. Pre and postconditions are first-order predicate logic formulas over the program variables (plus maybe auxiliary variables).

6.3.3. Hoare Triples A triple {<f.o. formula>} <WP> {<f.o formula>} is called a Hoare triple (after C.A.R. Hoare, inventor of monitors, Hoare s logic, quicksort, etc, etc )

{<f.o. formula>} <WP> {<f.o formula>} precondition postcondition while program

There are two possible semantics to a Hoare triple {p} S {q} 1. Partial correctness interpretation 2. Total correctness interpretation

6.3.3.1 Partial Correctness Under the partial correctness interpretation means that: {p} S {q} if p is a true statement about the variables of S initially, and S terminates then q is a true statement about the variables of S afterwards.

6.3.3.2 Total Correctness Under the total correctness interpretation means that: {p} S {q} if p is a true statement about the variables of S initially, then S terminates and q is a true statement about the variables of S afterwards.

6.3.3.3 Which One? Termination is obviously an important safety aspect of software (think nuclear power station!). However, the analysis of termination uses variants, while the analysis of functional correctness uses invariants.

The two approaches are quite different, and best carried out separately. Technically, we can have a complete logic for partial correctness (c.f. Gödel s Completeness Theorem allows all true statements to be proved). We cannot have a complete logic for total correctness

6.3.3. Examples Consider the world s simplest program: { x = 7 } x:= x+1 { x = 8 } (1) is a true statement, both under the partial and total correctness interpretations since x:= x+1 has no loops.

There is nothing special about the input value 7: { x = y } x:=x+1 { x = y+1 } (2) is a more general true statement, both under the partial and total correctness interpretations. Notice the auxiliary variable y. This is the most general statement we can imagine!

Exercise: Try to find some true Hoare triples which are more general than (1) but less general than (2). How many are there? Let s specify a program that does addition.

{ n 0 } // precondition x := m; y := n; while ( ~(y = 0) ) do { x := x + 1; y := y 1 } { x = m + n } //postcondition

This Hoare triple is true under both partial and total correctness interpretations. Notice how the precondition filters out all cases leading to an infinite loop. Notice how we copy m and n into x and y so we can refer to them unchanged in the postcondition.

{ true } // precondition x := m; y := n; while ( ~(y = 0) ) do { x := x + 1; y := y 1 } { x = m + n } //postcondition

Now we have weakened (generalised) the precondition, true places no constraints on the input data at all! Since true is satisfied by all input values of n, including negative values, the triple is not true under total correctness interpretation. It is still true under partial correctness.

{ x > 0 & y > 0 } GCD { divides( res, x) & divides( res, y ) & ~( h ( h > res & divides( h, x) & divides( h, y) ) } Where: def divides( X, Y) Z ( X * Z = Y )

is a specification for an algorithm for computing the greatest common divisor (gcd) of x and y, returning its result in res. Exercise: Write out Euclid s algorithm for gcd as a while program. We can add arrays of integers and Booleans. We just sketch the approach with an example of a simple linear search on an array.

{true} out := max; count := 0; while ( count < max ) do { if ( my_array[count] = in ) then { out := count } else { skip }; count := count + 1 } } { out = max ~ x ( my_array[x] = in ) & out < max my_array[out] = in }

We can basically just add array expressions as expressions in our logic. We can think of them as functions over a finite domain. We can, (but won t), formalise this.

6.4. Hoare s Logic of While Programs In this section we introduce Hoare s logic of while programs (usually just called Hoare s Logic). This should be a logic for reasoning about programs. But what actually is a logic?

6.4.1. First-Order Predicate Calculus (Revisited) First-order logic consists of a language, and a set of rules (a calculus), for deriving new facts (theorems) from existing facts (axioms). This approach is often called the axiomatic method.

Rules: φ, φ ϕ (Modus Ponens) ϕ φ ϕ φ φ φ φ (Expansion) (Contraction)

(ϕ φ) δ (Associativity) ϕ ( φ δ ) _φ ϕ_ ( -Introduction) x φ ϕ where x is not free in ϕ

A formal proof P using first-order predicate calculus, from a set T of axioms, is a sequence of formulas P φ 1, φ 2,, φ n where for each i = 1 n, either: (1) φ i is in T, or (2) φ i follows from φ j, φ k for j, k < i, by one of the rules of the predicate calculus We say P is a proof of φ n.

6.4.2. Hoare s Proof Rules There is one axiom schema (i.e. an infinite set of axioms for each x, φ and t.) { φ x [t] } x := t { φ } (Assignment Schema) where φ x [t] means φ with variable x replaced by term t everywhere x is free.

There are 4 proof rules, one for each programming construct and one as glue. (Composition) { φ } S 1 {ϕ }, {ϕ } S 2 {δ } { φ } S 1 ;S 2 { δ }

(Composition) { φ & b } S 1 {ϕ }, {φ & ~b } S 2 {ϕ } { φ } if b then{s 1 }else{ S 2 } {ϕ } (While Rule) { φ & b } S {φ } { φ } while b do{s} {φ & ~b }

We need a 4 th rule to act as logical glue to the rest of predicate calculus, to reason about the data types. (Recall Section 6.2.) (Consequence) φ 0 φ, { φ } S {ϕ }, ϕ ϕ 0 { φ 0 } S { ϕ 0 }

A formal proof P using Hoare s logic, from a set T of data type axioms (first-order formulas), is a sequence of first-order formulas and Hoare triples P φ 1, φ 2,, φ n (we say P is a proof of φ n ) where for each i = 1 n, either:

(1) φ i is a Hoare triple {p i } S i {q i } which is either an assignment axiom, or follows from previous Hoare triples and/or firstorder formulas φ j, φ k, φ l for j, k, l < i, by one of the rules of Hoare s logic (2) φ i is a first-order formula and follows from φ j, φ k for j, k < i, by one of the rules of the predicate calculus

6.5. Floyd s Method Hoare s logic is cumbersome and difficult to use correctly. It s really only useful if implemented on computer using some AI program to reason. We need a practical method for analysing correctness.. on the back of an envelope!

Floyd s method is also known as the method of invariant assertions. It uses a graphical model of programs as flowcharts, and usually gives a compact visual proof, at least for small programs. It s easier to use by hand, but harder to automate.

6.5.1. Flowcharts A flowchart is a graphical representation of a single procedure or function in an imperative (C or Pascal like) language. There are 4 building blocks for flowcharts. These are linked together by their arrows to construct a flowchart.

1. Assignment Blocks A box containing a single variable assignment. We will sometimes allow sequences of assignments separated by semicolon to save space. v := exp

2. Decision (Choice) Diamonds A diamond shape containing a single Boolean expression. no cond yes

3. Start Symbol A round cornered box marking the unique entry point of the flowchart. Start

4. Halt Symbol A round cornered box marking a (not necessarily unique) exit point from the flowchart. Halt

Start x:= m y:= n no y >0 yes Halt x:= x+1 y:= y-1

Above, we have a simple flowchart to add two positive integers m and n. It is a straightforward exercise to translate any while program into a flowchart. e.g. the above flowchart would be a translation of

x := m; y := n; while ( y > 0 ) do { x := x + 1; y := y 1 }

Translating flowcharts into while programs is more difficult because of the unbounded branching structure of flowcharts effectively a hidden goto construct. The famous Böhm Jacopini Theorem states that this can be done. This is the theoretical foundation for structured programming.

6.5.2. Labeling with Invariant Assertions Floyd s method consists of labeling the entry point of every graphic symbol: box, diamond halt with a first order logic formula. [N.B. A start symbol has no entry point.]

Definition. A labeling of a flowchart is valid if for every execution of the flowchart (on any input data), if the label formula after Start is true (the precondition) then every label formula is true at the instant that execution passes through it. In particular the label entering Halt is true as we pass through it (the postcondition).

Since valid labels are always true when we pass through them (but perhaps not at other times) we call such logical assertions invariant assertions Here is a valid labeling of the previous flowchart.

m 0 & n 0 Start x 0 & n 0 x = m+(n-y) & y 0 x = m+n no x:= m y:= n y >0 yes x = m+(n-y) & y > 0 Halt x = m+(n-(y-1)) & y > 0 x:= x+1 y:= y-1

The formula after the Start symbol represents the precondition for the algorithm. In this case m 0 & n 0 (a sufficient condition for the algorithm to work)

Each formula before a Halt symbol (there may be several) represents a (local) postcondition for the algorithm. We should take the disjunction (or) of all such postconditions, as the global postcondition. But if all such formulas are the same we can take any one of them.

A formula before the entry point of a loop (which must be a branching instruction) is called a loop invariant, in this case x = m+(n-y) & y 0 Notice again in this algorithm we take copies of m an n with x and y, so we can compare the final values with the initial values.

We can apply Floyd s method to proving a partial correctness statement {p}s{q} by: (1) Translating the program S into a flowchart (2) Labeling the Start symbol with p and each Halt symbol with q. (3) Finding a valid labeling of all other flowchart points so that the total labeling is valid.

(1) and (2) are easy. The hard work is (3). Question: How can we find a valid labeling of all the other points? Answers: 1. Drag the precondition forwards with logical rules 2. Drag the postcondition backwards with logical rules 3. Make inspired guesses at loops!

What logical rules can we use? Recall the axiom schemas and rules of Hoare s logic. We will define some related rules for flowcharts. First notice that we can carry out ordinary first-order logic on any label.

This means we can: 1. Replace any sub-formula by a logically equivalent formula. 2. Weaken any formula, i.e. if p q and we have p we can replace it with q. 3. Add any tautology as a conjunction, e.g. if we have p we can replace it by say p & x = x.

1. Branching Rule (Forwards) P hypothesis P & ~cond no cond yes P & cond conclusions

2. Assignment Rule (Forwards) P hypothesis x := exp P [exp/x] conclusion

Conditions on Forwards Assignment Rule: (1). Every occurrence of x in an occurrence of exp must be free in P. Thus x doesn t get bound by a quantifier in P[exp/x] after the substitution [exp/ x]. Otherwise we must rename bound instances of x. (2) If x does not occur in exp, then not every occurrence of exp must be replaced by x in the conclusion. (Otherwise they must be.)

(3). No function occurring in exp has side effects which affect the value of exp. This can be achieved if a function f returns values through its return parameter only. Otherwise we must manually check the side effects of f. An operation like x + 1 will satisfy this condition, while operations like x++ or ++x will not.

Condition (1) prevents e.g: x:int ( x * x 0 ) x := x * x x:int ( x 0 ) The hypothesis is obviously true, while the conclusion is obviously false.

If we rename x in the hypothesis, (say to y) then it is clear that it isn t referring specifically to the program variable x. y:int ( y * y 0 ) x := x * x y:int ( y * y 0 )

Condition (2) makes the assignment rule flexible and useful. E.g. to derive the obvious labeling true x := m x = m

we can reason Add a tautology true & m = m x := m true & x = m Here there is only one substitution of m. This is clearly necessary to get the result.

We obtain the result by weakening the hypothesis and conclusion again (in this case deleting a conjunct) true x := m x = m

3. Assignment Rule (Backwards) P[x/exp] conclusion x := exp P hypothesis This rule has no conditions, so it may be easier to use!

The difficult part of Floyd s method is always finding the right loop invariants. It can be proven mathematically that we must guess these, i.e. there is no universal rule that we can use to calculate the result. Let s analyse the validity of the labeled flowchart we saw above.

It s convenient to split the diagram into an outer loop free part and an inner loop body. (A) m 0 & n 0 Start x:= m (B) x 0 & n 0 (C) x = m+(n-y) & y 0 y:= n (D) x = m+n no y >0 yes Halt

Formula (A) is our precondition m 0 & n 0 So it doesn t logically follow from anything. Formula (B) x 0 & n 0 follows from (A) using the forward assignment rule, when we replace m in (A) by x.

Formula (C) x = m+(n-y) & y 0 is a good guess. It doesn t follow by either rule, but is clearly true the first time around. Formula (D) x = m+n follows from x = m + ( n y ) & y = 0 which follows from (C) by the branching rule.

Now let s check the validity of formulas labeling the loop body. (E) x = m+(n-y) & y > 0 (F) x = m+(n-(y-1)) & y > 0 x:= x+1 y:= y-1 (C) (G) x = m+(n-y) & y 0

Formula (E) x = m+(n-y) & y > 0 follows from (C) and the branching rule with the condition y > 0. From (E) we can conclude x + 1 = m + ( ( n-y ) + 1 ) & y > 0 hence x + 1 = m + ( n - (y - 1 ) ) & y > 0

From this formula, using the forwards assignment rule we obtain formula (F) x = m+(n-(y-1)) & y > 0 From (F) we can deduce x = m+(n-(y-1)) & y-1 0 From this formula using the assignment rule we obtain formula (G) (the same as (C) ) x = m+(n-y) & y 0

Thus we have established that: If we enter the loop body with the loop invariant (C) true, then we exit it with (C) being true. So (C) really is a loop invariant.

Notice that (C) is allowed to become (temporarily) false inside the loop body. E.g. inspecting (F) we see that (C) is clearly false at the same point. However, the invariant (C) must be restored by the time we leave the loop body.

Compare this loop body analysis using Floyd s method with Hoare s proof rule for while loops (While Rule) { φ & b } S {φ } { φ } while b do{s} {φ & ~b }

The analyses are identical General Strategy: Pull out the loop body S and prove its invariant. Then put it back in context. Notice also how the formula ~b in Hoare s Rule reappears in the Branching Rule for Floyd s method.

Finally remember that Floyd s method is for proving partial correctness. It does not prove that we will reach a Halt symbol, but that if we reach a halt symbol then the postcondition will be true. The Hoare triples derivable from Floyd s method are the same as those using Hoare s. So Floyd s method is relatively complete too.

6.6. Verifying Functional Programs A functional program works by transforming its input values into some output values without any intermediate state. We call this stateless or side effect free programming.

We also say that functional program fragments are referentially transparent. They have the same meaning (reference) regardless of their context. This makes functional programs exceptionally easy to analyze mathematically.

We can make a simple model of functional programming to illustrate the proof method of verification by induction. First, we extend while programs (which are state based) to allow function routines.

<FWP> ::= function <identifier> ( <var_decl>* ) : <return_type> { <WP> } function header function body

We also extend the syntax of expressions so that function identifiers can appear inside Expressions, e.g. x := my_function( y1,, yn ) Such function routines are not yet stateless since we have allowed semicolon (;) and while loops inside.

Definition. A function routine f FWP is purely functional or stateless if its body contains only assignment statements, and if_then_else constructs Let s see some examples

function plus ( x, y : int ) : int { if ( y = 0 ) then { plus := x } else { plus := 1 + plus ( x, y 1 ) } } Notice we also use a function name as a return variable name of return type.

function times ( x, y : int ) : int { if ( y = 0 ) then { times := 0 } else { times := plus ( x, times( x, y 1 ) ) } }

Notice one function routine can call another. The calling routine is then stateless if it has no while loops or assignments and the called routine is stateless too. The advantage of stateless function routines is the ease with which they can be analysed.

Motivation. In an imperative program there may be an unbounded number of states. Using Floyd s method we must discover an invariant for each possible state. In a stateless function routine there are just two states: initial and final.

We only need to find a relationship between these two states. Since recursion and induction go hand in hand the key to analysis is induction. We assume a basic familiarity with proof by induction and illustrate the verification method by examples.

Example 1. Claim For all x 0 and all y 0, plus( x, y ) = x + y. Proof. By induction on y. Basis. Suppose y = 0. Then by definition of plus: plus ( x, y ) = plus( x, 0 ) = x = x + 0 = x + y

Induction Step. Suppose y > 0. By definition of plus, plus( x, y ) = 1 + plus( x, y-1 ) = 1 + ( x + ( y 1 ) ) by the induction hypothesis since y-1 < y (**) = x + y by laws of arithmetic.

Claim For all x 0 and all y 0 times( x, y ) = x*y Proof. By induction on y. Basis. Suppose y = 0. By definition of times times( x, y ) = times( x, 0 ) = 0 = x * 0 = x * y.

Induction Step. Suppose y > 0. By definition of times: times( x, y ) = plus( x, times( x, y-1 ) ) = plus( x, x * ( y-1) ) by the induction hypothesis, since y-1 < y (**) = x + x*(y-1) By our result above for plus, and since x 0 and y >0, so that x*(y-1) 0. (***) = x * y

Notes: 1. The variable for induction is usually the recursion variable of the program, i.e. the variable which is modified (often decremented) in recursive calls. 2. (**) To use the induction hypothesis we must ensure that the induction variable strictly decreases.

3. (***) To use a result about a purely functional or stateless routine we must prove that we can satisfy its preconditions. Let s see a more complex example involving tail recursion.

function power ( q, b, e : int ) : int { if ( e = 0 ) then { power := q } else { if even(e) then{ power = power(q, b*b, e/2)} else{ power = power(q*b, b, e-1)} } }

Claim For all e 0 power(q, b, e) = q*b e and hence power(1, b, e) = b e. Proof. By induction on e. Basis. Suppose e = 0. Then by definition of power, power( q, b, e) = q = q * b 0 = q * b e

Induction Step Suppose e > 0. We have two sub-cases. Sub-case 1. Suppose e is even. Then by definition of power, power( q, b, e ) = power( q, b*b, e/2 ) = q * (b 2 ) e/2 by the induction hypothesis, since e/2 < e because e > 0, = q * b 2*e/2 = q * b e

Sub-case 2. Suppose e is not even. Then by definition of power, power( q, b, e ) = power( q*b, b, e-1 ) = q * b * b e-1 by the induction hypothesis since e-1 < e, = q * b e. Notice how sub-cases 1 and 2 reflect the branching structure of the program.

For non-numeric data types such as strings, we need to find a natural number function of data elements such as string length, to perform induction over. Consider the following algorithm.

function equals( x,y:string ) :bool { if x = empty then { if y = empty then { equals := true } else { equals := false } } else { equals := ( head(x)= head(y)) & equals ( tail(x), tail(y) ) }

Claim For all x : string and for all y : string, equals( x, y ) = true x = y Proof. By induction on the length of x. Basis. Suppose x = 0, i.e. x is empty. We have two sub-cases.

Subcase 1. Suppose y is empty. Then by definition of equals, equals( x, y ) = equals( empty, empty ) = true but x = y so equals( x, y ) = true x = y

Subcase 2. Suppose y is not empty. Then by definition of equals, equals( x, y ) = equals( empty, y ) = false and x y so equals( x, y ) = true x = y.

Induction Step. Suppose x > 0. Then x empty. By definition of equals, equals( x, y ) = ( head(x) = head(y) ) & equals ( tail(x), tail(y) ) = ( head(x) = head(y) ) & tail(x) = tail(y)

by the induction hypothesis, since tail(x) < x because x empty = ( x = y ). So equals( x, y ) = true x = y. Choosing the best variable for induction over can be critical to simplifying a proof. Consider the following algorithm.

function plus (x, y : int ) : int { if ( x = 0 ) then { plus := y } else { if ( y = 0 ) then{ plus := x } else{ plus := 1 + plus( x, y-1) } } }

Claim. For all x 0 and for all y 0, plus( x, y ) = x + y. At first sight it seems we should prove this result by induction on x, with basis case corresponding to the line of code if ( x = 0 ) then { plus := y }

But notice that in the recursive call plus := 1 + plus( x, y-1) x doesn t decrease! So we can t use the induction hypothesis about x. Instead we would need a subinduction result for y. Things are much easier if we prove by induction on y from the beginning.

Proof. By induction on y. Basis. Suppose y = 0. Sub-case 1. Suppose x = 0. By definition of plus, plus( x, y ) = plus( 0, y ) = y = 0 = x + y. Sub-case 2. Suppose x 0. Then by definition of plus plus( x, y ) = plus( x, 0 ) = x = x + y.

Induction Step. Suppose y > 0. Subcase 1. Suppose x = 0. Then by definition of plus, plus( x, y ) = plus( 0, y) = y = x + y.

Sub-case 2. Suppose x 0. Then by definition of plus, plus( x, y ) = 1 + plus( x, y-1 ) = 1 + ( x + (y-1) ) by the induction hypothesis, since y-1 < y = x + y. Conclusion. Functional programming is the study of recursion and induction.