# Verification of sequential and concurrent programs (2nd ed.)

01 May 1997-

TL;DR: Verification of sequential and concurrent programs has been studied extensively in the Verification of Sequential and Concurrent Programs (VSP) project as mentioned in this paper, where the authors provide a systematic exploration of one of the most common approaches to program verification.

Abstract: Computer programs are an indispensable part of many of the systems we rely upon in our daily lives, and the proper functioning and safety of these systems is of paramount importance. The development of methods that ensure program correctness is therefore a key challenge for computer scientists. This third edition of Verification of Sequential and Concurrent Programs provides a systematic exploration of one of the most common approaches to program verification, known as the "assertional" approach. Following the successful formula of previous editions, this approach is applied to deterministic and nondeterministic sequential programs of varying complexity, together with both parallel and distributed concurrent programs. The expanded content of this thorough new edition also includes coverage of the verification of object-oriented programs. For each class of programs, the authors introduce an operational semantics and proof systems for the verification of partial and total correctness, justified formally in corresponding soundness theorems. Case studies supplied throughout the book demonstrate the use of the proof systems to formally verify solutions to classical problems, such as sorting, manipulation of lists, producer/consumer and mutual exclusion.

## Summary (50 min read)

Jump to: [8 1 Introduction] – [1.1 An Example of a Concurrent Program 9] – [10 1 Introduction] – [1.2 Program Correctness 11] – [1.2 Program Correctness] – [12 1 Introduction] – [1.3 Structure of this Book 13] – [1.3 Structure of this Book] – [14 1 Introduction] – [1.3 Structure of this Book 15] – [1.4 Automating Program Verification] – [1.5 Assertional Methods in Practice 17] – [1.5 Assertional Methods in Practice] – [18 1 Introduction] – [20 2 Preliminaries] – [Sets] – [Tuples] – [Relations] – [24 2 Preliminaries] – [2.1 Mathematical Notation 25] – [Strings] – [Proofs] – [Induction] – [28 2 Preliminaries] – [2.2 Typed Expressions] – [Types] – [Variables] – [Constants] – [2.2 Typed Expressions 31] – [Expressions] – [32 2 Preliminaries] – [Fixed Structure] – [States] – [2.4 Formal Proof Systems] – [2.5 Assertions] – [40 2 Preliminaries] – [2.6 Semantics of Assertions 41] – [42 2 Preliminaries] – [2.7 Substitution 43] – [44 2 Preliminaries] – [46 2 Preliminaries] – [48 2 Preliminaries] – [2.10 Bibliographic Remarks] – [52 2 Preliminaries] – [3.9 Case Study: Partitioning an Array . . . . . . . . . . . . . . . . . . . . 99] – [3.1 Syntax] – [3.2 Semantics] – [3.2 Semantics 59] – [Properties of Semantics] – [3.3 Verification 63] – [3.3 Verification] – [3.3 Verification 65] – [Partial Correctness] – [3.3 Verification 67] – [3.3 Verification 69] – [Total Correctness] – [3.3 Verification 71] – [Decomposition] – [3.3 Verification 75] – [CONSEQUENCE] – [3.4 Proof Outlines] – [3.4 Proof Outlines 81] – [3.5 Completeness] – [3.5 Completeness 87] – [3.5 Completeness 89] – [Proof.] – [3.6 Parallel Assignment 91] – [3.6 Parallel Assignment] – [3.6 Parallel Assignment 93] – [Verification] – [Syntax] – [3.8 Auxiliary Axioms and Rules 97] – [3.8 Auxiliary Axioms and Rules] – [3.9 Case Study: Partitioning an Array 99] – [3.9 Case Study: Partitioning an Array] – [3.9 Case Study: Partitioning an Array 101] – [Proof of Property P2] – [Proof of Property P4] – [Termination] – [3.10 Systematic Development of Correct Programs] – [Summation Problem] – [3.11 Case Study: Minimum-Sum Section Problem] – [3.12 Exercises] – [3.12 Exercises 123] – [3.13 Bibliographic Remarks] – [3.13 Bibliographic Remarks 125] – [4 Recursive Programs] – [4.1 Syntax] – [4.2 Semantics] – [4.3 Verification 133] – [4.3 Verification 135] – [Discussion] – [4.3 Verification 141] – [4.3 Verification 143] – [4.4 Case Study: Binary Search] – [4.4 Case Study: Binary Search 147] – [4.5 Exercises 149] – [4.5 Exercises] – [4.6 Bibliographic Remarks] – [5 Recursive Programs with Parameters] – [5.1 Syntax] – [5.1 Syntax 153] – [5.2 Semantics] – [5.2 Semantics 155] – [5.3 Verification 157] – [5.3 Verification] – [Partial Correctness: Non-recursive Procedures] – [5.3 Verification 159] – [Partial Correctness: Recursive Procedures] – [5.3 Verification 163] – [Modularity] – [5.3 Verification 167] – [5.3 Verification 171] – [Formal Problem Specification] – [Auxiliary Proof: Permutation Property] – [Auxiliary Proof: Sorting Property] – [5.5 Exercises] – [5.6 Bibliographic Remarks 183] – [6 Object-Oriented Programs] – [Local Expressions] – [Statements and Programs] – [6.1 Syntax 189] – [6.1 Syntax 191] – [6.2 Semantics] – [Semantics of Local Expressions] – [6.2 Semantics 193] – [Updates of States] – [Semantics of Statements and Programs] – [6.3 Assertions 197] – [6.3 Assertions] – [6.3 Assertions 199] – [Substitution] – [6.4 Verification 201] – [6.4 Verification 203] – [6.4 Verification 205] – [6.5 Adding Parameters] – [6.5 Adding Parameters 209] – [6.6 Transformation of Object-Oriented Programs] – [6.6 Transformation of Object-Oriented Programs 213] – [6.6 Transformation of Object-Oriented Programs 215] – [6.7 Object Creation 217] – [6.7 Object Creation] – [Assertions] – [6.7 Object Creation 221] – [6.7 Object Creation 223] – [6.7 Object Creation 225] – [6.8 Case Study: Zero Search in Linked List 227] – [6.8 Case Study: Zero Search in Linked List 231] – [6.9 Case Study: Insertion into a Linked List] – [6.9 Case Study: Insertion into a Linked List 233] – [6.9 Case Study: Insertion into a Linked List 235] – [6.9 Case Study: Insertion into a Linked List 237] – [6.10 Exercises 239] – [6.11 Bibliographic Remarks] – [6.11 Bibliographic Remarks 241] – [7 Disjoint Parallel Programs] – [7.1 Syntax] – [7.2 Semantics] – [Determinism] – [7.2 Semantics 251] – [Sequentialization] – [7.3 Verification 253] – [Parallel Composition] – [7.3 Verification 255] – [7.3 Verification 257] – [7.4 Case Study: Find Positive Element 261] – [7.4 Case Study: Find Positive Element] – [7.4 Case Study: Find Positive Element 263] – [7.5 Exercises] – [7.6 Bibliographic Remarks] – [8 Parallel Programs with Shared Variables] – [8.1 Access to Shared Variables] – [8.2 Syntax] – [8.3 Semantics] – [8.3 Semantics 273] – [Component Programs] – [8.4 Verification: Partial Correctness 275] – [No Compositionality of Input/Output Behavior] – [Parallel Composition: Interference Freedom] – [8.4 Verification: Partial Correctness 277] – [8.4 Verification: Partial Correctness 279] – [8.4 Verification: Partial Correctness 281] – [8.4 Verification: Partial Correctness 283] – [8.5 Verification: Total Correctness 285] – [8.5 Verification: Total Correctness 287] – [8.5 Verification: Total Correctness 289] – [8.6 Case Study: Find Positive Element More Quickly 291] – [8.6 Case Study: Find Positive Element More Quickly] – [8.6 Case Study: Find Positive Element More Quickly 293] – [8.7 Allowing More Points of Interference] – [8.7 Allowing More Points of Interference 297] – [8.8 Case Study: Parallel Zero Search] – [8.9 Exercises] – [8.10 Bibliographic Remarks] – [9 Parallel Programs with Synchronization] – [9.1 Syntax] – [9.2 Semantics] – [9.3 Verification 315] – [9.3 Verification 317] – [9.4 Case Study: Producer/Consumer Problem 319] – [9.4 Case Study: Producer/Consumer Problem] – [9.4 Case Study: Producer/Consumer Problem 321] – [9.4 Case Study: Producer/Consumer Problem 323] – [9.5 Case Study: The Mutual Exclusion Problem 325] – [9.5 Case Study: The Mutual Exclusion Problem 327] – [A Busy Wait Solution] – [9.5 Case Study: The Mutual Exclusion Problem 329] – [9.5 Case Study: The Mutual Exclusion Problem 331] – [A Solution Using Semaphores] – [9.5 Case Study: The Mutual Exclusion Problem 333] – [9.6 Allowing More Points of Interference] – [9.7 Case Study: Synchronized Zero Search] – [9.7 Case Study: Synchronized Zero Search 339] – [9.7 Case Study: Synchronized Zero Search 341] – [9.7 Case Study: Synchronized Zero Search 343] – [9.8 Exercises] – [9.9 Bibliographic Remarks 345] – [9.9 Bibliographic Remarks] – [10 Nondeterministic Programs] – [10.1 Syntax] – [10.2 Semantics] – [Symmetry] – [Nondeterminism] – [Failures] – [Modeling Concurrency] – [10.5 Case Study: The Welfare Crook Problem] – [10.6 Transformation of Parallel Programs 363] – [10.6 Transformation of Parallel Programs] – [10.6 Transformation of Parallel Programs 365] – [10.6 Transformation of Parallel Programs 367] – [10.7 Exercises] – [10.8 Bibliographic Remarks] – [10.8 Bibliographic Remarks 371] – [11 Distributed Programs] – [Sequential Processes] – [Distributed Programs] – [11.1 Syntax 377] – [11.1 Syntax 379] – [11.2 Semantics] – [11.2 Semantics 381] – [11.3 Transformation into Nondeterministic Programs] – [11.3 Transformation into Nondeterministic Programs 383] – [Proof of the Sequentialization Theorem 11.1] – [11.3 Transformation into Nondeterministic Programs 387] – [11.3 Transformation into Nondeterministic Programs 389] – [11.4 Verification] – [RULE A9:] – [11.4 Verification 393] – [11.4 Verification 395] – [11.5 Case Study: A Transmission Problem] – [11.5 Case Study: A Transmission Problem 397] – [11.5 Case Study: A Transmission Problem 399] – [11.5 Case Study: A Transmission Problem 401] – [11.6 Exercises] – [11.6 Exercises 403] – [11.7 Bibliographic Remarks 405] – [11.7 Bibliographic Remarks] – [12 Fairness] – [12.1 The Concept of Fairness] – [Selections and Runs] – [12.1 The Concept of Fairness 411] – [Fair Nondeterminism Semantics] – [12.2 Transformational Semantics] – [12.3 Well-Founded Structures] – [12.4 Random Assignment] – [12.4 Random Assignment 417] – [12.5 Schedulers 419] – [12.5 Schedulers] – [At certain moments during a computation, the program pre-sents the set E of currently enabled components to the scheduler (provided E 6= ∅). By consulting its local state, the scheduler returns to the program a nonempty subset I of] – [12.5 Schedulers 421] – [The Scheduler FAIR] – [12.5 Schedulers 423] – [12.5 Schedulers 425] – [The Scheduler QUEUE] – [12.6 Transformation] – [12.7 Verification 431] – [12.7 Verification 433] – [12.7 Verification 435] – [12.7 Verification 437] – [12.7 Verification 439] – [12.8 Case Study: Zero Search] – [12.9 Case Study: Asynchronous Fixed Point Computation] – [12.9 Case Study: Asynchronous Fixed Point Computation 447] – [12.9 Case Study: Asynchronous Fixed Point Computation 451] – [12.10 Exercises] – [12.10 Exercises 453] – [12.11 Bibliographic Remarks] and [Fairness]

### 8 1 Introduction

- Statement R is then immediately executed as an indivisible action; during its execution all other components of the parallel program are suspended.
- If B evaluates to false, then the component executing the await statement itself is suspended while other components can proceed.
- The suspended component can be retried later.
- Indeed, with each loop iteration, turn is switched.
- Thus a component can be activated uninterruptedly for at most “one and a half” iterations.

### 1.1 An Example of a Concurrent Program 9

- Assume again that f has exactly one positive zero.
- Consider an execution sequence of ZERO-4 in which the component S1 has just found this zero and is about to execute the statement found := true.
- Now S1 proceeds and terminates with found := true.
- The authors assure you that the above solution is correct.

### 10 1 Introduction

- The execution time of the statement R decreases this suspension time and results in a possible speed-up in a parallel execution.
- Here such an improvement is possible —the assignments to the variable turn can be taken out of the scope of the await statements.
- Thus the authors claim that the following program is a better solution to the problem.
- The only difference from Solution 5 is that now component S2 can be activated —or as one says, interfere— between wait turn = 1 and turn := 2 of S1, and analogously for component S1.
- Then this statement can be interchanged with the.

### 1.2 Program Correctness 11

- The first assignment turn := 1 (inside the loop) cannot be executed because immediately before its execution turn = 2 should hold, but by their assumption S1 has just passed wait turn =.
- But then S2 terminates, so found is true and S1 will also terminate —immediately after finishing the current loop iteration.
- Just in time —in the next loop iteration it would be blocked!.
- A similar argument holds for activating S1.

### 1.2 Program Correctness

- The problem of zero search seemed to be completely trivial, and yet several errors, sometimes subtle, crept in.
- The design of the final solution proceeded through a disquieting series of trials and errors.
- Correctness means that certain desirable program properties hold.
- Moreover, as observed before, the authors are then also interested in establishing: 4. Interference freedom, that is, no component of a parallel program can manipulate in an undesirable way the variables shared with another component.

### 12 1 Introduction

- The parallel program ZERO--3 solves the zero search problem only under the assumption of fairness.
- For this purpose, an informal understanding of the program semantics is used.
- Such formulas serve as so-called assertions expressing desirable program states.
- In 1991 an assertional proof system was introduced by de Boer [1991a] for a parallel object-oriented language called POOL, developed by America [1987].

### 1.3 Structure of this Book 13

- Interestingly, the proof rules suggested for the a posteriori verification of sequential programs remain useful for formulating strategies for program development.
- The development starts with an abstract system model which is stepwise refined to a detailed model that can form a basis for a correct program.
- Using temporal logic more general program properties than input/output behavior can be expressed, for example so-called liveness properties, and the fairness assumption can be handled.
- The authors do not treat this approach here but refer the reader instead to the books by Manna and Pnueli [1991,1995].

### 1.3 Structure of this Book

- This book presents an approach to program verification based on Hoare-style proof rules and on program transformations.
- This structure enables us to explain program verification in an incremental fashion and to have fine-tuned verification methods for each class.
- For the classes of programs the authors use the following terminology.
- In a sequential program the control resides at each moment in only one point.
- The concurrent programs discussed in Section 1.1 are of this.

### 14 1 Introduction

- Distributed programs are concurrent programs with disjoint components that communicate by explicit message passing.
- Next, the authors introduce Hoare-style proof rules allowing us to verify the partial and total correctness of programs.
- Each of the subsequent chapters ends with a series of exercises and bibliographic remarks.
- The authors capture this concept by using a block statement and an appropriate semantic transition rule that models the desired stack behavior implicitly.
- In Chapter 7 the authors study the simplest form of parallel programs, so-called disjoint parallel programs.

### 1.3 Structure of this Book 15

- In Chapter 8 the authors study parallel programs that permit unrestricted use of shared variables.
- Verification of such programs is based on the test of interference freedom due to Owicki and Gries [1976a].
- Finally, the authors explain how parallel programs can be transformed into equivalent nondeterministic ones although at the price of introducing additional control variables.
- Based on this program transformation the authors develop proof techniques for distributed programs due to Apt [1986].
- More specifically, the proof rule allowing us to deal with nondeterministic programs under the assumption of fairness is developed by means of a program transformation that reduces fair nondeterminism to ordinary nondeterminism.

### 1.4 Automating Program Verification

- In this book the authors present program verification as an activity requiring insight and calculation.
- Essentially, model checking rests on algrorithms for exploring the reachable state space of a program.
- For further details the authors refer to the books by Clarke, Grumberg, and Peled [1999], and by Baier and Katoen [2008].
- Then of course the question is whether the answer for the abstract system implies the corresponding answer for the concrete system.

### 1.5 Assertional Methods in Practice 17

- It attempts to verify programs by proofs carried out by means of interactive theorem provers instead of state space exploration and thus does not need finite-state abstractions.
- Deductive verification automates the axiomatic approach to program verification presented in this book.
- Well-known are the provers Isabelle/HOL, see Nipkow, Paulson and Wenzel [2002], and PVS, see Owre and Shankar [2003], both based on higher-order logic.
- To apply these provers to program verification both the program semantics and the proof systems are embedded into higher-order logic and then suitable tactics are formalized to reduce the amount of human interaction in the application of the proof rules.
- As far as possible decision procedures are invoked to check automatically logical implications needed in the premises of the proof rules.

### 1.5 Assertional Methods in Practice

- One can observe that the notion of an assertion and the corresponding programming methods appeared in practice only in recent years.the authors.
- Meyer [1997] introduced the paradigm of design by contract for the objectoriented programming language Eiffel.
- The contract is agreed upon before an implementation is developed that satisfies this contract.
- The contracts are written in the Java Modeling Language JML, which allows the user to specify so-called rich interfaces of classes and methods that are not yet implemented.

### 18 1 Introduction

- Checking whether an implementation (a program) satisfies a contract is done either by formal verification using proof rules (as outlined above) or —in a limited way— at runtime.
- The second approach requires that the assertions in the contracts are Boolean expressions.
- Then during each particular run of the implementation it is checked automatically whether along this run all assertions of the contract are satisfied.
- As an example of a successful application of verification techniques to specific programming languages let us mention ESC/Java (Extended Static Checker for Java) which supports the (semi-)automated verification of annotated Java programs, see Flanagan et al. [2002].
- Another example involves Java Card, a subset of Java dedicated for the programming of Smart Cards the programs of which are verified using interactive theorem provers, see van den Berg, Jacobs and Poll [2001], and Beckert, Hähnle and Schmitt [2007].

### 20 2 Preliminaries

- For program verification assumes again knowledge of Section 2.4.
- Finally, to show the soundness of these proof systems the Substitution Lemma intro- duced in Section 2.8 is needed.

### Sets

- Finite sets may be specified by enumerating their elements between curly brackets.
- More generally, sets are specified by referring to some property of their elements: {x | Recall that in a set one does not distinguish repetitions of elements.
- Thus {true, false} and {true, false, true} are the same set.
- Similarly, the order of elements is irrelevant.

### Tuples

- In sets the repetition of elements and their order is irrelevant.
- If these things matter, the authors use another way of grouping elements: ordered pairs and tuples.
- By definition, two pairs (a, b) and (c, d) are identical if and only if their first components and their second components agree.
- More generally, let n be any natural number.
- Note that 2-tuples are the same as pairs.

### Relations

- Note that 2-ary relations are the same as binary relations.
- Instead of 1-ary and 3-ary relations one usually talks of unary and ternary relations.
- For any natural number n the n-fold relational composition.

### 24 2 Preliminaries

- Mostly the authors use prefix notation for function application and write f(a) = b instead of afb.
- The authors are sometimes interested in functions with special properties.

### 2.1 Mathematical Notation 25

- Given any index i, the finite sequence a0.
- Prefixes and suffixes of finite sequences are defined similarly.
- The authors apply this notation also to infinite sequences.
- In this book the computations of programs are described using the chain notation.

### Strings

- The syntactic objects considered in this book are strings.
- The authors introduce several classes of strings: expressions, assertions, programs and correctness formulas.
- The symbol = is used for the “semantic equality” of objects.

### Proofs

- Mathematical proofs are often chains of equalities between expressions.
- For the conciseness of mathematical statements the authors sometimes use the quantifier symbols ∃ and ∀ for, respectively, there exists and for all.
- The formal definition of syntax and semantics of these quantifiers appears in Sections 2.5 and 2.6.

### Induction

- In this book the authors often use inductive definitions and proofs.
- Prove that P holds for n+1 from the induction hypothesis that P holds for n.
- The authors can also use this induction principle to justify inductive definitions based on natural numbers.
- The implicit claim of this definition is: A more interesting example is the following.
- Consider the set of (fully bracketed) arithmetic expressions with constants 0 and 1, the variable v, and the operator symbols + and ·.

### 28 2 Preliminaries

- Is the smallest set of strings over the alphabet {0, 1, v,+, ·, (, )} satisfying the following inductive definition: Induction basis.
- Thus there are here three cases at the induction basis and two at the induction step.
- In this book the authors give a number of such inductive definitions; usually the keywords “induction basis” and “induction step” are dropped.
- Inductive definitions form the basis for inductive proofs.

### 2.2 Typed Expressions

- Typed expressions occur in programs on the right-hand sides of assignments and as subscripts of array variables.
- To define them the authors first define the types that are used.

### Types

- Tn are called argument types and T the value type.
- Occasionally other basic types such as character are used.

### Variables

- The authors distinguish two sorts of variables: simple variables, array variables or just arrays.
- Simple variables of type Boolean are called Boolean variables.
- In programs, simple variables are usually denoted by more suggestive names such as turn or found.
- The number of arguments of the higher type associated with the array a is called its dimension.
- The authors denote the set of all simple and array variables by Var.

### Constants

- The value of variables can be changed during execution of a program, whereas the value of constants remains fixed.
- Among the constants of basic type the authors distinguish integer constants and Boolean constants.

### 2.2 Typed Expressions 31

- In the sequel the authors drop the subscripts when using =, since from the context it is always clear which interpretation is meant.
- This definition is slightly unusual in that the authors classify the nonlogical symbols of Peano arithmetic and the connectives as constants.
- This allows us to define concisely expressions in the next section.

### Expressions

- Out of typed variables and constants the authors construct typed expressions or, in short, expressions.
- For binary constants op the authors mostly use the infix notation (s1 op s2) instead of prefix notation op(s1, s2).
- In the following list the constants in each line bind more strongly than those in the next line: · , mod and div, + and −,.

### 32 2 Preliminaries

- Thus binary function symbols bind more strongly than binary relation symbols.
- Symbols of stronger binding power are bracketed first.
- Also, they can be substituted for (see Section 2.7).
- They cannot be quantified over (see Section 2.5) and their value cannot be fixed in a direct way (see Section 2.3).
- In the following simple and subscripted variables are usually denoted by the letters u, v.

### Fixed Structure

- The integer constant 1 denotes the integer number 1 and the Boolean constant true denotes the Boolean value true.
- The unary constant | | denotes the absolute value function.
- The unary constant ¬ denotes the negation of Boolean values: ¬(true) = and ¬ = true.

### States

- In contrast to constants, the value of variables is not fixed but given through so-called proper states.
- These error states are just special symbols and not mappings from variables to data values as proper states; they are introduced in Chapters 3, 9 and 10, respectively.
- For singleton sets X,Y , and Z the authors omit the brackets { and } around the singleton element.

### 2.4 Formal Proof Systems

- The authors main interest here is in verifying programs.
- To this end the authors investigate socalled correctness formulas.
- To show that a given program satisfies a certain correctness formula the authors need proof systems for correctness formulas.
- The formulas ϕ of A are called axioms and are considered as given facts.
- With the help of proof rules further facts can be deduced from given formulas.

### 2.5 Assertions

- To this end, the authors use formulas from predicate logic.
- In the context of program verification these formulas are called assertions because they are used to assert that certain conditions are true for states.

### 40 2 Preliminaries

- Thus in contrast to Boolean expressions, quantifiers can occur in assertions.
- Note that quantifiers are allowed in front of both simple and array variables.
- To this end the authors extend the binding order used for expressions by stipulating that the connectives → and ↔ , bind stronger than ∃ and ∀.
- Also, the authors can always delete the outer brackets.
- The authors also use other abbreviations of this form which are obvious.

### 2.6 Semantics of Assertions 41

- In logic one distinguishes different kinds of occurrences.
- In the above example, the first occurrence of y is free and the other two are bound.
- By var(p) the authors denote the set of all simple and array variables that occur in an assertion p. By free(p) they denote the set of all free simple and array variables that have a free occurrence (or occur free) in p.

### 42 2 Preliminaries

- See Exercise 2.6 for the precise relationship.
- The following simple lemma summarizes the relevant properties of the meaning of an assertion.

### 2.7 Substitution 43

- And denotes a function from expressions to expressions and from assertions to assertions.
- Substitution is not so easy to define when subscripted variables are involved.
- In the second case it is checked whether the syntactically different subscripted variables a[x] and a[1] are aliases of the same location.
- This semantic equivalence is made precise in the Substitution Lemma 2.4 below.

### 44 2 Preliminaries

- Note that the definition of substitution does not take into account the infix notation of binary constants op; so to apply substitution the infix notation must first be replaced by the corresponding prefix notation.
- The following example illustrates the application of substitution.

### 46 2 Preliminaries

- Using these inductive clauses the substitution for each variable xi from the list x̄ is pursued simultaneously.
- This is illustrated by the following example.
- The first clause of the Lemma 2.2 on Identical Substitutions holds also, appropriately rephrased, for simultaneous substitutions: for all expressions s.

### 48 2 Preliminaries

- And when s 6≡ u the same conclusion follows by the Identical Substitution Lemma 2.2 and the definition of an update.
- The remaining cases are straightforward and left to the reader.
- The base case, which concerns Boolean expressions, is now implied by (i).

### 2.10 Bibliographic Remarks

- The authors use of types is very limited in that no subtypes are allowed and higher types can be constructed only directly out of the basic types.
- A more extended use of types in mathematical logic is discussed in Girard, Lafont and Taylor [1989], and of types in programming languages in Cardelli [1991] and Mitchell [1990].
- For simplicity all functions and relations used in this book are assumed to be totally defined.
- A theory of program verification in the presence of partially defined functions and relations is developed in the book by Tucker and Zucker [1988].

### 52 2 Preliminaries

- The authors definition of substitution for a simple variable is the standard one used in mathematical logic.
- The definitions of substitution for a subscripted variable, of a state, and of an update of a state are taken from de Bakker [1980], where the Substitution Lemma 2.4 also implicitly appears.
- To the reader interested in a more thorough introduction to the basic concepts of mathematical logic the authors recommend the book by van Dalen [2004].
- Part II Deterministic Programs 3 while Programs.

### 3.9 Case Study: Partitioning an Array . . . . . . . . . . . . . . . . . . . . 99

- Called while programs, which are included in all other classes of programs studied in this book.the authors.
- The former does not take into account the possibility of divergence while the latter does.
- The authors introduce here two proof systems —one for proving the correctness formulas in the sense of partial correctness and the other for proving them in the sense of total correctness.
- In Section 3.9 the authors prove as a first case study the correctness of the well- known partition program.

### 3.1 Syntax

- Following the conventions of the previous chapter, the letter u stands for a simple or subscripted variable, t for an expression and B for a Boolean expression.
- Since types are implied by the notational conventions of the previous chapter, the authors do not declare variables in the programs.
- Sometimes instead of programs the authors talk about statements.
- The statement skip changes nothing and just terminates.
- Since this interpretation of sequential composition is associative, the authors need not introduce brackets enclosing S1; S2.

### 3.2 Semantics

- You may be perfectly happy with this intuitive explanation of the meaning of while programs.
- This style has proved to be error-prone both for implementing programming languages and for writing and reasoning about individual programs.
- The idea of the denotational approach is to provide an appropriate semantic domain for M[[S]] and then define M[[S]] by induction on the structure of S, in particular, using fixed point techniques to deal with loops, or more generally, with recursion (Scott and Strachey [1971], Stoy [1977], Gordon [1979],. . .).
- That is why the authors prefer to work with an operational approach proposed by Hennessy and Plotkin [1979] and further developed in Plotkin [1981].
- Here, definitions remain very simple for all classes of programs considered in this book.

### 3.2 Semantics 59

- It consists of axioms and rules about transitions (3.1).
- This “high level” view abstracts from all details of the evaluation of expressions in the execution of assignments.
- This lemma explains the title of this part of the book: deterministic programs.
- On the other hand, in subsequent chapters the authors deal with programs admitting various computations from a given state and for which they retain this definition.
- Thus the negative information consists here of the possibility of divergence.

### Properties of Semantics

- So, in contrast to Section 3.7, both the partial correctness semantics M[[S]](σ) and the total correctness semantics Mtot [[S]](σ) can yield more than one outcome.
- But, as with the parallel programs of Chapters 8 and 9, the nondeterminism is bounded for the class of nondeterministic programs studied in this chapter.
- Note that the conventional conditionals and loops can be modeled by alternative and repetitive commands.
- The above if command has n + 1 guarded commands where the last one models the case of termination.
- The following lemmata are counterparts of the Input/Output Lemma 3.3 and the Change and Access Lemma 3.4, now formulated for nondeterministic programs.

### 3.3 Verification 63

- See Exercise 3.1. ⊓⊔ Clause (iii) of the above lemma states that two possible parsings of an ambiguous statement S1; S2; S3 yield programs with the same semantics.
- This justifies their previous remark in Section 3.1 that the sequential composition is associative.
- Note that clause (v) fails for the case of Mtot semantics.
- See Exercise 3.2. ⊓⊔ Recall that Var stands for the set of all simple and array variables.
- Part (i) of the Change and Access Lemma states that every program S changes at most the variables in change(S), while part (ii) states that every program S accesses at most the variables in var(S).

### 3.3 Verification

- Program correctness is expressed by so-called correctness formulas.
- The 64 3 while Programs precondition describes the set of initial or input states in which the program S is started and the postcondition describes the set of desirable final or output states.
- The uniform pattern of definitions in (i) and (ii) is followed for all semantics defined in the book.

### 3.3 Verification 65

- Clearly, all three formulas are true in the sense of partial correctness.
- Namely, if there existed a finite computation, its final state would satisfy false which is impossible. ⊓⊔.

### Partial Correctness

- Informally the above rule can be phrased as follows.
- If I is established upon execution of all the Si,0 sections and is preserved by each joint transition started in a state satisfying its Boolean condition, then I holds upon termination.
- The word “global” relates to the fact that the authors reason here about all processes simultaneously and consequently adopt a “global” view.
- When proving that an assertion is a global invariant the authors usually argue informally, but with arguments that can easily be formalized in the underlying proof system PN.

### 3.3 Verification 67

- To this end the authors repeatedly apply the assignment axiom while proceeding “backwards.”.
- Combining the final correctness formulas obtained for each assignment by two applications of the composition rule, the authors get the desired result.
- Let us see now how the loop rule rule can be used.
- The authors choose here as an example the first program (written in a textual form) that was formally verified.
- This historic event was duly documented in Hoare [1969].

### 3.3 Verification 69

- Intuitively, p describes the relation between the variables of DIV which holds each time the control is in front of the loop S0.
- The only step in the above proof that required some creativity was finding the appropriate loop invariant.
- The form of the assignment axiom makes it easier to deduce a precondition from a postcondition than the other way around; so the proofs of (3.5) and (3.6) proceeded “backwards.”.
- Finally, the authors did not provide any formal proof of the implications used as premises of the consequence rule.

### Total Correctness

- The semantics Mfair induces the following notion of program correctness: a correctness formula {p} S {q} is true in the sense of fair total correctness, abbreviated |=fair {p} S {q}, if Mfair [[S]]([[p]]) ⊆ [[q]].
- The transformation Tfair enables us to develop a proof system for fair total correctness.
- The starting point is the following corollary of the Embedding Theorem 12.3.

### 3.3 Verification 71

- Clearly, the only proof rule of PW that introduces the possibility of nontermination is the loop rule, so to deal with total correctness this rule must be strengthened.
- The authors now introduce the following refinement of the loop rule: RULE 7: LOOP II {p ∧.
- The two additional premises of the rule guarantee termination of the loop.

### Decomposition

- As for while programs it is sometimes more convenient to decompose the proof of total correctness of a recursive program into two separate proofs, one of partial correctness and one of termination.
- Formally, this can be done using the decomposition rule A1 introduced in Section 3.3, but with the provability signs ⊢p and ⊢t referring to the proof systems PR and TR, respectively.
- The authors apply the decomposition rule A1 to the factorial program studied in Example 4.4.
- Therefore the authors only need to establish termination.
- Applying now the simplified form of the recursion II rule the authors get (4.3).

### 3.3 Verification 75

- Correctness and that all proof rules of PW (TW) are sound for partial correctness.
- Then the result follows by the induction on the length of proofs.
- The authors consider all axioms and proof rules in turn.

### CONSEQUENCE

- Thus the consequence rule is sound for partial correctness.
- This contradicts the choice of σ and proves (3.20).
- Thus the loop II rule is sound for total correctness.
- Therefore the authors often apply proof rules to reason directly about the truth of correctness formulas.

### 3.4 Proof Outlines

- A better solution consists of a logical organization of the proof with the main steps isolated.
- In the case of correctness proofs of while programs, a possible strategy lies in using the fact that they are structured.
- The proof rules follow the syntax of the programs; so the structure of the program can be used to structure the correctness proof.
- The authors can simply present the proof by giving a program with assertions interleaved at appropriate places.

### 3.4 Proof Outlines 81

- Thus, in a proof outline, some of the intermediate assertions used in the correctness proof are retained and loop invariants are always retained.
- Thus there exists a standard proof outline of the form {p} S∗ {q}.
- More precisely, the authors introduce the following definition.
- The authors consider only two representative ones.

### 3.5 Completeness

- A natural question concerning any proof system is whether it is strong enough for the purpose at hand, that is, whether every semantically valid (i.e., true) formula can indeed be proved.
- Here the authors are interested in the completeness of the proof systems PW and TW.
- The authors introduce the following more general definition.
- (3) The proof rules presented here for while programs are not powerful enough.
- The authors also observe that the syntax for expressions as introduced in Chapter 2 is not powerful enough to express all necessary bound functions.

### 3.5 Completeness 87

- By the Definability Theorem 3.4 the authors can express weakest preconditions syntactically.
- Note that wlp(S, q) and wp(S, q) are determined only up to logical equivalence.
- To guarantee expressibility the authors need an extension of the set of integer expressions which allows us to express all partially defined computable functions and thus in particular iter(S, σ).

### 3.5 Completeness 89

- Theorem 3.5. (i) The proof system PW is complete for partial correctness of while programs.
- (ii) Assume that the set of all integer expressions is expressive.
- Then the proof system TW is complete for total correctness of while programs.

### Proof.

- The case of sequential composition is easy.
- With this preparation the authors can now prove the completeness of PW.

### 3.6 Parallel Assignment 91

- By the assumption about the expressiveness of the set of all integer expressions there exists an integer expression t such that σ(t) = iter(S, σ) for all proper states σ with M[[S]](σ) ⊓⊔ Similar completeness results can be established for various other proof systems considered in subsequent chapters.
- All these proofs proceed by induction on the structure of the programs and use intermediate assertions constructed by means of the weakest precondition or similar semantics concepts.
- As the proof systems become more complicated, so do their completeness proofs.
- In fact, for parallel and distributed programs the proofs become quite involved and tedious.
- The authors do not give these proofs and concentrate instead on the use of these proof systems for verifying programs, which is the main topic of this book.

### 3.6 Parallel Assignment

- This shows the usefulness of the parallel assignment.
- The authors briefly introduce syntax, semantics, and an axiom for the verification of parallel assignments.

### 3.6 Parallel Assignment 93

- In the following the authors prove this relationship.
- The proofs of these claims use the Coincidence Lemma 2.3 and the definition of an update of a state.

### Verification

- Thus, as with the assignment axiom 2 for ordinary assignments, this axiom formalizes backward reasoning about random assignments.
- For partial correctness the answer is “yes.”.
- Thus for proofs of partial correctness of nondeterministic programs with random assignments the authors consider the following proof system PNR.
- The reason is that in the presence of random assignments some repetitive commands always terminate but the actual number of repetitions does not depend on the initial state and is unbounded.
- Variables ranging over W can appear only in assertions and not in programs.

### Syntax

- Namely, if B evaluates to false, the latter statement simply terminates.
- In the same way, the authors may use the failure statement to check whether an array is accessed only within a certain section.
- Thus the failure statement can be used to model bounded arrays.
- As a final example consider the problem of extending the parallel assignment to the subscripted variables.
- The failure statement can then be used to catch the error.

### 3.8 Auxiliary Axioms and Rules 97

- To prove correctness of the failure admitting programs the authors introduce two proof rules.
- In the following proof rule for partial correctness the authors assume that the guard B evaluates to true when S is executed.
- In contrast, in the following proof rule for total correctness the authors also have to show that the precondition p implies that the guard B evaluates to true, thus avoiding a failure.
- Theorem 3.6. (i) The proof system PW augmented by the failure rule is sound for partial correctness of failure admitting programs.
- The authors shall discuss other statements that can cause a failure in Chapters 6 and 10.

### 3.8 Auxiliary Axioms and Rules

- Apart from using proof outlines the presentation of correctness proofs can be simplified in another way —by means of auxiliary axioms and rules.
- This can lead to a different organization of the correctness proof.
- In the case of while programs these axioms and rules for combining correctness formulas are not necessary, in the sense that their use in the correctness proof can be eliminated by applying other rules.
- This is the consequence of the Completeness Theorem 3.5.
- That is why these rules are called auxiliary rules.

### 3.9 Case Study: Partitioning an Array 99

- This lemma holds for all programs considered in this book and any semantics.
- Theorem 3.7. (Soundness of Auxiliary Axioms and Rules) (i) Axiom A2 is true for partial correctness of arbitrary programs.
- (ii) Proof rules A3–A7 are sound for partial correctness of arbitrary pro- grams.
- Clearly, other auxiliary rules can be introduced but the authors do not need them until Chapter 11 where some new auxiliary rules are helpful.

### 3.9 Case Study: Partitioning an Array

- To illustrate the input/output behaviour of PART the authors give two examples.
- Implication (3.39) states that the bijection property is preserved when the interval in enlarged.

### 3.9 Case Study: Partitioning an Array 101

- The following program is from Foley and Hoare [1971] except that for convenience the authors use parallel assigments.
- Property P0 expresses that upon termination pi holds the initial values of the array element a[f ].
- Thus PART permutes the array section a[m : n] and leaves other elements of a unchanged.
- By the conjunction rule, the authors deduce (3.41) in the sense of partial correctness from P0, the above consequence of P2, P3, and P4.

### Proof of Property P2

- S∗ {q} for partial correctness such that for every used assertion r (including p and q) the implication r → GI holds.
- Thus the assertions used in the proof outline are equivalent or stronger than GI.
- This may be needed to establish GI inside the proof outline.
- Consider now the permutation property, i.e., that PART permutes the elements of the array a but leaves a unchanged outside an interval [x′ : y′] containing [m : n].

### Proof of Property P4

- To prove property P4 and to prepare ourselves for the termination proof of PART the authors need to establish more loop invariants.
- Then the authors have the following proof outlines for partial correctness.

### Termination

- To prove the termination property T {m ≤ f ≤ n} PART {true} the authors reuse the invariants established for the three loops in the proof outline of Figure 3.4 and add appropriate bound functions.
- Let us first consider the two inner loops.
- Thus it remains to be shown that each iteration of the inner loops decreases the value of the bound functions.
- More subtle is the argument for the outer loop.

### 3.10 Systematic Development of Correct Programs

- The authors now discuss an approach of Dijkstra [1976] allowing us to develop programs together with their correctness proofs.
- The authors follow here the exposition of Gries [1982].
- All correctness formulas are supposed to hold in the sense of total correctness.
- The main issue in Dijkstra’s approach is the development of loops.

### Summation Problem

- To this end, the authors compare now the precondition and postcondition of S1.
- The authors see that adding a[k] to x will “transform” one assertion into another.

### 3.11 Case Study: Minimum-Sum Section Problem

- The authors now systematically develop a less trivial program.
- The authors study here an example from Gries [1982].

### 3.12 Exercises

- Give both an informal argument and a formal proof in the system PW.
- Show that the assignment axiom can be proved from the above axiom using the consequence rule.

### 3.12 Exercises 123

- (iv) Determine the weakest precondition wp(S, true).
- Fibonacci number Prove this correctness formula in the system TW. 3.11.
- Show that the following proof rule is sound for partial correctness: {p ∧ (i) Give the transition axioms or rules specifying the operational semantics of the repeat-loop.

### 3.13 Bibliographic Remarks

- This class is the kernel of imperative programming languages; in this book it serves as the starting point for investigating recursive, object-oriented, parallel and distributed programs.
- The approach presented here is usually called Hoare’s logic.
- It has been successfully extended, in literally hundreds of papers, to handle other programming constructs.
- The survey paper Apt [1981] should help as a guide to the history of the first ten years in this vast domain.

### 3.13 Bibliographic Remarks 125

- The verification of while programs also have been developed, for example, one based on denotational semantics.
- In Zwiers [1989] the auxiliary rules presented in Section 3.8 are called adaptation rules.
- Such identifiers appear in the treatment of recursion and in the derivation of programs from specifications.
- In Filliâtre [2007] this informal correctness proof is formalized and certified using the interactive theorem prover Coq.
- He points out that two assertions used in Hoare [1971b] 126 3 while Programs are not invariants of the outer loop of Partition but hold only in certain parts of the loop.

### 4 Recursive Programs

- In this chapter the authors introduce parameterless procedures and in the next chapter pro- cedures with parameters.
- The authors call such pro- grams recursive programs.
- In Section 4.2 the authors extend the semantics introduced 127 128 4 Recursive Programs in Section 3.2 to recursive programs.
- In Section 4.3 the authors deal with partial cor- rectness and total correctness.

### 4.1 Syntax

- Such occurrences of P are called recursive calls.
- All procedure calls in the main statement refer to procedures that are declared in D. Example 4.1.

### 4.2 Semantics

- Assume the declaration (4.1) of the factorial program.
- Assume the declaration (4.1) of the factorial procedure.
- Then the following hold for the main statement Fac:.

### 4.3 Verification 133

- Then the authors modify the auxiliary axioms and proof rules by adding the restriction that specific variables do not occur in change(D).
- Thus PR is obtained by extending the proof system PW by the recursion rule 8 and the auxiliary rules A2–A6 where the authors use the versions of auxiliary rules modified by change(D) as explained above.
- In the actual proof not all assumptions about procedure calls are needed, only those assumptions that do appear in the procedure body.
- The authors illustrate this proof presentation by returning to the factorial program.
- The desired conclusion now follows by the simplified form of the recursion rule. ⊓⊔.

### 4.3 Verification 135

- In this subsection the provability sign ⊢ refers to the proof system for total correctness that consists of the proof system TW extended by the appropriately modified auxiliary rules introduced in Section 3.8.
- The expression t plays the role analogous to the bound function of a loop.
- The intuition behind this rule is as follows.
- To prove total correctness of recursive programs the authors use the following proof system TR: PROOF SYSTEM TR :.

### Discussion

- It is useful to see why the authors could not retain in this section the original formation rule (formation rule (viii)) defining proof outlines for total correctness for a while loop.
- Individually, the while programs S1 and S2 satisfy the proof outlines for total correctness in which all assertions, including the loop invariants, equal true and the bound functions are in both cases max(x, 0).
- Suppose now for a moment that the authors adopt the above proof outlines as proof outlines for total correctness of the component programs S1 and S2.
- By the parallelism with shared variables rule 27 the authors then obtain the correctness formula {true} S {true} in the sense of total correctness.

### 4.3 Verification 141

- With this theorem the authors can state the following soundness result.
- The proof system PR is sound for partial correctness of recursive programs.
- The proof combines Theorem 4.2 with Theorem 3.1(i) on soundness of the proof system PW and Theorem 3.7(i),(ii) on soundness of the auxiliary rules.
- Additionally, the authors shall need the following lemma that clarifies the reason for the qualification that the integer variable z is used as a constant.
- Finally, the authors shall need the following observation.

### 4.3 Verification 143

- With this theorem the authors can state the following soundness result.
- The proof system TR is sound for total correctness of recursive programs.
- The proof combines Theorem 4.5 with Theorem 3.1(ii) on soundness of the proof system TW and Theorem 3.7(iii) on soundness of the auxiliary rules. ⊓⊔.

### 4.4 Case Study: Binary Search

- Given a variable val, the authors want to find out whether its value occurs in the section a[first : last], and if yes, to produce the index mid such that a[mid] = val.
- Last] is sorted, this can be done by means of the recursive binary search procedure shown in Figure 4.3, also known as Since a[first.
- (An iterative version of this program is introduced in Exercise 4.10.).
- The authors now prove correctness of this procedure.

### 4.4 Case Study: Binary Search 147

- This justifies the first application of the consequence rule.
- The authors leave the justification of the second application as Exercise 4.9.
- This completes the proof of partial correctness.

### 4.5 Exercises 149

- Further, the Boolean expressions a[mid] < val and a[mid] > val are irrelevant for the proof, so drop them from the assertions of the proof outline.
- (Formally, this step is justified by the last two formation rules for proof outlines.).

### 4.5 Exercises

- Complete the proof of partial correctness discussed there by justifying the application of the consequence rule used in the proof outline of the else branch.
- Allow the failure statements in the main statements and procedure bodies.
- Add to the proof systems PR and TR the corresponding failure rules from Section 3.7 and prove the counterparts of the Soundness Corollary 4.1 and Soundness Corollary 4.2.

### 4.6 Bibliographic Remarks

- Procedures (with parameters) were initially introduced in the programming language FORTRAN.
- Recursive procedures were first introduced in ALGOL 60.
- Their semantics was defined by the so-called copy rule.
- It is also shown there that the considered proof system for partial correctness is incomplete if in the subsidiary proofs used in the premises of the recursion rule only the axioms and proof rules of the PW proof system are used.
- This clarifies why in Example 4.4 and in Section 4.5 the authors used in these subsidiary proofs the substitution and invariance rules.

### 5 Recursive Programs with Parameters

- The presentation follows the one of the last chapter.
- In Section 5.1 the authors introduce the syntax of recursive procedures with parameters.
- To properly capture its meaning the authors need to introduce a block statement that allows us to distinguish between local and global variables.
- The approach is a modification of the approach from the previous chapter, where the additional difficulty consists of a satisfactory treatment of parameters.

### 5.1 Syntax

- When considering recursive procedures with parameters the authors need to distinguish between local and global variables.
- Informally, a block statement introduces a non-empty sequence of local variables, all of which are explicitly initialized by means of a parallel assignment, and provides an explicit scope for these local variables.
- The precise explanation of a scope is more complicated because the block statements can be nested.
- The authors assume as in the previous chapter that all procedures whose calls appear in the main statement are declared in D. Additionally, they assume now that the procedure calls are well-typed, which means that the numbers of formal and.

### 5.1 Syntax 153

- Actual parameters agree and that for each parameter position the types of the corresponding actual and formal parameters coincide.
- Note that the above definition of programs puts no restrictions on the actual parameters in procedure calls; in particular they can be formal parameters or global variables.
- The above version of the factorial procedure does not use any local variables.
- So far the authors did not clarify why the block statement is needed when considering procedures with parameters.

### 5.2 Semantics

- In order to define the semantics of the considered programs the authors extend the transition system of the previous chapter to take care of the block statement and of the procedure calls in the presence of parameters.
- The transition axiom for the block statement, given below, ensures that the local variables are initialized as prescribed by the parallel assignment, upon termination, the global variables whose names coincide with the local variables are restored to their initial values, held at the beginning of the block statement.
- From now on, to ensure a uniform presentation for the procedures with and without parameters the authors identify the statement begin local ū := t̄; S end, when ū is the empty sequence, with S.
- So when the procedure P has no parameters, this transition axiom reduces to the transition axiom (viii).
- Also it ensures that the values of the formal parameters are not changed by a procedure call: note that, thanks to the semantics of a block statement, upon.

### 5.2 Semantics 155

- Termination of a procedure call the formal parameters are restored to their initial values.
- This transition axiom clarifies that the authors consider here the call-by-value parameter mechanism, that is, the values of the actual parameters are assigned to the formal parameters.
- So in the above example during the computation of the procedure call Fac(x) block statements of the form begin local u := u − 1;S end are in- 156 5 Recursive Programs with Parameters troduced.
- The factorial procedure defined above does not satisfy this restriction.
- The partial and total correctness semantics are defined exactly as in the case of the recursive programs considered in the previous chapter.

### 5.3 Verification 157

- A block statement the initialization statement of which refers on the lefthand side to the formal parameters and on the right-hand side to the actual parameters of the procedure call.
- As in the previous chapter the authors now consider syntactic approximations of the recursive programs and express their semantics in terms of these approximations.
- The following lemma is a counterpart of the Input/Output Lemma 4.1.
- The complication now is that in the case of procedure calls variable clashes can arise.
- The authors deal with them in the same way as in the definition of the transition axiom for the procedure call.

### 5.3 Verification

- The notions of partial and total correctness of the recursive programs with parameters are defined as in Chapter 4.
- First, the authors introduce the following rule that deals with the block statement:.

### Partial Correctness: Non-recursive Procedures

- Consider now partial correctness of recursive programs.
- The main issue is how to deal with the parameters of procedure calls.

### 5.3 Verification 159

- This issue the authors discuss the parameters of non-recursive procedures first.
- In many cases, however, the authors can also prove procedure calls correct by instantiating generic procedure calls, instead of proving for each specific call its corresponding block statement correct.
- The set change(D) denotes all the global variables that can be modified by the body of some procedure declared by D. Example 5.7.
- One cannot derive this formula by an application of the copy rule because the proof rule for block statements does not allow the local variable u to occur (free) in the postcondition.the authors.

### Partial Correctness: Recursive Procedures

- Note that the presence of procedure calls with parameters does not affect the definition of change(S).
- In the case of a program consisting of mutually recursive procedure declarations the authors have the following generalization of the above rule.
- As in Section 4.3, the authors modify the auxiliary axioms and proof rules introduced in Section 3.8 so that the conditions for specific variables refer to the extended set change(S).

### 5.3 Verification 163

- Thus PRP is obtained by extending the proof system PW by the block rule 10, the instantiation rule 11, the recursion rule 12, and the auxiliary rules A2–A6.
- Next, the authors prove a generic invariance property of arbitrary procedure calls.
- This yields by the recursion III rule (no assumptions are needed here) {z̄ = x̄} P (x̄) {z̄ = x̄}, from which the conclusion follows by the instantiation axiom.
- ⊓⊔ Assume the declaration (5.1) of the factorial procedure.

### Modularity

- In the example above the authors combined two correctness formulas derived independently.
- In general, more procedures may be used and an arbitrary ‘chain’ of auxiliary properties may be constructed.
- The authors shall illustrate this approach in the case study considered at the end of this chapter.

### 5.3 Verification 167

- In the sense of partial correctness, assuming the declaration (5.1) of the factorial procedure.
- Applying now the simplified form of the recursion IV rule the authors get the desired conclusion. ⊓⊔.

### 5.3 Verification 171

- With this theorem the authors can state the following soundness result.
- The proof system TRP is sound for total correctness of recursive programs with parameters.
- Sorting is accomplished ‘in situ’, i.e., the elements of the initial array section are permuted to achieve the sorting property.

### Formal Problem Specification

- To write the desired correctness formula the authors introduce some notation.
- In other words, the authors establish some auxiliary correctness formulas first, using among others the recursion III rule.
- This procedure is non-recursive, so to verify them it suffices to prove the 174 5 Recursive Programs with Parameters corresponding properties of the procedure body using the proof systems PW and TW.
- Property P1 states the bounds for ri and le.
- Property P2 implies that the call Partition(n, k) permutes the array section a[m : n] and leaves other elements of a intact, but actually is a stronger statement involving an interval [x′ : y′] that includes [m : n], so that the authors can carry out the reasoning about the recursive calls of Quicksort.

### Auxiliary Proof: Permutation Property

- Until further notice the provability symbol ⊢ refers to the proof system PW augmented with the the block rule, the instantiation rule and the auxiliary rules A3–A7.
- In Figure 5.3 a proof outline is given that uses as assumptions the correctness formulas P1, P2, and Q2.
- More specifically, the used correctness formula about the call of Partition is derived from P1 and P2 by the conjunction rule.
- In turn, the correctness formulas about the recursive calls of Quicksort are derived from Q2 by an application of the instantiation rule and the invariance rule.

### Auxiliary Proof: Sorting Property

- In Figure 5.4 a proof outline is given that uses as assumptions the correctness formulas P3, Q2, and Q3.
- In the following the authors justify the correctness formulas about Partition and the recursive calls of Quicksort used in this proof outline.
- Moreover, by the invariance axiom, the authors have A2 {J} Quicksort(m, v) {J}.
- Then after applying the substitution rule with the substitution [x′, y′ := x, y] and the consequence rule the authors obtain Q1, or more precisely P1, P2, P3 ⊢ Q1.

### 5.5 Exercises

- Prove the following two properties of recursive programs.
- This exercise considers the modularity rule 12 ′ introduced in Section 5.3.
- 7. Prove the Soundness Theorem 5.5 for the proof system TRP.
- 8. Consider the Partition procedure defined in Section 5.5.
- Allow the failure statements in the main statements and procedure bodies.

### 5.6 Bibliographic Remarks 183

- And proof theory of the call-by-value parameter mechanism adopted here avoids any renaming and seems to be new.
- For other parameter mechanisms like call-by-name (as in ALGOL) or callby-reference (as in Pascal) a renaming of local variables in procedure bodies is unavoidable to maintain the static scope of variables.
- Clarke’s article initiated an intense research on the question of whether complete Hoare-style proof systems could be obtained for programs with a restricted ALGOL-like procedure mechanism.
- The first proof of partial correctness of Quicksort is given in Foley and Hoare [1971].
- In their approach the authors use several auxiliary rules which together have the same effect as the adaptation rule.

### 6 Object-Oriented Programs

- The local state of an object is a mapping that assigns values to its instance variables.
- Upon termination of the method call the control returns to the local state of the caller.
- The authors first restrict the language to simple method calls which do not involve parameters.
- In Section 6.3 the authors introduce the syntax and semantics of the assertion language.

### Local Expressions

- The set of expressions used here extends the set of expressions introduced in Section 2.2.
- The authors call them local expressions to stress that they refer to local properties of objects.
- Simple variables of type object and array variables with value type object are called object variables.
- As a specific case, the authors distinguish the simple object variable this which at each state denotes the currently executing object.
- Example 6.1. ⊓⊔ Summarizing, the set of expressions defined in Section 2.2 is extended by the introduction of the basic type object, the constant null of type object, and the set IV ar of (simple and array) instance variables.

### Statements and Programs

- The authors extend the definition of statements given in Section 3.1 with block statements, as introduced in Section 5.1, and method calls which are described by the following clause: S ::= s.m.
- The local object expression s in the method call s.m denotes the called object.
- Because the statements now include method calls, the authors allow for recursive (albeit parameterless) methods.
- To ensure correct use of the variable this, the authors only consider statements in which this is read-only, that is, they disallow assignments to the variable this.
- Further, to ensure that instance variables are permanent, the authors require that in each block statement begin local ū := t̄;S end they have var(ū) ⊆.

### 6.1 Syntax 189

- The execution of this method call by the current object, denoted by this, transfers control from the local state of the current object to that of the called object y.
- Using the method call y.getx it assigns to the instance variable z of the current object the value of the instance variable x of the object denoted by y, using the variable return.
- Since count is an instance variable, the call up.inc of the method inc of up does not affect the value of count of the object down (and vice versa), assuming up 6= down, i.e., when up and down refer to distinct objects.
- The above example illustrates one of the main features of instance variables.
- The authors represent a (non-circular) linked list using the instance object variable next that links the objects of the list, and the constant null that allows us to identify the last element of the list.

### 6.1 Syntax 191

- The authors want to compute the sum of the instance variables val.
- The first one updates the variable sum, while the second one allows us to progress to the next object in the list.
- The recursive call of the method find of the object denoted by the instance variable next involves a transfer of the control from the local state of the calling object this to the local state of the 192 6 Object-Oriented Programs next object in the list.
- If next equals null, then the search terminates and the void reference is returned, through the variable return, also known as This call is conditional.
- For the main statement S in Example 6.3, the authors have count ∈ change(S), given the declarations of the methods inc and reset.

### 6.2 Semantics

- In this section the authors define the semantics of the introduced object-oriented programs.
- The authors first define the semantics of local expressions.
- Subsequently the authors introduce a revised definition of an update of a state and provide the transition axioms concerned with the newly introduced programming constructs.

### Semantics of Local Expressions

- The main difficulty in defining the semantics of local expressions is of course how to deal properly with the instance variables.
- As already mentioned above, each instance variable has a different version (‘instance’) in each object.
- Then the authors determine the local state of this object, which is σ(o), or σ(σ(this)), and subsequently apply this local state to the considered instance variable x.

### 6.2 Semantics 193

- This two-step procedure is at the heart of the definition given below.
- So in each proper state a variable of type object equals some object of Dobject, which can be the null object.
- Note that a state σ also assigns a local state σ(null) to the null object.
- As the authors will see below this local state will never be accessed by an object-oriented program.

### Updates of States

- Next, the authors proceed with the revision of the definition of a state update for the case of instance variables.
- Here, the intuition the authors provided when explaining the semantics of instance variables, is of help.

### Semantics of Statements and Programs

- To define the semantics of considered programs the authors introduce three transition axioms that deal with the assignment to (possibly subscripted) instance variables and with the method calls.
- The second transition axiom shows that the authors reduce the semantics of method calls to procedure calls with parameters by treating the variable this as a formal parameter and the called object as the corresponding actual parameter.
- Then the variable this would remain a global variable throughout the computation.
- In the last two transitions the authors performed the following simplifications in configurations on the right-hand side.

### 6.3 Assertions 197

- Each such assignment arises only within the context of the block statement in the transition axiom (xii) and is activated in a state σ such that σ(s) 6= null.
- When considering verification of object-oriented programs the authors shall only consider computations that start in a proper state σ such that σ(this) 6= null, i.e., in a state in which the current object differs from the void reference.
- The Absence of Blocking Lemma 6.1 implies that such computations never lead to a proper state in which this inequality is violated.
- The partial correctness semantics is defined exactly as in the case of the recursive programs with parameters considered in Chapter 5.
- The total correctness semantics additionally records failures.

### 6.3 Assertions

- Local expressions of the programming language only refer to the local state of the executing object and do not allow us to distinguish between differ- 198 6 Object-Oriented Programs ent versions of the instance variables.
- Using them and the normal this variable (that is of type object) the authors can generate the following global expressions: next, next.
- This and next.x are not global expressions, since neither this nor x are instance variables.
- The authors call a global expression of the form s.u a navigation expression since it allows one to navigate through the local states of the objects.
- Next refers to the object that can be reached by ‘moving’ to the object denoted by the value of next of the current object this and evaluate the value of its variable next.

### 6.3 Assertions 199

- Other words, the authors can view an instance variable u as an abbreviation for the global expression this.u.
- Note that this semantics also provides meaning to global expressions of the form null.u.
- Such expressions are meaningless when specifying correctness of programs because the local state of the null object can never be reached in computations starting in a proper state σ such that σ(this) 6= null (see the Absence of Blocking Lemma 6.1).
- Example 6.10. ⊓⊔ Assertions are constructed from global Boolean expressions as in Section 2.5.
- This means that only normal variables can be quantified.

### Substitution

- The substitution operation [u := t] was defined in Section 2.7 only for the normal variables u and for the expressions and assertions as defined there.
- The authors now extend the definition to the case of instance variables u and global expressions and assertions constructed from them.
- This explains the use of conditional expressions below.
- The following example should clarify this definition.
- The authors have the following counterpart of the Substitution Lemma 2.4. Lemma 6.2. (Substitution of Instance Variables) See Exercise 6.3. ⊓⊔.

### 6.4 Verification 201

- This new definition ensures that when studying program correctness the authors limit ourselves to meaningful computations of object-oriented programs.
- The correctness notions are then defined in the familiar way using the semantics M and Mtot.
- Since by definition fail, ⊥ 6∈ [[q]] holds, as in the case of the failure admitting programs from Section 3.7, |=tot {p} S {q} implies that S neither fails nor diverges when started in a proper state σ satisfying p and such that σ(this) 6= null.

### 6.4 Verification 203

- So the authors obtain the above correctness formula (6.2) by an application of the composition rule, the consequence rule and, finally, the block rule.
- Finally, using the substitution rule A7 with the substitution u := this the authors obtain the desired correctness formula.
- Given an arbitrary method m (so in particular for the above method inc), the authors now wish to prove the correctness formula {other = null} other.m {false} in the sense of partial correctness.
- Now, by the assignment axiom for normal variables the authors have 204 6 Object-Oriented Programs {other = null} this := other {this = null}.
- Further, by the invariance axiom A2 the authors have {false} S {false}, so by the composition rule and the block rule they obtain (6.3).

### 6.4 Verification 205

- Thus TO is obtained by extending proof system TW by the block rule, the assignment to instance variables axiom, instantiation II rule, the recursion VI rule, and the auxiliary rules A3–A6.
- Count = z} in the sense of total correctness.

### 6.5 Adding Parameters

- The authors now extend the syntax of the object-oriented programs by allowing parametrized method calls.
- Further, the authors assume the same restriction as in Chapter 5 in order to avoid name clashes between local variables and global variables.
- Then the main statement y.setx(t) sets the value of the instance variable x of the object y to the value of the local expression t. ⊓⊔ Example 6.16.
- Consider an instance object variable next and the method definition setnext(u) :: next := u.
- Then the main statement x.setnext(next); next := x inserts in this list the object denoted by the object variable x between the current object denoted by this and the next one, denoted by next, see Figures 6.2 and 6.3. ⊓⊔.

### 6.5 Adding Parameters 209

- To prove partial correctness of object-oriented programs with parameters the authors use the following proof system POP : PROOF SYSTEM POP :.
- Thus POP is obtained by extending the proof system PW by the block rule, the assignment to instance variables axiom, the instantiation III rule, the recursion VII rule, and the auxiliary axioms and rules A2–A7.
- An application of the block rule concludes the proof.
- Note that even though the assignment to the variable this does not appear in the considered program, it is crucial in establishing the program correctness.

### 6.6 Transformation of Object-Oriented Programs

- The proof rules for reasoning about the correctness of object-oriented programs (with parameters) are derived from the corresponding proof rules for recursive programs of Chapter 5.
- First the authors transform instance variables into normal array variables.
- The following lemma clarifies the outcome of this transformation.
- The authors establish the correspondence between an object-oriented program S and its transformation Θ(S) using an alternative semantics of the recursive.

### 6.6 Transformation of Object-Oriented Programs 213

- This way the authors obtain a precise match between S and Θ(S).
- The authors have the following correspondence between the two semantics.
- The proof proceeds by induction on the number of transitions, see Exercise 6.10.
- Further, the authors have the following correspondence between an object-oriented program S and its transformation Θ(S).

### 6.6 Transformation of Object-Oriented Programs 215

- It follows directly by the Assertion Lemma 6.6 and the Correctness Theorem 6.1. ⊓⊔.
- The proof proceeds by induction on the length of the derivation, see Exercise 6.14.
- ⊓⊔ Lemma 6.8. (Translation of Total Correctness Proofs of Method Calls).
- Next, the authors generalize the above lemmas about method calls to statements.

### 6.7 Object Creation 217

- The case of an application of the recursion rules VII and VIII is dealt with by the Translation Lemma 6.9, see Exercise 6.17. ⊓⊔.
- The authors can now establish soundness of the considered proof systems.
- Theorem 6.2. (Soundness of POP and TOP) (i) The proof system POP is sound for partial correctness of object-oriented programs with parameters.
- The proof system TOP is sound for total correctness of object-oriented programs with parameters.

### 6.7 Object Creation

- In this section the authors introduce and discuss the dynamic creation of objects.
- Given the method definition setnext(u) :: next := u, which sets the instance object variable next, the following method inserts a new element in a list of objects linked by their instance variable next: insert :: begin local z := next; next := new; next.setnext(z) end.
- After the assignment of a new object to this 218 6 Object-Oriented Programs variable, the method call next.setnext(z) sets the instance variable next of the newly created object to the value of z. ⊓⊔.
- The authors call local expressions obeying these restrictions pure.
- The authors do allow for arrays with value type object, e.g., arrays of type integer → object.

### Assertions

- In the programming language the authors can only refer to objects that exist; objects that have not been created cannot be referred to and thus do not play a role.
- Therefore, the authors do not allow the instance Boolean variable created to occur in assertions.
- By definition, these are states in which this and null refer to created objects and all (possibly subscripted) normal object variables and all (possibly subscripted) instance object variables of created objects also refer to created objects.
- Further, for every instance object variable y the authors have that σ(σ(y)) = true.
- Such quantification requires a more sophisticated analysis as the following example shows.

### 6.7 Object Creation 221

- Since the authors restrict the semantics of assertions to consistent states, the universal quantifier ∀x and the elements of the array a range over created objects.
- Thus p states that the array a stores all created objects (and only those).
- More specifically, the authors do not have {p} u := new {p}, so the invariance axiom does not hold any more.
- ⊓⊔ First, the authors define the substitution operation for expressions.
- The following example shows that in the above lemma the restriction to pure global expressions and to consistent states is necessary.

### 6.7 Object Creation 223

- The authors extend the substitution operation to pure assertions along the lines of Section 2.7.
- The authors have the following substitution lemma.
- The proof proceeds by induction on the complexity of s and p, using Lemma 6.10 for the base case of Boolean expressions (see Exercise 6.19).
- The following lemma shows that the restriction concerning conditional expressions in pure assertions does not affect the expressiveness of the assertion language because conditional expressions can always be removed.

### 6.7 Object Creation 225

- By the object creation rule and the consequence rule, the authors thus derive {y = this} next := new {p}, as desired. ⊓⊔.
- To prove partial correctness of object-oriented programs with object creation the authors use the following proof system POC : PROOF SYSTEM POC :.
- Thus POC is obtained by extending the proof system POP by the axiom and rule for object creation.
- Thus TOC is obtained by extending the proof system TOP by the axiom and rule for object creation.

### 6.8 Case Study: Zero Search in Linked List 227

- Objects which starts with the object y, ends with return, and all its objects, except possibly the last one, are different from null and do not store zero.
- The postcondition q thus states that the returned object is null or stores zero and that for some array section a[k : n] the above assertion p holds.
- The authors establish a more general correctness formula, namely {true} y.find {q}.
- From which the desired formula follows by the instantiation II rule.
- To justify this proof outline it suffices to establish the following three claims.

### 6.8 Case Study: Zero Search in Linked List 231

- This completes the justification of the proof outline.
- By the recursion VI rule the authors now derive from (6.4) and the fact that r → y 6= null the correctness formula 232 6 Object-Oriented Programs {r} y.find {true}.
- Find {true}, from which the desired correctness formula follows by the elimination rule.

### 6.9 Case Study: Insertion into a Linked List

- By putting null.next = null this requirement can easily be met.
- The assertion q0 states that the chain of objects is ‘broken’ at the kth position.
- The assertion q1 states that the instance variable next of the object.

### 6.9 Case Study: Insertion into a Linked List 233

- Finally, the assertion q2 states that the instance variable next of this new object refers to the object at position k+1.
- By the simplified version of the recursion V rule, it suffices to prove {p} begin local this := y;S end {q}, where S denotes the body of the method insert.
- This claim also follows by an application of the assignment axiom for normal variables and a trivial application of the consequence rule.
- For the second implication recall that z = next stands for z = this.

### 6.9 Case Study: Insertion into a Linked List 235

- To justify the proof outline in Figure 6.7 it suffices to establish the following two claims.
- By the assignment axiom for normal variables and the consequence rule, it suffices to observe that this = a[k] → next = a[k].

### 6.9 Case Study: Insertion into a Linked List 237

- By the assignment axiom for instance variables and the consequence rule, the authors therefore derive the correctness formula {q0 ∧ q1 ∧ this = a[k].
- Next the authors obtain the assertion if this = a[k].

### 6.10 Exercises 239

- To compute the sum of the instance integer variables val the authors used in Example 6.4 a normal integer variable sum, a normal object variable current that points to the current object, and two methods, add and move, defined as follows: add :: sum := sum + val, move :: current := next.
- Then the following main statement S computes the desired sum: S ≡ sum := 0; current := first; while current 6= null do current.add; current.
- Prove {p} S {q} in the sense of both partial and total correctness.

### 6.11 Bibliographic Remarks

- Dahl and Nygaard [1966] introduced in the 1960s the first object-oriented programming language called Simula.
- The proof theory for recursive method calls presented here is based on de Boer [1991b].
- The Java Modeling Language (JML) can be used to specify Java classes and interfaces by adding annotations to Java source files.
- Banerjee and Naumann [2005] further discuss restrictions on aliasing to ensure encapsulation of classes in an object-oriented programming language with pointers and subtyping.
- Recent work on assertional methods for object-oriented programming languages by Barnett et al. [2005] focuses on object invariants and a corresponding methodology for modular verification.

### 6.11 Bibliographic Remarks 241

- Leavens [2006] also introduce a class of invariants which support modular reasoning about complex object structures.
- There exist a number of tools based on theorem provers which assist in (semi-)automated correctness proofs of object-oriented programs.
- In particular, Flanagan et al. [2002] describe ECS/Java (Extended Static Checker for Java) which supports the (semi-)automated verification of annotated Java programs.
- The KeY Approach of Beckert, Hähnle and Schmitt [2007] to the verification of object-oriented software is based on dynamic logic.

### 7 Disjoint Parallel Programs

- That is why the authors introduce and study them in several stages.
- And in this chapter the authors investigate disjoint parallelism, the simplest form of parallelism.
- Disjointness means here that the component programs have only reading access to common variables.
- Disjoint paral- lelism provides a good preparation for studying these extensions.
- Additionally, the authors need a proof rule dealing with the so-called auxiliary variables; these are vari- ables used to express properties about the program execution that cannot be expressed solely in terms of program variables.

### 7.1 Syntax

- Note that disjoint programs are allowed to read the same variables.
- Disjoint parallel programs are generated by the same clauses as those defining while programs in Chapter 3 together with the following clause for disjoint parallel composition: S ::= [S1‖. . .‖Sn], where for n > 1, S1, . . .,.
- Sn are pairwise disjoint while programs, called the components of S.
- Thus the authors do not allow nested parallelism, but they allow parallelism to occur within sequential composition, conditional statements and while loops.

### 7.2 Semantics

- This form of modeling concurrency is called interleaving.
- Recall that the empty program E denotes termination.
- [E‖y := 2‖z := 3] denotes a parallel program where the first component has terminated.
- Therefore the authors introduce two types of input/output semantics for disjoint programs in just the same way as for while programs.

### Determinism

- Unlike while programs, disjoint parallel programs can generate more than one computation starting in a given initial state.
- Thus a weaker form of determinism holds here, in that for every disjoint parallel program S and proper state σ, Mtot [[S]](σ) has exactly one element, either a proper state or the error state ⊥.
- This turns out to be a simple corollary to some results concerning properties of abstract reduction systems.
- Suppose that → satisfies the diamond property.
- To deal with infinite sequences, the authors need the following lemma.

### 7.2 Semantics 251

- Then for every a, yield(a) has exactly one element.
- Suppose now that it has exactly one element, say b.
- To apply the Yield Lemma 7.4 to the case of disjoint parallel programs, the authors need the following lemma.

### Sequentialization

- The Determinism Lemma helps us provide a quick proof that disjoint parallelism reduces to sequential composition.
- In Section 7.3 this reduction enables us to state a first, very simple proof rule for disjoint parallelism.
- To relate the computations of sequential and parallel programs, the authors use the following general notion of equivalence.
- Two computations are input/output equivalent, or simply i/o equivalent, if they start in the same state and are either both infinite or both finite and then yield the same final state.

### 7.3 Verification 253

- Sn are activated in a sequential order: first execute exclusively S1, then, in case of termination of S1, execute exclusively S2, and so forth.
- This claim follows immediately from the observation that the computations of S1; . . .;.
- By the Determinism Lemmata 3.1 and 7.6, both sides of the above inclusion have exactly one element.

### Parallel Composition

- The Sequentialization Lemma 7.7 suggests the following proof rule for disjoint parallel programs.
- Thus when added to the previous proof systems PW or TW for partial or total correctness of while programs, it yields a sound proof system for partial or total correctness of disjoint parallel programs.
- For a very simple application let us look at the following example.
- Though simple, the sequentialization rule has an important methodological drawback.

### 7.3 Verification 255

- This proof rule links parallel composition of programs with logical conjunction of the corresponding pre- and postconditions and also sets the basic pattern for the more complicated proof rules needed to deal with shared variables and synchronization in Chapters 8 and 9.
- Requiring disjointness of the pre- and postconditions and the component programs in the disjoint parallelism rule is necessary.
- But let us see in more detail where a possible proof breaks down.
- The general approach thus consists of extending the program by the assignments to auxiliary variables, proving the correctness of the extended program and then deleting the added assignments.
- Auxiliary variables should neither influence the control flow nor the data flow of the program, but only record some additional information about the program execution.

### 7.3 Verification 257

- This deletion process can result in incomplete programs.
- For proofs of total correctness of disjoint parallel programs the authors use the following proof system TP.
- Whether some variables are used as auxiliary variables is not visible from proof outlines; it has to be stated separately.

### 7.4 Case Study: Find Positive Element 261

- This proves the soundness of the auxiliary variables rule for partial correctness.
- The case of total correctness is handled analogously using (7.8) instead of (7.7).
- ⊓⊔ Corollary 7.1. (Soundness of PP and TP) (i) The proof system PP is sound for partial correctness of disjoint parallel programs.
- These proofs rely on the Input/Output Lemma 3.3 and the Change and Access Lemma 3.4, which also hold for disjoint parallel programs (see Exercises 7.1 and 7.2). ⊓⊔.

### 7.4 Case Study: Find Positive Element

- The authors study here a problem treated in Owicki and Gries [1976a].
- 0)} 262 7 Disjoint Parallel Programs in the sense of total correctness.
- To speed up the computation, FIND is split into two components which are executed in parallel: the first component S1 searches for an odd index k and the second component S2 for an even one.
- This is a version of the program FINDPOS studied in Owicki and Gries [1976a] where the loop conditions have been simplified to achieve disjoint parallelism.
- To prove that FIND satisfies its input/output specification (7.9), the authors first deal with its components.

### 7.4 Case Study: Find Positive Element 263

- The authors prove (7.10) and (7.11) using the proof system TW for total correctness of while programs.
- Also, the bound function t1 decreases with each iteration through the loop.
- The authors can now apply the rule of disjoint parallelism to (7.10) and (7.11) because the corresponding disjointness conditions are satisfied.

### 7.5 Exercises

- 1. Prove the Input/Output Lemma 3.3 for disjoint parallel programs.
- 2. Prove the Change and Access Lemma 3.4 for disjoint parallel programs.
- 3. Let x and y be two distinct integer variables and let s and t be integer expressions containing some free variables.

### 7.6 Bibliographic Remarks

- The symbol ‖ denoting parallel composition is due to Hoare [1972].
- The interleaving semantics presented here is a widely used approach to modeling parallelism.
- Abstract reduction systems as used in Section 7.2 are extensively covered in Terese [2003].
- The proof of the Sequentialization Lemma 7.7 is based on the fact that transitions of disjoint programs commute, see Exercises 7.5 and 7.6.
- Its correctness proof is a variation of the corresponding proof of FINDPOS in Owicki and Gries [1976a].

### 8.2 Syntax

- Formally, shared variables are introduced by dropping the disjointness requirement for parallel composition.
- Atomic regions may appear inside a parallel composition.
- Syntactically, these are statements enclosed in angle brackets 〈 and 〉.
- Parallel programs with shared variables (or simply parallel programs) are generated by the same clauses as those defining while programs together with the following clause for parallel composition: S ::= [S1‖. . .‖Sn], where S1, . . ., Sn are component programs (n > 1).

### 8.3 Semantics

- The semantics of parallel programs is defined in the same way as that of disjoint parallel programs, by using transition axioms and rules (i)–(vii) introduced in Section 3.2 together with transition rule (xvii) introduced in Section 7.2.
- To complete the definition the authors still need to define the semantics of atomic regions.
- In the informal Section 8.1 the authors have already indicated that parallel programs with shared variables can exhibit nondeterminism.
- The lemma follows immediately from the shape of the transition axioms and rules (i) – defining the transition relation.
- Since T is finitely branching, there are only finitely many children M1, . . .,Mn of Ni. Clearly, finiteness of the computation tree implies finiteness of Mtot [[S]](σ), and by definition an infinite path in the tree means that S can diverge from σ, thus yielding ⊥ ∈ Mtot [[S]](σ). ⊓⊔.

### 8.3 Semantics 273

- Usually, the authors may assume only that the hardware guarantees the atomicity of a single critical reference, that is, an exclusive read or write access to a single shared variable, either a simple one or a subscripted one.
- Note that (iii) is obtained if both x and y are first read and then changed.
- This definition is not realistic, but for programs all of whose atomic actions contain at most one shared variable access, this definition models exactly their execution on conventional computer hardware.
- Generally speaking, the authors can observe the following dichotomy: .
- The larger the grain of atomicity the easier the correctness proof of the program.

### Component Programs

- Total correctness of component programs can be proved by using the proof system TW for the total correctness of while programs together with the atomic region rule 26 for atomic regions introduced in Section 8.4.
- This rule is clearly sound for total correctness.
- In the premises of this rule the authors separated proofs outlines involving S∗ and S∗∗ for the facts that the assertion p is kept invariant and that the bound function t decreases, but only the proof.
- In the context of parallel programs it is possible that components interfere with the termination proofs of other components.
- By a path the authors mean here a possibly empty finite sequence of normal assignments and atomic regions.

### 8.4 Verification: Partial Correctness 275

- Removing all brackets 〈 and 〉 from S and the proof outline {p} Inserting appropriate assertions in front of the subprograms of S1 that are nonnormal subprograms of S yields a standard proof outline {p} S∗∗1 {q} for partial correctness.
- The claim now follows by the Strong Soundness Theorem 3.3. ⊓⊔.
- This shows that the introduction of atomic regions leads to a straightforward extension of the proof theory from while programs to component programs.

### No Compositionality of Input/Output Behavior

- Much more complicated is the treatment of parallel composition.
- Let us make this observation more precise by examining correctness formulas for the programs of Example 8.1.
- Si as premises and yields the input/output specification { ∧n i=1 pi} [S1‖. . .‖Sn] { ∧n i=1 qi} for the parallel program as a conclusion under some nontrivial conditions.
- Recall that this is possible for disjoint parallel programs —see the sequentialization rule 23.
- For parallel programs [S1‖. . .‖Sn] with shared variables the authors have to investigate how the input/output behavior is affected by each action in the computations of the component programs Si.

### Parallel Composition: Interference Freedom

- The total correctness of a parallel program is proved by considering interference free standard proof outlines for the total correctness of its component programs.
- In the definition of interference freedom both the assertions and the bound functions appearing in the proof outlines must now be tested.
- Total Correctness) (1) Let S be a component program, also known as Definition 8.4. (Interference Freedom.
- Consider a standard proof outline {p} S∗ {q} for total correctness and a statement A with the precondition pre(A).
- The authors say that A does not interfere with {p}.

### 8.4 Verification: Partial Correctness 277

- Thus interference freedom means that the execution of atomic steps of one component program never falsifies the assertions used in the proof outline of any other component program.
- Its premises are now much more complicated.
- The restriction to standard proof outlines reduces the amount of testing to a minimal number of assertions.
- In the case of two component programs of length ℓ1 and ℓ2, proving interference freedom requires proving ℓ1×ℓ2 additional correctness formulas.
- As a first application of the parallelism with shared variables rule let us prove partial correctness of the parallel programs considered in Section 8.1.

### 8.4 Verification: Partial Correctness 279

- Auxiliary Variables Needed However, once a slightly stronger claim about the program from Example 8.2(i) is considered, the parallelism with shared variables rule 27 becomes too weak to reason about partial correctness.
- The reason for this mismatch is that the authors cannot express in terms of the variable x the fact that the first component x := x+2 should still be executed.
- The authors now prove the correctness formula (8.1) using additionally the rule of auxiliary variables.

### 8.4 Verification: Partial Correctness 281

- In particular, the introduction of the auxiliary variable done required some insight into the execution of the given program.
- It thus mirrors exactly the control flow in the component.
- Summarizing, to prove partial correctness of parallel programs with shared variables, the authors use the following proof system PSV : PROOF SYSTEM PSV :.

### 8.4 Verification: Partial Correctness 283

- Then an argument analogous to the one given in the proof of the Strong Soundness Theorem 3.3 and the Strong Soundness for Component Programs Lemma 8.5 shows that τ |= r. Case 2 j 6= k.
- The parallelism with shared variables rule 27 is sound for partial correctness of parallel programs.
- The proof system PSV is sound for partial correctness of parallel programs.
- Follows by the same argument as the one given in the proof of the Soundness Corollary 7.1. ⊓⊔ 284 8 Parallel Programs with Shared Variables.

### 8.5 Verification: Total Correctness 285

- Indeed, if along such “shorter” paths the decrease of the bound function t is guaranteed, then it is also guaranteed along the “longer” paths that do take into account the loop bodies.
- The authors can now formulate the revised definition of a proof outline.
- The only exception is the formation rule (v) dealing with while loops which is replaced by the following formation rule.
- ⊓⊔ 286 8 Parallel Programs with Shared Variables.

### 8.5 Verification: Total Correctness 287

- (condition (i)) nor increases the bound functions (condition (ii)) used in the proof outline of any other component program.
- Note that the correctness formulas of condition (ii) have the same form as the ones considered in the second premise of formation rule (xi) for proof outlines for total correctness of while loops.
- In particular, the value of bound functions may drop during the execution of other components.
- By referring to this extended notion of interference freedom, the authors may reuse the parallelism with shared variables rule 27 for proving total correctness of parallel programs.
- Here even(x) and odd(x) express that x is an even or odd integer value, respectively.

### 8.5 Verification: Total Correctness 289

- This shows that the value of t during the execution of the segment η decreases; that is, τ2(t) < τ1(t). (8.16) Since this is true for any two consecutive configurations of the form (16) in the infinite computation ξ, the statements (8.15) and (8.16) yield a contradiction.
- Consider interference free standard proof outlines for total correctness for component programs of a parallel program.
- By removing from each of these proof outlines all annotations referring to the bound functions, the authors obtain interference free standard proof outlines for partial correctness.
- Follows by the same argument as the one given in the proof of the Soundness Corollary 7.1. ⊓⊔.

### 8.6 Case Study: Find Positive Element More Quickly 291

- To enhance readability in each step the authors annotated the transition relation → with the index of the activated component.
- It is easy to see why with the new definition of proof outlines for total correctness the authors can no longer justify the proof outlines suggested above.
- Unfortunately, the stronger premises in the new formation rule (xi) for total correctness proof outlines of while loops given in Definition 8.3 reduce its applicability.
- The authors have seen that the component program S1 terminates when considered in isolation.
- As the authors are going to see, many parallel programs can be successfully handled in the way proposed here.

### 8.6 Case Study: Find Positive Element More Quickly

- Here the authors consider an improved program FINDPOS for the same problem.
- 0)} 292 8 Parallel Programs with Shared Variables in the sense of total correctness, where a 6∈ change.
- What is new is that now S1 should stop searching once S2 has found a positive element and vice versa for S2.
- Thus some communication should take place between S1 and S2.
- To prove (8.17) in the system TSV, the authors first construct appropriate proof outlines for S1 and S2.

### 8.6 Case Study: Find Positive Element More Quickly 293

- Except for the new postconditions which are the consequences of the new loop conditions, all other assertions are taken from the corresponding proof outlines in Section 7.4.
- Note that the invariants and the bound functions satisfy the new conditions formulated in Definition 8.3.
- To apply the parallelism with shared variables rule 27 for the parallel composition of S1 and S2, the authors must show interference freedom of the two proof outlines.
- This amounts to checking 24 correctness formulas!.
- The only nontrivial cases deal with the interference freedom of the postcondition of S1 with the assignment to the variable eventop in S2 and, symmetrically, of the postcondition of S2 with the assignment to the variable oddtop in S1.

### 8.7 Allowing More Points of Interference

- The fewer points of interference there are, the simpler the correctness proofs of parallel programs become.
- On the other hand, the more points of interference parallel programs have, the more realistic they are.
- The first transformation achieves this by reducing the size of atomic regions.
- The authors treat the case when S has no initialization part S0 and when T results from S by splitting 〈R1; R2〉 into 〈R1〉; 〈R2〉.
- The authors first define good and almost good (fragments of) computations for the program T .

### 8.7 Allowing More Points of Interference 297

- The cases when S has an 298 8 Parallel Programs with Shared Variables initialization part S0 and where T results from S by splitting the atomic region 〈if B then R1 else R2 fi〉 are left as Exercise 8.11.
- The authors could have reformulated the Corollaries 8.5 and 8.6 also as proof rules and integrated them in the proof systems PSV and TSV introduced in Sections 8.4 and 8.5.
- The authors prefer to keep them separate to stress their status as additional program transformations.

### 8.8 Case Study: Parallel Zero Search

- Both corollaries are applicable here by virtue of the fact that x does not appear in S2 and y does not appear in S1.
- The authors prove (8.19) in the proof system PSV for partial correctness of parallel programs with shared variables introduced in Section 8.4.
- The three for each component are pairwise symmetric.
- The remaining cases in the interference freedom proof are straightforward and left to the reader.
- Since for the initialization part of T the correctness formula {true} found := false;x := 0 : y := 1 {p1 ∧ p2} holds, a straightforward application of the rule for sequential composition and the consequence rule yields the desired partial correctness result (8.18).

### 8.9 Exercises

- 1. Prove the Input/Output Lemma 3.3 for parallel programs.
- 2. Prove the Change and Access Lemma 3.4 for parallel programs.
- Finally, apply the rule of auxiliary variables (rule 25).

### 8.10 Bibliographic Remarks

- As already mentioned, the approach to partial correctness and total correctness followed here is due to Owicki and Gries [1976a] and is known as the “Owicki/Gries method.”.
- The presentation follows Apt, de Boer and Olderog [1990], in which the stronger formation rule for proof outlines for total correctness of while loops (formation rule (viii) given in Definition 8.3) was introduced.
- The Owicki/Gries method has been criticized because of its missing compositionality as shown by the global test of interference freedom.
- This motivated research on compositional semantics and proof methods for parallel programs —see, for example, Brookes [1993] and de Boer [1994].

### 9 Parallel Programs with Synchronization

- To formulate such waiting conditions the authors ex- tend the program syntax of Section 9.1 by a synchronization construct, the await statement introduced in Owicki and Gries [1976a].
- This is a situation where some components of a parallel program did not terminate and all nonterminated components 307 308 9 Parallel Programs with Synchronization are blocked because they wait eternally for a certain condition to become satisfied.
- In this chapter the authors present a method of Owicki and Gries [1976a] for prov- ing deadlock freedom.
- These transformations are used in the case study in Section 9.7 where the authors prove correctness of the zero search program ZERO-6 from Chapter 1.

### 9.1 Syntax

- A component program is now a program generated by the same clauses as those defining while programs in Chapter 3 together with the following clause for await statements: S ::= await B then S0 end, where S0 is loop free and does not contain any await statements.
- Thanks to this syntactic restriction no divergence or deadlock can occur during the execution of S0, which significantly simplifies their analysis.
- Parallel programs with synchronization (or simply parallel programs) are then generated by the same clauses as those defining while programs, together with the usual clause for parallel composition: S ::= [S1‖. . .‖Sn], where S1, . . ., Sn are component programs (n > 1).
- Note that await statements may appear only within the context of parallel composition.
- If B evaluates to false, the component gets blocked and the other components take over the execution.

### 9.2 Semantics

- This transition rule formalizes the intuitive meaning of conditional atomic regions.
- A deadlock arises if the program has not yet terminated, but all nonterminated components are blocked.
- Thus, for parallel programs with synchronization, there is no analogue to the Absence of Blocking Lemma 8.1.

### 9.3 Verification 315

- This is how deadlock freedom is established in the second premise of the following proof rule for total correctness of parallel programs.
- To prove total correctness of parallel programs with synchronization, the authors use the following proof system TSY : PROOF SYSTEM TSY :.
- Proof outlines for parallel programs with synchronization are defined in a straightforward manner (cf. Chapter 7).
- The following example illustrates the use of rule 29 and demonstrates that for the components of parallel programs the authors cannot prove in isolation more than weak total correctness.

### 9.3 Verification 317

- The proof is by induction on the length of the transition sequence considered in the formulation of the lemma, and proceeds analogously to the proof of the Strong Soundness for Parallel Programs Lemma 8.8.
- By the definition of a proof outline, in particular formation rule (xii) for the await statements, there exist assertions p and q and an annotated version.
- The proof system PSY is sound for partial correctness of parallel programs with synchronization.
- The proof is analogous to the proof of the Termination Lemma 8.9.

### 9.4 Case Study: Producer/Consumer Problem 319

- ⊓⊔ Corollary 9.3. Rule 29 is sound for total correctness of parallel programs with synchronization.
- Consider interference free standard proof outlines for weak total correctness for component programs.
- By removing from each of these proof outlines all annotations referring to the bound functions, the authors obtain interference free proof outlines for partial correctness.
- The claim now follows from the Parallelism Corollary 9.1 and the Deadlock Freedom Lemma 9.5. ⊓⊔ Corollary 9.4. (Soundness of TSY).

### 9.4 Case Study: Producer/Consumer Problem

- The authors assume that the producer and consumer work in parallel and proceed at a variable but roughly equal pace.
- Moreover, the producer should not have to wait with the production of a new value if the consumer is momentarily slow with its consumption.
- Thus the producer adds values to the buffer and the consumer removes values from the buffer.
- The producer and consumer are modeled as two components PROD and CONS of a parallel program.
- For a correct access of the buffer the components PROD and CONS share an integer variable in counting the number of values added to the buffer and an integer variable out counting the number of values removed from the buffer.

### 9.4 Case Study: Producer/Consumer Problem 321

- Recall that for a Boolean expression B the statement wait B abbreviates await B then skip end.
- The verification of (9.13) follows closely the presentation in Owicki and Gries [1976a].
- Note also that the bound function t1 clearly satisfies the conditions required by the definition of proof outline.

### 9.4 Case Study: Producer/Consumer Problem 323

- Also the bound function t2 satisfies the conditions required by the definition of proof outline.
- Let us now turn to the test of interference freedom of the two proof outlines.
- Naive calculations suggest that 80 correctness formulas must be checked!.
- It thus remains to check the assertions outside the I-part against possible interference.
- Examine all conjuncts occurring in the assertions used in this proof outline.

### 9.5 Case Study: The Mutual Exclusion Problem 325

- An appropriate framework for the treatment of liveness properties is temporal logic (see Manna and Pnueli [1991,1995]).
- To formalize conditions (i) and (ii) the authors assume that each process.
- Si uses the resource and RELi (abbreviation for release protocol) denotes the part of the program that process Si executes to release the resource.
- The authors also assume that no await statements are used inside the sections NCi and CSi.

### 9.5 Case Study: The Mutual Exclusion Problem 327

- To reason about the mutual exclusion condition (a) the authors use the following lemma.
- Then the mutual exclusion condition (a) is satisfied for the parallel program S. Proof.
- To reason about the absence of blocking condition (b) the authors use the Deadlock Freedom Lemma 9.5.

### A Busy Wait Solution

- First, let us consider the case of parallel programs without synchronization.
- The authors consider here the following simple busy wait solution to the mutual exclusion problem for two processes due to Peterson [1981].
- Intuitively, the Boolean variable flagi indicates whether the component Si intends to enter its critical section, i ∈ {1, 2}.
- The variable turn is used to resolve simultaneity conflicts: in case both components S1 and S2 intend to enter their critical sections, the component that set the variable turn first is delayed in a busy wait loop until the other component alters the value of turn.

### 9.5 Case Study: The Mutual Exclusion Problem 329

- With the help of the Mutual Exclusion Lemma 9.6 the authors prove now the mutual exclusion condition (a) for the extended program MUTEX-B ′.
- First, let us check that these are indeed proof outlines for partial correctness of S′1 and S ′ 2.
- The only interesting parts are the busy wait loops.
- Next the authors show interference freedom of the above proof outlines.

### 9.5 Case Study: The Mutual Exclusion Problem 331

- Thus no normal assignment or await statement of S′2 interferes with the proof outline for S′1.
- This shows that the above proof outlines for S′1 and S ′ 2 are interference free.
- Thus the Mutual Exclusion Lemma 9.6 yields the mutual exclusion condition (a) for the extended parallel program MUTEX-B ′ and the Auxiliary Variables Lemma 9.7 (i) for the original program MUTEX-B .

### A Solution Using Semaphores

- The letters P and V originate from the Dutch verbs “passeren” (to pass) and “vrijgeven” (to free).
- Intuitively, the binary semaphore out indicates whether all processes are out of their critical sections.
- To prove correctness of this solution, the authors have to prove the properties (a) and (b).
- To this end, the authors introduce an auxiliary variable who that indicates which component, if any, is inside the critical section.
- Note that the binary P - and V -operations have been extended to atomic actions embracing assignment to the auxiliary variable who.

### 9.5 Case Study: The Mutual Exclusion Problem 333

- Considered in isolation these are correct proof outlines.
- To show that this assertion is kept invariant under the extended P -operation, the authors consider the body of this await statement.
- This finishes the proof of interference freedom.
- It suffices now to apply the Mutual Exclusion Lemma 9.6 and the Auxiliary Variables Lemma 9.7(i).

### 9.6 Allowing More Points of Interference

- These transformations are the same as in Section 8.7 and as before can be used in two ways.
- First, they allow us to derive from a parallel program another parallel program with more points of interference.
- In the next section the authors illustrate the second use of them.

### 9.7 Case Study: Synchronized Zero Search

- Step 1. Simplifying the Program Step 2. Decomposing Total Correctness.
- To prove (9.26) the authors use the fact that total correctness can be decomposed into termination and partial correctness.
- More precisely the authors use the following observation.
- To prove deadlock freedom the authors need two Boolean auxiliary variables after1 and after2 to indicate whether the execution of the component programs T1 and T2 is just after one of the assignments to the variable turn.

### 9.7 Case Study: Synchronized Zero Search 339

- This conjunct is crucial for showing deadlock freedom below.
- Note also that the bound function t1 clearly satisfies the conditions required by the definition of proof outline.
- Clearly, this is indeed a proof outline for weak total correctness of U2.
- Let us now check the two proof outlines for interference freedom.
- Finally, conjunct (9.36) is preserved because, by the proof outline of U2, whenever the variable after2 is set to true, the variable turn is simultaneously set to 1.

### 9.7 Case Study: Synchronized Zero Search 341

- Contain variables that can be modified by U1.
- This completes the proof of interference freedom.

### 9.7 Case Study: Synchronized Zero Search 343

- From Section 8.8 the authors now “lift” the standard proof outlines to the present programs T1 and T2.
- Since the variable turn does not occur in the assertions used in the proof outlines in Section 8.8, any statement accessing turn preserves these assertions.
- From Section 8.8 the authors can also lift the test of interference freedom to the present proof outlines.
- Indeed, consider any of the correctness formulas to be checked for this test.

### 9.8 Exercises

- 1. Prove the Input/Output Lemma 3.3 for parallel programs with synchronization.
- 2. Prove the Change and Access Lemma 3.4 for parallel programs with synchronization.
- 3. Prove the Stuttering Lemma 7.9 for parallel programs with synchronization.

### 9.9 Bibliographic Remarks 345

- Consider the programs ZERO-5 and ZERO-6 of Section 1.1.
- Show that the total correctness of ZERO-6 as proven in Case Study 9.7 implies total correctness of ZERO-5.

### 9.9 Bibliographic Remarks

- As already mentioned, this chapter owes much to Owicki and Gries [1976a]: the idea of modeling synchronization by await statements, the approach to proving deadlock freedom and the solution to the producer/consumer problem presented in Section 9.4 are from this source.
- Schneider and Andrews [1986] provide an introduction to the verification of parallel programs using the method of Owicki and Gries.
- Nipkow and Nieto [1999] formalized the method of Owicki and Gries in the interactive theorem prover Isabelle/HOL introduced by Nipkow, Paulson and Wenzel [2002], which is based on higher-order logic.
- The await statement is a more flexible and structured synchronization construct than the classical semaphore introduced in Dijkstra [1968].
- More solutions to the mutual exclusion problem are discussed in Raynal [1986].

### 10 Nondeterministic Programs

- Dijkstra’s guarded commands are also a preparation for the study of distributed programs in Chapter 11.
- In Section 10.1 the authors introduce the syntax and in Section 10.2 the semantics of the nondeterministic programs.
- In Section 10.3 the authors discuss the advantages of this language.
- The authors extend this approach to nondeterministic programs and illustrate it by the case study of a welfare crook program.

### 10.1 Syntax

- If more than one guard Bi evaluates to true any of the corresponding statements.
- If all guards evaluate to false, the alternative command will signal a failure.
- Si the whole command is repeated starting with a new evaluation of the guards Bi. Moreover, contrary to the alternative command, the repetitive command properly terminates when all guards evaluate to false.
- The authors call the programs generated by this grammar nondeterministic programs.

### 10.2 Semantics

- Here fail is an exceptional state, originally considered in Section 3.7 in the context of the semantics of the failure statement, that represents a runtime detectable failure or abortion.
- As before, the semantics M[[S]] of nondeterministic programs S is based on the transition relation → , but it now maps proper initial states into sets possibly containing several final states.

### Symmetry

- This often enhances the clarity of programs.
- Note that both programs terminate with the gcd stored in the variables x and y.

### Nondeterminism

- Nondeterministic programs allow us to express nondeterminism through the use of nonexclusive guards.
- Surprisingly often, it is both clumsy and unnecessary to specify a sequential algorithm in a deterministic way —the remaining choices can be resolved in an arbitrary way and need not concern the programmer.
- As a simple example, consider the problem of computing the maximum of two numbers.
- In fact, it does not matter which one will be chosen —the final values of the variables twop and threep will always be the same.

### Failures

- Recall that an alternative command fails rather than terminates if none of the guards evaluates to true.
- The authors presented already in Section 3.7 a number of natural examples concerning the failure statement that showed the usefulness of failures.

### Modeling Concurrency

- Nondeterminism arises naturally in the context of parallel programs.
- Which one depends on the order in which the three assignments are executed.
- The authors can use nondeterministic programs to model this behavior.

### 10.5 Case Study: The Welfare Crook Problem

- In this section the authors generalize the approach of Section 3.10 to the systematic program development to the case of nondeterministic programs.
- The authors illustrate the development of a nondeterministic program that follows these steps by solving the following problem due to W. Feijen.
- Practically speaking, all three lists are endless, so no upper bounds are given.
- The problem is to develop a program CROOK to locate the alphabetically first such person.
- The values iv, jv and kv can be used in the assertions but not in the program.

### 10.6 Transformation of Parallel Programs 363

- In developing this program the crucial step consisted of the choice of the guards B1, B2 and B3.
- Accidentally, the choice made turned out to be sufficient to ensure that upon loop termination the postcondition q holds.

### 10.6 Transformation of Parallel Programs

- Let us return now to the issue of modeling parallel programs by means of nondeterministic programs, originally mentioned in Section 10.3.
- The question arises whether the authors cannot avoid these difficulties by decomposing the task of verifying parallel programs into two steps: (1) transformation of the considered parallel programs in nondeterministic sequential ones, (2) verification of the resulting nondeterministic programs using the proof systems of this chapter.
- For parallel programs with shared variables things are more difficult.
- More precisely, the transformation of a parallel program S ≡ [S1‖. . .‖Sn] in the syntax of Chapter 9 into a nondeterministic program T (S) introduces a fresh integer variable pci for each component Si. For a labeled program R̂ let first(R̂) denote the first label in R̂ and last(R̂) the last label in R̂.
- The authors define these component transformations Ti(R̂)(c).

### 10.6 Transformation of Parallel Programs 365

- Consider the parallel composition S ≡ [S1‖S2] in the program FINDPOS of Case Study 8.6.
- Since each component program uses the labels 1, 2, 3, the termination values are term1 = term2 =.
- For parallel programs S with shared variables, one can prove that S and T (S) are equivalent modulo the program counter variables.
- Consider the parallel program S ≡ [S1‖S2‖S3] with the following labeled components:.

### 10.6 Transformation of Parallel Programs 367

- The final if statement in T (S) converts this “premature” termination into a failure.
- These examples reveal one severe drawback of the transformation: the structure of the original parallel program gets lost.
- Instead, the authors are faced with a nondeterministic program on the level of an assembly language where each atomic action is explicitly listed.
- Therefore the authors do not pursue this approach any further.
- In the next chapter the authors are going to see, however, that for distributed programs a corresponding transformation into nondeterministic programs does preserve the program structure without introducing auxiliary variables and is thus very well suited as a basis for verification.

### 10.7 Exercises

- Transform the parallel program MUTEX-S of Section 9.5, which ensures mutual exclusion with the help of semaphores, into a nondeterministic program using the transformation of Section 10.6.
- 11. (i) Prove that the proof system PN is complete for partial correctness of nondeterministic programs.

### 10.8 Bibliographic Remarks

- Their correctness and various semantics are discussed in de Bakker [1980] and Apt [1984].
- Their systematic development was originated in Dijkstra [1976] and was popularized and further explained in Gries [1981].
- The program for the welfare crook developed in Section 10.5 is due to W. Feijen.
- The idea of linking parallel programs to nondeterministic programs goes back to the work of Ashcroft and Manna [1971] and Flon and Suzuki [1978, 1981].

### 10.8 Bibliographic Remarks 371

- The main emphasis of the work of Chandy and Misra and of Back lies in the systematic development of parallel programs on the basis of equivalent nondeterministic ones.
- The systematic development of parallel implementations starting from sequential programs of a particular simple form (i.e., nested for loops) is pursued by Lengauer [1993].
- Related to the approach of action systems are the system specification method TLA (Temporal Logic of Actions) by Lamport [1994,2003] and the abstract machines in the B-method by Abrial [1996].
- The latter method has recently been extended to Event-B (see, for example, Abrial and Hallerstede [2007] and Abrial [2009]).
- Also here the basic form of the specifications consists of an initialization part and a single do loop containing only atomic actions.

### 11 Distributed Programs

- A distributed program consists of a collection of processes that work concur- rently and communicate by explicit message passing.
- Asynchronous communication can be modeled by synchronous communication if the buffer is introduced as an explicit component of the distributed system.
- From the more recent version of CSP from Hoare [1985] the authors use two concepts here: communication channels instead of process names and output guards in the alternatives of repetitive commands.
- This transformation is studied in detail in Section 11.3.

### Sequential Processes

- Then S consists only of the nondeterministic program S0.
- While values of different types can be communicated along the same channel, each individual communication requires two i/o commands of a matching type.
- This is made precise in the following definition.
- The authors say that two generalized guards match if their i/o commands match.
- Then the communication between the i/o commands takes place.

### Distributed Programs

- This system consists of the proof system PN augmented by the group of axioms and rules 34, A8 and A9.
- This system consists of the proof system TN augmented by the group of axioms and rules 35 and A9.
- This system consists of the proof system TN augmented by the group of axioms and rules 36 and A9.

### 11.1 Syntax 377

- Condition (ii) states that in a distributed program each communication channel connects at most two processes.
- A deadlock arises here when not all processes have terminated, none of them has ended in a failure and yet none of them can proceed.
- The authors now illustrate the notions introduced in this section by two examples.
- The processes first execute independently of each other their initialization parts i := 0 and j := 0. Then the first communication along the channel link occurs with the effect of b[0] := a[0].
- The process FILTER has an array b of the same type serving as an intermediate store for processing the character sequence and the process RECEIVER has an array c of the same type to store the result of the filtering process.

### 11.1 Syntax 379

- The process FILTER can communicate with both other processes.
- Along channel input it is ready to receive characters from process SENDER until ‘∗’ has been received.
- Thus the distributed program TRANS can pursue computations with different communication sequences among its processes.
- Finally, the process RECEIVER terminates once it has received from FILTER the character ‘∗’.
- If SENDER did not send any ‘∗’, a deadlock would arise when the processes FILTER and RECEIVER waited in vain for some further input.

### 11.2 Semantics

- The authors now provide a precise operational semantics of distributed programs by formalizing the above informal remarks.
- Let us clarify the meaning of this transition by discussing its conditions.
- The generalized guards gj1and hj2 match, so syntactically a communication between Sk and Sℓ can take place.
- Condition (1) states the semantic condition for this communication: the Boolean parts of gj1 and hj2 hold in the initial state σ.
- The above transition axiom explains how main loops are executed.

### 11.2 Semantics 381

- Here the authors consider a proper state σ and three kinds of special states: ⊥ representing divergence, fail representing failure and ∆ representing deadlock.
- —it is possible due to the presence of the repetitive commands.
- Only the total correctness semantics takes all of these possibilities into account.
- As in Chapter 9, weak total correctness results from total correctness by ignoring deadlock.
- The authors conclude this section by proving the bounded nondeterminism of distributed programs.

### 11.3 Transformation into Nondeterministic Programs

- The meaning of distributed programs can be better understood through a transformation into nondeterministic programs.
- In contrast to the transformation of parallel programs into nondeterministic programs described in Section 10.6 the authors do not need here any additional control variables.
- This is due to the simple form of the distributed programs considered here, where i/o commands appear only in the main loop.
- In the next section the authors use this transformation as a basis for the verification of distributed programs.
- Semantic Relationship Between S and T (S) The semantics of S and T (S) are not identical because the termination behavior is different.

### 11.3 Transformation into Nondeterministic Programs 383

- Clearly TERM → BLOCK but not the other way round.
- As noted above, upon termination of S, the condition TERM holds, whereas upon termination of T (S) only a weaker condition BLOCK holds.
- Deadlocks of S are transformed into terminal configurations of T (S) in whose 384 11 Distributed Programs state the condition TERM does not hold.
- To prove the above theorem the authors introduce some auxiliary notions and prove some of their properties.