Contentsi

The Theory and Practice ofConcurrency
A.W. Roscoe
Published 1997, revised to 2000 and lightly revised to 2005.
The original version is in print in April 2005 with Prentice-Hall (Pearson).
This version is made available for personal reference only. This version isc Pearson and Bill Roscoe.
copyright ()Contents

Prefaceix

0 Introduction

1

I

0.1

Background1

0.2

Perspective

4

0.3

Tools

7

0.4

What is a communication?

8

A FOUNDATION COURSE IN CSP

1 Fundamental concepts

11
13

1.1

Fundamental operators

14

1.2

Algebra29

1.3

The traces model and traces reﬁnement

35

1.4

Tools

48

2 Parallel operators

51

2.1

Synchronous parallel

51

2.2

Alphabetized parallel

55

2.3

Interleaving

65

2.4

Generalized parallel

68

iv

Contents
2.5

Parallel composition as conjunction

70

2.6

Tools

74

2.7

Postscript: On alphabets

76

3 Hiding and renaming
Hiding77

3.2

Renaming and alphabet transformations

86

3.3

A basic guide to failures and divergences

93

3.4

Tools

99

4 Piping and enslavement

101

4.1

Piping101

4.2

Enslavement

107

4.3

Tools

112

5 Buﬀers and communication
5.1

115

Pipes and buﬀers

115

5.2

Buﬀer tolerance

127

5.3

The alternating bit protocol

130

5.4

Tools

136

5.5

Notes (2005)

137

6 Termination and sequential composition
6.1

II

77

3.1

What is termination?

139
139

6.2

Distributed termination

143

6.3

Laws

144

6.4

Eﬀects on the traces model

147

6.5

Eﬀects on the failures/divergences model

148

THEORY

7 Operational semantics

151
153

7.1

A survey of semantic approaches to CSP

153

7.2

Transition systems and state machines155

Contentsv

7.3

Firing rules for CSP

162

7.4

Relationships with abstract models

174

7.5

Tools

181

7.6

Notes

182

8 Denotational semantics

183

8.1

Introduction

183

8.2

The traces model

186

8.3

The failures/divergences model

195

8.4

The stable failures model

211

8.5

Notes

218

9 Analyzing the denotational models

221

9.1

Deterministic processes

221

9.2

Analyzing ﬁxed points

227

9.3

Full abstraction

232

9.4

Relations with operational semantics

242

9.5

Notes

247

10 Inﬁnite traces249

10.1 Calculating inﬁnite traces249

10.2 Adding failures255

10.3 Using inﬁnite traces262

10.4 Notes

271

11 Algebraic semantics

273

11.1 Introduction273

11.2 Operational semantics via algebra

275

11.3 The laws of ⊥N

279

11.4 Normalizing

281

11.5 Sequential composition and SKIP

291

11.6 Other models

294

11.7 Notes

297

vi Contents
12 Abstraction

III

299

12.1 Modes of abstraction

300

12.2 Reducing speciﬁcations

310

12.3 Abstracting errors: specifying fault tolerance

313

12.4 Independence and security

320

12.5 Tools

330

12.6 Notes

330

PRACTICE

13 Deadlock!

335
337

13.1 Basic principles and tree networks

337

13.2 Speciﬁc ways to avoid deadlock349

13.3 Variants

365

13.4 Network decomposition376

13.5 The limitations of local analysis

379

13.6 Deadlock and tools

381

13.7 Notes

386

14 Modelling discrete time389

14.1 Introduction389

14.2 Meeting timing constraints

390

14.3 Case study 1: level crossing gate395

14.4 Checking untimed properties of timed processes

405

14.5 Case study 2: the alternating bit protocol

410

14.6 Urgency and priority

417

14.7 Tools

420

14.8 Notes

420

15 Case studies423

15.1 Combinatorial systems: rules and tactics

424

15.2 Analysis of a distributed algorithm

430

15.3 Distributed data and data-independence445

15.4 Analyzing crypto-protocols

468

15.5 Notes

488

Contents
A Mathematical background

vii
491

A.1 Partial orders

491

A.2 Metric spaces

510

B A guide to machine-readable CSP

519

B.1 Introduction

519

B.2 Expressions

520

B.3 Pattern matching526

B.4 Types

528

B.5 Processes

532

B.6 Special deﬁnitions

535

B.7 Mechanics

538

B.8 Missing features

539

B.9 Availability

539

C The operation of FDR

541

C.1 Basic operation

541

C.2 Hierarchical compression

553

Notation

563

Bibliography

567

Main index

577

Index of named processes

589Preface

Since C.A.R. Hoare’s text Communicating Sequential Processes was published in
1985, his notation has been extensively used for teaching and applying concurrency
theory. This book is intended to provide a comprehensive text on CSP from theperspective that 12 more years of research and experience have brought.
By far the most signiﬁcant development in this time has been the emergence of tools to support both the teaching and industrial application of CSP. Thishas turned CSP from a notation used mainly for describing ‘toy’ examples which
could be understood and analyzed by hand, into one which can and does support
the description of industrial-sized problems and which facilitates their automatedanalysis. As we will see, the FDR model checking tool can, over a wide range ofapplication areas, perform analyses and solve problems that are beyond most, if notall, humans.
In order to use these tools eﬀectively you need a good grasp of the fundamental concepts of CSP: the tools are most certainly not an alternative to gaining an
understanding of the theory. Therefore this book is still, in the ﬁrst instance, a text
on the principles of the language rather than being a manual on how to apply its
tools. Nevertheless the existence of the tools has heavily inﬂuenced both the choice
and presentation of material. Most of the chapters have a section speciﬁcally on theway the material in them relates to tools, two of the appendices are tool-related,
and there is an associated web site
http://www.comlab.ox.ac.uk/oucl/publications/books/concurrency/
on which readers can ﬁnd• a list of tools available for CSP

x

Preface• demonstrations and details of some of the tools• directories of example ﬁles containing most of the examples from the text
and many other related ones
• practical exercises which can be used by those teaching and learning fromthis book• a list of materials available to support teaching (overhead foils, solutions toexercises, etc.) and instructions for obtaining themas well as supporting textual material. Contact information, etc., relating to those
tools speciﬁcally mentioned in the text can be found in the Bibliography.
The Introduction (Chapter 0) gives an indication of the history, purpose andrange of applications of CSP, as well as a brief survey of the classes of tools thatare available. There is also a discussion of how to go about one of the major steps
when using CSP to model a system: deciding what constitutes an event. It provides
background reading which should be of interest to more experienced readers before
beginning the rest of the book; those with no previous exposure to concurrency
might ﬁnd some parts of the Introduction of more beneﬁt after looking at Part I.
The rest of the book is divided into three parts and structured to make it
usable by as wide an audience as possible. It should be emphasized, however, thatthe quantity of material and the diﬀering levels of sophistication required by various
topics mean that I expect it will be relatively uncommon for people to attempt thewhole book in a short space of time.
Part I (Chapters 1–6) is a foundation course on CSP, covering essentiallythe same ground as Hoare’s text except that most of the mathematical theory isomitted. At an intuitive level, it introduces the ideas behind the operational (i.e.,transition system), denotational (traces, failures and divergences) and algebraic
models of CSP, but the formal development of these is delayed to Part II. PartI has its origins in a set of notes that I developed for an introductory 16-lecture
course for Oxford undergraduates in Engineering and Computing Science. I would
expect that all introductory courses would cover up to Section 5.1 (buﬀers), with thethree topics beyond that (buﬀer tolerance, communications protocols and sequential
composition1 ) being more optional.
Part II and Part III (Chapters 7–12 and 13–15, though Chapter 12 arguably
belongs equally to both) respectively go into more detail on the theory and practice
1 Instructors who are intending to deal at any length with the theory presented in Part II should
consider carefully whether they want to include the treatment of sequential composition, since it
can reasonably be argued that the special cases it creates are disproportionate to the usefulness ofthat operator in the language. Certainly it is well worth considering presenting the theory without
these extra complications before going back to see how termination and sequencing ﬁt in.

Prefacexi

of CSP. Either of them would form the basis of a one-term graduate course as afollow-on to Part I, though some instructors will doubtless wish to mix the material
and to include extracts from Parts II and III in a ﬁrst course. (At Oxford, introductory courses for more mathematically sophisticated audiences have used partsof Chapters 8 and 9, on the denotational semantics and its applications, and somecourses have used part of Chapter 13, on deadlock.) The chapters of Part III arelargely independent of each other and of Part II.2
This book assumes no mathematical knowledge except for a basic understanding of sets, sequences and functions. I have endeavoured to keep the level ofmathematical sophistication of Parts I and III to the minimum consistent with giving a proper explanation of the material. While Part II does not require any further
basic knowledge other than what is contained in Appendix A (which gives an introduction to the ideas from the theory of partial orders and metric/restriction spaces
required to understand the denotational models), the mathematical constructions
and arguments used are sometimes signiﬁcantly harder than in the other two parts.
Part II describes various approaches to the semantic analysis of CSP. Depending on your point of view, you can either regard its chapters as an introduction
to semantic techniques for concurrency via the medium of CSP, or as a comprehensive treatment of the theory of this language. Each of the three complementary
semantic approaches used – operational, denotational and algebraic – is directly
relevant to an understanding of how the automated tools work. My aim in this parthas been to give a suﬃciently detailed presentation of the underlying mathematics
and of the proofs of the main results to enable the reader to gain a thorough understanding of the semantics. Necessarily, though, the most complex and technicalproofs are omitted.
Chapter 12 deserves a special mention, since it does not so much introduce
semantic theory as apply it. It deals with the subject of abstraction: forminga view of what a process looks like to a user who can only see a subset of its
alphabet. A full understanding of the methods used requires some knowledge ofthe denotational models described in Chapters 8, 9 and 10 (which accounts for theplacing of Chapter 12 in Part II). However, their applications (to the formulationof speciﬁcations in general, and to the speciﬁcation of fault tolerance and security
in particular), are important and deserve attention by the ‘practice’ community as
well as theoreticians.
Chapter 13, on deadlock avoidance, is included because deadlock is a much
2 The only dependency is of Section 15.2 on Chapter 14. It follows from this idependence thata course based primarily on Part III need not cover the material in order and that instructors can
exercise considerable freedom in selecting what to teach. For example, the author has taught atool-based graduate course based on Section 15.1, Chapter 5, Section 15.2, Appendix C, Chapter
14, Chapter 12 (Sections 12.3 and 12.4 in particular), the ﬁrst half of Chapter 13 and Section 15.4.

xii Preface
feared phenomenon and there is an impressive range of techniques, both analytic andautomated, for avoiding it. Chapter 14 describes how the untimed version of CSP(the one this book is about) can be used to describe and reason about timed systems
by introducing a special event to represent the passage of time at regular intervals.
This has become perhaps the most used dialect of CSP in industrial applications of
FDR. Each of these two chapters contains extensive illustrative examples; Chapter
15 is based entirely around ﬁve case studies (two of which are related) chosen toshow how CSP can successfully model, and FDR can solve, interesting, diﬃcult
problems from other application areas.
The ﬁrst appendix, as described above, is an introduction to mathematical
topics used in Part II. The second gives a brief description of the machine-readable
version of CSP and the functional programming language it contains for manipulating process state. The third explains the operation of FDR in terms of the theory
of CSP, and in particular describes the process-compression functions it uses.
At the end of each chapter in Parts II and III there is a section entitled‘Notes’. These endeavour, necessarily brieﬂy, to put the material of the chapter incontext and to give appropriate references to related work.
Exercises are included throughout the book. Those in Part I are mainly
designed to test the reader’s understanding of the preceding material; many ofthem have been used in class at Oxford over the past three years. Some of thosein Parts II and III have the additional purpose of developing sidelines of the theory
not otherwise covered.
Except for one important change (the decision not to use process alphabets,
see page 76), I have endeavoured to remain faithful to the notation and ideas presented in Hoare’s text. There are a few other places, particularly in my treatmentof termination, variable usage and unbounded nondeterminism, where I have either
tidied up or extended the language and/or its interpretation.
Bill Roscoe
May 1997

Acknowledgements
I had the good fortune to become Tony Hoare’s research student in 1978, which gaveme the opportunity to work with him on the development of the ‘process algebra’version of CSP and its semantics from the ﬁrst. I have constantly been impressedthat the decisions he took in structuring the language have stood so well the twin
tests of time and practical use in circumstances he could not have foreseen. The
work in this book all results, either directly or indirectly, from his vision. Those

Prefacexiii

familiar with his book will recognize that much of my presentation, and many of
my examples, have been inﬂuenced by it.
Much of the theory set out in Chapters 7, 8, 9 and 11 was established by theearly 1980s. The two people most responsible, together with Tony and myself, forthe development of this basic theoretical framework for CSP were Steve Brookes
and Ernst-Rudiger Olderog, and I am delighted to acknowledge their contributions.
We were, naturally, much inﬂuenced by the work of those such as Robin Milner,
Matthew Hennessy and Rocco de Nicola who were working at the same time onother process algebras.
Over the years, both CSP and my understanding of it have beneﬁted from thework of too many people for me to list their individual contributions. I would like tothank the following present and former students, colleagues, collaborators and correspondents for their help and inspiration: Samson Abramsky, Phil Armstrong, Geoﬀ
Barrett, Stephen Blamey, Philippa Hopcroft (née Broadfoot), Sadie Creese, Naiem
Dathi, Jim Davies, Richard Forster, Paul Gardiner, Michael Goldsmith, Anthony
Hall, Jifeng He, Huang Jian, Jason Hulance, David Jackson, Lalita Jategaonkar
Jagadeesan, Alan Jeﬀrey, Mark Josephs, Ranko Lazić, Eldar Kleiner, Gavin Lowe,Helen McCarthy, Jeremy Martin, Albert Meyer, Michael Mislove, Nick Moﬀat, Lee
Momtahan, Tom Newcomb, David Nowak, Joel Ouaknine, Ata Parashkevov, David
Park, Sriram Rajamani, Joy Reed, Mike Reed, Jakob Rehof, Bill Rounds, Peter
Ryan, Jeﬀ Sanders, Bryan Scattergood, Steve Schneider, Brian Scott, Karen Seidel,
Jane Sinclair, Antti Valmari, David Walker, Wang Xu, Jim Woodcock, Ben Worrell,
Zhenzhong Wu, Lars Wulf, Jay Yantchev, Irfan Zakiuddin and Zhou Chao Chen.
Many of them will recognize speciﬁc inﬂuences their work has had on my book. A
few of these contributions are referred to in individual chapters.
I would also like thank all those who told me about errors and typos in theoriginal edition.
Special thanks are due to the present and former staﬀ of Formal Systems(some of whom are listed above) for their work in developing FDR, and latterly
ProBE. The remarkable capabilities of FDR transformed my view of CSP and mademe realize that writing this book had become essential. Bryan Scattergood waschieﬂy responsible for both the design and the implementation of the ASCII version
of CSP used on these and other tools. I am grateful to him for writing Appendix B
on this version of the language. The passage of years since 1997 has only emphasised
the amazing job he did in designing CSPM , and the huge expressive power of theembedded functional language. Ranko Lazić has both provided most of the results
on data independence (see Section 15.3.2), and did (in 2000) most of the work inpresenting it in this edition.
Many of the people mentioned above have read through drafts of my bookand pointed out errors and obscurities, as have various students. The quality ofxivPrefacethe text has been greatly helped by this. I have had valuable assistance from Jim
Davies in my use of LATEX.
My work on CSP has beneﬁted from funding from several bodies over theyears, including EPSRC, DRA, ESPRIT, industry and the US Oﬃce of Naval Research. I am particularly grateful to Ralph Wachter from the last of these, without
whom most of the research on CSP tools would not have happened, and who has
speciﬁcally supported this book and the associated web site.
This book could never have been written without the support of my wife
Coby. She read through hundreds of pages of text on a topic entirely foreign toher, expertly pointing out errors in spelling and style. More importantly, she put
up with me writing it.
Internet edition
The version here was extensively updated by me in 2000, with the addition of somenew material (in particular a new section for Chapter 15). Various errors have also
been corrected, but please continue to inform me of any more.
A great deal more interesting work has been done on CSP since 1997 than
this version of the book reports. Much of that appears, or is referenced, in papers
which can be downloaded from my web site or from those of other current andformer members of the Oxford Concurrency group such as Gavin Lowe, Christie
Bolton and Ranko Lazić. As I write this I anticipate the imminent publication (in
LNCS) of the proceedings of the BCS FACS meeting in July last year on “25 years
of CSP”. This will provide an excellent snapshot of much recent work on CSP. I
have given a brief description of some of this extra work in paragraphs marked 2005,
mainly in the notes sections at the ends of chapters. These contain a few citations
but do not attempt to cover the whole literature of interest.
If anyone reading this has any feedback on any sort of book – either following
on from (part of) this one or something completely diﬀerent – that you would liketo see written on CSP, please let me know.
Bill Roscoe
April 2005

Chapter 0

Introduction

CSP is a notation for describing concurrent systems (i.e., ones where there is morethan one process existing at a time) whose component processes interact with eachother by communication. Simultaneously, CSP is a collection of mathematical models and reasoning methods which help us understand and use this notation. In thischapter we discuss the reasons for needing a calculus like CSP and some of thehistorical background to its development.

0.1

Background

Parallel computers are starting to become common, thanks to developing technology and our seemingly insatiable demands for computing power. They provide themost obvious examples of concurrent systems, which can be characterized as systems where there are a number of diﬀerent activities being carried out at the sametime. But there are others: at one extreme we have loosely coupled networks ofworkstations, perhaps sharing some common ﬁle-server; and at the other we havesingle VLSI circuits, which are built from many subcomponents which will often do
things concurrently. What all examples have in common is a number of separate
components which need to communicate with each other. The theory of concurrency is about the study of such communicating systems and applies equally to allthese examples and more. Though the motivation and most of the examples we see
are drawn from areas related to computers and VLSI, other examples can be foundin many ﬁelds.
CSP was designed to be a notation and theory for describing and analyzing
systems whose primary interest arises from the ways in which diﬀerent components interact at the level of communication. To understand this point, consider
the design of what most programmers would probably think of ﬁrst when paral-

2Introduction

lelism is mentioned, namely parallel supercomputers and the programs that run onthem. These computers are usually designed (though the details vary widely) sothat parallel programming is as easy as possible, often by enforcing highly stylized
communication which takes place in time to a global clock that also keeps the various parallel processing threads in step with each other. Though the design of theparallel programs that run on these machines – structuring computations so that
calculations may be done in parallel and so that transfers of information requiredﬁt the model provided by the computer – is an extremely important subject, it is
not what CSP or this book is about. For what is interesting there is understanding
the structure of the problem or algorithm, not the concurrent behaviour (the clock
and regimented communication having removed almost all interest here).
In short, we are developing a notation and calculus to help us understandinteraction. Typically the interactions will be between the components of a concurrent system, but sometimes they will be between a computer and external humanusers. The primary applications will be areas where the main interest lies in the
structure and consequences of interactions. These include aspects of VLSI design,communications protocols, real-time control systems, scheduling, computer security,
fault tolerance, database and cache consistency, and telecommunications systems.
Case studies from most of these can be found in this book: see the table of contents.
Concurrent systems are more diﬃcult to understand than sequential ones forvarious reasons. Perhaps the most obvious is that, whereas a sequential program isonly ‘at’ one line at a time, in a concurrent system all the diﬀerent components are in(more or less) independent states. It is necessary to understand which combinationsof states can arise and the consequences of each. This same observation meansthat there simply are more states to worry about in parallel code, because thetotal number of states grows exponentially (with the number of components) rather
than linearly (in the length of code) as in sequential code. Aside from this state
explosion there are a number of more speciﬁc misbehaviours which all create theirown diﬃculties and which any theory for analyzing concurrent systems must be able
to model.
Nondeterminism
A system exhibits nondeterminism if two diﬀerent copies of it may behave diﬀerently
when given exactly the same inputs. Parallel systems often behave in this way
because of contention for communication: if there are three subprocesses P ,Q and
R where P and Q are competing to be the ﬁrst to communicate with R, which inturn bases its future behaviour upon which wins the race, then the whole system
may veer one way or the other in a manner that is uncontrollable and unobservablefrom the outside.
Nondeterministic systems are in principle untestable, since however many

0.1

Background3

times one of them behaves correctly in development with a given set of data, it
is impossible to be sure that it will still do so in the ﬁeld (probably in subtly
diﬀerent conditions which might inﬂuence the way a nondeterministic decision istaken). Only by formal understanding and reasoning can one hope to establish
any property of such a system. One property we might be able to prove of a given
process is that it is deterministic (i.e., will always behave the same way when oﬀered
a given sequence of communications), and thus amenable to testing.
Deadlock
A concurrent system is deadlocked if no component can make any progress, generally
because each is waiting for communication with others. The most famous example
of a deadlocked system is the ‘ﬁve dining philosophers’, where the ﬁve philosophers
are seated at a round table with a single fork between each pair (there is a pictureof them on page 61). But each philosopher requires both neighbouring forks to eat,so if, as in the picture, all get hungry simultaneously and pick up their left-handfork then they deadlock and starve to death. Even though this example is anthropomorphic, it actually captures one of the major causes of real deadlocks, namely
competition for resources. There are numerous others, however, and deadlock (particularly nondeterministic deadlock) remains one of the most common and feared
ills in parallel systems.
Livelock
All programmers are familiar with programs that go into inﬁnite loops, never tointeract with their environments again. In addition to the usual causes of this typeof behaviour – properly called divergence, where a program performs an inﬁnite
unbroken sequence of internal actions – parallel systems can livelock. This occurs
when a network communicates inﬁnitely internally without any component communicating externally. As far as the user is concerned, a livelocked system looks
similar to a deadlocked one, though perhaps worse since the user may be able toobserve the presence of internal activity and so hope eternally that some output
will emerge eventually. Operationally and, as it turns out, theoretically, the two
phenomena are very diﬀerent.
The above begin to show why it is essential to have both a good understanding of the way concurrent systems behave and practical methods for analyzing
them. On encountering a language like CSP for the ﬁrst time, many people ask
why they have to study a new body of theory, and new speciﬁcation/veriﬁcation
techniques, rather than just learning another programming language. The reason
is that, unfortunately, mathematical models and software engineering techniquesdeveloped for sequential systems are usually inadequate for modelling the subtletiesof concurrency so we have to develop these things alongside the language.

4

0.2

Introduction

Perspective

As we indicated above, a system is said to exhibit concurrency when there can beseveral processes or subtasks making progress at the same time. These subtasks
might be running on separate processors, or might be time-sharing on a single
one. The crucial thing which makes concurrent systems diﬀerent from sequential
ones is the fact that their subprocesses communicate with each other. So while asequential program can be thought of as progressing through its code a line at atime – usually with no external inﬂuences on its control-ﬂow – in a concurrent systemeach component is at its own line, and without relying on a precise knowledge of theimplementation we cannot know what sequence of states the system will go through.
Since the diﬀerent components are inﬂuencing each other, the complexities of thepossible interactions are mind-boggling. The history of concurrency consists bothof the construction of languages and concepts to make this complexity manageable,
and the development of theories for describing and reasoning about interacting
processes.
CSP has its origins in the mid 1970s, a time when the main practical problems
driving work on concurrency arose out of areas such as multi-tasking and operating
system design. The main problems in those areas are ones of maintaining an illusionof simultaneous execution in an environment where there are scarce resources. The
nature of these systems frequently makes them ideally suited to the model of aconcurrent system where all processes are able (at least potentially) to see thewhole of memory, and where access to scarce resources (such as a peripheral) is
controlled by semaphores. (A process seeks a semaphore by executing a claim, or
P , operation, and after its need is over releases it with a V operation. The system
must enforce the property that only one process ‘has’ the semaphore at a time. Thisis one solution to the so-called mutual exclusion problem.)
Perhaps the most superﬁcially attractive feature of shared-variable concurrency is that it is hardly necessary to change a programming language to accommodate it. A piece of code writes to, or reads from, a shared variable in very muchthe same way as it would do with a private one. The concurrency is thus, fromthe point of view of a sequential program component, in some senses implicit. As
with many things, the shared variable model of concurrency has its advantages anddisadvantages. The main disadvantage from the point of view of modelling general interacting systems is that the communications between components, which
are plainly vitally important, happen too implicitly. This eﬀect also shows up whenit comes to mathematical reasoning about system behaviour: when it is not madeexplicit in a program’s semantics when it receives communications, one has to allow
for the eﬀects of any communication at any time.
In recent years, of course, the emphasis on parallel programming has moved

0.2

Perspective

5

to the situation where one is distributing a single task over a number of separate
processors. If done wrongly, the communications between these can represent a real
bottleneck, and certainly an unrestricted shared variable model can cause problems
in this way. One of the most interesting developments to overcome this has been
the BSP (Bulk Synchronous Parallelism) model [76, 130] in which the processors
are synchronized by the beat of a relatively infrequent drum and where the communication/processing trade-oﬀ is carefully managed. The BSP model is appropriate
for large parallel computations of numerical problems and similar; it does not give
any insight into the way parallel systems interact at a low level. When you need
this, a model in which the communications between processors are the essence ofprocess behaviour is required. If you were developing a parallel system on which torun BSP programs, you could beneﬁt from using a communication-based model atseveral diﬀerent levels.
In his 1978 paper [54], C.A.R. Hoare introduced, with the language CSP(Communicating Sequential Processes), the concept of a system of processes, eachwith its own private set of variables, interacting only by sending messages to eachother via handshaken communication. That language was, at least in appearance,very diﬀerent from the one studied in this book. In many respects it was like thelanguage occam [57, 60] which was later to evolve from CSP, but it diﬀered fromoccam in one or two signiﬁcant ways:• Parallelism was only allowed into the program at the highest syntactic level.
Thus the name Communicating Sequential Processes was appropriate in a
far more literal way than with subsequent versions of CSP.
• One process communicated with another by name, as if there were a single
channel from each process to every other. In occam, processes communicate
by named channels, so that a given pair might have none or many between
them.
The ﬁrst version of CSP was the starting point for a large proportion of thework on concurrency that has gone on since. Many researchers have continued touse it in its original form, and others have built upon its ideas to develop their own
languages and notations.
The great majority of these languages have been notations for describing andreasoning about purely communicating systems: the computations internal to thecomponent processes’ state (variables, assignments, etc.) being forgotten about.
They have come to be known as process algebras. The ﬁrst of these were Milner’s
CCS [80, 82] and Hoare’s second version of CSP, the one this book is about. It
is somewhat confusing that both of Hoare’s notations have the same name andacronym, since in all but the deepest sense they have little in common. Henceforth,6

Introduction

for us, CSP will mean the second notation. Process algebra notations and theories
of concurrency are useful because they bring the problems of concurrency into sharp
focus. Using them it is possible to address the problems that arise, both at the highlevel of constructing theories of concurrency, and at the lower level of specifying anddesigning individual systems, without worrying about other issues. The purpose ofthis book is to describe the CSP notation and to help the reader to understand it
and, especially, to use it in practical circumstances.
The design of process algebras and the building of theories around them has
proved an immensely popular ﬁeld over the past two decades. Concurrency proves
to be an intellectually fascinating subject and there are many subtle distinctions
which one can make, both at the level of choice of language constructs and in thesubtleties of the theories used to model them. From a practical point of view theresulting tower of Babel has been unfortunate, since it has both created confusion
and meant that perhaps less eﬀort than ought to have been the case has been
devoted to the practical use of these methods. It has obscured the fact that often
the diﬀerences between the approaches were, to an outsider, insigniﬁcant.
Much of this work has, of course, strongly inﬂuenced the development of
CSP and the theories which underlie it. This applies both to the untimed version
of CSP, where one deliberately abstracts from the precise times when events occur,and to Timed CSP, where these times are recorded and used. Untimed theories tend
to have the advantages of relative simplicity and abstraction, and are appropriate
for many real circumstances. Indeed, the handshaken communication of CSP is tosome extent a way of making precise timing of less concern, since, if one end of thecommunication is ready before the other, it will wait. Probably for these reasons
the study of untimed theories generally preceded that of the timed ones. The timed
ones are needed because, as we will see later on, one sometimes needs to rely upontiming details for the correctness of a system. This might either be at the level ofoverall (externally visible) behaviour, or for some internal reason. The realizationof this, and the increasing maturity of the untimed theories, have led to a growing
number of people working on real-time theories since the mid 1980s.
There are a number of reasons why it can be advantageous to combine timed
and untimed reasoning. The major ones are listed below.
• Since timed reasoning is more detailed and complex than untimed, it is useful
to be able to localize timed analysis to the parts of the system which reallydepend on it.
• In many cases proving a timed speciﬁcation can be factored into proving acomplex untimed one and a simple timed property. This is attractive for thesame reasons as above.

0.3

Tools

7

• We might well want to develop a system meeting an untimed speciﬁcation
before reﬁning it to meet detailed timing constraints.
There have been two distinct approaches to introducing time into CSP, andfortunately the above advantages are available in both. The ﬁrst, usually known as
Timed CSP (see, for example, [29, 31, 98, 99]), uses a continuous model of time andhas a mathematical theory quite distinct to the untimed version. To do it justicewould require more space than could reasonably be made available in this volume,and therefore we do not cover it. A complementary text by S.A. Schneider, based
primarily round Timed CSP, is in preparation at the time of writing.
The continuous model of time, while elegant, makes the construction of automated tools very much harder. It was primarily for this reason that the author
proposes (in Chapter 14) an alternative in which a timed interpretation is placedon the ‘untimed’ language. This represents the passage of time by the regularoccurrence of a speciﬁc event (tock ) and had the immediate advantage that theuntimed tools were applicable. While less profound than Timed CSP, it does, forthe time being at least, seem more practical. It has been used frequently in industrial
applications of FDR.

0.3

Tools

For a long time CSP was an algebra that was reasoned about only manually. Thiscertainly had a strong inﬂuence on the sort of examples people worked on – thelack of automated assistance led to a concentration on small, elegant examples that
demonstrated theoretical niceties rather than practical problems.
In the last few years there has been an explosion of interest in the development of automated proof tools for CSP and similar languages. The chief proof andanalytic tool for CSP at present is called FDR (standing for Failures/Divergences
Reﬁnement, a name which will be explained in Section 3.3), whose existence has
led to a revolution in the way CSP is used. To a lesser extent it has also inﬂuenced
the way CSP is modelled mathematically and the presentation of its models.
A number of other tools, with similar external functionality though based onvery diﬀerent algorithms, have been or are being developed. FDR appears to be themost powerful (for most purposes) and complete at the time of writing. Becauseof this, and because the author has played a leading role in its development andis therefore more familiar with it than other tools, this book is, so far as the useof tools is concerned, centred chieﬂy on FDR. Many of the examples and exercises
have been designed so they can be ‘run’ on it.
Equally useful from the point of view of learning about the language are
simulators and animators which allow the human user to experiment with CSP

8Introduction

processes: interacting with them in reality instead of having to imagine doing so.
The diﬀerence between this sort of tool and FDR is that simulations do not prove
results about processes, merely providing a form of implementation that allows
experimentation. At the time of writing the most capable such tool appears to be
ProBE (used by the author in a preliminary version and due to be released later in1997).
The above are general-purpose tools, in that they deal with more-or-less any
program and desired property which you want to investigate. More speciﬁc tools arecustomized to perform analyses of restricted classes of system (such as protocols)or to check for speciﬁc conditions such as deadlock.
These and other tool developments have led to a restructuring and standardization of the CSP notation itself. The fact that the tools have allowed so many
more practical-size examples to be developed has certainly inﬂuenced our perception of the relative importance and, too, uses of various parts of the language,especially the parts which are at the level of describing data and operations over it(for building individual communications, and constructing a process’s state). The
presentation in this book has been inﬂuenced by this experience and is based on
the standardized syntax with the important diﬀerence that (at the time of writing)the machine-readable syntax is ASCII, and the textual appearance of various constructs therefore diﬀers from the more elegantly typeset versions which appear here
in print. The ASCII syntax is given in an appendix and is used in Chapter 15 (CaseStudies).
On past experience it is reasonable to expect that the range and power oftools will increase markedly over the next few years. Thus a snap-shot from mid
1997 would soon get out of date. It is hoped to keep the web site associated withthis book (see Preface) as up-to-date as possible on developments and to include
appropriate references and demonstrations there.
It is only really since the advent of tools that CSP has been used to a signiﬁcant extent for the development and analysis of practical and industrial-scale
examples.

0.4

What is a communication?

CSP is a calculus for studying processes which interact with each other and theirenvironment by means of communication. The most fundamental object in CSP is
therefore a communication event. These events are assumed to be drawn from aset Σ (the Greek capital letter ‘Sigma’) which contains all possible communications
for processes in the universe under consideration. Think of a communication asa transaction or synchronization between two or more processes rather than as0.4

What is a communication?

9

necessarily being the transmission of data one way. A few possible events in very
diﬀerent examples of CSP descriptions are given below.
• In a railway system where the trains and signal boxes are communicating,a typical event might be a request to move onto a segment of track, thegranting or refusing of permission for this, or the actual movement.
• If trying to model the interaction between a customer and a shop, we could
either model a transaction as a single event, so that A, X , Y  might mean A
buys X for £Y, or break it up into several (oﬀer, acceptance, money, change,etc.). The choice of which of these two approaches to follow would depend
on taste as well as the reason for writing the CSP description.
• The insertion of an electronic mail message into a system, the various internaltransmissions of the message as it makes its way to its destination, and its
ﬁnal receipt would all be events in a description of a distributed network.
Note that the user is probably not interested in the internal events, and sowould probably like to be able to ignore, or abstract away their presence.
• If we were using CSP to describe the behaviour of VLSI circuits, an event
might be a clock tick, seen by a large number of parallel communications,or the transmission of a word of data, or (at a lower level) the switching ofsome gate or transistor.
More than one component in a system may have to co-operate in the performance of an event, and the ‘real’ phenomenon modelled by the event might takesome time. In CSP we assume ﬁrstly that an event only happens when all its
participants are prepared to execute it (this is what is called handshaken communication), and secondly that the abstract event is instantaneous. The instantaneous
event can be thought of as happening at the moment when it becomes inevitablebecause all its participants have agreed to execute it. These two related abstractions constitute perhaps the most fundamental steps in describing a system using
CSP.
The only things that the environment can observe about a process are theevents which the process communicates with it. The interaction between the environment and a process takes the same form as that between two processes: events
only happen when both sides agree.
One of the fundamental features of CSP is that it can serve as a notation
for writing programs which are close to implementation, as a way of constructing
speciﬁcations which may be remote from implementation, and as a calculus forreasoning about both of these things – and often comparing the two. For thisreason it contains a number of operators which would either be hard to implement

10

Introduction

in a truly parallel system, or which represent some ‘bad’ forms of behaviour, thus
making them unlikely candidates for use in programs as such. The reason for having
the bad forms of behaviour (deadlock, divergence and nondeterminism) represented
explicitly and cleanly is to enable us to reason about them, hopefully proving themabsent in practical examples.

Part IA foundation course in CSP

Chapter 1

Fundamental concepts

A CSP process is completely described by the way it can communicate with its
external environment. In constructing a process we ﬁrst have to decide on analphabet of communication events – the set of all events that the process (and anyother related processes) might use. The choice of this alphabet is perhaps themost important modelling decision that is made when we are trying to represent areal system in CSP. The choice of these actions determines both the level of detailor abstraction in the ﬁnal speciﬁcation, and also whether it is possible to get areasonable result at all. But this will only really become clear once we have a graspof the basic notation and start to look at some examples, though some guidance isgiven in Section 0.4. So let us assume for now that the alphabet Σ of all events has
been established.
The fundamental assumptions about communications in CSP are these:• They are instantaneous: we abstract the real time intervals the performanceof events takes into single moments – conceptually the moments when theevent becomes inevitable.
• They only occur when both the process and its environment allow them; but
at any moment when the process and its environment do agree on an event
then it (or some other event) must happen.
CSP is about setting up and reasoning about processes that interact with
their environments using this model of communication. Ultimately, of course, wewill want to set up parallel systems of processes that communicate with each other,but in this chapter we will meet a basic collection of operators that allow us to create
processes that simply describe (internally sequential) patterns of communication.

14

Fundamental concepts

1.1

Fundamental operators

1.1.1

Preﬁxing

The simplest CSP process of them all is the one which can do nothing. It is written
STOP and never communicates.
Given an event a in Σ and a process P , a → P is the process which is initiallywilling to communicate a and will wait indeﬁnitely for this a to happen. After a it
behaves like P . Thus
up → down → up → down → STOP
will communicate the cycle up, down twice before stopping. This operation on
processes (turning P into a → P ) is known as preﬁxing.
Clearly STOP and preﬁxing, together, allow us to describe just the processes
that make a ﬁxed, ﬁnite sequence of communications before stopping.
1.1.2

Recursion

If we want to use a version of the process above which, instead of quickly stopping,can go on performing up, down indeﬁnitely, we can use recursion. Two diﬀerent
processes which achieve this eﬀect are deﬁned by the equations
P1= up → down → P1

P2

= up → down → up → down → P2

The idea is that any use of the recursively deﬁned process’s name (P1 or P2 )on the right-hand side of the equations means exactly the same as the whole. It
should be intuitively clear that any process satisfying either of these equations has
the desired behaviour. The form of a recursive deﬁnition by a single equation isthat an identiﬁer representing the process being deﬁned is at the left-hand side, anda process term, probably involving the identiﬁer, is on the right. (If the identiﬁer
does not appear then the recursion is not really a recursion at all and simply deﬁnes
the identiﬁer on the left to be the process on the right.) We can draw a pictureillustrating the behaviour of P1 and P2 : see Figure 1.1
Instead of deﬁning one process by a single equation we can deﬁne a number
simultaneously by a mutual recursion. For example, if we set
Pu=

up → Pd

Pd=

down → Pu

1.1

Fundamental operators

15
up

down

up

P1

down

down

P2
up

Figure 1.1 The behaviour of P1 and P2 .
then Pu should behave in just the same way as P1 and P2 deﬁned earlier. The
mutual recursions we meet later will be more interesting!
Most of the recursions in this book will be written in this equational style,but sometimes it is useful to have a way of writing down a recursive term without
having to give it a name and a separate line. The single recursion P = F (P )(where F (P ) is any CSP term involving P ) deﬁnes exactly the same process as the‘nameless’ term µ P .F (P ). (µ is the Greek letter ‘mu’.) Thus
up → (µ p.down → up → p)deﬁnes yet another process alternating up’s and down’s.
We have seen quite a few ways of deﬁning recursive processes with all our
examples having very similar behaviour – invariably rather dull since we still canonly create processes whose sequence of communications is completely ﬁxed. In fact
all the theories we explain in this book will allow us to prove that the processes P1 ,P2 and Pu are equal. But that is a subject for later.
1.1.3

Guarded alternative

It is still only possible to deﬁne processes with a single thread of behaviour: all we
can do so far is to deﬁne processes which execute a ﬁxed ﬁnite or inﬁnite sequenceof actions. CSP provides a few ways of describing processes which oﬀer a choice ofactions to their environment. They are largely interchangeable from the point ofview of what they can express, each being included because it has its distinct uses
in programming.
The simplest of them takes a list of distinct initial actions paired with processes and extends the preﬁx operator by letting the environment choose any oneof the events, with the subsequent behaviour being the corresponding process.
(a1 → P1 | . . . | an → Pn )

16

Fundamental concepts
UandD
down

P

a

up

a

b

Q
up

b

down

STOP
STOP

Figure 1.2 The behaviours of two processes with choice.
can do any of the events a1 , . . . , an on its ﬁrst step and, if the event chosen is ar ,subsequently behaves like Pr . This construct is called guarded alternative. The
process
UandD=(up → down → STOP | down → up → STOP )can do the two events up and down in either order.
Combining this operator with recursion, it is now possible to deﬁne somecomplex behaviours. As a relatively simple example, consider the processesP= (a → P | b → Q)

Q

= (a → P | b → STOP )where P will accept any sequence of a’s and b’s except that it stops if given two
consecutive b’s. Indeed, it should not be hard to see that any deterministic ﬁnite
state machine – a ﬁnite collection of states, each of which has a ﬁnite set of actions
available and the next state depends deterministically on which of this set occurs(i.e., only one possible state per action) – can be encoded using this operator andmutual recursion with ﬁnitely many equations. The behaviours of this P and of
UandD are illustrated in Figure 1.2
Combining this construct with an inﬁnite mutual recursion which deﬁnes one
process COUNT n for every natural number n ∈ N we can deﬁne a system of counter
processes as follows:
COUNT 0= up → COUNT 1

COUNT n= (up → COUNT n+1| down → COUNT n−1 )(n > 0)1.1

Fundamental operators
down

down

COUNT 0

17

up

down

up
COUNT 1up
COUNT 2

COUNT 3Figure 1.3 The behaviour of COUNT n .
COUNT n is the process which will communicate any sequence of up’s and down’s,
as long as there have never been n + 1 more down’s than up’s. These are not,of course, ﬁnite state machines: there are inﬁnitely many fundamentally diﬀerent
states that any one of the COUNT n processes can pass through. The distinction
between ﬁnite-state and non-ﬁnite-state CSP processes is extremely important formodel checking, the term usually used for state exploration tools such as FDR (seeSection 1.4), since that method relies on being able to visit every state. Of course
the pictures of these processes are also inﬁnite – see Figure 1.3.
If A ⊆ Σ is any set of events and, for each x ∈ A, we have deﬁned a process
P (x ), then?x : A → P (x )deﬁnes the process which accepts any element a of A and then behaves like theappropriate P (a). This construct is known as preﬁx choice for obvious reasons.
Clearly it generalizes the guarded alternative construction, since any guarded alternative can be recast in this form, but if A is inﬁnite the reverse is not true. It
strictly generalizes it in cases where A is inﬁnite. ?x : {} → P (x ) means the sameas STOP and ?x : {a} → P (x ) means the same as a → P (a).
This operator tends to be used in cases where the dependency of P (x ) upon
x is mainly through its use of the identiﬁer x in constructing subsequent communications, in constructing the index of a mutual recursion, or similar. Thus we canwrite a process which simply repeats every communication which is sent to it:
REPEAT= ?x : Σ → x → REPEAT

or one which behaves like one of the counters deﬁned above depending on what its
ﬁrst communication is:
Initialize= ?n : N → COUNT n18

Fundamental concepts

In many situations it is useful to have an alphabet Σ which contains compound objects put together by an inﬁx dot. So if c is the name of a ‘channel’ and T is
the type of object communicated down it, we would have c.T = {c.x | x ∈ T } ⊆ Σ.
It is natural to think of processes inputting and outputting values of type T overc: an inputting process would typically be able to communicate any element of c.T
and an outputting process would only be able to communicate one. Rather thanwrite the input in the form ?y : c.T → P (y), where the uses of y in P (y) have to
extract x from c.x , it is more elegant to use the ‘pattern matching’ formc?x : T → P  (x )where the deﬁnition of P  is probably slightly simpler than that of P because it canrefer to the value x input along c directly rather than having to recover it from acompound object. For example, the process COPY , which inputs elements of T on
channel left and outputs them on channel right is deﬁned
COPY = left?x : T → right!x → COPY
It is the simplest example of a buﬀer process: one which faithfully transfers the
input sequence on one channel to its outputs on another.
Where we want to allow any communication over channel c, the set T canbe omitted: c?x → P (x ) means the same as c?x : T → P (x ) where T is the type ofc. In cases like this, one frequently writes the ‘outputs’ using an exclamation markc!x for symmetry or clarity, but this is usually a synonym for c.x . (The only cases
where this does not apply arise where a communication is more highly structured
than we have seen here and has both ‘input’ and ‘output’ components – see page
27 where this subject is discussed further.) So, where T is understood, we might
write
COPY = left?x → right!x → COPY
It is important to remember that, even though this syntax allows us to model
input and output over channels, the fundamental CSP model of communication still
applies: neither an input nor an output can occur until the environment is willingto allow it.
We broaden the guarded alternative operator to encompass arguments of theform c?x : T → P (x ) as well as ones guarded by single events. For now we willassume, as an extension of the earlier assumption of disjointness, that all of theevents and input channels used in the guards are distinct and that none of thesingle events belongs to more than one of the input channels.
For example, we can deﬁne a buﬀer process which, unlike COPY , does notinsist upon outputting one thing before inputting the next. If T is the type of1.1

Fundamental operators

19

objects being input and output, and left.T ∪ right.T ⊆ Σ, we can deﬁne a process
Bs∞ for every s ∈ T ∗ (the set of ﬁnite sequences of elements of T ) as follows:∞B∞
Bsˆy

∞= left?x : T → Bx∞= (left?x : T → Bxˆsˆy| right!y → Bs∞ )∞So Bs∞ is the buﬀer presently containing the sequence s, and B
is the initiallyempty one. Notice the basic similarity between this recursive deﬁnition and the ones
(particularly COUNT ) seen earlier. This tail recursive style, particularly when eachrecursive call is guarded by exactly one communication (one-step tail recursion)shows the state space of a process extremely clearly. This style of deﬁnition isimportant both in presenting CSP speciﬁcations and in veriﬁcation techniques.

The use of sequence notation should be self-explanatory here. We will, however, discuss the language of sequences in more detail in Section 1.3.
The example B ∞ above illustrates two important and related aspects of CSP
style that have also been seen in earlier examples: the uses of parameterized mutual
recursions and of identiﬁers representing ‘data’ values. The value of a parameterizedrecursion such as this one or COUNT is that it allows the succinct presentation of alarge (and even, as in both these cases, inﬁnite) set of processes. We will think of theparameters as representing, in some sense, the state of such a process at the pointsof recursive call. In particular, even though the recursive call may be within thescope of an identiﬁer x , this identiﬁer cannot inﬂuence the value of the call unless it
appears within one of the parameters. A parameterized process can have any ﬁxed
number of parameters, which can be numbers, events, tuples, sets, sequences etc.,
though they may not be processes (or tuples etc. that contain processes).
The parameters can be written as subscripts (as in Bs∞ above), superscripts(e.g., R (a,b) ) or as ‘functional arguments’ (e.g., R(n, x )). The ﬁrst two of thesewere the traditional style before the advent of machine-readable CSP, which only
accepts the third. There is no formal diﬀerence between the diﬀerent positions, thechoice being up to the aesthetic taste of the programmer. Often, in more complex
examples, they are combined.
The identiﬁers used for input (i.e., those following ‘?’) are the second main
contributor to process state. Each time an input is made it has the eﬀect of creatinga new binding to the identiﬁer, whose scope is the process it enables (i.e., in c?x → P
and (c?x → P | d → Q) it is P ). Both these identiﬁers and the ones introduced asparameters can be used freely in creating events and parameters, and in deciding
conditionals (see later). They cannot, however, be assigned to: you should think of
CSP as a declarative language in its use of identiﬁers. CSP ‘programs’ have a great
deal in common with ones in a functional language such as Haskell.

20

Fundamental concepts

Example 1.1.1 (cash-point machine) Anyone who has read Hoare’s book will
be familiar with his use of vending machines as examples of CSP descriptions. This
type of example is useful because it models a form of interaction with which thereader can identify – placing himself or herself in the role of one process communicating in parallel with another.
Cash-point machines (or Automated Teller Machines – ATMs) provide a
related example where, because of the increased value of transactions and the needfor diﬀerent machines to co-operate with each other and with central databases,
there is perhaps better reason to be interested in formal speciﬁcation. It is also agood example later when we come to look at real time, since there are actually agood many real-time constraints on the operation of these machines.
At various points through this chapter and the rest of this book we will use
examples drawn from this world to illustrate CSP constructs and ideas. For the
moment we will only attempt to describe the interface between the machine andthe customer.
We will have to imagine that the set Σ of all communications contains events
such as in.c and out.c for all cards c ∈ CARD, pin.p for all possible PIN numbers p,
and req.n, dispense.n and refuse for all n drawn from possible withdrawal amounts(the set of which we denote by WA). In general we will simply assume that Σ
contains all events which are used in our process descriptions.
We ﬁrst describe a rather simple machine which goes through cycles of accepting any card, requiring its PIN number, and servicing one request for withdrawal
which is always successful, before returning the card to the customer.
ATM 1= in?c : CARD → pin.fpin (c) → req?n : WA →dispense!n → out.c → ATM 1

Here fpin (c) is the function which determines the correct PIN number of card c. The
set of all PIN numbers will be written PIN . It may appear from this description that
we are assuming that the customer never makes a mistake with his PIN number.
But this is not the case: what we are saying is (i) that the machine does not allow
the customer to proceed with his request until he has inserted the right number and(ii) that we do not deem a ‘handshaken’ communication to have taken place until
the customer has inserted this number. Incorrect numbers are not modelled in thistreatment: they can be thought of in terms of one partner trying out successive
communications until he ﬁnds one which is not refused.
This illustrates one of the most important principles which one should bear inmind when making a CSP abstraction of a system, whether a ‘human’ one like this,a parallel machine, or a VLSI chip. This is that we should understand clearly whenan event or communication has taken place, but that it is often possible to abstract1.1

Fundamental operators

21

several apparent events (here the cycles of inserting numbers and acceptance orrejection) into a single one. Clearly in this case both parties can clearly tell when
the communication has actually taken place – a PIN number has been enteredand accepted – which is perhaps the most important fact making this a legitimate
abstraction.
Despite these observations the model, in particular the abstraction surrounding the PIN number, is not ideal in the sense that it describes a system we probably
would not want. The chief diﬃculty surrounding the PIN number insertion is thata customer who had forgotten his number would be able to ‘deadlock’ the system
entirely with his card inside. In fact we will, in later examples, reﬁne this single
synchronization into multiple entry and acceptance/rejection phases. Later, when
we deal with time, we will be able to model further features that there might be in
the interface, such as a time-out (if no response is received within a set amount oftime, the ATM will act accordingly). (End of example)
Exercise 1.1.1 A bank account is a process into which money can be deposited andfrom which it can be withdrawn. Deﬁne ﬁrst a simple account ACCT 0 which has events
deposit and withdraw , and which is always prepared to communicate either.
Now extend the alphabet to include open and close. ACCT 1 behaves
like ACCT 0 except that it allows no event before it has been opened, and allows no further
event after it has been closed (and is always prepared to accept close while open). Youmight ﬁnd it helpful to deﬁne a process OPEN representing an open account.

Exercise 1.1.2

ACCT 0 and ACCT 1 have no concept of a balance. Introduce aparameter representing the balance of an OPEN account. The alphabet is open and close
as before, deposit . and withdraw . (which have now become channels indicating theamount of the deposit or withdrawal) plus balance. ( is the set of positive and negative
integers), a channel that can be used to ﬁnd out the current balance. An account has
zero balance when opened, and may only be closed when it has a zero balance. Deﬁneprocesses ACCT 2 and ACCT 3 which (respectively) allow any withdrawal and only thosewhich would not overdraw the account (make the balance negative).

Exercise 1.1.3

Exercise 1.1.4 Figure 1.4 shows the street map of a small town. Roads with arrows
on are one-way. Deﬁne a mutually recursive set of CSP processes, one for each labelledcorner, describing the ways traﬃc can move starting from each one. The alphabet is{north, south, east, west}, an action only being available when it is possible to move in theappropriate direction, and then having the eﬀect of moving the traveller to the next label.
Exercise 1.1.5 Deﬁne a process SUM with two channels of integers: in and sum. It
is always prepared to input (any integer) on in and to output on sum. The value appearing
on sum is the sum of all the values input so far on in. Modify your process so that it
can also output (on separate channels prod and last) the product of all the inputs and themost recent input.

22

Fundamental concepts
A

B

C

D

E

N

W

E
S

F

G

Figure 1.4 A town plan.
1.1.4

Further choice operators

External choice
The various ways of deﬁning a choice of events set out in the last section all set
out as part of the operator what the choice of initial events will be. In particular,
in guarded alternatives such as (a → P | b → Q), the a and b are an integral partof the operator even though it is tempting to think that this process is a choice
between the processes a → P and b → Q. From the point of view of possible
implementations, the explicitness of the guarded alternative has many advantages1
but from an algebraic standpoint and also for generality it is advantageous to havea choice operator which provides a simple choice between processes; this is what wewill now meet.
P 2 Q is a process which oﬀers the environment the choice of the ﬁrst eventsof P and of Q and then behaves accordingly. This means that if the ﬁrst event
chosen is one from P only, then P 2 Q behaves like P , while if one is chosenfrom Q it behaves like Q. Thus (a → P ) 2 (b → Q) means exactly the sameas (a → P | b → Q). This generalizes totally: any guarded alternative of thesorts described in the last section is equivalent to the process that is obtained byreplacing all of the |’s of the alternative operator by 2’s.2 Therefore we can regard
2 as strictly generalizing guarded alternative: for that reason we will henceforth
tend to use only 2 even in cases where the other would have been suﬃcient. (Infact, in ordinary use it is rare to ﬁnd a use of 2 which could not have been presented
1 Note that guarded alternative is provided in occam.
2 This transformation is trivial textually, but less so syntactically since the preﬁxes move frombeing part of the operator to become part of the processes being combined, and also we are movingfrom a single operator of arbitrary ‘arity’ to the repeated use of the binary operator 2. The factthat 2 is associative (see later) means that the order of this composition is irrelevant.

1.1

Fundamental operators

23

as a guarded alternative, at least if one, as in occam, extends the notation of aguard to include conditionals.)
The discussion above leaves out one important case that does not arise
with guarded alternatives: the possibility that P and Q might have initial eventsin common so that there is no clear prescription as to which route is followed
when one of these is chosen. We deﬁne it to be ambiguous: if we have written
a program with an overlapping choice we should not mind which route is taken
and the implementation may choose either. Thus, after the initial a, the process (a → a → STOP ) 2 (a → b → STOP ) is free to oﬀer a or b at its
choice but is not obliged to oﬀer both. It is thus a rather diﬀerent process toa → ((a → STOP ) 2 (b → STOP )) which is obliged to oﬀer the choice of a and b.
This is the ﬁrst example we have met of a nondeterministic process: one which isallowed to make internal decisions which aﬀect the way it looks to its environment.
We will later ﬁnd other examples of how nondeterminism can arise fromnatural constructions, more fundamentally – and inevitably – than this one.
A deterministic process is one where the range of events oﬀered to the environment depends only on things it has seen (i.e., the sequence of communications
so far). In other words, it is formally nondeterministic when some internal decision
can lead to uncertainty about what will be oﬀered. The distinction between deterministic and nondeterministic behaviour is an important one, and we will later(Section 3.3) be able to specify it exactly.
Nondeterministic choice
Since nondeterminism does appear in CSP whether we like it or not, it is necessary
to be able to reason about it cleanly. Therefore, even though they are not constructs
one would be likely to use in any program written for execution in the usual sense,
CSP contains two closely related ways of presenting the nondeterministic choice ofprocesses. These are
P

Q

and

S

where P and Q are processes, and S is a non-empty set of processes. The ﬁrst ofthese is a process which can behave like either P or Q, the second is one that canbehave like any member of S .
S for ﬁnite S using . The case where S isClearly we can represent
inﬁnite leads to a number of diﬃculties in modelling since (obviously) it introducesinﬁnite, or unbounded, nondeterminism. It turns out that this is somewhat harder
to cope with than ﬁnite nondeterminism, so we will sometimes have to exclude it
S there are several otherfrom consideration. Apart from the explicit operator
operators we will meet later which can introduce unbounded nondeterminism. We

24

Fundamental concepts

will mention this in each case where it can arise, and the precautions necessary to
avoid it.
It is important to appreciate the diﬀerence between P 2 Q and P
Q.
The process (a → STOP ) 2 (b → STOP ) is obliged to communicate a or b if
oﬀered only one of them, whereas (a → STOP ) (b → STOP ) may reject either.
It is only obliged to communicate if the environment oﬀers both a and b. In theﬁrst case, the choice of what happens is in the hands of the environment, in thesecond it is in the hands of the process. Some authors call these two forms ofchoice external and internal nondeterminism respectively, but we prefer to think of‘external nondeterminism’ as ‘environmental choice’ and not to confuse it with aform of nondeterminism.
The process P can be used in any place where P
Q would work, since
there is nothing we can do to stop P Q behaving like P every time anyway. If
R is such that R = R P we say that P is more deterministic than R, or that it
reﬁnes R. Since (PQ) P = P
Q for any P and Q, it follows that P is,
as one would expect, always more deterministic than P Q. This gives the basic
notion of when one CSP process is ‘better’ than another, and forms the basis of themost important partial orders over CSP models. When P R = R we will writeRP

The concept of reﬁnement will turn out to be exceptionally important.
Example 1.1.2 (nondeterministic atm) From the point of view of the user ofour cash-point machine, it will probably be nondeterministic whether his request
for a withdrawal is accepted or not. We could therefore remodel his view of it asfollows:
ATM 2= in?c : CARD → pin.fpin (c) → req?n : WA →((dispense.n → out.c → ATM 2)(refuse → (ATM 2 out.c → ATM 2)))

Notice that it is also nondeterministic from the point of view of the user whether
he gets his card back after a refusal.
Even if the machine’s decision is entirely deterministic given the information
it can see (such as how much money it has, the state of the network connecting
it to central machines and the health of the customer’s account) this does not
reduce the validity of the above model. For the customer cannot know most of thisinformation and chooses not to include the rest of it in modelling this interface. He
has introduced an abstraction into the model and is paying for the simple modelwith some nondeterminism.

1.1

Fundamental operators

25

Abstraction is another important idea of which we will see much more later,
especially Chapter 12. (End of example)
Conditional choice
Since we allow state identiﬁers into CSP processes through input and process parameters, a further form of choice is needed: conditional choice based on the value ofa boolean expression. In the informal style of presenting CSP there is no need tobe very prescriptive about how these choices are written down,3 though obviously
a tighter syntax will be required when we consider machine-readable CSP. Howevera choice is written down, it must give a clear decision about which process theconstruct represents for any legitimate value of the state identiﬁers in scope, andonly depend on these.
Conditionals can thus be presented as if ... then ... else ... constructs (asthey are in the machine-readable syntax), as case statements, or in the following
syntax which elegantly reduces the conditional to an algebraic operator: P <I b>
IQ
means exactly the same as if b then P else Q. Because it ﬁts in well with the restof CSP notation, we will tend to quote this last version when discussing or using
conditionals. It is also legitimate to use conditionals in computing sub-process
objects such as events. Thus the two processes
ABS 1= left?x → right!((−x )<I x < 0>I x ) → ABS 1

ABS 2= left?x → ( (right!(−x ) → ABS 2 )<I x < 0>I (right!x → ABS 2 ))are equivalent: both input numbers and output the absolute values.
The use of conditionals can obviously reduce the number of cases of a parameterized mutual recursion that have to be treated separately to one (simply replacing each case by one clause in a conditional), but they can, used judiciously,
frequently give a substantial simpliﬁcation as well. Consider, for example, a twodimensional version of our COUNT process which now represents a counter on achess board. It will have two parameters, both restricted to the range 0 ≤ i ≤ 7.
One is changed by the events {up, down}, the other by {left, right}. There are noless than nine separate cases to be considered if we were to follow the style (usedfor COUNT earlier) of dealing with the diﬀerent possible initial events one by one:see Figure 1.5. Fortunately these all reduce to a single one with the simple use of
3 Indeed, in many presentations of CSP they seem to be considered so informal that they are
not described as part of the language.

26

Fundamental concepts

Figure 1.5 The nine case diﬀerent sets of initial events in Counter (i , j ).
conditionals:
Counter (n, m) =

(down
2 (up
2 (left
2 (right→ Counter (n − 1, m))<I n > 0>I STOP→ Counter (n + 1, m))<I n < 7>I STOP→ Counter (n, m − 1))<
I m > 0>I STOP→ Counter (n, m + 1))<
I m < 7>I STOP

Note that the availability of each event has been deﬁned by a conditional,
where the process produced when the event is not available is STOP , which ofcourse makes no contribution to the initial choices available.4
Multi-part events: extending the notation of channels
Thus far all events we have used have been atomic (such as up and down) or havecomprised a channel name plus one ‘data’ component (such as left.3). In general we
allow events that have been constructed out of any ﬁnite number of parts using theinﬁx dot ‘.’ (which is assumed to be associative). In written CSP it is a convention,
which is enforced as a rule in machine-readable CSP5 (see Appendix B) that a
4 This style of coding in CSP is essentially the same as the use of boolean guards on communications in occam alternatives. We could, of course, explicitly extend the guarded alternative
in CSP to include a boolean component, but since the above style is possible there is little pointfrom a formal point of view. The machine-readable form understood by FDR does include such ashorthand: b & P abbreviates if b then P else STOP.
5 In machine-readable CSP all channels have to be declared explicitly

1.1

Fundamental operators

27

channel consists of an identiﬁer (its name or tag) plus a ﬁnite (perhaps empty)
sequence of data types, and that Σ then consists of all events of the form
c.x1 . . . . xn
where c is such a name, T1 , . . . , Tn is its sequence of types, and xi ∈ Ti for each i .
The most common use for communications with more than two parts is when
we want to set up what is eﬀectively an array of channels for communication ina parallel array where the processes are probably similarly indexed. Thus if we
had processes indexed P (i ) forming a one-dimensional array, we might well have achannel of type N.N.T where T is a data type that these processes want to send toeach other. If c were such a channel, then c.i .j .x might represent the transmissionof value x from P (i ) to P (j ). We will see many examples like this once we haveintroduced parallel operators.
They can also, however, be used to achieve multiple data transfers in a single
action. This can even be in several directions at once, since the input (?) and output(!) modes of communication can be mixed in a multi-part communication. Thus
c?x : A!e → P
represents a process whose ﬁrst step allows all communications of the form {c.a.b |a ∈ A} where b is the value of the expression e. The identiﬁer x is then, of course,bound to the relevant member of a in the body of P . The advent of machinereadable CSP and FDR has proved the usefulness of this type of construct, and has
led to the adoption of conventions to deal with various cases that can arise. Oneof these shows the subtle distinction between the use of the inﬁx dot ‘.’ and theoutput symbol ! in communications. For example, if d is a channel of type A.B .C .D
then if the communication d ?x .y!z .t appears in a process deﬁnition it is equivalent
to d ?x ?y!z !t because an inﬁx dot following a ? is taken to be part of a patternmatched by the input. Thus one ? can bind multiple identiﬁers until overridden
by a following !. None of the examples in this book uses this or any other related
convention – in the rare examples where more than one data component follows
a ? we will follow the good practice of using only ? or ! as appropriate for eachsuccessive one – but further details of them can be found in Appendix B and [39].
One very useful notation ﬁrst introduced in machine-readable CSP, which
we will use freely, allows us to turn any set of channels and partially deﬁned events
into the corresponding events. This is the {| c1 , c2 |} notation which forms theappropriate set of events from one or more channels: it is formally deﬁned as follows.
If c has type T1 .T2 . . . Tn as above, 0 ≤ k ≤ n and ai ∈ Ti for 1 ≤ i ≤ k , thenevents(c.a1 . . . ak ) = {c.a1 . . . ak .bk +1 . . . bn | bk +1 ∈ Tk +1 , . . . , bn ∈ Tn }

28

Fundamental concepts

is the set of events which can be formed as extensions of c.a1 . . . ak . We can thendeﬁne{| e1 , . . . , er |} = events(e1 ) ∪ . . . ∪ events(er )Exercise 1.1.6 Extend the deﬁnition of COUNT n so that it also has the events up5,
up10, down5 and down10 which change the value in the register by the obvious amounts,
and are only possible when they do not take the value below zero.
Exercise 1.1.7 A change-giving machine which takes in £1 coins and gives change
in 5, 10 and 20 pence coins. It should have the following events: in£1, out5p, out10p,
out20p. Deﬁne versions with the following behaviours:(a) CMA gives the environment the choice of how it wants the change, and if an extra£1 is inserted while it still has a non-zero balance it increases the amount of change
available accordingly.
(b) CMB behaves like CMA except that it will only accept a further £1 if its balanceis less than 20p.
(c) CMC is allowed to choose any correct combination of change nondeterministically,
only allowing the insertion of £1 when it has zero balance.
∞
Exercise 1.1.8 COPY represents a one-place buﬀer and B
represents an unbounded
one. These are just two examples of processes representing communication media for transmitting information from channel left to channel right. Describe ones with the following
behaviours (except for the last one, their output streams must always copy the input ones
without loss, and preserving order):(a) FCOPY behaves like COPY except that it is allowed to input a second item whenit already contains one, but if it does it breaks (STOP).
(b) DELAY can hold up to two items, but cannot output the ﬁrst one unless it is full.
Thus its outputs are (after the initial input) always one or two behind its inputs,
unlike the case with COPY where they are always zero or one behind.
(c) BUFF  is a buﬀer that cannot be guaranteed to accept an input except whenempty, but neither can it be guaranteed not to accept one. When non-empty, it
never refuses to output the next item due.
(d) LEAKY behaves like COPY except that it loses every third item.
Redesign the process ATM 1 so that the action of accepting a PIN
number is broken into the successive input of up to three numbers (any PIN numbers),
with a correct or incorrect one being rewarded with ok or wrong respectively. After ok it
carries on in the same way as the original ATM 1, and after the third wrong it reverts tothe initial state (without returning the card).

Exercise 1.1.9

1.2

Algebra1.1.5

29

A few important processes

There are a few processes with very basic behaviour that it is useful to have standard
names for. We have already met STOP , the process that does nothing at all. Twomore are
RUN A = ?x : A → RUN A
the process which, for a set of events A ⊆ Σ, can always communicate any memberof A desired by the environment, andChaos A = STOP(?x : A → Chaos A )which can always choose to communicate or reject any member of A. Evidently
Chaos {} and RUN {} are both equivalent to STOP . If no alphabet is speciﬁed forone of these processes (RUN or Chaos ) then we understand it (the alphabet) to be
the whole of Σ. Clearly Chaos A is reﬁned by both STOP and RUN A .
Two other important constants (div and SKIP ) will be introduced later(respectively Sections 3.1 and 6.1) once the concepts they involve have been established.

1.2

AlgebraOne of our primary ways of understanding CSP will be to develop a set of algebraiclaws which the operators satisfy. An algebraic law is the statement that two expressions, involving some operators and identiﬁers representing arbitrary processes(and perhaps other things such as events) are equal. By ‘equal’, we mean that thetwo sides are essentially the same: for CSP this means that their communicating
behaviours are indistinguishable by the environment.
Everyone with the most basic knowledge of arithmetic or set theory is familiar
with the sort of algebra we are now talking about. There are a number of basic
patterns that many laws conform to; the following are a few familiar examples
illustrating these:
x +y
x ×y
x ∪y
(x + y) + z(x + y) × z
0+x{} ∩ x
x ∪x

=
=
=
=
=
=
=
=

y +x
y ×x
y ∪x
x + (y + z )(x × z ) + (y × z )x{}x

a commutative, or symmetry law
ditto
ditto
associativity(right) distributive law
unit law (0 is a left unit of +)zero law ({} is a left zero of ∩)idempotence

30

Fundamental concepts

We will ﬁnd all of these patterns and more amongst the laws of CSP. Let
us now consider what laws ought to relate the CSP operators we have met so far:preﬁxing, external choice, nondeterministic choice, and conditionals.
We would expect the choice between P and itself to be the same as P , thechoice between P and Q the same as that between Q and P , and the choice between
three processes P , Q and R to be the same however bracketed. And this will all
apply whether we are talking about internal (nondeterministic) choice or external
choice. In other words, these properties all hold whether the environment or theprocess gets to choose which path is chosen. Thus there are idempotence, symmetry
and associative laws for both 2 and :P 2P = P

2-idem

(1.1)

P

P = P

 -idem(1.2)

P 2Q = Q 2P

2-sym(1.3)

P

 -sym

(1.4)

P 2 (Q 2 R) = (P 2 Q) 2 R

2-assoc

(1.5)

R

 -assoc

(1.6)

P

(Q

Q = Q

R) = (PP

Q)

These three laws (idempotence, symmetry and associativity) are just whatis needed to ensure that the nondeterministic choice operator over sets, S , makes
sense (see Exercise 1.2.5). For what we mean by this (for ﬁnite S = {P1 , . . . , Pn })must be the same as P1 . . . Pn , and since sets are oblivious to the repetitionand order of their elements, we need
to be idempotent (ignoring repetitions),
symmetric (ignoring order) and associative (so that bracketing is not required).
Clearly the operator S has laws that we could write down too, but these would
not follow such conventional forms as it is not an ordinary binary operator. We will
always feel at liberty to rewrite {P1 , . . . , Pn } as
P1

...

Pn

and similar without formal recourse to laws.
Notice that each law has been given a name and a number to help us refer
to it later.

1.2

Algebra31

If we have any operator or construct F (·) which, in any ‘run’ takes at mostone copy of its argument, then it is natural to expect that F (·) will be distributive,in thatF (PF(Q) = F (P )
S)

=

F (Q)

{F (P ) | P ∈ S }(i.e., the operator distributes overand distributes through ). In the ﬁrst ofthese, this is because the argument on the left-hand side can act like P or like Q,
so the eﬀect of running F (P Q) must be either like running F (P ) or like running
F (Q). Since that is precisely the set of options open to F (P )F (Q), the twosides are equal. The second is just the same argument applied to an arbitrary,rather than two-way, choice. All of the operators, other than recursion, which wehave described so far fall into this category. The distributive laws for some of theconstructs seen to date are:P 2 (QP2
a → (Pa→?x : A → (P?x : A →(P 2 R)

2-dist(1.7){P 2 Q | Q ∈ S }2-Dist(1.8)

prefix-dist

(1.9)R) = (P 2 Q)
S =Q) = (a → P )S =(a → Q){a → Q | Q ∈ S }Q) = (?x : A → P )S =(?x : A → Q){?x : A → Q | Q ∈ S }prefix-Dist (1.10)
input-dist (1.11)
input-Dist (1.12)

Note that there is a pair for each. In fact, of course, the second of each pair implies
the other. An operator that distributes overS will be called fully distributive,
whereas one that distributes over will be called ﬁnitely distributive. In future,
we will generally only quote one of each pair of distributive laws explicitly, to save
space. It may be assumed that they both hold if either does, except in the rare cases(always explicitly ﬂagged) of operators that are ﬁnitely but not fully distributive.
You should, in general, expect an operator F (P ) to be distributive unless it
has the chance, in a single run, to compare two diﬀerent copies of P . If it can makesuch a comparison then F (PQ) may be diﬀerent from F (P ) F (Q) because32

Fundamental concepts

the two copies it compares may be diﬀerent (one P and one Q) whereas in thesecond case they must be the same (whichever they are). This is why recursion is
not distributive. We only have to consider a simple example likeµ p.((a → p)(b → p))(µ p.a → p)and(µ p.b → p)

where the left-hand side can perform any sequence of a’s and b’s (at its own choice)while the right-hand side has to be consistent: once it has communicated one a it
must keep on doing a’s.
2-dist is actually only one of the two distributive laws for 2 over . The
other one (the right distributive law) follows from this one and 2-sym. There arealso (left and right) distributive laws for over itself – provable from the existing
set of laws for (see Exercise 1.2.1 below).
There is a further law relating the two forms of choice whose motivation ismuch more subtle. Consider the process P (Q 2 R). It may either behave like P
or oﬀer the choice between Q and R. Now consider(PQ) 2 (PR)

a process which the distributive laws of 2 can expand to(P 2 P )(P 2 R)(Q 2 P )(Q 2 R)

The ﬁrst of these four equals P by 2-idem. It follows that the ﬁrst and lastalternatives provide all the options of the ﬁrst process. Every behaviour of thesecond and third is possible for one of the other two: every set of events they reject
initially is also rejected by P (for they oﬀer the choice of the ﬁrst actions of P andanother process), and every subsequent behaviour belongs to one of P , Q and R.
We therefore assert that these two processes are equal – in other words, distributes
over 2.
P(Q 2 R) = (PQ) 2 (PR)

 -2-dist (1.13)

The following is the chief law relating preﬁxing and external choice. It saysthat if we give the environment the choice between processes oﬀering A and B , thenwe get a process oﬀering A ∪ B whose subsequent behaviour depends on which of
A and B the ﬁrst event belongs to:(?x : A → P ) 2 (?x : B → Q) = ?x : A ∪ B → ((P Q)<
I x ∈ A ∩ B>
I
(P <
x
∈
A>
I
I Q))

2-step (1.14)

1.2

Algebra33

We have called this a step law because it allows us to compute the ﬁrst-step behaviour of the combination (i.e., the selection of initial actions plus the processthat succeeds each action) from the ﬁrst step behaviour of the processes we are
combining.6
STOP is the process that oﬀers no choice of initial actions. This can ofcourse be written as the preﬁx choice over an empty set:
STOP -step (1.15)

STOP = ?x : {} → P
It is an immediate consequence of the last two laws that
STOP 2 (?x : A → P )=?x : A → P

Of course we would expect that the external choice of any process with STOP would
have no eﬀect. This gives us our ﬁrst unit law:2-unit (1.16)

STOP 2 P = P(There is no need for a right unit law as well as this one, since it is easily inferredfrom this one and the symmetry law 2-sym.)Conditional choice is idempotent and distributive:<I ·>I -idem (1.17)

P<
I b>
IP = P

(P

Q)<
I b>
I R = (P <
I b>
I R)

R<
I b>
I (P

Q) = (R<
I b>
I P)

(Q <
I b>
I R)

<
I ·>
I -dist-l (1.18)

(R<
I b>
I Q)

<
I ·>
I -dist-r (1.19)

Left and right distributive laws are required here because conditional choice is not
symmetric.
The conditional behaviour is brought out by the following pair of laws:P<
I true>
IQ = P<
I true>I -id (1.20)

P<
I false>
IQ = Q<
I false>I -id (1.21)

6 From here on, in quoting laws about preﬁxed processes, we will usually refer only to the form

?x : A → P . The others, namely a → P and c?x : A → P (and the more complex forms for
multi-part events discussed above) can be transformed into this form easily, and so quoting a lotof extra laws to deal with them would serve no particular purpose.

34

Fundamental concepts

There are other laws in which conditional choice interacts with boolean operators on the condition(s), but we do not attempt to enumerate them here (though
see the exercises below). One interesting class of laws is that almost all operators
distribute over this form of choice as well as over . The only ones that do not areones (in particular preﬁx choice) that may modify the bindings of identiﬁers usedin the boolean condition. An example of a law that does hold is<I ·>I -2-dist (1.22)

P 2 (Q <I b>
I R) = (P 2 Q)<
I b>
I (P 2 R)

while the failure of this distribution in the presence of binding constructs is illustrated by?x : N →?x : N → (P <I x is even>I Q) =?x : N → ((?x : N → P )<I x is even>
I (?x : N → Q))
since the distribution of <I x is even>I through the inner preﬁx choice results in x
being bound to the ﬁrst input rather than the second.
The fundamental law of recursion is that a recursively deﬁned process satisﬁes
the equation deﬁning it. Thus the law is (in the case of equational deﬁnitions) justa part of the program. For the µ form of recursion this law isµ-unwind (1.23)µ p.P = P [µ p.P /p]where the notation Q[R/p] means the substitution of the process R for all free (i.e.,
not bound by some lower-level recursion) occurrences of the process identiﬁer p.
We have already noted that recursion fails to be distributive.
Laws of the sort seen in this section serve several functions: they provide a
useful way of gaining understanding and intuition about the intended meaning of
constructs, they can (as we will see later) be useful in proofs about CSP processes,
and ﬁnally, if presented and analyzed highly systematically, they can be shown tocompletely deﬁne the meaning, or semantics of language constructs (in a sense weare not yet in a position to appreciate but which is fully explained in Chapter 11).
Whenever we introduce a new operator in later chapters, we will usually use someof its laws to help explain how it behaves.
Using the laws quoted in the text for , prove that it distributes overitself (i.e., that P  (Q  R) = (P  Q)  (P  R)).

Exercise 1.2.1

Exercise 1.2.2

Suggest some laws for

S and how it relates to .



Exercise 1.2.3 Write down the left and right distributive laws of · I b I · through

.

1.3

The traces model and traces reﬁnement

35

Exercise 1.2.4 Use 2-step and other laws given above to prove that(?x : A → P ) 2 (?x : A → Q) = (?x : A → P )  (?x : A → Q)

Exercise 1.2.5 Suppose we try to extend the binary operator ⊕ (e.g. ) to ﬁnite
non-empty sets by deﬁning{P1 , . . . , Pn } = P1 ⊕ (P2 ⊕ . . . (Pn−1 ⊕ Pn ) . . .)Show that this makes sense (i.e., the value of
S is independent of the way S is written
down) only if ⊕ is idempotent, symmetric and associative. For example, it must be
idempotent because {P , P } = {P }, and hence P ⊕ P ={P , P } ={P } = P .
In this case prove that(A ∪ B ) = (A) ⊕ (

B ) for any non-empty A and B .

What additional algebraic property must ⊕ have to make{} well deﬁned in sucha way that this union law remains true? [Hint: 2 has this property but  does not.] Whatis then the value of{}?

Exercise 1.2.6 Complete the following laws of the conditional construct by ﬁlling in
the blank(s) (. . .) in each(b) P I bI (Q I b ∧ cI R) = . . . I bIR(c) (P I cI Q) I b
I R = . . . I cI ...
(a) P I ¬b I Q = . . . I b I . . .

1.3

The traces model and traces reﬁnement

Imagine you are interacting with a CSP process. The most basic record you mightmake of what happens is to write down the trace of events that occur: the sequenceof communications between you (the environment) and the process. In general, a
trace might be ﬁnite or inﬁnite: ﬁnite either because the observation was terminatedor because the process and environment reach a point where they cannot agree on
any event, inﬁnite when the observation goes on for ever and inﬁnitely many events
are transacted.
There are two basic levels of detail at which we might record traces: either
we write down the events that occur in order or we write them down with the exact
times when they happen. The choice of which of these is picked selects between thetwo main ways of looking at CSP. The version of CSP covered in this book is untimed
CSP, where only the order of events matters. The more detailed version, Timed CSP,
includes the time of each event in traces. A trace thus becomes a sequence of event/time pairs (with the times increasing, of course). The basic principle of untimed
CSP is that, while the relative order of what processes communicate does matter

36

Fundamental concepts(and can be used to distinguish and specify them), the exact timing of events doesnot. (We will see a way of building a diﬀerent model of time into ‘untimed’ CSP in
Chapter 14. References to work on Timed CSP can be found in Section 14.8.)
It is natural to model an untimed CSP process by the set of all traces it canperform. It turns out that recording only ﬁnite traces is suﬃcient in the majorityof cases – after all, if u is an inﬁnite trace then all its ﬁnite preﬁxes (initial subsequences) are ﬁnite traces – and for the time being we will do this. In Section 8.3.2
and Chapter 10 we will see the subtle distinctions inﬁnite traces can make in somecases – though at some cost in terms of theoretical diﬃculty.
1.3.1

Working out traces(P )For any process P , we deﬁne traces(P ) to be the set of all its ﬁnite traces – membersof Σ∗ , the set of ﬁnite sequences of events. For example:• traces(STOP ) = {} – the only trace of the process that can perform noevent is the empty trace;• traces(a → b → STOP ) = {, a, a, b} – this process may have communicated nothing yet, performed an a only, or an a and a b;
• traces((a → STOP ) 2 (b → STOP )) = {, a, b} – here there is a choiceof ﬁrst event, so there is more than one trace of length 1;• traces(µ p.((a → p) 2 (b → STOP ))) = {an , anˆb | n ∈ N} – thisprocess can perform as many a’s as its environment likes, followed by a b
after which there can be no further communication.
Note the use of ﬁnite sequence notation here: a1 , a2 , . . . , an  is the sequence
containing a1 , a2 to an in that order. Unlike sets, the order of members of a sequence
does matter, as does the number of times an element is repeated. Thus a, a, b,a, b and b, a are all diﬀerent.  denotes the empty sequence. If s and t are two
ﬁnite sequences, then sˆt is their concatenation: the members of s followed by thoseof t: for example a, bˆb, a = a, b, b, a. If s is a ﬁnite sequence and n ∈ N,
then s n means the n-fold concatenation of s: s 0 =  and s n+1 = (s n )ˆs. If s isan initial subsequence, or preﬁx of t, in that there is a (possibly empty) sequencew with t = sˆw , then we write s ≤ t. We will meet more sequence notation later
when it is required.
For any process P , traces(P ) will always have the following properties:• traces(P ) is non-empty: it always contains the empty trace ;• traces(P ) is preﬁx closed: if sˆt is a trace then at some earlier time during
the recording of this, the trace was s.

1.3

The traces model and traces reﬁnement

37

There are two important things we can do with traces(P ): give a meaning,or semantics, to the CSP notation, and specify the behaviour required of processes.
The set of all non-empty, preﬁx-closed subsets of Σ∗ is called the traces model –the set of all possible representations of processes using traces. It is written T andis the ﬁrst – and simplest – of a number of models for CSP processes we will bemeeting in this book. The formal deﬁnitions of the rest of them can be found inPart II.
Hopefully, given the earlier explanations of what the various constructs of
CSP ‘meant’, the example sets of traces are all obviously correct in the sense thatthey are the only possible sets of traces that the various processes might have. We
can, in fact, calculate the trace-set of any CSP process by means of a set of simple
rules – for in every case we can work out what the traces of a compound process(such as a → P or P 2 Q) are in terms of those of its components (P and Q). Thus
the traces of any process can be calculated by following its syntactic construction.
The rules for the preﬁxing and choice constructs are all very easy:
1. traces(STOP ) = {}2. traces(a → P ) = {} ∪ {aˆs | s ∈ traces(P )} – this process has either done
nothing, or its ﬁrst event was a followed by a trace of P .
3. traces(?x : A → P ) = {} ∪ {aˆs | a ∈ A ∧ s ∈ traces(P [a/x ])} – thisis similar except that the initial event is now chosen from the set A andthe subsequent behaviour depends on which is picked: P [a/x ] means thesubstitution of the value a for all free occurrences of the identiﬁer x .
4. traces(c?x : A → P ) = {} ∪ {c.aˆs | a ∈ A ∧ s ∈ traces(P [a/x ])} – thesame except for the use of the channel name.
5. traces(P 2 Q) = traces(P ) ∪ traces(Q) – this process oﬀers the traces of P
and those of Q.
6. traces(P Q) = traces(P ) ∪ traces(Q) – since this process can behave likeeither P or Q, its traces are those of P and those of Q.

7. traces( S ) = {traces(P ) | P ∈ S } for any non-empty set S of processes.
8. traces(P <I b>I Q) = traces(P ) if b evaluates to true; and traces(Q) if b evaluates to false.7
7 Technical note: The treatment of identiﬁers representing input values and process parameters,
and appearing in boolean expressions, is very lightweight here. This treatment implicitly assumes
that the only terms for which we want to compute traces(P ) are those with no free identiﬁers –so that for example any boolean expression must evaluate to true or false. The advantage ofthis approach is that it frees us from the extra notation that would be needed to deal with themore general case, but there is certainly no reason why we could not deal with processes with free
identiﬁers as ‘ﬁrst class objects’ if desired.

38

Fundamental concepts

The traces of a guarded alternative can be computed by simply re-writing it
as an external choice (i.e., replacing all |’s by 2’s).
Notice that the traces of internal and external choice are indistinguishable.
What this should suggest to you is that traces(P ) does not give a complete description of P , since we certainly want to be able to tell P 2 Q and P Q apart.
We will see the solution to this problem later, but its existence should not preventyou from realizing that knowledge of its traces provides a great deal of information
about a process.
The ﬁnal construct we need to deal with is recursion. Think ﬁrst abouta single, non-parameterized, recursion p = Q (or equivalently µ p.Q, where Q is
any process expression possibly involving the identiﬁer p). This means the process
which behaves like Q when the whole recursively deﬁned object is substituted forthe process identiﬁer p in its body: Q[µ p.Q/p] as in the law µ-unwind. The way
traces have been calculated through the other constructs means that a term, likeQ, with a free process identiﬁer p, represents a function F from sets of traces tosets of traces: if p has set of traces X , then Q has traces F (X ). For example, if
Q is a → p, F (X ) = {} ∪ {aˆs | s ∈ X }. traces(µ p.Q) should be a set X thatsolves the equation X = F (X ).
Now it turns out that the functions F over T that can arise from CSP
process descriptions always have a least ﬁxed point in the sense that X = F (X ) andX ⊆ Y whenever Y = F (Y ) – this least ﬁxed point always being the appropriate
value to pick for the recursion. Two separate mathematical theories can be used
to demonstrate the existence of these ﬁxed points – but we will leave the details ofthese till Chapter 8 and Appendix A.
The case of parameterized and other mutual recursions is little diﬀerent,
though the greater generality makes it somewhat harder to formulate. In this case
we have a deﬁnition for a collection of processes, where the deﬁnition of each may
invoke any or all of the others. This deﬁnes what we might term a vector of process
names (where, in the case of a parameterized family, the parameter value is part of
the name, meaning that there are as many names as there are parameter values)
to be equal to a vector of process expressions. The problem of determining thetrace-set of one of these mutually deﬁned processes then comes down to solving anequation X = F (X ) where X is a vector of trace-sets – one for each process nameas above – and F (·) is now a function which both takes and delivers a vector oftrace-sets. For example, in the mutual recursion
PQ= (a → P ) 2 (b → Q)
= (c → Q) 2 (b → P )all the vectors have length 2 – one component corresponding to each of P and Q.
Given a vector X = XP , XQ , the function F produces a vector, YP , YQ  say,

1.3

The traces model and traces reﬁnement

39

where
• YP = {}∪{aˆs | s ∈ XP }∪{bˆs | s ∈ XQ } i.e., the result of substituting
X into the recursive deﬁnition of P , and• YQ = {}∪{cˆs | s ∈ XQ }∪{bˆs | s ∈ XP } i.e., the result of substituting
X into the recursive deﬁnition of Q.
In the case of COUNT , the vectors would be inﬁnite – with one component for eachnatural number. B ∞ will also produce inﬁnite vectors, but this time there is one
component for each ﬁnite sequence of the type being transmitted.
The extraction of ﬁxed points is mathematically the same whether the functions are on single trace-sets or on vectors. The only diﬀerence is that the intended
process value in the case of a mutual recursion will be one of the components of theﬁxed point vector, rather than the ﬁxed point itself.
All of the recursions we have seen to date (and almost all recursions one
meets in practice) have a property that makes them easier to understand – andreason about. They are guarded, meaning that each recursive call comes after (i.e.,
is preﬁxed by) a communication that is introduced by the recursive deﬁnition8
rather than being exposed immediately. Examples of non-guarded recursions areµ p.p (perhaps the archetypal one), µ p.p 2 (a → p), and the parameterized mutual
recursion (over the natural numbers)9
P (n) = (a → P (1))<
I n = 1>I P ((3n + 1) div 2<I n odd>
I n div 2)
The point about a guarded recursion is that the ﬁrst-step behaviour does notdepend at all on a recursive call, and when a recursive call is reached, the ﬁrst stepof its behaviour, in turn, can be computed without any deeper calls, and so on. In
other words, we are guaranteed to have communicated at least n events before arecursive call is made at depth n.
1.3.2

Traces and laws

In Section 1.2 we introduced the notion of equality between processes provable
by a series of laws. One can have two quite diﬀerent processes, textually, which
8 This deﬁnition will be modiﬁed later to take account of language constructs we have not met

yet.
9 The interesting thing about this particular example is that it is not known whether or not theseries (of parameters) generated by an arbitrary starting value will always reach 1, so in fact we
do not know whether all the components of this recursion will always be able to communicate ana. Of course not nearly this amount of subtlety is required to give unguarded mutual recursions!

40

Fundamental concepts

are provably equal by a series of these laws. Whatever the text of a process, theprevious section gives us a recipe for computing its set of traces. We should realizethat these two theories have to be squared with each other, since it would be aridiculous situation if there were two processes, provably equal in the algebra, thatturned out to have diﬀerent trace-sets.
Of course this is not so, and all the laws quoted are easily shown to be valid
in the sense that the traces of the processes on the left- and right-hand sides arealways the same. For example, since the traces of P 2 Q and P
Q are both
given by union, the trace-validity of their idempotence, symmetry and associative
laws follow directly from the same properties of set-theoretic union (∪). Since
and 2 are indistinguishable from each other in traces, their distributive laws overeach other are equally simple, for example
traces(P(Q 2 R))= traces(P ) ∪ (traces(Q) ∪ traces(R))= (traces(P ) ∪ traces(Q))∪ (traces(P ) ∪ traces(R))= traces((PQ) 2 (PR))

On the other hand, since there are distinctions we wish to make between
processes that we know are not made by traces, we would expect that there areprocesses P and Q such that traces(P ) = traces(Q) (which we can abbreviate
P =T Q) but such that P = Q is not provable using the laws. This is indeed so, as
our investigations of more reﬁned models in later chapters will show.
Clearly the validity of the various laws with respect to traces means we canprove the equality of traces(P ) and traces(Q) by transforming P to Q by a series oflaws. The rather limited set of operators we have seen to date means that the range
of interesting examples of this phenomenon we can discuss yet is rather limited.
However, there is one further proof rule which greatly extends what is possible: theprinciple of unique ﬁxed points for guarded recursions.

Unique ﬁxed points
If Z = F (Z ) is the ﬁxed-point equation generated by any guarded recursion (single,
parameterized or mutual) for trace-sets and Y is a process (or vector of processes)
whose trace-sets satisﬁes this equation, then X =T Y where X is the process (orvector) deﬁned by the recursion. In other words, the equation has precisely one
solution over10 T or the appropriate space of vectors over T . This rule is often
10 IMPORTANT: though the UFP rule is stated here in terms of the traces model T , because
this is the only model we have seen so far, it applies equally to all models of CSP to be found in
this book except for some introduced in Chapter 10.

1.3

The traces model and traces reﬁnement41

abbreviated UFP; theoretical justiﬁcation of this rule will have to wait until wehave developed the mathematics of ﬁxed points.
For example, recalling the ﬁrst two recursive processes we deﬁned:
P1= up → down → P1

P2

= up → down → up → down → P2

We know, by unwinding the ﬁrst of these deﬁnitions twice, thatP1

= up → down → up → down → P1(†)

Thus it satisﬁes the equation deﬁning P2 . Since P2 is guarded we can deducethat P1 =T P2 – in other words, traces(P1 ) is a solution to an equation with only
one solution, namely traces(P2 ). Of course it was obvious that these two processes
are equivalent, but it is nice to be able to prove this!
In applying this rule in future we will not usually explicitly extract the tracesets of the process we are claiming is a ﬁxed point. Instead, we will just apply laws
to demonstrate, as in (†) above, that the syntactic process solves the recursivedeﬁnition.
Most interesting examples of the UFP rule seem to derive from mutual recursions, where we set up a vector Y that satisﬁes some mutual recursion X = F (X ).
Indeed, the mutual recursion is usually in the form of a one-step tail recursion (precisely one event before each recursive call). The thing to concentrate on is how
these vectors Y are constructed to model the state spaces that these tail recursions
so clearly describe.
As an easy but otherwise typical example, suppose our COUNT process wereextended so that the parameter now ranges over all the integers Z rather than justthe non-negative ones:
ZCOUNT n= up → ZCOUNT n+1 2 down → ZCOUNT n−1

The striking thing about this example, when you think about it, is that the valueof the parameter n actually has no eﬀect at all on the behaviour of ZCOUNT n :whatever its value, this process can communicate any sequence of up’s and down’s.
This might lead us to believe it was equal to the process
AROUND=up → AROUND 2 down → AROUND

and indeed we can use the UFP rule to prove AROUND =T ZCOUNT n for alln. Let A be the vector of processes with structure matching the ZCOUNT recursion (i.e., it has one component for each n ∈ Z) where every component equals

42

Fundamental concepts

AROUND . This is a natural choice since we conjecture that every ZCOUNT nequals AROUND . Applying the function FZC of the ZCOUNT recursion to thisvector we get another whose nth component is
FZC (A)n= up → An+1 2 down → An−1
= up → AROUND 2 down → AROUND= AROUND= An(where the second line follows by deﬁnition of A and the third by deﬁnition of
AROUND ). Thus A is indeed a ﬁxed point of FZC , proving our little result.
The basic principle at work here is that, in order to prove that some process P(in this case AROUND ) is equivalent to a component of the tail recursion X = F (X )(in this case ZCOUNT ) you should work out what states P goes through as it
evolves. Assuming it is possible to do so, you should then form a hypothesis about
which of these states each component of X matches up with. In our case there
is only one state of P , and all the components of ZCOUNT match up with it.
You then form the vector Y by replacing each component of X by the state of P
conjectured to be equivalent, and then try to prove that this creates a solution to
the tail recursion: if you can do this, you have completed the proof.
Both in the text and the exercises, there will be a number of examples following basically this argument through the rest of Part I (see, for example, pages
59, 85 and 146, and Exercises 2.3.3 and 6.3.1).
Exercise 1.3.1

Prove the validity in traces of the laws prefix-dist (1.9) and 2-step(1.14).
Recall the processes P1 , and Pu and Pd from Section 1.1.2. Provethat Pu =T P1 by the method above. [Hint: show that a vector consisting of P1 and one
other process is a ﬁxed point of the Pu , Pd  recursion.]

Exercise 1.3.2

Exercise 1.3.3

Use laws and the UFP rule to prove that

Chaos A  RUN A =T Chaos A
for any alphabet A.

1.3.3

Speciﬁcation and reﬁnement

Traces are not just a dry and abstract model of processes to help us decide equality,
but give a very usable language in speciﬁcation. A speciﬁcation is some condition

1.3

The traces model and traces reﬁnement

43

that we wish a given process to satisfy. Since a CSP process is, by assumption,
characterized completely by its communicating behaviour, it is obviously the casethat we will be able to formulate many speciﬁcations in terms of traces(P ). In
fact, most trace speciﬁcations one meets in practice are what we term behaviouralspeciﬁcations: the stipulation that each s ∈ traces(P ) meets some condition R(s).
This is termed a behavioural speciﬁcation because what we are doing is ‘lifting’the speciﬁcation R on the individual recorded behaviours (i.e., traces) to the wholeprocess.
There are two diﬀerent approaches to behavioural speciﬁcations and their
veriﬁcation. The ﬁrst (which is that adopted in Hoare’s book, where you can ﬁnd
many more details than here) is to leave R explicitly as a speciﬁcation of traces(generally using the special identiﬁer tr to range over arbitrary traces of P ). ThenP sat R(tr )means∀ tr ∈ traces(P ).R(tr )This is meaningful however R is constructed, though usually it is expressed in
predicate logic using trace notation.
In order to be able to express this sort of property it is useful to extend ourrange of trace notation:• If s is a ﬁnite sequence, #s denotes the length of s (i.e., number of members).
• If s ∈ Σ∗ and A ⊆ Σ then s  A means the sequence s restricted to A: thesequence whose members are those of s which are in A.   A =  and(sˆa)  A = (s  A)ˆa if a ∈ A, s  A otherwise.
• If s ∈ Σ∗ then s ↓ c can mean two things depending on what c is. If c
is an event in Σ then it means the number of times c appears in s (i.e.,#(s  {c})), while if c is a channel name (associated with a non-trivial datatype) it means the sequence of values (without the label c) that have beencommunicated along c in s. For example
c.1, d .1, c.2, c.3, e.4 ↓ c = 1, 2, 3
The following are some examples of speciﬁcations describing various featuresof some of the processes we have already met.
• The various processes in Section 1.1.2 all satisfy the condition:
tr ↓ down ≤ tr ↓ up ≤ tr ↓ down + 1(‡)

which states that they have never communicated more down’s than up’s, andneither do they fall more than one behind.

44

Fundamental concepts• The speciﬁcation of COUNT n is similar but less restrictive:tr ↓ down ≤ tr ↓ up + n∞• Band COPY both satisfy the basic buﬀer speciﬁcation:

tr ↓ right ≤ tr ↓ left
(noting that here ≤ means preﬁx and the things to its left and right are∞sequences of values). This is in fact the strongest speciﬁcation that B
meets, but COPY meets further ones.
Hoare gives a set of proof rules for establishing facts of the form P sat R(tr ) –essentially a re-coding into logic of the rules we have already seen for computing
traces(P ). The following rules cover the operators we have seen to date (bearing in
mind the known equivalences between forms of preﬁxing).
STOP sat(tr = )∀ a ∈ A.P (a) sat Ra (tr )?a : A → P sat(tr =  ∨ ∃ a ∈ A. ∃ tr  . tr = aˆtr  ∧ Ra (tr  ))P sat R(tr ) ∧ Q sat R(tr )P 2 Q sat R(tr )P sat R(tr ) ∧ Q sat R(tr )P Q sat R(tr )P sat R(tr ) ∧ ∀ tr .R(tr ) ⇒ R  (tr )P sat R  (tr )P sat R(tr ) ∧ P sat R  (tr )P sat R(tr ) ∧ R  (tr )The most interesting is that relating to recursion, and in fact Hoare’s rule canusefully (and validly) be generalized in two ways: his assumption that the recursion
is guarded is not necessary for this style of proof (though it is in many similar
proof rules, some of which we will see later), and we can give a version for mutual
recursion by attaching one proposed speciﬁcation to each component of the vector
of processes being deﬁned.
Proof rule for recursion Suppose X = F (X ) is the fixed point equation for(vectors of) trace-sets resulting from some recursive definition, and that X is the(least) fixed point which it defines. Let Λ be the indexing set of the vectors, so thatX = Xλ | λ ∈ Λ. Suppose that for each λ there is a specification Rλ such that

1.3

The traces model and traces reﬁnement

45• STOP sat Rλ (tr ) for all λ ∈ Λ, and• ∀ λ ∈ Λ.Yλ sat Rλ (tr ) ⇒ ∀ λ ∈ Λ.F (Y )λ sat Rλ (tr )then Xλ sat Rλ (tr ) for all λ ∈ Λ.
Paraphrasing this: we attach a speciﬁcation Rλ to each component of themutual recursion, and providing all of these are satisﬁed by STOP and, on the assumption that they all hold of recursive calls they hold of the body of the recursion,then we can infer they hold of the actual process(es) deﬁned by the recursion. This
rule is formally justiﬁed in Section 9.2.
The above can be used to prove that the COUNT processes meet the vectorof speciﬁcations quoted for them above and, provided one can come up with appro∞
meets
priate speciﬁcations for the Bs∞ processes for s = , one can prove that B
its speciﬁcation.
The most curious feature of this is the role played by STOP . It does notseem a very useful process and yet its satisfying R is a precondition to the above rule(and Hoare’s). At ﬁrst sight it seems unlikely that many useful speciﬁcations will
be met by STOP , but in fact any behavioural trace speciﬁcation which is satisﬁedby any process at all is satisﬁed by STOP . For traces(STOP) = {} ⊆ traces(P )for any P , and so if all the traces of P satisfy R, so do all those of STOP .
This shows precisely the limitation of trace speciﬁcations: while they can saythat a process P cannot do anything stupid, they cannot force it to do anything at
all. For this reason they are often termed safety or partial correctness conditions,while liveness or total correctness conditions are ones that additionally force a process to be able to do things. In later chapters we will develop models that allow us
to build liveness speciﬁcations.
In order to satisfy ‘sat R(tr )’ a process’s traces must be a subset of the traces
which R allows. In fact, most of the example speciﬁcations given above have theproperty that the target process has the largest possible set of traces of any processsatisfying it. This can be expressed in several diﬀerent, but equivalent, ways (where
P is the process and R the trace condition):• P =T {Q | Q sat R(tr )} or, in other words, P is trace-equivalent to thenondeterministic choice over all processes meeting the speciﬁcation.
• Q sat R(tr ) ⇒ traces(Q) ⊆ traces(P )• traces(P ) = {s | ∀ t ≤ s.R(t)} the largest preﬁx-closed set of traces satisfying
R. (It is worth noting that the set of traces satisfying each of the trace
speciﬁcations on page 43 above is not preﬁx closed. For example, the trace
down, up satisﬁes the speciﬁcation (‡) there, but since the preﬁx down46

Fundamental concepts
does not, the longer trace is not possible for a process all of whose traces
satisfy (‡).)

Remember we deﬁned that Q reﬁnes P , written P
Q if P = Q
P.
Interpreted over the traces model, this leads to the slightly weaker concept oftraces reﬁnement
P

T Q≡ P =T Q

P ≡ traces(Q) ⊆ traces(P )The above properties demonstrate that, for any satisﬁable behavioural trace speciﬁcation R there is always a process PR (given by the formula in the ﬁrst, and whose
traces are the expression in the third) that is the most nondeterministic satisfying
R and such that
Q sat R(tr ) ⇔ PR

T Q

Let us say that PR is the characteristic process of R. In other words, satisfaction(sat) can be replaced by deciding reﬁnement against a suitably chosen process.
∞is the (characteristic process of the) trace speciﬁcation of
For example, Ba buﬀer, and a process will trace-reﬁne it if, and only if, it meets the trace-based∞, and all but the last of your answers to
buﬀer speciﬁcation. Thus COPY T B
Exercise 1.1.8 should have the same property. (Here, we are taking the liberty ofwriting P T Q as the equivalent of Q T P . We will do this for all order relations
in future without comment, as the need arises.)

Which approach one prefers – abstract or process-based speciﬁcation – will
depend on both personal taste and, to some extent, the example being considered.
Perhaps the major hurdle to overcome in adopting the latter is grasping the ideathat a CSP process can be a speciﬁcation as well as a model of an implementation.
Of course, ideally, one should cultivate the ability to move backwards and forwards
between the two approaches.
There are some major advantages in identifying each speciﬁcation with themost nondeterministic process satisfying it.
• As we will see, this is the form in which the proof tool FDR codes speciﬁcations and allows them to be mechanically veriﬁed or refuted.
• Reﬁnement has many properties that can be exploited, for example it istransitive:
P

Q ∧Q

T ⇒P

T

1.3

The traces model and traces reﬁnement

47

and monotone: if C [·] is any process context, namely a process deﬁnition
with a slot to put a process in, thenP

Q ⇒ C [P ]C [Q]If C [Q] is a process deﬁnition with component Q, with an overall target
speciﬁcation S , we might be able to factor the proof of S
C [Q] into twoparts. First, ﬁnd a speciﬁcation P such that S
C [P ]. Second, prove
P Q, which implies thanks to monotonicity that C [P ] C [Q]. Transitivity then gives S
C [Q]. This software engineering technique is known ascompositional development.
Note how the identiﬁcation of processes and speciﬁcations allowed us to consider the object C [P ], which we might read as ‘C [Q], on the assumption thatthe process Q satisﬁes the speciﬁcation P ’.
• It allows one to move gradually from speciﬁcation to implementation, using
the transitivity property quoted above, creating a series of processes
Spec

P1

...

Pn

Impl

where the ﬁrst is the speciﬁcation, and each is created by reﬁning the previous
one till an acceptable implementation is reached. This is known as stepwise
reﬁnement.
It is worth noting that, since the reﬁnement P
Q is expressible as theequality P Q = P , it makes sense to try to prove it algebraically. Recall Exercise
1.3.3.
Of course, the limitations of trace speciﬁcation discussed earlier still apply
here. It is worth noting that STOP T P and RUN T P for all processes P .
From here on this text will tend to emphasize the reﬁnement-based approach
to formulating and proving speciﬁcations. And while we will still sometimes formulate speciﬁcations abstractly in terms of traces and other behaviours we will see
later, we will usually look to reﬁnement-based (often automated) proofs based on
their characteristic processes. Therefore we will not give any of the sat rules for thefurther operators and models we introduce later in this book; the interested readercan, of course, ﬁnd many of them in Hoare’s text.
1.3.4

Afters and initials

If P is any process, initials(P ) (abbreviated P 0 in some publications on CSP) is
the set of all its initial events
initials(P ) = {a | a ∈ traces(P )}48

Fundamental concepts

This set is often used in speciﬁcations and other deﬁnitions.
For example, initials(STOP ) = {} and initials(?x : A → P (x )) = A.
If s ∈ traces(P ) then P /s (pronounced ‘P after s’) represents the behaviourof P after the trace s is complete. Over the traces model, P /s can be computed
traces(P /s) = {t | sˆt ∈ traces(P )}This operator should not be thought of as an ordinary part of the CSP
language, rather as a notation for discussing behaviour of processes in fairly abstract
contexts, to represent the behaviour of P on the assumption that s has occurred.
The best reason for not including it as an operator you could use in programs isthat it is not implementable in a conventional sense: the process(STOP

a → a → STOP )/a

is equivalent to a → STOP , but no reasonable implementation acting on the nondeterministic choice here can force it to do anything.
Over the traces model it is true thatP =T ?x : initials(P ) → P /x 
but we will ﬁnd that this is not true over more discriminating models.
Exercise 1.3.4 (a) Let N ≥ 0. Give a trace speciﬁcation for a process with events
a, b and c which states that the diﬀerence between the number of a’s and the total numberof b’s and c’s is at most N .
(b) Now ﬁnd a CSP deﬁnition of a process DN for which this is the strongest speciﬁcation. [Hint: give a parameterized recursion whose parameter is the present diﬀerence.]
D0 is equivalent to a well-known simple process: what is it and why?
(c)What traces reﬁnements hold between the DN ?

Give the strongest trace speciﬁcation satisﬁed by COPY = left?x →right!x → COPY . Use the proof rules for sat given above to prove that COPY meets it.

Exercise 1.3.5

See Exercise 1.1.7. Give a trace speciﬁcation that a machine with
events {in£1, out5p, out10p, out20p} has never given out more money than it has received.

Exercise 1.3.6

1.4

Tools

There are two types of tool available at the time of writing which will help thereader learn the ideas of this chapter: animators and reﬁnement checkers.

1.4

Tools

49

With an animator such as ProBE you can write an arbitrary process description and interact with it much as described in the text. In other words, you canplay at being ‘the environment’. In fact, an animator may give you various options
about how much control you want over the process (i.e., how much you want to be
automatic) and, in particular, will give you the option of controlling the process
more precisely than the real environment could. For example, if you like, it will let
you make all its internal decisions: an internal choice P Q will be implemented
as a process which can take an invisible τ (tau) action to each of P and Q. If
you decide to take control over the τ actions, then you have the power to resolve
the nondeterministic choices and can thus explore whichever avenue you desire. τ
actions will be discussed properly in Chapter 3. In essence, an animator allows you
to explore the transition picture of your process, like the simple examples shown in
Figures 1.1 and 1.2.
Both ProBE and FDR work by loading in scripts: ﬁles of deﬁnitions (of processes and functions, etc., used within the process code). You then select processes
deﬁned within the current script to animate or prove things about. A ﬁle containing
all the important examples in this chapter can be found on the web site associatedwith this book (see the Preface). You are, naturally, encouraged to try out yoursolutions to exercises on the tools. They must, of course, be written in the machinereadable (ASCII) version of CSP that these tools use. Full details of this version
can be found in Appendix B. In this version, events and channels are written verymuch as in this chapter, but must all be declared.
Of the constructs deﬁned in this chapter, two are not supported in themachine-readable version because their eﬀects can easily be achieved in other ways.
These are guarded alternative (a → P | . . . | z → Q) and the form of preﬁx choicewithout a channel name preceding the ‘?’: one can write c?x, c.n?x:T, etc., butthere is no direct equivalent of ?x : A → P . Both of these can be written in termsof the external choice operator (written [] rather than 2): the case of guarded
choice has already been discussed in the text, and the preﬁx choice above can be
written [] a:A @ a -> P which is the literal translation of 2a∈A a → P . |~| (themachine-readable version of ) and several other operators we will meet later also
have indexed forms like this.
The machine-readable version of conditional is if..then..else.. rather
than P <I b>
I Q. Process parameters are written in ‘argument’ style P(a,b,...,z).
Look at the demonstration ﬁles for examples of all these things and more.
The alphabet Σ of all events is written Events in machine-readable CSP.
You will quickly appreciate the diﬀerence, once you have used them, between
animators and reﬁnement checkers like FDR. FDR does not let you interact witha process, rather it allows you to check assertions about them and will explore
all of the states of a process necessary to verify these. It only shows you speciﬁc

50

Fundamental concepts

behaviours when you debug failures of reﬁnement.
The checks for FDR to perform can be pre-loaded into FDR by includinglines such as
assert Spec [T= Imp
in the scripts you write for it. (This represents the check of process Imp tracereﬁning process Spec.) Note that it gives you a choice of modes and models forchecks; the only thing we are in a position to understand yet is trace checks in thereﬁnement mode.
Finite-state machines
Thanks to the existence of inﬁnite types it is all too easy to write process descrip∞
which have inﬁnitely many states. Since FDR
tions, such as COUNT 0 and B
works by expanding the state spaces of processes it will not terminate if asked to
do much with one of these. There is nothing to stop you applying an animator to
an inﬁnite-state process, though obviously you will never be able to explore all of
one of these!
One can usually get round this problem by restricting the range of the oﬀending parameter(s) to that which will be encountered in the example being considered.
Examples of this can be found in this chapter’s demonstration ﬁle, and we have already seen one: the process Counter (n, m) restricts both its parameters to therange {0, 1, . . . , 7} and thus has 64 states.
This restriction is most often annoying at the speciﬁcation end of reﬁnement,
since it is sometimes the case that we would (as with buﬀers) like to have an
inﬁnite-state speciﬁcation, since this is what best represents our requirements. All
one can do at the time of writing is to choose a ﬁnite-state speciﬁcation which
we know reﬁnes the ‘real’ one (for example, the speciﬁcation that a process is abuﬀer with capacity no greater than 5) and prove it. It is likely that future releasesof the tool will be able to handle some inﬁnite-state speciﬁcations (though not
implementations), but you should always expect this to be less eﬃcient.
You will, after using the tool, get a feel for the sizes of process it can handle
comfortably. As a guide, with the syntax you have seen so far, the current versionof FDR will deal comfortably with a few hundred states to a few thousand states.
(This number will increase vastly as we meet the syntax of parallelism.)

Chapter 2

Parallel operators

All the processes deﬁned so far have, at least in their obvious executions, only one
thread of action. The whole idea of concurrency is to be able to reason about systems
where there are a number of processes with independent control, interacting where
necessary. In this chapter we see how to add operators which model this within ourframework.

2.1

Synchronous parallel

We have already set down the principle that processes interact by agreeing, or
handshaking, on communications. The simplest form of the CSP parallel operator
insists that processes agree on all actions that occur. It is written P  Q. For
example, if a ∈ Σ, then(a → REPEAT )  REPEAT
will have the same behaviour (except, perhaps, for precise timing details that wechoose to ignore) as µ p.a → p. We can see this by following through how thiscombination works. Recall that
REPEAT = ?x : Σ → x → REPEAT
Since both sides have to agree on all events, it is clear that the only possible ﬁrst
event is a, and this indeed is a possible event for the right-hand process. The copyof REPEAT on the right-hand side then forces the second event to be an a, whichis accepted by REPEAT on the left-hand side, forcing the third event to be a also,
and so on for ever.

52

Parallel operators

Perhaps the clearest description of this parallel operator is contained in thefollowing law:?x : A → P ?x : B → Q = ?x : A ∩ B → (P  Q)

-step is also symmetric, associative and distributive. We do not quote these laws explicitly here since they will be subsumed later into laws for generalizations of .
Turning parallel processes into sequential ones
It is important to realize that CSP makes no fundamental distinction between ‘parallel’ and ‘sequential’ processes. There are just processes, and you can use any
operator on any process. Indeed, any parallel CSP process is equivalent to sequential processes with the same pattern of communications.
The law -step (together with the other properties listed above, and thelaws quoted in the previous chapter) can be used for this transformation. For
example, ifPQ= (a → a → STOP ) 2 (b → STOP )= (a → STOP ) 2 (c → a → STOP )these laws prove P  Q = a → STOP .
When the component processes are recursively deﬁned, the algebraic laws
alone will probably not be enough. In this case we use a combination of laws andthe UFP rule: the parallel combination is expanded until we have a guarded expression for it and every other parallel combination discovered during the exploration.
Consider, for example, the combination(a → REPEAT )  REPEAT
discussed earlier:= (a → REPEAT )  (?x : Σ → x → REPEAT )= a → (REPEAT  (a → REPEAT ))The underlining here indicates the parallel expression we have uncovered behind
the guard a. Now we could use the symmetry of  to observe that this second
combination equals the original one, so that(a → REPEAT )  REPEAT = a → (a → REPEAT )  REPEAT
showing that the process satisﬁes the guarded recursion P = a → P . Alternatively(as would have been the only option if this example were not so symmetric) we

(2.1)

2.1

Synchronous parallel

53

could expand this second parallel combination in the same way that we did theﬁrst, and would ﬁnd
REPEAT  (a → REPEAT ) = a → (a → REPEAT )  REPEAT
At this point we notice that the parallel combination reached here is one we haveseen before, so there is no need to expand it again (in general you should proceed byexpanding each combination you ﬁnd until there is none you have not seen before).
We have thus expanded two processes and shown that they satisfy the guarded
mutual recursion
R
Q

= a→Q
= a→R

Depending on which route we have followed, this has proved via the UFP
rule that the parallel combination is trace equivalent to one of the processes P
and R above. Of course, the fact that P , Q and R are equivalent is itself an easy
consequence of the UFP rule.
When the processes in parallel depend on a parameter introduced by recursion or input, it is likely that the family of processes uncovered by the exploration
will be another parameterized one. Some examples can be found in the exercises
below and in later sections.
Example 2.1.1 (customers and atm’s) A customer of one of our cash-point
machines might be described by the following expression.
CUST 1 =in.card → pin?p : S → req.50 →dispense?x : {y ∈ WA | y ≥ 50} → out.card → CUST 1

He only has one card (card), after which he remembers his PIN number belongs to
the set S ⊆ PIN and so will try these numbers. He always expects to withdraw£50, and get his card back. Notice that he is quite happy to accept more than £50
from the machine. Provided his memory is accurate and fpin (card) ∈ S , the parallel
combination ATM 1  CUST 1 is equivalent toµ q.

in.card → pin.fpin (card) → req.50 →dispense.50 → out.card → q

Since we are insisting that both parties must agree on all communications
taking place in P  Q, there is the unavoidable possibility that they might be unable
to agree (even when each process has some events it could have performed if it were
not forced to agree). This is illustrated by what happens when fpin (card) ∈ S , when

54

Parallel operators

the above combination becomes in.card → STOP . This is known as deadlock. We
discussed deadlock in general terms earlier, but this is the ﬁrst proper example
we have come across of a deadlocking CSP network. Note that STOP behaves
just like a deadlocked process – one of its main roles in CSP is to provide a clean
representation of deadlock, just like provides one of nondeterminism.
If we force CUST 1 to use ATM 2 rather than ATM 1, then it will deadlock
as soon as the ATM decides to refuse a request – for this customer will not take nofor an answer. It is important here that the decision of whether to accept or refuse
a request is made by (nondeterminism) rather than 2 (external choice), for thelatter would not have given rise to the deadlock. We can modify the customer toaccept refusals more gracefully.
CUST 2 =in.card → pin?n : S → req.50 →((dispense?x : {y ∈ WA | y ≥ 50} → out.card → CUST 2)
2 (refuse → out.card → CUST 2))

But this combination still deadlocks if the customer does not get his card back.
(Presumably the machine designer wants the customer to be deadlocked in thiscircumstance!)µ q. (in.card → pin.fpin (card) → req.50 →((dispense.50 → out.card → q)(refuse → (out.card → q) STOP )))(End of example)
The traces of P  Q are easy to compute: since this process can perform anaction just when its two arguments can, it follows that
traces(P  Q) = (traces(P )) ∩ (traces(Q))
It is worth noting that, even though this implies traces(P  P ) = traces(P ),the existence of nondeterminism (which we know is not described fully by traces)
makes it possible that P  P will not behave like P : for both sides may makediﬀerent nondeterministic choices and so fail to agree on any communication. Thismeans  is not idempotent. For example, if P = (a → STOP ) (b → STOP ),which cannot deadlock on its ﬁrst step, then P  P = P STOP , which can. The
reasons for this are closely connected with our discussion of distributivity in Section
1.2: P  P clearly requires two copies of P and so can compare them.
How do COUNT 0
COUNT 3 , COUNT 0
Counter (0, 0) and
REPEAT behave, where they are all as described in the previous chapter?

Exercise 2.1.1
COUNT 0

2.2

Alphabetized parallel

55

For each either ﬁnd an existing process that behaves like the appropriate combination, ordeﬁne a new (sequential) process that does.
Prove trace equivalence in at least one case using the UFP rule.
Construct a customer for ATM 2 who has two cards, and whose
reaction to refuse of the ﬁrst card is to attempt to take money out with the second. Heshould do this whether or not the machine is prepared to give him the ﬁrst card back. Hint:
you might ﬁnd it easier to solve the problem of how the customer deals with an arbitrary
list of cards (as a parameter to the process).

Exercise 2.1.2

2.2

Alphabetized parallel

The more processes we combine using , the more have to agree on every event.
This is not what we will usually want (though it is a theme we will expand on
in Section 2.5), and so we require a more general version of the parallel operator.
What we need to reﬂect is the truth that, when two processes P and Q are placedin parallel, some of the communications of P are with Q, and some are not.
If X and Y are subsets of Σ, P X Y Q is the combination where P isallowed to communicate in the set X , which we will call its alphabet, Q is allowed
to communicate in its alphabet Y , and they must agree on events in the intersection
X ∩ Y . Thus P Σ Σ Q = P  Q. So, for example,(a → b → b → STOP ) {a,b} {b,c} (b → c → b → STOP )behaves likea → b → c → b → STOP
since initially the only possible event is a (as the left-hand side blocks b); then bothsides agree on b; then the right-hand side blocks b so only c is possible and ﬁnallythey agree on b again. In most cases, as in this one, the alphabets of individual processes composed in parallel will be the sets of events which they can communicate.
But they have to be given explicitly for a number of subtle reasons – for example,
we often give processes strictly larger alphabets than the sets of events they actuallyuse (frequently the process is then STOP ). You should note that the same process
can be used in diﬀerent parallel compositions with diﬀerent alphabets.1
A pantomime horse has two actors in it: one playing the front and one theback. You can think of it as a parallel composition of two processes showing that
1 In allowing this we are giving a diﬀerent presentation to that in Hoare’s book, where a process
has an intrinsic alphabet αP which makes the presentation of this particular parallel operator
easier. See Section 2.7 for more details of this diﬀerence.

56

Parallel operators

Figure 2.1 A parallel process.
the two halves have to co-operate on moving, but each has control of some otheractivities.
Front F B Backwhere

F = {forward , backward , nod , neigh}B = {forward, backward , wag, kick }If, in fact, Front will only nod the horse’s head until it has moved forwards, andBack will only wag its tail until it has moved backwards:
Front= forward → Front 
2 nod → Front

Back= backward → Back 
2 wag → Backthen the composition will never move whatever the processes Front  and Back  are(since they are never reached), but it will simply nod and wag for ever. It will beequivalent to RUN {nod,wag} .
When P can perform any of the events A (being equivalent to a process ofthe form ?x : A → P  ) and Q can perform the events B (respectively ?x : B → Q  ),

2.2

Alphabetized parallel

57

then P X Y Q can perform any of= (A ∩ (X  Y )) ∪ (B ∩ (Y  X )) ∪ (A ∩ B ∩ X ∩ Y )C

The ﬁrst component of this union are the events P can perform on its own (because
they are in X and not Y ); similarly, the second are the events Q can do by itself.
The ﬁnal component are the events which they can synchronize on: the ones thatthey both can do and are in both their alphabets. The law expressing this is thefollowing
P X Y Q = ?x : C → ( P  <I x ∈ X>
IP

X Y
Q<
I x ∈ Y>I Q)

X Y -step(2.2)

where C is as above. X Y is distributive, like most operators, over and <I b>
I . Thesecond of these can be used to give an alternative version of the above law:
P X Y Q= ?x : C → ((P  X Y Q  )<I x ∈ X ∩ Y>
I
(P  X Y Q <I x ∈ X>I P X Y Q  ))All we have done here is to distribute the two conditionals in X Y -step outside
X Y and to discard the one of four cases (x ∈ X ∪ Y ) that cannot arise.
The rest of its basic laws are given below. It has symmetry and associativity
laws that are slightly more complex than usual because of the alphabets.
X Y -dist(2.3)

P X Y Q = Q Y X P

X Y -sym

(2.4)(P X Y Q) X ∪Y Z R = P X Y ∪Z (Q Y Z R)

X Y -assoc

(2.5)

P X Y (QR) = (P X Y Q)(P X Y R)

As the last of these begins to show, composing a large network using thisbinary operator gets rather clumsy because of the bookkeeping required on thealphabets. We therefore include a better, indexed notation for n-way parallel composition:

i=1 (Pi , Xi ) = P1 X X ∪...∪X (. . . (Pn−1 X
n

1

2

n

n−1

Xn Pn ) . . .)So, for example, if
COPY  (c, d )= c?x : T → d .x → COPY  (c, d )58Parallel operators
c0

c1

c2

c3

cn-1

cn

Figure 2.2 A simple chain connected in parallel.
and Xr = cr .T ∪ cr +1 .T (with c0 , c1 , . . . , cn all being distinct) thenr =0 (COPY  (cr , cr +1 ), Xr )n−1

represents a chain of n one-place buﬀer processes. COPY  (c0 , c1 ) can input avalue on channel c0 without requiring the co-operation of any other process in the
network. This value is then communicated across the channels c1 , . . . , cn−1 in turn(each transfer requiring the agreement of the two processes involved) until it appears
at the far end and COPY  (cn−1 , cn ) is able to output it without needing any otherprocess to agree. The network is shown in Figure 2.2. It is natural to think of thechannels c0 and cn as external, because they are only in the alphabet of one process
each, and the rest are internal.
The reason it is natural to think of the above network as a chain is because thealphabets Xr = cr .T ∪ cr +1 .T of the processes only have non-empty intersection –corresponding to the possibility of communication between them – for consecutively
numbered cells. By appropriate choices of alphabets it is possible to construct
networks using  which have any chosen ﬁnite graph structure. The graph with
one node per process and an edge between processes with non-empty intersectionof alphabets is termed the communication graph. One might be tempted to put
arrows on this graph to correspond to the direction of the channels, but this would
be a mistake: you should remember that communication in CSP is symmetric andthat channels are just a gloss on this.
Just as with the synchronous parallel operator, any system of sequential processes put in parallel with X Y can be expanded into a (usually recursive) sequential
one using the laws (predominantly X Y -step) and the UFP rule. Consider, forexample, the combination
COPY  (a, b) {|a,b|} {|b,c|} COPY  (b, c)
The initial events of the two processes are respectively {| a |} and {| b |} (since
they are both ready to input). The initial events of the combination are therefore(showing the full calculation!)({| a |} ∩ {| b |} ∩ {| a, b |} ∩ {| b, c |})∪ ({| a |} ∩ ({| a, b |}  {| b, c |}))
∪ ({| b |} ∩ ({| b, c |}  {| a, b |}))

2.2

Alphabetized parallel

59

which reduces to {} ∪ {| a |} ∪ {} = {| a |} (i.e., there is no shared event possible
initially, no event possible for the right-hand process, but the left-hand one caninput). This is, of course, exactly what one would have expected.
Thus the original process (which we will name CC0 ) equals (by X Y -step)a?x → ((b!x → COPY  (a, b)) {|a,b|} {|b,c|} COPY  (b, c))Call the parallel combination here CC1 (x ) (the x is needed because it depends on
the input value). Now both processes can only perform shared (b) events, and agree
on one, so by another use of X Y -step turns CC1 (x ) into
b!x → (COPY  (a, b) {|a,b|} {|b,c|} c!x → COPY  (b, c))If we similarly call the parallel combination here CC2 (x ), we ﬁnd that neither
process can perform any b action, but each can perform some of its own actions
independently. It equals
a?y → (b!y → COPY  (a, b) {|a,b|} {|b,c|} c!x → COPY  (b, c))
2 c!x → (COPY  (a, b) {|a,b|} {|b,c|} COPY  (b, c))which, naming the ﬁrst parallel combination CC3 (y, x ), equals
a?y → CC3 (y, x )2 c!x → CC0
In CC3 (y, x ), the left-hand process can only perform the shared event b!y, while
the right-hand one can only perform its own action c!x . It follows that this processequalsc!x → ((b!y → COPY  (a, b)) {|a,b|} {|b,c|} COPY  (b, c))which is c!x → CC1 (y). Since there are no more parallel combinations to expand, the state exploration is complete and we have shown that the processes CC0 ,CC1 (x ), CC2 (x ) and CC3 (y, x ) satisfy a guarded mutual recursion:
CC0
CC1 (x )CC2 (x )CC3 (y, x )

=
=
=
=

a?x → CC1 (x )b!x → CC2 (x )(c!x → CC0 ) 2 (a?y → CC3 (y, x ))c!x → CC1 (y)Thus these two systems are trace-equivalent by the UFP rule. A picture of thissystem of states is in Figure 2.3 (the picture over-simpliﬁes the values input andoutput in that it does not allow you to reconstruct the relationship between the

60

Parallel operators

a?x
c.x
b.x
c.x
a?x

Figure 2.3 The states of two one-place buﬀers in parallel.
values going in and those going out). Clearly this simple example is already gettinga bit tedious to expand. Much larger examples are impractical by hand – fortunately, however, tools like FDR are much better able to deal with the expansion
and bookkeeping than we are, and in fact a large part of what they do is precisely
this.
The traces of P X Y Q are just those which combine a trace of P and a
trace of Q so that all communications in X ∩ Y are shared.
traces(P X Y Q) = {s ∈ (X ∪ Y )∗ | s  X ∈ traces(P )∧ s  Y ∈ traces(Q)}
Example 2.2.1 (five dining philosophers) This is perhaps the best known of
all examples in this ﬁeld: it has already been brieﬂy described in the introduction.
As shown in Figure 2.4, ﬁve philosophers share a dining table at which they haveallotted seats. In order to eat (in the ﬁgure, from a tangled bowl of spaghetti inthe middle of the table!), a philosopher must pick up the forks on either side of him
or her but, as you see, there are only ﬁve forks. A philosopher who cannot pick up
one or other fork has to wait. We can model this story in various ways in CSP bychoosing diﬀerent episodes of philosophers’ lives as events, but the essential thingsfrom the point of view of interaction are when they pick up or put down their forks.

2.2

Alphabetized parallel

61

Figure 2.4 The ﬁve dining philosophers.
In order to make sure no fork can be held by two philosophers at once, we also
require a process to represent each fork.
We will therefore describe two classes of process: PHILi and FORK i , in eachcase for i ∈ {0, 1, 2, 3, 4}. The events of FORK i are• picksup.i .i and picksup.i 1.i where  represents subtraction modulo 5 (with⊕ being the corresponding addition operator). These respectively represent
FORK i being picked up by PHILi and PHILi1 .
• putsdown.i .i and putsdown.i 1.i , representing the fork being put down again.
FORK i= (picksup.i .i → putsdown.i .i → FORK i )2 (picksup.i 1.i → putsdown.i 1.i → FORK i )The philosophers have these same events, plus some individual ones. Whatturns out to be crucial in describing the philosophers is the order in which they pickup their forks. There are various options: either left-hand one ﬁrst, right-hand one

62

Parallel operators
PHIL0
FORK

FORK1

0

PHIL1

PHIL4

FORK4

FORK2

PHIL3

PHIL2
FORK3

Figure 2.5 The communication network of the dining philosophers.
ﬁrst, or some form of choice between the two. And of course diﬀerent philosophers
might have diﬀerent preferences. For simplicity, the following deﬁnition asserts thateach philosopher picks up the left fork ﬁrst and puts it down last.
PHILi= thinks.i → sits.i → picksup.i .i →picksup.i .i ⊕1 → eats.i → putsdown.i .i ⊕1 →putsdown.i .i → getsup.i → PHILi

The complete system is then formed by putting all of these processes inparallel, each having as its alphabet the set of events it can use. If AF i and
AP i are these sets for FORK i and PHILi respectively, the network is formed bycomposing together the ten pairs{(FORK i , AF i ), (PHILi , AP i ) | i ∈ {0, 1, 2, 3, 4}}in parallel. The communication graph of the resultant network, with an edge between two processes if their alphabets have non-empty intersection, is shown in
Figure 2.5.
So how does this system behave? We have already noted that one philosopher
might have to wait for a neighbour to put down a fork. The greatest danger,
however, is that they might all get hungry at once and all manage to pick up theirleft-hand fork (as is about to happen in Figure 2.4). For then none can make any

2.2

Alphabetized parallel

63

progress and the system is deadlocked. The philosophers starve to death. We will
return to this example in Chapter 13 when we study the subject of deadlock inmore detail. Amongst other things, we will examine the impact of diﬀerent choicesof fork-picking-up. (End of example)
As well as demonstrating the use of the parallel operator, this example also
illustrates uses of events we have not seen before. Like many networks we will see,this one has numbers of processes which behave similarly except for the precise
events they use. Of course the easy way to deﬁne these is to use parameterization:
PHILi rather than PHIL0 , . . . , PHIL4 separately. Notice, however, that unlike previous parameterized recursions, these processes do not depend on each other: PHIL2
only makes recursive calls to PHIL2 , for example. To create the arrays of events
that are needed to tie in with these arrays of processes, we use the channel notation
to create arrays of events as anticipated on page 27. Sometimes, as with the picksup
and putsdown events, we need a two-dimensional array (or even more).
One can mix the array and data-passing uses of channels. The best way of
implementing the chain of COPY  processes is to create an array of channels cwhose communications look like c.i !x or c.i ?x . COPY  (c.i , c.i + 1) would then be
equivalent to the process
COPY  (i ) = c.i ?x → c.i +1!x → COPY  (i )Example 2.2.2 (cash-point machine with extended interface) The modelof ATM and customer given above using synchronous parallel only gives their common interface. The new operator allows us to bring in the actions which they
perform by themselves or at other interfaces. This has already been seen in the
pantomime horse and dining philosopher examples.
We can, for example, bring in a component of an ATM’s state to represent
the amount of money it contains: it can always (except when full) be reﬁlled when
not in use by a customer, but rejects requests for more money than it has in; thecustomer spends nondeterministic amounts of money and goes back for more when
he has none left. The reﬁll and spend events only belong to one of the two alphabets.
If the capacity of the machine is £N , and the customer makes withdrawalsof £M (where M < N ), we need to deﬁne processes ATM ref n and CUST spend mfor each integer 0 ≤ n ≤ N and 0 ≤ m ≤ M . They are
ATM ref n= ((reﬁll → ATM ref N )<I n < N>I STOP )2 (in?c : CARD → pin.fpin (c) → req?w : WA →((dispense.w → out.c → ATM ref n−w )<I w ≤ n>I
(refuse → out.c → ATM ref n )))64

Parallel operators
CUST spend 0= in.card → pin?p : S → req.M →((dispense?x : {y ∈ WA | y ≥ M } →out.card → CUST spend x )2 (refuse → out.card → CUST spend 0 ))CUST spend m={spend .r → CUST spend m−r | 1 ≤ r ≤ m}
(m > 0)

The alphabets of ATM ref n and CUST spend m are respectively X and Y ,whereZ= in.CARD ∪ out.CARD ∪ pin.PIN ∪ req.WA∪ dispense.WA ∪ {refuse}X= Z ∪ {reﬁll }Y= Z ∪ spend .N(Z represents the common communications of the two processes; the others are their‘external’ actions.) The combination ATM ref n X Y CUST spend m then represents
their interaction given initial capital £n and £m respectively. Note again that thecustomer has no control over reﬁlling and the machine has none over spending.
(End of example)
Find pairs of actors (Front i , Back i ) (i = 1, 2, 3) for the pantomime
Exercise 2.2.1
horse so that the overall behaviour is respectively (using the same alphabets for the parallel
composition as on page 56)
PH1=neigh → forward → kick → backward → PH1

PH2=

forward → neigh → PH2
2 backward → kick → PH2

PH3=

neigh → wag → forward → PH3
2 wag → neigh → forward → PH3

Find a process with alphabet F ∪ B which cannot be constructed in this way, and explain
why it is impossible.

Exercise 2.2.2

Let X = {a, b, c, d} and Y = {c, d}, and let

P

=

a→c→P
2 b→d →PQ=

c→d →Q

What are the traces of P X Y Q? Which of these traces are terminal, in the sense thatthey are not preﬁxes of any other trace? What can you say about the behaviour of aprocess after it has performed such a trace?

2.3

Interleaving

65

Use the methods illustrated in this section to expand P X Y Q to asequential process (where P and Q are as in the previous question). You should ﬁnd somestates in this expansion equivalent to STOP – corresponding to deadlock. Compare thesestates to the terminal traces.

Exercise 2.2.3

Find a process R with alphabet Z = {a, b} such that R Z X (P X Y Q) is
deadlock-free.

Exercise 2.2.4
Extend the deﬁnition of ATM ref n by adding an additional pair ofchannels with which it communicates with a central computer. After a customer has
requested a withdrawal the request is relayed by the ATM to the computer, which sends
one of three responses: OK , OD or retain. These indicate, respectively:• Issue the money, if there is enough in the ATM.
• The request is too large for the balance, refuse it but give the card back.
• Refuse the request and retain the card.
Your ATM should now be a process deﬁned without nondeterministic choice which, fromthe customer’s perspective (since he or she cannot see these other interactions), looks justlike ATM 2 .
Formulate trace speciﬁcations of the following properties in the alphabets of the examples to which they refer.

Exercise 2.2.5(a) The numbers of times the pantomime horse has wagged its tail and neighed always
diﬀer (in absolute value) by at most one.
(b) The number of cards handed back by the ATM is never greater than the number
inserted into it.
(c) Whenever PHILi eats, PHILi⊕1 is not holding any fork.
Find the characteristic process (over the respective alphabet) for each. How do you deal
with the events each system can do which are irrelevant to the speciﬁcation? Which ofthese is ﬁnite state? If any is inﬁnite state can you suggest a stronger, ﬁnite-state one
which the appropriate network will still satisfy and which is as close in meaning to theoriginal as possible? Prove (either manually or using FDR or a similar tool) that eachholds of one or more of the systems we have already seen (in the ﬁrst case in Exercise 2.2.1
(c)).

2.3

Interleaving

The parallel operators seen so far ( and X Y ) have the property that all partners
allowed to make a particular communication must synchronize on it for the event tooccur. The opposite is true of parallel composition by interleaving, written P ||| Q.
Here, the processes run completely independently of each other. Any event which

66

Parallel operators

the combination communicates arose in precisely one of P and Q. If they could
both have communicated the same event then the choice of which one executed it
is nondeterministic, but only one did. The law governing this is the following: if
P = ?x : A → P  and Q = ?x : B → Q  then
P ||| Q = ?x : A ∪ B → (P  ||| Q) (P ||| Q  )<I x ∈ A ∩ B>
I
(P ||| Q)<
I x ∈ A>I (P ||| Q  )|||-step

(2.6)

P ||| Q = Q ||| P

|||-sym(2.7)(P ||| Q) ||| R = P ||| (Q ||| R)

|||-assoc

(2.8)

|||-dist(2.9)

As one would expect, ||| is symmetric, associative and distributive.

P ||| (Q

R) = (P ||| Q)(P ||| R)

The process L1 = up → down → L1 keeps tr ↓ down (the number of down’s
it has communicated to date) between tr ↓ up − 1 and tr ↓ up. By interleaving a
number of these we can increase this margin:
Ln = L1 ||| L1 ||| . . . ||| L1

n copies of L1

keeps tr ↓ down between tr ↓ up − n and tr ↓ up. Even though which of a numberof processes performs a given event is usually nondeterministic, the overall eﬀect
here is actually deterministic.
Clearly Ln ||| Lm = Ln+m , whereas Ln  Lm = Lmin{n,m} .
The combination of interleaving and recursion can allow us to describe complex behaviours which would otherwise need inﬁnite mutual recursions. For example, we can simulate the inﬁnite-state recursion COUNT by a single line
Ctr

= up → (Ctr ||| down → STOP )or, more subtly
Ctr = up → (Ctr  ||| µ P .down → up → P ) or evenCtr 

= up → (Ctr  ||| down → Ctr  )All of these behave the same as COUNT 0 . In each case see if you can understand
why.

2.3

Interleaving

67

The above uses of ||| have all involved combinations of processes that use thesame events, creating nondeterminism about which side carries out an event. In
practice such uses, though clever when they work, are rather rare except for the
special case of an abstraction mechanism we will meet in Chapter 12. In creating
practical networks, it is usual to ﬁnd processes which use disjoint sets of eventsor perhaps soon come into a state where they do this. Think back to the ﬁve
dining philosophers: the ﬁve philosophers do not (in our model!) talk to each other,and neither do the ﬁve forks. Therefore we can achieve exactly the same eﬀect aspreviously by ﬁrst composing these two groups by interleaving:
FORKS

=

FORK 0 ||| FORK 1 ||| . . . ||| FORK 4

PHILS

=

PHIL0 ||| PHIL1 ||| . . . ||| PHIL4

and then, if AFS = AF0 ∪AF1 ∪AF2 ∪AF3 ∪AF4 , we can form the complete system
FORKS AFS Σ PHILSThe traces of P ||| Q are just the interleavings of traces of P and Q. We
need to deﬁne an operator for producing the interleavings of a given pair of traces:
this is deﬁned recursively below
 ||| s= {s}s |||  = {s}aˆs ||| bˆt= {aˆu | u ∈ s ||| bˆt}∪{bˆu | u ∈ aˆs ||| t}Given thistraces(P ||| Q) =

{s ||| t | s ∈ traces(P ) ∧ t ∈ traces(Q)}A bag is a process with channels left and right which behaves like abuﬀer except that the order in which things come out is not necessarily that in which they
are put in. Use ||| and COPY to deﬁne a bag with capacity N . Explain your deﬁnition.
Now deﬁne an inﬁnite capacity bag by following the style of recursion in the process Ctr
above.

Exercise 2.3.1

Exercise 2.3.2 Prove that COUNT 0 ||| COUNT 0 is trace-equivalent to COUNT 0 .
You should do this by calculating the sets of traces directly (bearing in mind what has
already been established about traces(COUNT 0 )).

68

Parallel operators

Exercise 2.3.3
numbers

Consider the following mutual recursion indexed by pairs of natural× :CT 2(n, m)=

up → (CT 2(n + 1, m)  CT 2(n, m + 1))
2 ((down → CT 2(n − 1, m)) I n > 0 I STOP)
2 ((down → CT 2(n, m − 1)) I m > 0 I STOP)Show that it is satisﬁed by the vectors COUNT n+m | (n, m) ∈
COUNT n ||| COUNT m | (n, m) ∈×  and× and deduce that COUNT n ||| COUNT m and COUNT n+m are trace-equivalent for all(n, m) ∈ × .
If you look at this question carefully, you will see that it shows a way of using the
UFP rule to prove the equivalence to two systems where there is a many–one relation ofequivalence between the underlying state spaces.

Suppose we need multiple cash-point machines to cope with increased
customer demand. Why is an interleaving of two or more of our existing machines (forexample ATM 2 ||| ATM 2) not a good idea?

Exercise 2.3.4

Hint: think what might happen in this model when two customers are using themsimultaneously. How might you avoid this problem?

2.4

Generalized parallel

The eﬀects of all the parallel operators we have seen so far, and more, can beachieved with a single operator which, for whatever reason, has become the mostcommonly used with FDR even though it does not appear in Hoare’s book. In
P X Y Q, we decide which events are synchronized and which are not by looking
at X and Y . In the new operator, we simply give the interface: P  Q is theXprocess where all events in X must be synchronized, and events outside X canproceed independently. It is called generalized or interface parallel. We will always
have
P ||| Q = P  Q{}

and, provided P and Q never communicate outside X and Y ,P X Y Q = P



X ∩Y

Q

(The case when P or Q do not satisfy this condition is left as an exercise.)2.4

Generalized parallel

69

In almost all cases one meets, this new operator just gives a diﬀerent presentation of something we could have written with X Y . However, you should realize
there are new eﬀects that could not have been achieved without it: if X is nonempty but does not cover all events that can be used by P and by Q then P  Q
Xacts a little bit like the alphabetized parallel and a little bit like P ||| Q. There
are some events that are synchronized and some which can ambiguously come fromeither side. For example, COUNT 0  COUNT 0 is a process that will allow twice{up}

as many down’s as up’s, since the down events proceed independently.
If P = ?x : A → P  and Q = ?x : B → Q  then the initial events of P  Q
X

are C = (X ∩ A ∩ B ) ∪ (A  X ) ∪ (B  X ). The behaviour is shown by the following
step law, whose complexity reﬂects the operator’s generality: an event may now be
synchronized, unsynchronized but ambiguous, or from one side only
P  Q = ?x : C → (P   Q  )<I x ∈ X>I
X(((P   Q) (P  Q  ))<I x ∈ A ∩ B>
I
((P

X
 
X

  -step (2.10)

XQ)<
I x ∈ A>I (P  Q  )))X

X

It is symmetric and distributive:
P Q = Q PX

P  (Q  -sym (2.11)

XXR) = (P  Q)

X

X

(P  R)  -dist (2.12)

X

X

It has the following weak (in that both interfaces are the same) associativity
propertyP  (Q  R) = (P  Q)  R)
X

X

X

  -assoc (2.13)

XX

but the possibility, in P  (Q  R), of X containing an event not in Y that Q
X

Y

and R can both perform, makes it hard to construct a universally applicable andelegant associative law.
The traces of P  Q are simply combinations of traces of P and Q whereX

actions in X are shared and all others occur independently. As with the interleaving
operator, the best way to calculate the trace-set is in terms of an operator that maps
each pair of traces to the set of possible results (which is always empty when they
do not agree on X ). The following clauses allow one to calculate s  t (a set ofX

traces, like s ||| t) for all s, t ∈ Σ∗ ; below x denotes a typical member of X and y atypical member of Σ  X .

70Parallel operatorss t= t sXX  

= {}

  x 

= {}

X

X

  y = {y}Xx ˆs  yˆt= {yˆu | u ∈ x ˆs  t}

x ˆs  x ˆt= {x ˆu | u ∈ s  t}

x ˆs  x  ˆt= {}yˆs  y  ˆt= {yˆu | u ∈ s  y  ˆt}

X

X

X

X

X

X


if x = xX∪ {y  ˆu | u ∈ yˆs  ˆt}
X

Given this, it is possible to deﬁne
traces(P  Q) =

X{s  t | s ∈ traces(P ) ∧ t ∈ traces(Q)}X

If we do not assume that P and Q never communicate outside X andY , how can we express P X Y Q in terms of ? [Hint: use STOP.]

Exercise 2.4.1

Z

Describe the behaviours of the following processes; in each case ﬁnd
a tail-recursive process equivalent to it.

Exercise 2.4.2(i) COPY

COPY{|left|}(ii) COPY

COPY{|right|}

Exercise 2.4.3 Show that (P ||| Q)
What does this tell you about the ‘law’P

2.5R) =? (P

(Q
X

Y

Q)
X

R and P ||| (QR) need not be equivalent.

R
Y

Parallel composition as conjunction

The uses seen so far of the synchronized parallel operator  and the alphabetized
one X Y have all had broadly the intuition one would have expected of a parallel
operator, namely describing interactions between processes which might reasonably
be expected to run concurrently and communicate with each other. But they can

2.5

Parallel composition as conjunction71

be used in a rather diﬀerent way in situations where we are using CSP more in
the manner of a speciﬁcation language than as a method of describing systems as
implemented.
It turns out to be very diﬃcult, even impractical, to implement handshaken
communication in anything like the generality implied by the CSP parallel operators, at least if a genuinely parallel implementation is required. In particular,
handshakes involving more than two parties come into this ‘impractical’ category.
Except in special circumstances, CSP descriptions which are intended to model theconstruction of parallel systems tend to respect this restriction.
Multi-way handshaking is nevertheless an extremely useful construct in CSP:
it is used to build up speciﬁcations of intended behaviour (i.e., processes that areprobably going to be used on the left-hand side of a reﬁnement check). For parallel
composition turns out to be equivalent to the conjunction (i.e. logical ‘and’) oftrace speciﬁcations. In this style of use, you should view parallel as belonging to
the category of CSP operators (for example ) whose main role is in constructing
speciﬁcations rather than implementations.
Suppose Q is a process using only events from Y . In P Σ Y Q = P  Q,Y

it can be thought of as adding to P , since every communication of P in Y must
be possible for Q. As P participates in all of the combination’s events, we canthink of Q’s role as simply being to restrict P ’s behaviour. If P represents a trace
speciﬁcation, then P Σ Y Q is a stronger one.
As a simple example, consider a robot which roams around the plane by making movements in the four directions {N , S , E , W }. It can also report its position.
If its initial co-ordinates are (0, 0), it becomes the process ROBOT 0,0 where
ROBOT n,m

= position.(n, m) → ROBOT n,m
2 N → ROBOT n+1,m
2 S → ROBOT n−1,m2 E → ROBOT n,m+1
2 W → ROBOT n,m−1

We can restrict the area it can roam over by placing it parallel with processes
stopping it entering forbidden areas. For example, if it is actually sitting on a rectangular table whose corners are {(0, 0), (n, 0), (n, m), (0, m)} then we can enforce
this either by putting it in parallel with four COUNT -like processes:
CT (E , W )0
CT (W , E )mCT (N , S )0
CT (S , N )nalphabet {E , W }alphabet {E , W }alphabet {N , S }alphabet {N , S }72

Parallel operators

where
CT (a, b)0
CT (a, b)r= a → CT (a, b)1= a → CT (a, b)r +1
2 b → CT (a, b)r −1

if r > 0or by using two processes (each imposing both limits in one dimension) or just one(imposing all four limits). We could prevent it entering a speciﬁc square, (r , s), say,by placing it in parallel with the following process with alphabet {N , S , E , W }:BLOCK (r , s)n,m =(N → BLOCK (r , s)n+1,m )<I n = r −1 ∨ m = s>
I STOP
2 (S → BLOCK (r , s)n−1,m )<I n = r +1 ∨ m = s>
I STOP
2 (E → BLOCK (r , s)n,m−1 )<I n = r ∨ m = s+1>
I STOP
2 (W → BLOCK (r , s)n,m+1 )<I n = r ∨ m = s−1>
I STOP
Note the use we have again made here of the conditional construct to reduce thenumber of clauses. Clearly we can use as many of these as we like to ban any ﬁnite
region of space. Notice that BLOCK (0, 0) stops the robot from re-entering theorigin once it has left it – it cannot be prevented from being there initially!
Other things we could do would be to stop it doing more than K actions in
total say, representing its fuel capacity, or from communicating its position whenin speciﬁed areas.
One of the simplest and most useful examples of this style is the banning of
events: P Σ X STOP = P  STOP is the process which behaves like P except
X

that events in X are banned.
This style of use of the parallel operator amounts to building up a complex
behaviour by adding together a number of simple constraints. Clearly the numberof participants in a given action in this example might get very large. But thisneed not worry us since, as we already know, it is quite possible to have a parallel
process equivalent to a sequential one, and the eventual implementation of our
speciﬁcation will almost certainly be very diﬀerent from the combination of theparallel constraints.
The exercises below illustrate this style well, and we will see further examples
at various points in this book, especially in Section 15.1.
Exercise 2.5.1

We can describe a bank as a process that simply opens and closes:

BANK = bank open → bank close → BANKInterleave this with the process that records what day of the week it is:
DAYS = Monday → Tuesday → . . . → Sunday → DAYS

2.5

Parallel composition as conjunction

73

P
A

B
C

Figure 2.6 Some railway track (see Exercise 2.5.3).
Express the following as parallel constraints to this system:(i) It opens no more than once per day.
(ii) It is always closed at midnight (when the day events occur).
(iii) It is never open on a Sunday.
(iv) It is always open at least two times per week.

Exercise 2.5.2
Put your solutions to the previous exercise and Exercise 1.1.3 inparallel via interleaving. Impose the following constraints:(i) An account can only be opened or closed when the bank is open.
(ii) Balance enquiries may not be made on Sundays.

Exercise 2.5.3 Figure 2.6 shows a section of a railway network. There are signals at
A, B , C governing entry to the section, and points at P which connect the line from A toeither B or C . The alphabet is as follows:
signal .X .Y for X ∈ {A, B , C } and Y ∈ {red, green} indicate the change of the signal at
X to colour Ypoint.X for X ∈ {B , C } represents the points being switched to connect A to X
enter .X .t for X ∈ {A, B , C } and t ∈ Trains represents train t entering the section atXleave.X .t (X and t as above) represents t leaving at X .
Assume that initially all signals are red, the points connect A to B , and the trackis empty.
Give trace speciﬁcations for each of the following properties:(i) Each signal alternates between turning green and red.
(ii) Only one signal can be green at any time.
(iii) The points alternate between the two directions.

74

Parallel operators(iv) The points only switch when all signals are red and there is no train on the track.
(v) A signal can only turn green when there is no train on the track.
(vi) The signals at B and C only turn green when the points are appropriately set.
Build a process that meets all of these speciﬁcations and which has, within reason,
all of the traces which they allow. Do this by building one or more processes for eachconstraint and combining them appropriately in parallel.
The above speciﬁcations allow a train to enter against a red signal. Introduce anextra event alarm which occurs (before anything else) if this happens, and modify yourprocess deﬁnition appropriately.

2.6

Tools

The last three binary parallel operators we have seen are supported in machinereadable CSP. They are written as follows:
P X Y Q

is written P [X||Y] Q

P ||| Qis written P ||| QP Q

is written P [|X|] Q

X(P  Q can easily be modelled using the others, for example P[|Events|] Q.)
Indexed versions are written as follows:

i=1 (Pi , Ai )is written|| i:{1..N} @ [A(i)] P(i)|||i=1 Pi

is written||| i:{1..N} @ P(i)

N

N



N

Pi

is written[|X|] i:{1..N} @ P(i)X i=1Note that the last of these assumes that all the Pi synchronize on the set X , andthat no other event is synchronized at all.
The addition of parallel operators has an enormous eﬀect on the expressive
power of the language, in the sense that it becomes possible to describe many complex and interesting systems concisely and naturally. One eﬀect that is very noticeable is the exponential state explosion that can, and frequently does, occur whenNPi
we put a lot of processes in parallel. If each Pi has just two states, then |||i=1

has 2N . Synchronizing events, as in  (Pi , Ai ), usually prevents the combination
i=1
reaching some arrangements of component states; it often leaves enough of them toleave a lot of work.
N

2.6

Tools

75

With an animator this state explosion only shows up if you seek to cover
all the states, but with a model checker2 you usually have to visit each reachable
state, and so it is common experience (one each reader who uses these techniques
will doubtless share) that the time and space taken for reﬁnement checks frequently
increases exponentially with the size of a parallel system.
Overcoming this complexity barrier is a major active research topic at thetime of writing. It seems most unlikely that it can be got around for every parallel
combination and speciﬁcation; the objective is to do so for as many classes of usefulproblems as possible. We will discuss the techniques FDR uses at several later points
in this book, especially Section C.2, when we understand enough of the theory.
The existence of this barrier does not prevent one from modelling manysystems which are both non-trivial and practical without any attempt to get around
it at all other than by making the enumeration of states as eﬃcient as possible inboth space and time, and sometimes careful coding of the CSP to avoid unnecessary
states. Thus at the time of writing FDR can, even on the author’s laptop computer,
deal entirely explicitly with combinations with order 107 states at several million
states per hour.
In order to achieve this eﬃciency, FDR uses very diﬀerent techniques forcomputing the state spaces of low-level processes (broadly speaking, ones deﬁnable
in the syntax introduced in Chapter 1) and high-level ones (broadly speaking, parallel combinations of low-level ones). When FDR says it is compiling a system it
is using relatively slow symbolic techniques for turning low-level components into
explicit state-machines. This does not enumerate the states of the entire system(assuming it involves a high-level construct), but rather gives eﬃcient rules for computing the initial actions and next states of any combination of low-level states thatmight arise.
A process structured as the parallel combination of reasonably-sized lowlevel components will thus tend to be explored much more eﬃciently by FDR thanan equivalent one which is structured so that it is entirely compiled at low level.
Certainly one of the keys to the successful use of FDR is an understanding of thisfact and the division into high- and low-level syntax that lies behind it. This is
explained in more detail in Appendix C.
2 Model checker is the name for the class of tools to which FDR belongs in a broad sense:
one can deﬁne a model checker as a tool which seeks to verify that a system which is deﬁned
by transitions between (sometimes very large) ﬁnite sets of states satisﬁes some speciﬁcation andwhich performs the veriﬁcation by traversing the entire state space. (This traversal might be onestate-at-a-time or use some way of dealing with many at once.) In other classes of model checkers,
the speciﬁcation is usually deﬁned in a language other than that used for the implementation(often a specially deﬁned logic). What characterizes a reﬁnement checker like FDR is that the
speciﬁcation is another process in the same language.

76

2.7

Parallel operators

Postscript: On alphabets

The most signiﬁcant diﬀerence between the version of CSP used in this book andthat in Hoare’s text is the treatment of alphabets. Hoare stipulates that every
process P has its own associated alphabet αP . One can think of the alphabet of aprocess as representing its type. A process may only communicate events from its
alphabet, but there may be events in its alphabet which it can never communicate
and which do not even appear in its description. The presence of alphabets makes
the parallel operator more elegant, since by writing P  Q we know immediatelythat P has control over αP and Q has control over αQ, and so they interact in, andmust co-operate on, αP ∩ αQ. This is in contrast with our version where alphabets
are given explicitly: P X Y Q. Hoare makes a number of stipulations about thealphabets of the processes that are composed together; most of the operators requirethat all processes combined have the same alphabet and that the result is the sameagain. Others, such as  and hiding, have special rules. The CSP operators in thealphabetized theory are thus polymorphic in a sense very close to the usual one.
The disadvantages of the alphabetized version of CSP are ﬁrstly the needto give all processes alphabets (which can clutter deﬁnitions, especially recursions),
the occasional need for special language constructs to get the ‘typing’ right, andadditional theoretical complexity. The main manifestation of the last of these is theneed to construct separate mathematical models for every diﬀerent alphabet where
we can get away with just one.
The choice of one version or the other is largely a matter of taste, though it
is certainly the case that the balance changes from application to application. We
do not regard this as an important issue, since everything done in one version of
CSP can be done in the other with trivial changes.
In this book we sometimes refer to the ‘alphabet’ of a process. This, in an
informal sense, means the same as Hoare’s, namely the set of communications it
might use. However, whenever we need such an alphabet to have semantic signiﬁcance (as in the set of events a P controls in a parallel combination), it has to bedeﬁned and used explicitly.

Chapter 3

Hiding and renaming

It is often useful either to remove certain actions from the view of the environment or
to apply mappings to a process’s events. In this chapter we introduce the operatorsthat allow us to do these things.

3.1

HidingConsider the parallel combination of COPY  (cr , cr +1 ) processes we saw on page
58. We said there that it would be natural to think of c0 and cn as being external
channels, and the others as internal ones. If they really are internal then the factthat we can still see the communications passing along them is unfortunate fromseveral points of view.
• Seeing these communications clutters up our picture of the process and makes
it impossible to show that this system behaves like an n-place buﬀer implemented some other way. We should not have to see unnecessary internal
details of a system.
• By leaving the internal communications visible we are leaving open the possibility that another process might be put in parallel with the currently deﬁned
network, with some of these internal events in its alphabet. Thus, it would
be able to stop these events from happening. In this case, and in many like it,
we would expect ‘internal’ communications such as these to proceed without
requiring further control from outside.
Both of these diﬃculties can be avoided by hiding the internal events, making theminvisible to and uncontrollable by the environment.

78

Hiding and renaming

Given any process P and any set of events X , the process P \ X behaves
like P except that the events from X have been internalized in this way. If we wantto hide a single event or channel a then we will sometimes write P \ a rather thanP \ {a} or P \ {| a |}.
Thus, if we want to hide all the communication between a pair of parallel
processes we would write (P X Y Q) \ (X ∩ Y ) or (P  Q) \ Z . This createsZ

point-to-point, invisible communication, which is arguably closest to the ‘natural’
parallel operator of implementations such as occam. In specifying a real parallel
communicating system, rather than one devised as a speciﬁcation where the parallel
operator takes the role of conjunction as described in Section 2.5, one almost always
uses a combination of the parallel and hiding operators.1 The natural view of thechain of buﬀers would be
(

n−1
r =0

(COPY  (cr , cr +1 ), {| cr , cr +1 |})) \ ({| c1 , . . . , cn−1 |})The only communications visible in this system are its inputs and outputs,
namely {| c0 , cn |}. Since we are no longer seeing the internal workings, we canpotentially prove this equivalent to a totally diﬀerent one which might have diﬀerent internal channels or none at all, or to another CSP description intended as a
speciﬁcation.
Perhaps the easiest way of understanding the eﬀect of the hiding operator
is to see how it transforms the picture of a process’s transitions. We saw a few ofthese in previous chapters (Figures 1.1, 1.2, etc.). Any process can be given such atransition system, which provides a much less abstract view of how it behaves thanits set of traces2 . The shape of the transition system remains exactly the same, but
hidden actions are transformed into invisible actions, which we label τ (the Greek
letter ‘tau’). An example is shown in Figure 3.1. Invisible (or internal) actions
are to be thought of as ones which (a) do not contribute to the trace, because theenvironment cannot see them and (b) the process can perform by itself. τ is a
special event that is never in Σ.
Since it is a unary (one-place) rather than binary operator (on processes),
the only one of the ‘usual’ sorts of algebraic laws that apply to it is the distributive
law. There is a rich collection of laws, nevertheless, of which the following are afew:(PQ) \ X = (P \ X )(Q \ X )hide-dist

1 Some other process algebras, notably CCS, combine parallel and hiding into a single operator:
they do not factor the ‘natural’ operator into two parts like CSP.
2 A complete set of recipes for deriving these transition systems is given in Chapter 7, where itis the method of presenting the operational semantics of CSP.

(3.1)

3.1

Hiding79\{a} =
a

b

b

τ

b

b

b

a

b

a

τ

τ

Figure 3.1 The eﬀects of hiding on a transition system.

(P \ Y ) \ X = (P \ X ) \ Y

hide-sym(3.2)(P \ Y ) \ X = P \ (X ∪ Y )hide-combine(3.3)

null hiding(3.4)

hide-step 1

(3.5)

P \ {} = P
(a → P ) \ X =P \Xa → (P \ X )if a ∈ X
if a ∈ X

The second of these is an easy consequence of the third. The ﬁnal law above shows
the hiding actually happening: the a disappears when it is an element of X . Notethat this shows that a process whose only initial action is a single τ is equivalent
to whatever state follows the τ .
This is not a full ‘step’ law, in the sense we have already used to describe
other operators, since that requires the process to have an arbitrary set of initialactions. The full version is more complex because it has to deal with what happens
when (i) there is a choice of hidden actions and (ii) there is a choice between hidden
and visible actions. Rather than writing down the whole law immediately let us
look at each of these two situations separately.
(a → P 2 b → Q) \ {a, b}
has two hidden actions possible. Now only one happens, and we cannot be surewhich, so in fact this equates to (P \ {a, b})(Q \ {a, b}). This creates the80

Hiding and renamingﬁrst principle we are looking for here: when there is more than one hidden action
possible, it is nondeterministic which occurs. And in fact the usual3 way of creatinga transition picture of the process P Q is by creating one whose initial state has
two τ actions: one to P and one to Q.
It is tempting to think that we should either give hidden actions the ability
to exclude visible ones from the same choice – because the hidden action occurs assoon as it is possible – or perhaps the reverse. In fact, neither of these views is
consistent with what we already know. Consider the process(a → P 2 b → Q) \ b(the same as above except that only one of the two events is hidden). If either theunhidden or the hidden event were preferred, this would equal
a→P \borQ \bwhich, if we then hid a, would in either case give a diﬀerent answer from hiding{a, b} together, in contradiction to the law hide-combine. Thus both the hidden
and unhidden actions must remain possible. The right way to think about how thistype of process behaves is that as soon as an internal action becomes available thensomething must happen, but it might be a visible action rather than a hidden one.
Unless we do manage to get a visible communication, a hidden one must occur. The
right answer to what the above process equals turns out to be((a → (P \ b))

STOP ) 2 (Q \ b)We must get the options of Q \ b if we wait long enough, but may also get the
chance of the a if we are quick enough. The principle underlying this is that, in achoice between visible and hidden actions, we may get the chance of communicating
one of the visible ones, but given a long enough wait, one of the hidden ones mustoccur. It is perhaps easiest to understand this by considering transition pictures
like Figure 3.2.
The combination (P STOP ) 2 Q arises frequently in theoretical work on
CSP because of this phenomenon with hiding. It is convenient to introduce an extra,
asymmetric choice operator to represent it directly: P  Q. This can be thoughtof as a ‘time-out’ or ‘sliding choice’ operator in which, as above, the options of P
are oﬀered for a short time before it opts to behave like Q. For obvious reasons therepresentation of a time-out is very imperfect in a model without time – we will see
how to make them more realistic in Chapter 14. There is no need to quote P  Q’s
3 This is exactly how FDR and ProBE represent nondeterministic choice, as previously describedin Section 1.4.

3.1

Hiding

81

a

P\b

τ

Q\b

Figure 3.2 Hiding creating a ‘time-out’.
algebraic laws, etc., formally because they can all be derived from those of
and STOP . See Exercise 3.1.6, for example.

, 2

The complete step law for hiding is given below:(?x : A → P ) \ X =⎧?x : A → (P \ X )⎪⎪⎨if A ∩ X = {}(?x : (A  X ) → (P \ X ))⎪⎪⎩  {(P [a/x ]) \ X | a ∈ A ∩ X } if A ∩ X = {}hide-stepIt should be noticed that this ‘step’ law is unlike all of the ones we have seen before,
in that, while it obviously uses one step of the process it is applied to, it does notnecessarily give us the ﬁrst visible action of the result. Of course this is perfectly
natural with a hiding operator, but it does mean that one might never come to aconclusion from it about what the initial actions of P \ X are: just think what
would happen if you were to apply it to (µ p.a → p) \ a.
Notice that in the buﬀer example above we hid all the internal communications at once, at the outermost level, where we could have combined the cells insteps hiding the internal channels as we go. This is represented by the complex
expression((. . . (COPY  (c0 , c1 ) {|c0 ,c1 |} {|c1 ,c2 |} COPY  (c1 , c2 )) \ {| c1 |} . . .){|c0 ,cn−1 |} {|cn−1 ,cn |} COPY (cn−1 , cn )) \ {| cn−1 |}(We will see a much more convenient way of writing this down in Section 4.1.)
Provided that moving the hiding does not inﬂuence the number of processes thathave to agree on an action, it should not matter whether we hide that action at an

(3.6)

82

Hiding and renaming

inner or an outer level of a parallel combination. Thus, we can expect(P X Y Q) \ Z = (P \ Z ∩ X ) X Y (Q \ Z ∩ Y )provided X ∩ Y ∩ Z = {}(P  Q) \ Z = (P \ Z )  (Q \ Z )X

Xprovided X ∩ Z = {}hide-X Y -dist

(3.7)

hide-  -dist

(3.8)

X

These laws are helpful in understanding how a network put together withparallel and hiding operators behaves: we can move all the hiding to the outermost
level so we can ‘see’ all of the communications in the network at once before applying
a single hiding operator to get rid of the ones we don’t want to see. As we will see
in later chapters, these laws are vital in support of reasoning about deadlock, andare crucial in advanced model-checking techniques.
Hiding can remove other details aside from communications between partners. For example, we might want to conceal the spending of CUST spend and thereﬁlling of ATM ref in order to concentrate on their common interface.
CUST spend r \ spend .N
can be expected to behave exactly like CUST 2, while ATM ref r \ reﬁll behaves
like an implementation of ATM 2: it is strictly more deterministic because it neverswallows the card. It is nevertheless nondeterministic, even though ATM ref r isdeterministic, because since we cannot see when the machine is being reﬁlled, we get
imperfect knowledge of when a request for funds is refused. Notice how this hiding ofdetails actually invisible to the customer makes the ATM exhibit nondeterminism,
just as he or she observes. We will study the process of abstracting like this from asubset of a process’s events in Chapter 12.
Hiding is the most common source of nondeterminism in CSP descriptions.
It often shows up in real systems where one parallel partner has to arbitrate between
two others. For example, we know that the process
P = a → c → STOP 2 b → d → STOPoﬀers the environment the choice between a and b, with subsequent behaviour
depending on which option is chosen. If we give it the alphabet X = {a, b, c, d } ofall events it can perform, then simply putting it in parallel with processes whichchoose a and b respectively does not change the way it looks to the outside world:
N = P X {a,b} (a → STOP {a} {b} b → STOP )3.1

Hiding83

N can be expected to behave in the same way as P . If, however, we ‘complete’
the parallel composition by hiding the internal events N \ {a, b} then we introduce
nondeterminism. The result will behave like(c → STOP )(d → STOP )This type of behaviour is what makes nondeterminism an inevitable constituent of
any theory describing concurrency where arbitration is present in some form.
If we had allowed our ATM to be reﬁlled when full, or the customer to spend
a zero sum, then the hiding above would have introduced divergence, which is thepossibility of a process entering into an inﬁnite sequence of internal actions. For
then the ATM would allow an inﬁnite sequence of hidden reﬁll actions without
ever interacting with the user, and the customer could perform an inﬁnite numberof hidden spend .0’s. Clearly a process which is diverging is useless, and arguably
more useless than STOP , since we can never detect by the lack of internal activity
that a diverging state will never do anything. A common source of divergence in
CSP occurs in parallel networks with internal communications hidden, where theprocesses can communicate inﬁnitely with each other without ever communicatingexternally. This is sometimes termed ‘livelock’ or ‘inﬁnite internal chatter’.
On the same principle that led us to introduce an operator for nondeterminism (i.e., that it is useful to have a clean representation of it) we will use a special
symbol for a divergent process: div is the process that does nothing but diverge.4
The only way of introducing divergence except through hiding and the symbol div
is by ill-formed recursions. The simplest recursive deﬁnition of them all, µ p.p isan example: clearly evaluating it will lead to an inﬁnite unwinding without getting
anywhere. Divergence plays an important role in the mathematical modelling of
CSP, so we will meet div frequently in later chapters.
Particular care has to be exercised in dealing with inﬁnite hiding, i.e., P \ X
for inﬁnite sets of events X . For it can introduce unbounded nondeterminism in justthe same way as the unconstrained use of . That this is so is readily demonstrated:
if S = {Pλ | λ ∈ Λ} for a set of events Λ chosen to be disjoint from those which thePλ themselves can communicate, then clearlyS = (? λ : Λ → Pλ ) \ Λ

4 In Hoare’s text, the process CHAOS is assumed to be able to diverge as well as everythingelse it can do, and there is no special representation for a simply diverging process. We distinguishthe special process div because it represents an important concept and, as we will see in later
chapters, diﬀerent mathematical theories of CSP treat it in widely varying ways. For us, Chaos
is not a divergent process and is in every model equivalent to its deﬁnition on page 29.

84

Hiding and renaming

The traces of P \ X are very easy to compute: if we deﬁne s \ X , for any
trace s, to be s  (Σ  X ), thentraces(P \ X ) = {s \ X | s ∈ traces(P )}Hiding versus constructiveness
It must be pointed out that the very useful notion of a guarded recursion ﬁts
uneasily with hiding. For the meaning of ‘guarded’ is that information – in thesense of communications – is added by a recursion. Another (and, in general, moreaccurate) term we can use is ‘constructive’. Hiding deletes events: consider therecursion
P = a → (P \ a)which, according to our earlier deﬁnition, is guarded because the recursive callis preﬁxed by an event. The problem is that communications are deleted by thehiding, so that what the recursion gives with one hand it takes away with the other.
In fact this recursion does not have a unique ﬁxed point over the traces model T :if S is any member of T at all (possibly able to communicate events other than a),then{} ∪ {aˆ(s \ a) | s ∈ S }is a solution to the ﬁxed point equation we get from the recursion. The least andnatural solution is, of course, {, a}. After the trace a we would expect that
this process would diverge, since it would perform a sequence of increasingly deeply
hidden a’s. Our intuition, therefore, is that this P = a → div.
This behaviour forces us to add a caveat to the deﬁnition of guardedness:no recursion in which the hiding operator is applied (directly or indirectly) to arecursive call should be considered guarded (at least, without a careful analysis
based on mathematical models).
Of course, this restriction applies equally to the derived operators we willmeet later that use hiding in their deﬁnition. In a few cases it is possible to assertthat recursions involving hiding are constructive, but to do this we will have tounderstand the mathematics of constructiveness a great deal better: see an example
on page 106 and Sections 8.2 and 9.2 for some of the theory.
It is easy to think that the above restriction prevents us from applying the
UFP rule to any process involving hiding: this is not so, it is only the recursion towhich the rule is applied that has to be constructive. A good example is the process

3.1

Hiding85

we get when we hide the internal channel of the combination we studied in the lastchapter:(COPY  (a, b) {|a,b|} {|b,c|} COPY  (b, c)) \ {| b |}Now of course we already know that the process inside the hiding is equivalent toCC0 , whereCC0

=a?x → CC1 (x )CC1 (x ) =b!x → CC2 (x )CC2 (x ) =(c!x → CC0 ) 2 (a?y → CC3 (y, x ))CC3 (y, x ) =c!x → CC1 (y)When we hide {| b |} in this we ﬁnd (applying hide-step) that
CC0 \ b=a?x → CC1 (x ) \ bCC1 (x ) \ b=CC2 (x ) \ bCC2 (x ) \ b=(c!x → CC0 \ b) 2 (a?y → CC3 (y, x ) \ b)CC3 (y, x ) \ b=

c!x → CC1 (y) \ b

which is not (applying the usual trick of replacing each term on the left-hand side
by a new recursive variable) guarded. However, the above equations imply triviallythat CC0 \ b, CC1 (x ) \ b and CC3 (y, x ) \ b satisfy the recursive deﬁnition
B02= a?x → B12 (x )B12 (x )= a?y → B22 (y, x )2 c!x → B02

B22 (y, x ) = c!x → B12 (y)which is guarded. (Note that B02 , B12 (x ) and B22 (x , y) respectively denote a twoplace buﬀer with nothing in, with x in and with x and y in.) So we have shown that
our original processes satisfy this guarded recursion and therefore equal its uniqueﬁxed point. It is quite irrelevant that the deﬁnition of the original processes involved
hiding. There was, we should point out, no need to go through the intermediatestep of discovering the C  recursion: it would have been just as good to prove thata vector of parallel/hiding combinations satisfy the B 2 recursion.
Note that what we actually proved here was that the parallel combination of
two one-place buﬀers, placed in parallel with the middle channel hidden, behaves
like a two-place buﬀer – clearly something we would expect.

86

Hiding and renaming

Take the dining philosophers network from pages 61 and 67 with thepicksup and putsdown events hidden (after the entire network has been combined). Can
this system still deadlock? Do you think hiding can ever aﬀect deadlock? Think carefully
and write down your conclusions – we will later develop theories that will answer thisquestion deﬁnitively.

Exercise 3.1.1

Exercise 3.1.2 If P = (a → P ) 2 (b → a → P ), we would expect that P \ b isequivalent to µ p.a → p. Use hide-step (3.6) and the laws of choice to show thatP \ b = a → (P \ b)and hence that this equivalence is true by the UFP rule. Make sure you understand why
the rule is valid here when it was invalid on the very similar equation P = a → (P \ a).

Exercise 3.1.3

If P = a?x → b!x → b!x → P then it is possible to ﬁnd a process Q

such that(P {|a,b|} {|b,c|} Q) \ {| b |} =T COPY  (a, c)(i.e., a one-place buﬀer). Find Q and use the UFP rule to prove the equivalence.
Give a CSP expression deﬁning the process equivalent to the one on
the left-hand side of Figure 3.1. Use the step law and laws about the choice operators toprove that the hidden process P \ {a} satisﬁes the equation

Exercise 3.1.4

P \ {a} = b → (STOP  b → P \ {a})Exercise 3.1.5

Use -2-dist, 2-dist and other standard laws to prove that(Q 2 R)  STOP=

(Q 2 R)  Q  R  STOP

(P 2 Q 2 R)  P=(P 2 Q 2 R)  (P 2 Q)  P

and hence

Prove, using the laws set out in Section 1.2, that  is distributive ineach argument and is associative. Hint: for associativity, use the result of the previous
exercise.

Exercise 3.1.6

Can you ﬁnd any other laws it satisﬁes (perhaps in relation to other operators)?

3.2

Renaming and alphabet transformations

In the previous section we saw how to remove certain events from sight. A lessdrastic eﬀect is achieved by renaming, which means applying a map that changes
which (visible) member of Σ a process is performing.
While one can imagine that the alphabet transformation thus accomplishedmight change through the life of a process – perhaps event a maps to b if it appears

3.2

Renaming and alphabet transformations

87

before the 12th event and to c later – in practice we rarely want to do this. Thus,
our renaming operators apply the same transformation throughout a process’s life:in this section we see three increasingly general ways of doing this.5
3.2.1

Injective functions

Suppose P is a CSP process and f : Σ → Σ is an injective, or 1–1, function (simply
meaning that f (x ) = f (y) implies x = y) from Σ to itself. f can be a partial
function provided its domain contains every event possible for P . Then f [P ] isthe process which can communicate f (a) whenever P can communicate a. The
communications of P have been renamed, or equivalently P has been subjected toan alphabet transformation. The transition system of f [P ] is that of P with thefunction f applied to the arcs.
All of this works whether f is injective or not. The reason why we want todistinguish this case is because it is both simpler to understand and is used mostoften in CSP descriptions of real systems. The point is that, in this case, f [P ] works
exactly like P except for the names of its events. (The sense in which this is nottrue when f is not 1–1 will be seen later.)If f is the function that swaps the events down and up, then f [COUNT 0 ]will behave like a counter through the negative numbers, since it will never allow
any more up’s than down’s.
If g is a function that maps (for any x ∈ T ) left.x to a.x and right .x to b.x
then g[COPY ] is the same as the parameterized process COPY  (a, b) (assuming,of course, that left, right, a and b are all channels of type T ). One could similarly
devise a renaming that would map a single FORK i from the dining philosophers
to any other FORK j , and likewise for the philosopher processes. In each case thisis possible because, except for the names of their events, the target process always
behaves identically to the original: evidently no renaming could make FORK i into
PHILi !
Thus, renaming is an alternative to parameterization as a way of creating
many similar processes to put into a network. Which method is better depends onthe example and the taste of the programmer.
One form of renaming that is useful when we want to create copies of a processwith entirely disjoint alphabets is process naming. If the compound event a.x is inΣ for each event communicable by P , then a.P is the process which communicatesa.x whenever P communicates x . The renaming function here is clear, but thisform of use is suﬃciently common that the shorthand a.P is commonly used. If
5 In Section 14.4.1 we will see how the variable renaming can be constructed by combining
constant renaming with other constructs; see also Exercise 3.2.5 below.

88

Hiding and renaming

a1 , a2 , . . . , an are distinct names, we can get n copies of P running independently
in parallel by naming them:r =1 (ar .P , ar .X )nor equivalently|||r =1 ar .Pnwhere X is whatever alphabet is natural for P and a.X = {a.x | x ∈ X }. Since
these processes have disjoint alphabets they do not interact at all. If either theenvironment or another process wants to communicate with one of them it has toselect the one by name, since the communications all include the given name.
Since injective renaming leaves the behaviour of a process unchanged except
for the names of actions, it has an extremely rich set of laws – too many to write
down conveniently! Essentially it distributes over all operators. We will give a listof laws that apply to any sort of renaming later, but three that apply speciﬁcallyto this one aref [P  Q] = f [P ]  f [Q] if f is 1–1
Xf [·]-  -distf (X )f [P X Y Q] = f [P ] f (X ) f (Y ) f [Q] if f is 1–1
f [P \ X ] = f [P ] \ f (X ) if f is 1–1

(3.9)

X

f [·]-X Y -dist (3.10)
f [·]-hide-sym (3.11)

The third of these is frequently used, in combination with the following, to change
the name of hidden actions. This might be done to prevent a clash of names for thesubsequent application of other laws. An example may be found in Section 13.7.
f [P \ X ] = P \ X

3.2.2

if f (y) = y for all y ∈ Σ  X

f [·]-hide-null (3.12)

Non-injective functions

The most common use of renaming f [P ] when f is not injective on the events of
P is when we want to forget about some level of detail in a process. Consider asplitting process which accepts inputs on channel in and, depending on what the
input is, sends it either to out1 or to out2.
SPLIT= in?x : T →((out1.x → SPLIT )<I x ∈ S>I (out2.x → SPLIT ))For some purposes the composition of messages may be unimportant. If we forgetthat detail by using the renaming function forget which remembers only the channel

3.2

Renaming and alphabet transformations

89

name, the process forget[SPLIT ] we get is equivalent to SPLIT  , where
SPLIT = in → (out1 → SPLIT out2 → SPLIT  )This has introduced nondeterminism because we have deliberately forgotten theinformation which allowed us to know whether out1 or out2 occurs. Though thismight appear a retrograde step, this type of abstraction is frequently beneﬁcial, for• it allows us to demonstrate that some aspect of the correctness of the systemdoes not depend on precisely how decisions are made, and• in cases where this is true the details of decision making frequently clutter
proofs.
Several examples of this type of abstraction in deadlock analysis can be found later,
on pages 354 and 369, for example.
Non-injective renaming becomes more dangerous when the alphabet transformation f in use maps an inﬁnite set of events to a single one (i.e., f is notﬁnite-to-one). This, like S for inﬁnite S , and P \ X for inﬁnite X , is a constructwhich can introduce unbounded nondeterminism.
3.2.3

Relational renaming

Various treatments of CSP have included a second sort of renaming, using inverse
functions: f −1 [P ] can communicate a whenever P can communicate f (a). This isequivalent in expressive power to the direct image renaming we have seen alreadywhen f is 1–1, but it can produce some interesting eﬀects when f is many-to-one.
For a single event in P can be transformed into the choice between many diﬀerent
ones – though all leading to the same place. What we will now describe here is amore general form of renaming that encompasses both direct and inverse functions,and at the same time corresponds most closely to the notation for renaming usedin machine-readable CSP.
A function can be thought of as a set of ordered pairs: (x , y) is in the set
if f (x ) = y. A set of pairs is a function if no x is mapped to more than one y. A
relation on the other hand, is any set of ordered pairs, with no restriction as to how
many things a given object can be related to. If (x , y) ∈ R we write x R y. If R isa relation, its domain and range are respectively
dom(R) =ran(R) ={x | ∃ y.x R y}{y | ∃ x .x R y}

The composition of two relations R ◦ S is{(x , z ) | ∃ y.x R y ∧ y S z }90Hiding and renaming(confusingly, because of a clash of conventions, this is the opposite way round to
the way composition of functions works). The relational image R(x ) of x under R
is {y | x R y}.
If R is a relation whose domain includes all the events of P , then P [[R]] isthe process that can perform each event in R(a) whenever P can perform a. If R
is a function then this is identical to the renaming R[P ]. If f is a function thenits inverse f −1 is the relation {(y, x ) | (x , y) ∈ f }. The operator f −1 [P ] is thenidentical to P [[f −1 ]]. For example, if D is the relation which relates a to both itself
and b, then(a → STOP )[[D]] = (a → STOP ) 2 (b → STOP )If U is the universal relation Σ × Σ, then P [[U ]] = RUN if and only if thedivergence-free process P is deadlock-free.
The following laws, etc., are thus all true (suitably translated from the forms
below) for the functional form of renaming. Renaming distributes over both choice
operators:
Q[[R]]

[[R]]-dist (3.13)(P 2 Q)[[R]] = P [[R]] 2 Q[[R]][[R]]-2-dist (3.14)(PQ)[[R]] = P [[R]]If the initials of P  are A, then those of P  [[R]] are R(A) = {y | ∃ x ∈ A. (x , y) ∈ R}:(?x : A → P )[[R]] = ?y : R(A) →{(P [z /x ])[[R]] | z ∈ A ∧ z R y} [[R]]-step (3.15)

This shows that renaming can introduce nondeterminism when more than one
event in A maps under R to the same thing. This cannot happen when R is either
an injective function or f −1 for any function: in these cases the nondeterministic
choice is over a set of one process – no choice at all – as there is then only ever one
z such that z R y.
Renaming by one relation and then another is equivalent to renaming by thecomposition of these relations:(P [[R]])[[R  ]] = P [[R ◦ R  ]]

[[R]]-combine (3.16)

This law is one reason why relations are written on the right of a process rather than
(as with functions) on the left. It implies the following law for functional renaming,
where the opposite sense of composition is used
f [g[P ]] = (f ◦ g)[P ]f [·]-combine (3.17)

3.2

Renaming and alphabet transformations

91

Renaming in this most general form is such a powerful operator that most of
the useful distribution laws that held for 1–1 renaming are no longer true. (In mostcases versions can be found, but these tend to come with an unfortunately complex
set of side conditions.)
The traces of P [[R]] are just the images of those of P under the obvious
extension of R to traces:a1 , . . . an R ∗ b1 , . . . , bm  ⇔ n = m ∧ ∀ i ≤ n.ai R bi
traces(P [[R]])={t | ∃ s ∈ traces(P ).s R ∗ t}

A good way of deﬁning relations for use as alphabet transformations is touse a notation like substitution: we can write P [[a /b ]] to mean that the event orchannel b in P is replaced by a. (Note that all others remain the same – including
any a that is already there.) To modify more than one thing, or to send one thing
to more than one place, we write something likeP [[a, b /b, a ]]orP [[b, c /a, a ]]Note that the ﬁrst of these swaps a and b and the second maps a to both b and c.
One-to-many renaming as a magic wandRelational renaming gives us the ability to create a process that will oﬀer several
alternatives in place of a single event. On ﬁrst encountering this possibility one
is inclined to wonder what purpose it might serve, particularly since the result of
performing any of these alternatives is exactly the same. However there are two
important uses for it that one tends to meet in practice.
The ﬁrst is as an aid to creating processes that treat large numbers of eventsin the same way. Typically these are speciﬁcation processes or simple componentsof larger systems. For example you can deﬁne a process in which members of thesets A and B of events alternate by deﬁning one µ p.a → b → p alternate, andthen renaming a and b (respectively) to all members of A and B . One could deﬁne
Chaos A as(µ p.((a → p)

STOP ))[[x /a | x ∈ A]]

By using this style it is sometimes possible to achieve greater clarity than without(since evidently any use in this style could be replaced by a preﬁx choice), and insome cases it results in a more eﬃcient implementation for FDR.
The second use is rather more interesting, not least since it produces resultsthat do not seem possible using any other CSP construct. That is to create, in eﬀect,

92

Hiding and renaminga renaming operator that maps each event only to a single target, but one which
varies with more than just the input event. Thus we might rename the event apple
to either Cox or Braeburn depending on what has gone before it. This is achieved
by ﬁrst renaming the event to all its targets, and then designing a regulator processthat is put in parallel with the resulting process and which selects which of the new
events happens on each trace. For example, if Adam and Eve prefer the diﬀerent
varieties here we might deﬁneReg= Braeburn → Reg
2 Adam → Reg
2 Eve → Reg 

Reg = Braeburn → Reg 
2 Adam → Reg
2 Eve → Reg 

The construct
P [[Adam, Eve /apple, apple ]]{Adam,Eve,Braeburn,Cox }Reg

creates a process that will do one or other of Braeburn and Cox whenever P would
have done apple.
All sorts of weird and wonderful eﬀects can be achieved with variations on
this theme, such as hiding every other event a process does, or just the ﬁrst one.
Certainly when trying to achieve something unusual in CSP, it is one of the ﬁrst
things the author usually tries, and indeed we will see several indispensible uses ofthis idea in later chapters.
Recall that COPY = left?x → right!x → COPY . Suppose we
Exercise 3.2.1
want, instead, a process CELLf which inputs values v on channel left and immediately
outputs f (v ) on right. Find an appropriate alphabet transformation gf so that CELLf =gf [COPY ]. Under what conditions is gf injective?
Use an alphabet transformation to connect the output channel of
COPY to the input channel of CELLf and vice-versa (i.e., there are two processes runningin parallel). How does this process behave? How does it behave if COPY is replaced byright!x → COPY ?

Exercise 3.2.2

Add an extra channel in to COPY so that the resulting process can be initializedalong this channel and thereafter behaves as before, so achieving the eﬀect of the secondcase in the last paragraph for any x .

Exercise 3.2.3 Find renaming relations Ri which, applied to the process COUNT 0 ,achieve the following eﬀects:

3.3

A basic guide to failures and divergences

93(i) A process with events a, b and c, where the number of c’s is always less than orequal to the total of the a’s and b’s.
(ii) A process that can always communicate either up or down.
(iii) A process that has the same traces as COUNT 0 but may nondeterministicallysometimes refuse to communicate down when COUNT 0 would have accepted it.

Exercise 3.2.4 Find examples to show that the laws for distributing injective renaming over hiding and general parallel composition do not work when the function f is notinjective.
What weaker restrictions on the renamings could you make so that these laws
become valid again? You might ﬁnd thinking about the laws for distributing hiding overparallel helpful here.

Exercise 3.2.5 Remember the possibility quoted at the start of this section of mapping a to b if it is before the 12th event and to c thereafter. Use a combination of a
relational renaming and parallel composition with a process you deﬁne to achieve thiseﬀect. (Assume that the process P does not itself use events b and c.)Exercise 3.2.6 Show how to hide the odd-numbered communications that a process
performs, and how to hide just the ﬁrst communication it performs. (Assume that thealphabet of your process is contained in A, and that Σ contains a disjoint set of events Athat are in natural correspondence with A via a → a  .)3.3

A basic guide to failures and divergences

Though we knew this well enough already, our exposure to nondeterminism anddivergence in this chapter has shown that traces alone give a far from complete
picture of the way a process behaves. Whether or not you intend to study thedetails of how these phenomena are modelled in detail – this is done in Chapter 8 –you should at least gain a basic understanding of the two main tools that are used,in addition to traces.
Traces tell us about what a process can do, but nothing about what it must
do. The processes µ p.a → p and (µ p.a → p) STOP have the same traces, eventhough the second is allowed to do nothing at all no matter what we oﬀer it. In
order to distinguish these processes we need to record not only what a process cando, but also what it can refuse to do. A refusal set is a set of events that a process
can fail to accept anything from however long it is oﬀered. (It is not enough for it
simply to be refused for a ﬁnite time.) refusals(P ) is the set of P ’s initial refusals.
In fact, we need to know not only what P can refuse to do after the empty
trace, but also what it can refuse after any of its traces. A failure is a pair (s, X ),

94

Hiding and renaming

where s ∈ traces(P ) and X ∈ refusals(P /s). (Recall that P /s represents process P
after the trace s.) failures(P ) is the set of all P ’s failures.
One can calculate the failures of a process P in exactly the same way as wehave already shown how to calculate the traces of P : by induction on P ’s syntax.
For details of this you should see Chapter 8. But they can be calculated just as
easily from the transition diagram of a process: you simply collect together all of
the routes through this diagram which (ignoring τ ’s) result in a given trace. If thenode you end up at is stable – i.e., has no τ action leading out of it – then it gives
rise to a failure, since it can (and must) refuse all actions which do not lead out of
it. On the other hand, a node with one or more τ ’s (an unstable node) does notgive rise to a refusal since the internal action will eventually happen: as we cannot
sit at this node for ever it cannot give rise to a refusal. In other words, we haveto wait for the τ ’s to run out before we get refusals. In Figure 3.3 we see how to
calculate the failures of a few simple processes in this way. Assuming the alphabet
is {a, b, c}, each stable node is labelled with its maximal refusal. (If a node canrefuse X , then it can clearly refuse Y ⊆ X .)P1 is (a → b → STOP ) 2 (b → a → STOP ) (or equivalently (a → STOP ) |||(b → STOP )). It has a deterministic transition system (as it has no τ ’s, andno ambiguous branching on any visible actions). It follows that there is aunique path through the tree for any trace. Thus, there will be just one maximal refusal for any trace s: the complement of initials(P /s). Examples ofthis process’s failures are (, {}), (, {c}), (a, {a, c}) and (b, a, {a, b, c}).
P2 shows how internal actions can introduce nondeterminism. It could havearisen as ((c → a → STOP ) 2 (b → c → STOP )) \ c. Its initial refusals are
the subsets of {b, c} but it can also accept b initially. Its complete failuresare{(, X ) | X ⊆ {b, c}} ∪ {(a, X ), (b, X ) | X ⊆ {a, b, c}}P3 could be (a → STOP ) (b → STOP ). It has two initial τ ’s to choose from.
Its initial refusals are {X | {a, b} ⊆ X }. It can refuse either a or b separately
but must accept something if {a, b} is oﬀered. Notice how this is diﬀerent
from the initial behaviours of both P1 (which must accept either) and P2(which must accept a), even though all three have exactly the same initial
events possible.
P4 which could be (c → a → STOP ) 2 (c → b → STOP ) shows how ambiguous
branching on a visible action can lead to nondeterminism. Its refusals after
the trace c are {X | {a, b} ⊆ X }. The similarity to the initial refusals of
P3 is no accident: we know this process is equivalent to c → (a → STOPb → STOP ) and the equality simply reﬂects this fact.

3.3

A basic guide to failures and divergences

95

{c}

P1
a

P2
b

{a,c}

{b,c}

{b,c}

b

a

{a,b,c}{a,b,c}aτ

{a,b,c}{a,b,c}

P

3

τ

τ

{b,c}

b

{a,b,c}

P

4

{a,b}

c

c

{b,c}

{a,c}

a

b

τ

{a,c}

a

{a,b,c}{a,b,c}b{a,b,c}Figure 3.3 The refusal sets of some transition systems.
One process failures-reﬁnes another: P
traces(P ) ⊇ traces(Q)andF Q if and only if

failures(P ) ⊇ failures(Q)or, in other words, if every trace s of Q is possible for P and every refusal after thistrace is possible for P . Q can neither accept an event nor refuse one unless P does.
Among the processes of Figure 3.3, P2 and P3 are trace equivalent and both tracereﬁne P1 . The only failures reﬁnement that holds is that P2 reﬁnes P3 . Make sure
you understand why this is. We can deﬁne two processes to be failures-equivalent(=F ) if each failures-reﬁnes the other.
Failures allow us to distinguish between internal and external choice, some-

96

Hiding and renaming

thing we could not do with traces alone. This is shown by the examples in Figure
3.3, but comes across more clearly when we consider the failures of
Q1= (a → STOP ) 2 (b → STOP )Q2= (a → STOP )and(b → STOP )If Σ = {a, b}, the only refusal on  of the ﬁrst of these processes is {}: the only time
it will not communicate is if it is oﬀered nothing at all! Q2 can additionally refuse{a} and {b}, but cannot refuse {a, b} since whichever way the nondeterministic
choice is resolved it has to accept one or the other. On the other hand, the process
Q3= STOP((a → STOP ) 2 (b → STOP ))can refuse any set of events, because it can behave like STOP . In general, a process
can deadlock if, and only if, it can refuse the whole of Σ. The failures speciﬁcationof deadlock freedom is thus that, for all traces s, (s, Σ) ∈ failures(P ).
Full calculation of the failures of Q1 , Q2 and Q3 would reveal that
Q3

F Q2

F Q1

Failures reﬁnement gets very close to the natural notion of what reﬁnement‘ought’ to mean for CSP processes. The only real problem comes from the phenomenon of divergence that we noticed earlier in this chapter. A diverging process
such as (µ p.a → p) \ a is neither doing anything useful nor is it refusing anything
in the sense discussed above. The only really satisfactory way of dealing with divergence is to record the set of traces on which a process can diverge. We can calculate
this from one of our transition systems, since divergence here is simply an inﬁnite
path of τ ’s (if this graph is ﬁnite, this implies the existence of a τ -loop: a path of
τ ’s from a node back to itself).
When we look into the mathematical theory of how divergences are calculated, it turns out that seeing accurately what a process can do after it has alreadybeen able to diverge is very diﬃcult, and not really worth the eﬀort.6 (This canhappen, for example, if a process has a nondeterministic choice between diverging
or doing something else.) For once we take a process up to the point where it candiverge, there is no way we can rely on it doing anything. Therefore, the standard
mathematical model of CSP, the failures/divergences model, takes the decision thatany two processes that can diverge immediately (whatever else they can do) are (i)equivalent and (ii) completely useless. Speciﬁcally, once a process can diverge, we
6 On the other hand, the traces model and a reﬁnement of it we will be meeting in Section 8.4,
the stable failures model, allow one to see beyond any divergence by ignoring divergence altogether.

3.3

A basic guide to failures and divergences

97

assume (whether it is true or not) that it can then perform any trace, refuse anything, and always diverge on any later trace. divergences(P ) thus contains not only
the traces s on which P can diverge, but also all extensions sˆt of such traces. We
also need extended, strict sets of traces and failures when working with divergences:traces ⊥ (P ) = traces(P ) ∪ divergences(P )failures ⊥ (P ) = failures(P ) ∪ {(s, X ) | s ∈ divergences(P )}You can think of the second of these as saying that a process which is diverging is,in eﬀect, refusing everything. The representation of a process P in this model is(failures ⊥ (P ), divergences(P ))This can either be extracted from the transition graph by simply recording which
behaviours it can perform, as in Figure 3.3, or via clauses like those seen earlier
for traces(P ). The latter can be found in Section 8.3, as can further details of
the model, but for now it is quite suﬃcient for you to think primarily in termsof the former. That is, after all, essentially how FDR works out the failures anddivergences of a process. Your main aim in reading this section should, perhaps, beto understand what failures and divergence are, so that you know what it means
when FDR does the calculations involving them for you.
Because of the closure under divergence, over this model any process thatcan diverge immediately (i.e., without any visible communication) is equivalent to
div, no matter what else it may also be able to do.
P

One process failures/divergences-reﬁnes another, written P
Q when the context is clear), if and only if

FD Q (or justfailures ⊥ (P ) ⊇ failures ⊥ (Q) ∧ divergences(P ) ⊇ divergences(Q)(it turns out that this implies the corresponding relation for traces, so there is noneed to include that clause). div is the least reﬁned process under FD : div FD P
for all P .
The corresponding notion =FD of equivalence in the failures/divergencesmodel is the standard notion of equivalence for CSP processes over most of theliterature.7
Even though almost all of the correct processes one ever writes are divergencefree, we often need to be able to demonstrate that this is indeed so for ones we haveconstructed. This is why we need to go to the trouble of including divergence inour model of reﬁnement: if it were not there, we would have no way of telling if aprocess could diverge or not.
7 Though one needs to be careful with unboundedly nondeterministic ones.

98

Hiding and renaming

It is only when we know the failures and divergences of a process that we
can deﬁnitively tell whether it is deterministic or not. A process P is deﬁned to
be deterministic if, and only if, divergences(P ) = {} and sˆa ∈ traces(P ) ⇒(s, {a}) ∈ failures(P ). In other words, it cannot diverge, and never has the choiceof both accepting and refusing any action. It turns out that the deterministic
processes are exactly the maximal ones under FD – the processes that have noproper reﬁnements. P FD Q means, rather precisely, that Q is more deterministic
than P . Of the processes in Figure 3.3, only P1 is deterministic (as any processwith a deterministic transition system is, though the reverse is not true). We will
study the class of deterministic processes further in Part II of this book, especiallyin Section 9.1. The unique ﬁxed point (UFP) rule is valid with respect to both
failures and failures/divergences equivalence.
Failures and divergences in speciﬁcations
These three levels of reﬁnement – traces, failures, and failures/divergences – arewhat FDR allows you to check. Indeed, FDR stands for Failures/Divergences Reﬁnement.
The two new modes of reﬁnement F and FD allow us to formulate stronger
speciﬁcations of processes than are possible with traces reﬁnement, since you can
now make assertions about what a process can refuse and when it can diverge aswell as what traces it can perform. Just as with trace speciﬁcations, they canbe formulated either as behavioural speciﬁcations or, directly, as their characteristic processes. Thus deadlock freedom (either as a failures or failures/divergences
speciﬁcation) becomes the behavioural speciﬁcation∀ s.(s, Σ) ∈ failures(P )orref = ΣIn other words, P can never refuse all events; so there is always something it can do.
The right-hand form extends the convention seen on page 43, that tr represents anarbitrary trace, to the assumption that (tr , ref ) is an arbitrary failure (i.e., tr andref are respectively identiﬁers used to represent a trace and a refusal within a logicalexpression which thus becomes a predicate on failures). tr does not appear in theabove simply because this speciﬁcation is independent of traces. The characteristic
process of the above deadlock speciﬁcation is DF Σ , where
DF A ={a → DF A | a ∈ A}

DF Σ is, of course, the most nondeterministic deadlock-free process for, justas over the traces model, the characteristic process of any behavioural speciﬁcation
is equivalent to the nondeterministic choice of all processes that meet it. In similar

3.4

Tools

99

vein, the most nondeterministic divergence-free process (in the failures/divergencesmodel) is Chaos .
A speciﬁcation can be extremely abstract like the above, can be highly speciﬁc and attempt to deﬁne all the behaviour of one’s implementation – for example
if Q is a deterministic process such as B02 on page 85 then Q FD P is equivalent
to P =FD Q and so P must be a complete description of intended functional behaviour – or can be somewhere in between. A good example of the latter is the
buﬀer speciﬁcation which we will study in Section 5.1.
Divergence checking is a more complex activity than the rest of what FDR
does in its ‘checking’ phase, and therefore FD checks are slower. In practice weoften know that processes are divergence-free for independent reasons. The mostcommon use of failures checks is for proving full reﬁnements P FD Q for processes
P and Q that are already known (or are assumed) to be divergence-free. Indeed,at the time of writing, the author almost always structures a substantial failures/
divergences check this way. We will see some more sophisticated circumstanceswhere one has to check F rather than FD in later chapters.
Exercise 3.3.1
What failures/divergences reﬁnements hold between the following
processes: div, Chaos {a,b} , Chaos {a} , DF {a,b} , RUN {a,b} , RUN {a} , STOP, a → div anda → STOP? Which of them are deterministic?
Formulate a behavioural failures speciﬁcation (using the variables tr
and ref as discussed above) which asserts that a process must always accept the event a
if the number of a’s in tr is less than that of b’s in tr . What is the characteristic process(i) on the assumption that Σ = {a, b} and (ii) on the assumption that it is larger?

Exercise 3.3.2

3.4

Tools

The notation for hiding in machine-readable CSP is almost exactly the same as wehave used already: P\X, where X must be a set of events. While it is often convenient
to have X a single event or channel, or a set of channels, in written text, you must
convert it to the proper type for running. This is made easier by the {|a,b|}
notation, which corresponds to the notation {| a, b |} we have already deﬁned.
There is only one way of writing renaming, which (apart from the precise
way it is written) is a simple extension of the ‘substitution’ style renaming we saw
at the end of the section: you create a relation by using variations on the notation
P[[b <- a, d <- c]]
This relation maps b to a, d to c and leaves all other events alone. a,b,c,d can be
simple events or channel names. If you want to map one event to many (as in inverse

100

Hiding and renaming

function renaming) this can be done by using the same event on the left-hand sideof <- more than once: P[[a <- a, a <- b]] ‘shadows’ each a with the alternativeof a b. More sophisticated forms of this notation exist, in which the renamed pairs
are generated rather than explicitly listed: see Appendix B.
Process naming in the a.P style is not deﬁned in machine-readable CSP at
the time of writing. The reasons for this, which are connected with the type-theoryof channels, are discussed on page 112 (in connection with the main application ofprocess naming), together with how to get around this restriction.

Chapter 4

Piping and enslavement

In the previous chapter we pointed out that the most natural model of a real parallelsystem is probably to have a collection of processes synchronizing pairwise on theircommunications, and with these internal communications hidden. In this chapter
we see two operators which model common ways in which such systems are put
together. They are both derived operators, in the sense that they are both built
out of – and can thus be thought of as abbreviations for – other ones.

4.1

PipingA common and simple form of parallel composition is pipelining: taking a sequenceof processes which input on one channel and output on another, and connecting
them in sequence, the outputs of the r th process being fed into the inputs of the(r +1)th. We have already seen one example of this, namely the chain of COPY
processes.
If it has been decided to use this form of network and furthermore to hidethe internal communications, then the careful assignment of distinct labels to theindividual channels can be a little tiresome. The piping or chaining operator >>provides a more convenient way of creating such systems. It assumes that theprocesses have all been deﬁned so that their input channels are all called left andtheir output channels are all called right.1 If we combine two or more of them
together then it is natural that the input and output channels of the whole should
retain these names. Thus, P >> Q connects the right channel of P to the left channelof Q and hides these internal communications. This leaves the left channel of P
1 Of course the choice of this pair of names is somewhat arbitrary. Sometimes one sees in andout used instead.

102

Piping and enslavement

and the right channel of Q visible externally.
We can now write the sequence of COPY processes with hidden internal
communication as
COPY >> COPY >> . . . >> COPY
where the input and output channels are now left and right rather than c0 and cnof the previous example.
The piping operator can be expressed in terms of renaming, parallel andhiding: P >> Q =(P [[right, mid /mid , right ]] {|left,mid|} {|mid,right |}Q[[mid , left /left, mid ]]) \ {| mid |}where it is assumed left, right and the new channel name mid all have the same
type T . The reason for swapping the pairs (left, mid ) and (mid, right) rather thansimply using P [[mid /right ]] and Q[[mid /left ]] is to guard against the possibility that
P or Q might already have been able to communicate on the mid chosen. It makes
absolutely sure that the renamings we are using in this deﬁnition are 1–1.
Though this deﬁnition is actually symmetrical between left and right, thepiping operator is always used so that left is an ‘input’ channel (in the sense thatit accepts any element of {| left |} whenever it accepts any) and right is an ‘output’ channel. In other words, communications usually take the forms ‘left?x ’ and‘right!e’.
The piping operator is distributive in both its arguments (a fact that follows
from the distributivity of the operators used above to construct it) and associative.
(PQ) >> R = (P >> R)

P >>(Q

R) = (P >> Q)(Q >> R)

>>-dist-l

(4.1)(P >> R)

>>-dist-r

(4.2)

>>-assoc

(4.3)(P >> Q) >> R = P >>(Q >> R)

This last fact, which is so intuitively obvious that we have already taken advantage
of it without thinking in the COPY -chain, is actually rather subtle mathematically.2
In the left-hand side of the law, the communications between P and Q are hidden
before those between Q and R, and vice-versa on the right-hand side. It is intimately
2 A number of mathematical models have been discarded because they failed this test!

4.1

Piping103

tied up with the laws for interchanging parallel and hiding (hide-X Y -dist (3.7)
and hide-  -dist (3.8)).
X

There is also a range of laws for allowing us to compute the ﬁrst-step behaviour of P >> Q in common cases. These special forms are more easily applicablethan coding the entire set into a single law: in all of these it is assumed that x is
not free in Q nor y in P .
left?x → P >> left?y → Q = left?x → (P >> left?y → Q)

>>-step 1

(4.4)

right!x → P >> right!y → Q = right!y → (right!x → P >> Q)

>>-step 2

(4.5)

right!x → P >> left?y → Q = P >> Q[x /y]

>>-step 3

(4.6)

left?x → P >> right!y → Q = left?x → (P >> right!y → Q)
2 right!y → (left?x → P >> Q)

>>-step 4

(4.7)

The ﬁrst two correspond to the situation where only the left- or right-hand sides
can move because the other is stuck waiting for it. The third is what happens wheneach is willing to communicate across the hidden channel, and the ﬁnal one shows
the choice that appears when both are able to talk externally.
We can see these in operation if we consider the process COPY >> COPY .
This equals(left?x → right!x → COPY ) >>(left?y → right!y → COPY )= left?x → ((right!x → COPY ) >>(left?y → right!y → COPY ))(>>-step 1)= left?x → (COPY >>(right!x → COPY ))(>>-step 3)= left?x → (left?y → right!y → COPY >>(right!x → COPY ))= left?x → (right!x → (COPY >> COPY )2 left?y →(right!y → COPY >> right!x → COPY )) (>>-step 4)etc.
(By naming the various parallel terms, as we have done previously, this could havebeen shown equivalent by this unfolding to a very similar mutual recursion thatessentially the same process was proved equivalent to in the previous chapter.)

104

Piping and enslavement

While the above laws deal with all the cases where the process at either end
of >> is able to communicate exactly one of input and output, and we have theobvious cases of any input (left?x ) and only one output (right!x ) being possible,
it can of course happen that more complex situations arise. The following law
accounts for all of these cases: it is found by combining the step laws for parallel,
renaming and hiding (to the last of which it bears an obvious resemblance). If
P
Q= (left?x : A → P  ) 2 (right?x : B → P  )= (left?y : C → Q  ) 2 (right?y : D → Q  )(where any of A, B , C , D can be empty and, if not, A, C are likely to be the wholeof T and B , D are probably singletons), and x , y are respectively not free in Q, P ,thenP >> Q = (left?x : A → (P  >> Q)) 2 (right?y : D → (P >> Q  ))<I B ∩ C = {}>I(left?x : A → (P  >> Q)) 2 (right?y : D → (P >> Q  ){P  [z /x ] >> Q  [z /y] | z ∈ B ∩ C }

>>-step

The traces of P >> Q are simple to compute: assuming, for a slight simpliﬁcation,
P and Q only communicate in the set {| left, right |} they are3
traces(P >> Q) ={u ∈ {| left, right |}∗ | ∃ s ∈ traces(P ), t ∈ traces(Q).
∀ u  ≤ u. ∃ .s  ≤ s, t  ≤ t.
u  ↓ left = s  ↓ left ∧ s  ↓ right = t  ↓ left ∧ t  ↓ right = u  ↓ right}
Clearly this operator has its main uses modelling applications where information is passed along a sequence of processes. For example,
ITER = left?(data, input) → right!(data, F (data, input)) → ITER
is a process for performing one step of an iteration on some data. So if data is anumber andF (d , x ) =


d
x+
x

/2

then it carries one step of the Newton’s method approximation to a square root.
By piping N copies of ITER together we apply this number of iterations to each
3 In the ﬁrst edition of this book there was an error in this deﬁnition.

(4.8)

4.1

Piping105

data and starting value:
ITER >> ITER >> . . . >> ITER
Of course there is no reason why all the processes have to perform the same task.
The other primary application of the piping operator is in the study of communications mechanisms and protocols. A typical application here might be dealing
with a faulty communication channel, or simply one which uses a diﬀerent representation of information than the one we wish to deal with (encrypted, perhaps).
Suppose, therefore, that we wish to create a transparent channel of four-byte words
W , allowing a certain amount of buﬀering between two processes, when what weare supplied with is an unreliable channel M of bytes Byte which might lose or corrupt some proportion of its throughput. A good way of modelling this is to design
processes T and R (transmitter and receiver) such that
T >> M >> R∞
(page 19)
is a buﬀer of type W . A buﬀer is a process which, like COPY and B
copies information from its input to its output, preserving order and without loss,
and such that it never refuses to output an item it contains and will not refuse to
input when empty. We will give a formal speciﬁcation of this later (page 116).

The diﬃculty of deﬁning T and R will depend on just how bad we allow
M to be. Our task might be made easier by splitting each of the processes into
two: T = T1 >> T2 and R = R2 >> R1 should be such that T2 >> M >> R2 isa buﬀer of some type which it is easier to correct than W over the medium M(probably Byte or bits {0, 1}) and T1 >> B >> R1 a is a buﬀer of type W whenever
B is one of the intermediate type. This modularization could be taken further bydividing the problem into yet more layers. See Exercises 4.1.3 and 4.1.4 for detailsof what the processes we have been discussing might look like. The idea of dividing
communications protocols into layers like this is of great practical importance since
it allows a separation of concerns (e.g., dealing with security, error correction, andmessage structuring separately).
There is a natural relationship between the piping operator and buﬀers. It
will generally be true, for example, that P >> Q is a buﬀer if P and Q are. This
will be discussed more in the next chapter.
By combining >> with recursions, we can deﬁne dynamically expanding
chains of processes. For example, we can deﬁne an inﬁnite-capacity buﬀer with∞without using inﬁnite mutual recursion, just as ||| althe same behaviour as B
lowed us to do this with COUNT .
B + = left?x → (B + >> right!x → COPY )106

Piping and enslavement

Since the deﬁnition of piping involves hiding, we are not trivially able toassert that this recursion is constructive or guarded. In fact it is, and a formal
proof of this (for which we will need further mathematical machinery) follows thepattern of the informal argument below.
A recursion P = F (P ) is constructive if, in order to see n + 1 steps of the
behaviour of F (P ), we need only explore n steps of the behaviour of P . In otherwords, if P and P  are indistinguishable up to and including n communications,then F (P ) and F (P  ) are indistinguishable up to and including n + 1. Now theinitial input of the B + recursion clearly gives one step of behaviour without referringat all to the recursive call, so it will be enough to show that the process
B + >> right!x → COPY
that follows it is non-destructive: has always communicated as many actions as
it has used of B + . But this is actually rather obvious, since every communicationof B + is either visible (contributing to the length of the trace) or an output toright!x → COPY . But this latter process has always output at least as many things
as it has input, so every communication of B + that gets hidden is compensated forby one of these outputs. For the mathematics underpinning this argument, see
Section 8.2.
Show that if P and Q satisfy the trace speciﬁcation of a buﬀer:
Exercise 4.1.1
tr ∈ {| left, right |}∗ ∧ tr ↓ right ≤ tr ↓ left, then so does P >> Q.
Newton’s method of approximating the square root of a positive number x is, starting with an arbitrary guess r0 , to set rn+1 = (rn + x /rn )/2.

Exercise 4.1.2(i) Devise processes INIT and FINAL such that
INIT >> ITER >> ITER . . . >> ITER >> FINAL
inputs a number and outputs the N th iteration (there being N copies of the ITER
process deﬁned earlier). Choose x /2 as the ﬁrst guess at the square root.
(ii) Now, by using the pattern of recursionP=

left?(d, r ) → ((right!r → P ) I b I (I (d, x ) >> P ))where you should specify what b and I are, create a system which iterates as manytimes as it has to so that | r 2 − x |<  ( is a small positive constant). What
happens if the second number input to this dynamic network takes less, the same,or more iterations than the ﬁrst?

4.2

Enslavement

107

Exercise 4.1.3 Devise processes T1 and R1 that unpack a word of four bytes into its
individual 32 bits, and pack them up again. Thus, T1 >> R1 should be a buﬀer for words,
though the internal channel should be passing bits. (The best way to represent a word is
as a sequence of 32 bits.)
Exercise 4.1.4
M is to be a model of an unreliable medium which transmits values
in the set {0, 1, 2}. It sometimes loses data, but must transmit at least one out of every
N . Deﬁne the processes Mi for i = 0, 1, . . . , N −1, where Mi behaves like M0 except thatit may lose i values before being obliged to transmit one correctly. Which of these is theappropriate deﬁnition of M ?
Now deﬁne processes T † and R † such that T † >> M >> R † is a buﬀer of type {0, 1},
and explain informally why your deﬁnition works. Hint: use the value 2 as a punctuation
mark between transmitted values, using suﬃcient repetition to ensure one of each block
gets through.
Harder : do the same thing when the type of the medium is only {0, 1}.

4.2

Enslavement

It is useful to have an operator representing the situation where one process acts
as the slave of another. The slave is only allowed to communicate with its master,and all communications between master and slave are hidden. The general case ofthis operation is written
P //Y Q
which means the same as (P Σ Y Q) \ Y . It is usual to use it in the case where theslave has some name, m say, and the master’s communications with the slave arejust those with the name m in the same sense we saw it applied in process naming
earlier. This special form is written
P //m:Q
which means the same as P //M m.Q where M is the set of all elements of Σ of theform m.a.
As with >>, the laws and trace-set of P //Y Q can be deduced from thoseof the operators it is built from. Just as >> is associative, meaning that we canintroduce and hide the internal communications in either order, enslavement satisﬁes
the following law, which one might term a symmetry principle: if Y ∩ Z = {} then(P //Y Q)//Z R = (P //Z R)//Y Q

//-sym

(4.9)

108

Piping and enslavement

so, in particular, if m and n are distinct names then(P //m:Q)//n:R = (P //n:R)//m:Q
Enslavement is, of course, distributive in each argument and, like >>, it is best in
most cases to divide the step law into a number of commonly-occurring cases rather
than dealing with the most general one all the time. These are left as an exercise.
One common use of enslavement is to represent one process providing acomputational service to another, analogous to a (remote) procedure call. For
example, if we were modelling a microprocessor, it might well be appropriate torepresent the ﬂoating-point unit (FPU) as a slave to the CPU. The FPU mightthen be abstractly modelled by the process
FPU = fpreq?(data, op) → fpout!fpu(data, op) → FPU
where fpu is a function deﬁning the appropriate result for each ﬂoating-point calculation. In the combination CPU // fp:FPU the CPU would then send requests
to the FPU by a communication such as fp.fpreq!((a, b), +), and could then carryout some more operations before it required the result of this combination, whichit could get by inputting fp.fpout?x .
If the designer required a higher MFLOP rate (i.e., ﬂoating point speed) than
was obtainable from this simple server, there are at least two approaches he could
take to get greater performance. One would simply be to provide more FPUs, sothat with two of them the combination might look like
(CPU // fp1:FPU )// fp2:FPU
Rather than provide two entirely separate boxes, he might prefer to split one into
several phases by pipelining, so that it is able to handle more than one operation ata time. If there were three of these (perhaps denormalizing and aligning in FPU 1,
arithmetic in FPU 2 and normalizing, error detection and handling in FPU 3), theFPU might then become something like
(FPU 1 >> FPU 2 >> FPU 3)[[fpreq, fpout /left, right ]]and able to deal with three computations at once. This approach has the advantagethat it probably requires less extra silicon than providing three independent units,
but the disadvantages that one must always take the results in the order in which
the data was entered and that unless the three phases are well-balanced in the timethey take (probably not true in this case) the performance would not be so good.
Another use of enslavement is to provide a CSP process with access to a state
which can be assigned to, read from, or have other similar operations applied to it.

4.2

Enslavement

109

A slave process representing a simple variable might be written
VAR(x ) = assign?y → VAR(y) 2 read!x → VAR(x )The starting value of the variable could be dealt with by introducing a special error
value, or by making the initial state{VAR(x ) | x ∈ T }We can take this idea further and provide more complex data structures with
diﬀerent operations. These can, of course, be represented as a non-parallel CSP
process with appropriate internal state. In the case of some dynamic structures
there are interesting ways of modelling them via a combination of enslavement andrecursion.
Example 4.2.1 (sets via enslavement) If we want to model a ﬁnite set towhich we can add elements, remove them, and test for membership, then this canbe done with the recursive process deﬁned
SET= add ?x → (Cx //m:SET )2 del ?x → SET
2 isin?x → no → SET ,

where

Cx

= add ?y → (Cx <I y = x>I m.add!y → Cx )2 del ?y → (E <I y = x>I m.del!y → Cx )2 isin?y → (yes → Cx <I y = x>I
m.isin!y → m?a : {yes, no} → a → Cx )E

= add ?y → m.del!y → Cy
2 del ?y → m.del !y → E
2 isin?y → m.isin!y → m?a : {yes, no} → a → E

This works by holding the ﬁrst object entered and storing the rest of the set in arecursively called slave set. Cx represents one cell of the resultant network whichcontains x , while E is one which is empty because the last thing it held has been
deleted. Notice that when E is reﬁlled (which it is by the ﬁrst new element to comealong) then the same element is deleted from E ’s slave. This is necessary to get thesystem to work correctly – see if you can work out why.
The essential feature of this recursion is that it creates a network composedof a lot of simple cells, each of which was generated by one recursive call and which
can in turn make similar recursive calls. In the case above the network is always
a chain (though rather diﬀerent from the sort created by >> since it does all its

110

Piping and enslavement

external communication at one end), because each cell only has one potential slave.
If there are two then we get a binary tree, and so on.4 (End of example)
Using a similar strategy we can create an interesting version of the muchused example of a counter, in which each cell either knows that it and its slave are
set to zero (and communicating the event iszero) or that its slave is set to exactly
one less than itself.
Zero //=

up → (Succ//m:Zero // )2 iszero → Zero //

Succ

=

down → (m.iszero → NoSucc)
2 m.down → Succ)
2 up → m.up → Succ

NoSucc=iszero → NoSucc
2 up → Succ

This is well-deﬁned and is equivalent to the obvious sequential counter process with
the iszero event added to the zero state. An interesting variant can be found in
Section 8.2, where we study how ﬁxed points of recursions like this evolve and can be
regarded as constructive despite the presence of hiding in the enslavement operator.
Example 4.2.2 (quicksort) Many divide-and-conquer algorithms can be implemented as parallel CSP ‘programs’ using recursive enslavement. For example, thefollowing gives a version of quicksort.
Qsort

IN x

= last → end → Qsort
2 in?x → ((IN x //up:Qsort)//down:Qsort)= in?y → ((up.in!y → IN x )<I y > x>I (down.in!y → IN x ))2 last → up.last → down.last → OUTAx

OUTAx= up.out?y → out!y → OUTAx
2 up.end → out!x → OUTB

OUTB

= down.out?y → out!y → OUTB
2 down.end → end → XX= last → end → X
2 in?x → INx

4 No network created using enslavement alone can be anything other than a tree – a connected
network with no cycles. We will ﬁnd that trees play an important role in our discussion of deadlock
in Chapter 13.

4.2

Enslavement

111

Qsort takes a sequence of values on channel in, the end of which is signalled by last.
It then sorts these into descending order and outputs them on out, indicating theend of the output phase by end . The ﬁrst element of the input list is used as thepivot for quicksort, which is applied recursively to the elements of the remainderof the input which are respectively greater than, or less-than-or-equal-to, the pivot.
The state X is present so that the network can be re-used: see if you can understandwhat happens when this occurs. (End of example)
Create case-by-case step laws for (?x : A → P  )//Y (?x : B → Q  ).
You should deal (at least) with the cases A ∩ Y = {} and A ⊆ Y ∧ (Y ∩ A ∩ B ) = {}.
What is the general step law (recalling >>-step (4.8))?

Exercise 4.2.1

Deﬁne a one-step tail recursion COUNT † that behaves equivalently
to Zero // and prove this equivalence using the UFP rule and the laws you deﬁned in theprevious exercise. You can assume, if required, that the Zero // recursion is constructive.

Exercise 4.2.2

Hint: the most elegant way to prove this equivalence is probably in two applicationsof UFP. The ﬁrst shows that a vector whose (n+1)th component is Succ//m : COUNT †n(you should deﬁne the 0th component) is equivalent to COUNT † . The second uses thisto justify an application of UFP to the Zero // recursion. It can also be done directly but
you then have to be careful with the fact that Zero // has many states corresponding to eachn∈ .

Exercise 4.2.3 Mergesort is another divide-and-conquer sorting algorithm. It works
by dividing the input list into two parts (as equal as possible in length), recursively sortingthese, and then merging the two sorted results into a single sorted list. Adapt the strategy
used above for quicksort, copying the recursive structure of a master and two slaves, togive a CSP version of this.
Hints: split the input by sending odd- and even-numbered elements of the input,
respectively, to the two slaves. Be careful that your design does not diverge for an input
list of length 1.

Exercise 4.2.4

Produce a modiﬁed version of the process SET which does all of thefollowing.
(a) The elements are stored in increasing order: if a cell receives an add.x with x lessthan its current value y, then y is pushed on and x retained.
(b) The invariant preserved by (a) is exploited when deciding whether to send a del orisin message to the slave.
(c) It is possible for the element held by a slave to drop down into its immediate master
if the master has become empty (via a del or by doing this new function with its
own master).
(d) The set can always communicate on one of two new channels: least.x outputs theleast element from the set (the one held in the lowest cell) and removes it from theset, and isempty can be communicated whenever it is empty.

112

Piping and enslavement

In what ways is this new version more eﬃcient than the original? How would you convert
it into a process (externally) equivalent to the original?

4.3

Tools

The piping and enslavement operators are not directly supported by machinereadable CSP. The reasons for this are both related to the way this version of
the notation treats its channels.
The problem with the piping operator is the way it gives special importanceto the two channels left and right . There is nothing wrong with that in itself, butmany (perhaps most) large examples of pipes will involve a series of processes
P1 >> P2 >> . . . >> Pn−1 >> Pn
where the interfaces do not all have the same type. (Consider, for example, thelayered protocol idea described on page 105.) In order to make sense of such an
example it is necessary to be able to think of the channels left and right as having
diﬀerent types at diﬀerent points in the program: for obvious reasons this clashes
with the type discipline which says that each channel is declared with a single type.
There is no problem with the enslavement operator P //X Q itself: it does not
mention any speciﬁc channel and it is easy to deﬁne in terms of other constructs
which are supported. The problem comes because this operator is most often used
(as it was in this chapter) in its ‘named slave’ form P //a : Q. Machine-readable CSP
presently insists that each channel comprises an atomic name and a type. Adding
an extra name onto the beginning of an event does not preserve this discipline.
It is easy to achieve the same eﬀect of a named version of a process by usingparameterization and adding the name as a component of the type of each channel,
thus
B(n) = in.n?x -> out.n!x -> B(n)[] halt.n -> STOP
might replace n.B , whereB= in?x → out!x → B
2 halt → STOP

Since this is a signiﬁcantly diﬀerent style and it is easy to achieve the eﬀect ofenslavement via other constructs, it was decided not to include it directly in themachine-readable syntax.

4.3

Tools

113

One should also bear in mind that many of the most interesting examples of
the use of enslavement are dynamic networks (i.e., recursions through enslavement).
In their most natural forms these, being inﬁnite state, will not work on FDR, though
it can be entertaining to apply an animator such as ProBE to them.
It is, in fact, straightforward to re-create any network that comes out ofa pen-and-paper use of >> and //. This can either be done with the standard
parallel, renaming and hiding operators (in much the same way as these operators
were derived in the ﬁrst place) or using a recently-added construct speciﬁc to themachine-readable language. If (a1,b1), (a2,b2), . . . , (an,bn) are pairs of channels
where the two in each pair have the same type, thenP [a1 <-> b1, a2 <-> b2, ... , an <-> bn] Q
puts P and Q in parallel, joining the given pairs of channels together (with leftand right-hand ones of each pair being treated as a channel of P and Q respectively) and hides the resulting communications. Thus we can, if P and Q are twoprocesses that do not communicate outside {| left, right |}, implement P >> Q as
P [right <-> left] Q.
Unlike >>, this is not an associative operator and therefore must be fully
bracketed. The main cases where it fails to associate are where the diﬀerent uses ofit mention diﬀerent but overlapping sets of channels. We can, for example, achievea result very close to enslavement: suppose P is a process with arrays of channels
call.i and return.i (for i ∈ {1, . . . , n}) and that Slave is a process with channels
call’ and return’ designed to perform some subroutine. One can enslave n copiesof Slave to P by the construct(...(P [call.1 <-> call’, return.1 <-> return’] Slave)[call.2 <-> call’, return.2 <-> return’] Slave)...
[call.n <-> call’, return.n <-> return’] Slave)
Note how the same channels of the various copies of Slave are attached to diﬀerent
channels of P. Other bracketings of this would mean very diﬀerent (and generally
nonsensical in this context) things.
There are also extensions to allow the pairs of tied channels to be deﬁned by
a comprehension (as for sets and renamings, for example) and for combining a listof processes under a replicated version of the operator.
The example ﬁles on the web site that illustrate this chapter use this new
construct.

Chapter 5

Buﬀers and communication

We have already met buﬀer processes on numerous occasions. They are ones which
input data on one channel and output it in the same order on another. While
this may seem to be an extremely simple thing to achieve, you should bear in mind
that we might have to do so between two nodes of a complex and perhaps unreliablenetwork. Communications protocols are an extremely important application of CSP,
and it is almost certain that the appropriate speciﬁcation for such a protocol will
either simply be that it is a buﬀer, or be closely related to this. For that reason,
and also because they provide an excellent example of how to build and reason
about a CSP speciﬁcation, we will look in detail in this chapter at buﬀers, theirrelationship to the piping operator >>, and discuss some of the more elementarycommunications protocol topics.

5.1

Pipes and buﬀers

The trace speciﬁcation of a buﬀer is that its alphabet is left.T ∪ right.T for some
type T , and that for any trace s, s ↓ right ≤ s ↓ left.1 This is as much as we canusefully say with a trace speciﬁcation. This does, like any trace speciﬁcation, passsome unlikely processes, such as• STOP which never does anything• µ p.left?x → p which accepts inputs, but never gives them back1 Invariably T will be the type of left and right so that, for example {| left |} = left.T . We will

use whichever of these notations is most appropriate in future discussions of buﬀers, though theone on the left is problematic in cases where left and right may be used with diﬀerent types in theinternal and external channels of a buﬀer constructed as a chain.

116

Buﬀers and communication• µ p.left.0 → right.0 → p which transmits only 0’s• STOP

COPY , which may behave perfectly, but may also deadlock.

All of these fall short, in one way or another, because they either may, or must,refuse some communication we might reasonably expect a buﬀer to agree to. What
we need is to use a failures/divergences speciﬁcation stating:(i) All a buﬀer does is input on left and output on right. It correctly copies all
its inputs to its output channel, without loss or reordering.
(ii) Whenever it is empty (i.e., it has output everything it has input) then it
must accept any input.
(iii) Whenever it is non-empty, then it cannot refuse to output.
This can easily be translated into a speciﬁcation in terms of failures anddivergences. Since a diverging process is not responding to its environment; whether
an input or output is expected of it, it is clear that we cannot allow a buﬀer todiverge. We therefore stipulate that, for any buﬀer B , divergences(B ) = {}. The
rest of the speciﬁcation is then:(i) s ∈ traces(B ) ⇒ s ∈ (left.T ∪ right.T )∗ ∧ s ↓ right ≤ s ↓ left(ii) (s, X ) ∈ failures(B ) ∧ s ↓ right = s ↓ left ⇒ X ∩ left.T = {}(iii) (s, X ) ∈ failures(B ) ∧ s ↓ right < s ↓ left ⇒ right.T ⊆ X
These conditions simply translate the corresponding English clauses into mathematics. You should note, in particular, the statements that (ii) and (iii) make about therefusal set X : (ii) asserts that X ∩ left.T = {}, or in other words there is no elementof left.T that the process can refuse; (iii), on the other hand, states right.T ⊆ X ,a much weaker statement simply saying that there is some output available (if wegive it the opportunity to choose any output, it cannot refuse). This reﬂects theasymmetry between input and output, for we expect the environment to choose
what happens on left, but the process to choose what is output on right. In fact,of course, we can predict exactly which output will appear from (i) – if any output
other than what we would expect then the trace speciﬁcation would fail. It would
have been equivalent to have stated the following in place of (iii), which ‘looks up’
the next output:(iii) (s, X ) ∈ failures(B ) ∧ (s ↓ right)ˆa ≤ s ↓ left ⇒ right.a ∈ X
Any behavioural speciﬁcation based on failures will follow a pattern somewhat like the above, with a (possibly vacuous) condition on traces combined with

5.1

Pipes and buﬀers

117

various assertions about what the process may refuse after various classes of trace.
Newcomers to this ﬁeld are frequently over-optimistic about how much one can deduce about the traces from what is stated about refusals. It is tempting to believethat statements like (iii) , which state that a particular thing must be oﬀered, imply
that the next event will be that one. This is not so, and even if we were to statethat refusals(P /s) = {X | a ∈ X }, this would not imply that the next event is a –for the process might be able to nondeterministically accept or refuse some otherb. The principle to follow here is that, if you want to limit what traces a process
can do, then you should do so with a trace speciﬁcation like (i) above.
Examples of processes that satisfy the above speciﬁcation are COPY and∞. Just as with behavioural trace speciﬁcations, any satisﬁable behavioural failB
ures or failures/divergences speciﬁcation has a most nondeterministic process satS , where S is the set of all processes meeting the speciﬁcation. In
isfying it:
most practical cases this process can be expressed elegantly in CSP in a way thatreﬂects the structure of the speciﬁcation. We have already seen the speciﬁcations
for deadlock freedom (DF ) and divergence freedom (Chaos ) amongst many others.
The characteristic process of the buﬀer speciﬁcation is BUFF  where
BUFF 
BUFF sˆa= left?x → BUFF x 
= ((left?x → BUFF x ˆsˆa )2 right!a → BUFF s

STOP )∞
This, like B, keeps a record of its current contents. However, what it can refuse isgoverned by the speciﬁcation above: it cannot refuse to input when empty, but caneither accept or refuse an input when non-empty; it cannot refuse to output when
non-empty. In general, a process B is a buﬀer if, and only if, BUFF  FD B .
∞, BUFF  is inﬁnite state and therefore its usefulness for automated
Like B
checking is limited (see Section 5.4 for more details). If you are trying to establishthat a process B is a buﬀer by proving BUFF  FD B with FDR, then if this ispossible there is (as B must certainly be ﬁnite state itself for this to be a reasonableproposition) some limit N on the buﬀering capacity of B . If using a tool where it
is either impossible or ineﬃcient to deal with inﬁnite-state speciﬁcations, in orderto prove B is a buﬀer you can make an estimate of N , and attempt to proveN
BUFF N
FD B , where BUFF  is the most nondeterministic N -place buﬀer:

BUFF N
BUFF Nsˆa= left?x → BUFF Nx = (((left?x → BUFF N
STOP )
x ˆsˆa )<I #s < N −1>
I STOP )2 right!a → BUFF Ns

118

Buﬀers and communication

If the attempt to prove reﬁnement fails this will be for one of two reasons: either
your estimate of N was too low, or B is not a buﬀer. You can tell which one of theseis the problem either by inspecting the counter-example behaviour provided by thetool, or by checking against the following process, which we will call an N -place
weak buﬀer: it behaves like a buﬀer provided the environment does not over-ﬁll it(with more than N things) but breaks if this does happen= left?x → WBUFF Nx 

WBUFF N= ((left?x → (WBUFF N
I #s < N −1>
I div))
x ˆsˆa <STOP )
2 right!a → WBUFF Ns

WBUFF Nsˆa

If your process reﬁnes WBUFF N
 this does not mean it is a buﬀer, but doesmean that the reason why it failed BUFF N
 was because it could take in more thanN things at once. The strategy should then be repeated with a larger value of N .
If your process fails to reﬁne WBUFF N
 then it certainly is not a buﬀer. The
N
and
BUFF
have
a ‘sandwiching’ eﬀect on BUFF  : for
speciﬁcations WBUFF N


any N
WBUFF N

N +1
FD WBUFF 
FD BUFF 

...

N +1
FD BUFF 

FD . . .

FDN
FD BUFF 

Furthermore, one can show that any ﬁnite-state process that reﬁnes BUFF  willreﬁne BUFF N
 for suﬃciently large N , and a ﬁnite-state process that fails to reﬁne
2
BUFF  will fail to reﬁne WBUFF N
 for suﬃciently large N .
The piping operator >> is intimately connected with the buﬀer speciﬁcation,
as is shown by the following buﬀer laws.
BL1. If P and Q are buﬀers, then so is P >> Q. Note that this statement isequivalent to the fact that
BUFF 

FD BUFF  >> BUFF 

since the (monotonic) properties of reﬁnement mean that this single reﬁnement implies our law.
2 This is in part because the process BUFFN
 is the least upper bound of {WBUFF  | N ∈ Æ }.
See Chapter 8 and Appendix A for more details.

5.1

Pipes and buﬀers

119

BL2. If Q uses only the events left.T ∪right.T , and P and P >> Q are both buﬀers,
then Q is a buﬀer. This law represents a kind of quotient result comparedwith the product in BL1. It is also true on the other side, as shown by thenext law.
BL3. If P uses only the events left.T ∪right .T , and Q and P >> Q are both buﬀers,
then P is a buﬀer.
BL4. If P >> Q is a buﬀer and x is not free in either P or Q, then the following
process is also a buﬀer:
left?x → (P >> right!x → Q)
This process makes an arbitrary input (as any buﬀer must as its ﬁrst step),
and then behaves like the buﬀer P >> Q with the additional ability to output
what was input. While this result is a sometimes useful technical fact, thenext law, which is a kind of inverse to it, is the main analytic technique used
to prove that piped systems that are not entirely composed of smaller buﬀers,
are themselves buﬀers.
BL5. If x is free in neither P nor Q, which are such that
P >> Q FD left?x → (P >> right!x → Q)
then P >> Q is a buﬀer. This is a sort of inductive principle which, veryloosely paraphrased, says: if what the process does at ﬁrst is OK, and it
then reﬁnes an earlier view of itself, then everything it does is OK. Sometimes
when applying this law one ﬁnds that it is not general enough because P >> Qevaluates to left?x → (P  >> right!x → Q  ) for some other processes P  andQ  for which you suspect P  >> Q  is also a buﬀer. By doing this repeatedly
one might ﬁnd a set {Pλ >> Qλ | λ ∈ Λ} of piped combinations and ﬁndoneself using the following rather more complex generalization of BL5.
BL5 . If x is free in neither Pλ nor Qλ for any λ in Λ, a non-empty indexing set,
and for each λ ∈ ΛPλ >> Qλ FD left?x →{(Pλ >> right!x → Qλ ) | λ ∈ Λ}

then each Pλ >> Qλ is a buﬀer.
The applications of BL1 are many and obvious: for example, it shows that any
chaining-together of any ﬁnite number of buﬀers using >> is still a buﬀer. BL2
and BL3 are more subtle properties. They might well be used in combination with
BL5: if that rule can show P >> Q is a buﬀer and we already know that one of P

120

Buﬀers and communication

and Q is, then so is the other by BL2 or BL3 (see Exercise 5.1.3). We will see anapplication of BL4 a little later. But our main examples for this section will be on
the use of BL5 and BL5 , for these are both the most complex of the laws and theones that can establish the strongest-seeming results.
The form of BL1–BL3 ensures that all the visible uses of the channels left
and right have the same type. However, in BL4–BL5 , there is nothing to preventthe internal channel of the pipe having a diﬀerent type to the external one, andindeed these laws are frequently used when this is the case. See Exercise 5.1.2, forexample.
As an extremely simple example of BL5, suppose T = N, the natural numbers
and thatPQ= left?x → right !(2 × x ) → P= left?x → right !(x /2) → Q

then P >> Q is a buﬀer by BL5 because of the following simple calculation:

P >> Q= left?x → (right!(2 × x ) → P >> Q)

by >>-step 1

= left?x → (P >> right!((2 × x )/2) → Q) by >>-step 3
= left?x → (P >> right!x → Q)

Example 5.1.1 (overcoming message corruption) For a larger example, suppose we are faced with a communication medium E that corrupts occasional messages. We want to overcome these errors by constructing processes S and R suchthat S >> E >> R is a buﬀer. To do this we have to make some sort of assumption
about how bad E is: our task would be impossible if it could corrupt any or all messages. Let us assume it can store only one message at a time, can corrupt at mostone out of any three consecutive messages and, for simplicity, that the messages
being passed are simple bits (0 or 1). We can build a CSP process that represents
the medium: namely the most nondeterministic one that satisﬁes our assumptions
about its behaviour. E = E0 , where5.1

Pipes and buﬀers

121

E0

= left?x → (right!x → E0

right!(1−x ) → E2 )En+1

= left?x → right!x → En

for n = 0, 1

Here, En is the process that is obliged to transmit n values correctly before being
allowed to corrupt another. Notice that though E0 can corrupt the ﬁrst bit itreceives, it does not have to, and only becomes obliged to transmit two properly
when it does in fact corrupt one. A process that reliably corrupted every third bit
would be much easier to overcome than this one. Notice that (as P Q P )E0= left?x → (right!x → E0 right!(1−x ) → E2 )left?x → right!x → E0 = E1

and hence
E1 = left?x → right!x → E0

left?x → right!x → E1 = E2

In other words, E0 E1 E2 , which should not be very surprising given that the
only diﬀerence between these processes is how long they have to wait before being
allowed to corrupt a bit.
Notice how the fact that CSP can describe nondeterministic systems (having
the operator) means we can describe system components over which we have nocontrol and which might be nondeterministic. While it would be a strange decision
to use operators like in a process we are designing to build, having them is usefulin cases like this. What we are in fact doing is to use for E the speciﬁcation we areassuming it meets. Of course if, in reality, E fails to satisfy this speciﬁcation then
any results you may have proved are invalidated.
The obvious technique for overcoming the sort of error displayed by this E isto transmit each message three times through E and to take a majority vote. The
process descriptions for the sender and receiver process are
Smaj= left?x → right !x → right!x → right !x → Smaj

Rmaj

= left?x → left?y → left?z → right!(x <I x = y>I z ) → Rmaj

We can use BL5 to prove Smaj >> E >> Rmaj is a buﬀer using the decoma
position (Smaj >> E ) >> Rmaj (i.e., the ‘P ’ of BL5 is Smaj >> E ). Denote by Rmaj
,
a,b
a,b,c
Rmaj and Rmaj the process Rmaj after inputting the values a, a and b, or a andb and c respectively (in the given order). Smaj >> E >> Rmaj equals the following

122

Buﬀers and communication

series of processes, derived methodically using the step and distributive laws of >>.
left?x →(((right!x → right!x → right!x → Smaj )by >>-step 1 twice>> E0 ) >> Rmaj )= left?x →((right!x → right!x → Smaj )>>(right!x → E0 right!(1−x ) → E2 )>> Rmaj )by >>-step 3

= left?x →((right!x → right!x → Smaj )1−xx) (E2 >> Rmaj)))>>((E0 >> Rmajby >>-step 3 and >>-dist-l

= left?x →(((right!x → right!x → Smaj )x))>>(E0 >> Rmaj((right!x → right !x → Smaj )1−x)))>>(E2 >> Rmaj

by distributivity

This represents its ‘state’ after the ﬁrst of the triple communications has takenplace. Similar derivations shows that after the second communication it isleft?x →x ,x))(((right!x → Smaj ) >>(E0 >> Rmaj
x ,1−x((right!x → Smaj ) >>(E2 >> Rmaj )))1−x ,x((right!x → right !x → Smaj ) >>(E1 >> Rmaj)))
and that when all three communications are taken account of it is equivalent toleft?x →x ,x ,x))((Smaj >>(E0 >> Rmaj
x ,x ,1−x(Smaj >>(E2 >> Rmaj))
x ,1−x ,x(Smaj >>(E1 >> Rmaj))
1−x ,x ,x(Smaj >>(E0 >> Rmaj)))
x ,x ,x
x ,x ,1−xx ,1−x ,x1−x ,x ,xSince Rmaj
, Rmaj, Rmajand Rmajall equal right!x → Rmaj , distributivity implies this equals

left?x → (Smaj >>(E0
which, since E0

E1

E2

E1

E0 ) >> right!x → Rmaj )E2 , equals

left?x → (Smaj >> E0 >> right!x → Rmaj )5.1

Pipes and buﬀers

123

which is exactly what is required to prove our result using BL5. (End of example)
In the above example we took advantage of the properties of and reﬁnement
to convert what was rather a complex expression for the ‘ﬁnal’ state – we were left
with the possibility of any one of E0 , E1 and E2 in the middle – into what we
wanted for the basic form of BL5. The more complex second form BL5 exists forcases where we are not so lucky and where the states our system gets into after
transmitting the ﬁrst communication cannot be reconciled into the original one. It
can be applied both in cases where the choice is nondeterministic, as above, or incases where the system simply goes through an evolutionary cycle. As an exampleof the latter, consider the following.
Example 5.1.2 (parity bits) A pair of processes IP and CP , again transmitting
bits, insert an extra parity bit after each group of 8, and respectively check anddiscard this bit. We might describe these processes as follows: IP = IP (0, 0) and
CP = CP (0, 0) whereIP (b, n) ==CP (b, n) ==left?x → right!x → IP (b ⊕ x , n + 1)

for n < 8right!b → IP (0, 0)

for n = 8

left?x → right!x → CP (b ⊕ x , n + 1)

for n < 8

left.b → CP (0, 0)

for n = 8Note that the combination will deadlock if CP is oﬀered the wrong parity bit atany stage.
To prove that IP >> CP is a buﬀer, it is necessary to consider all the pairs{IP (b, n) >> CP (b, n) | b ∈ {0, 1}, n ∈ {0, 1, . . . , 8}}
If n < 8, it is easy to show that
IP (b, n) >> CP (b, n) = left?x → (IP (b ⊕ x , n + 1) >>right!x → CP (b ⊕ x , n + 1))
while IP (b, 8) >> CP (b, 8) = IP (0, 0) >> CP (0, 0) which in turn equals
left?x → (IP (x , 1) >> right!x → CP (x , 1))
It follows trivially that, for each b and n ≤ 8,
IP (b, n) >> CP (b, n)  left?x →{IP (b  , m) >> right!x → CP (b  , m) |b  ∈ {0, 1}, m ∈ {0, 1, . . . , 8}}

124

Buﬀers and communication

which is what is needed to show that each of these combinations is a buﬀer by BL5 .
(End of example)
Applying BL5 has much in common with applying the UFP rule: you need
to identify the set of states the system under consideration can go through, andshow that each of them behaves properly. In the present case each state is a pairof processes (P , Q) (corresponding to P >> Q): the way the right-hand side of therule separates these makes this very important. You should note that it is possible
to have P , Q, P  , Q  such that
P >> Q = P  >> Q  ,butleft?x → (P >> right!x → Q) = left?x → (P  >> right!x → Q  )Examples are P = Q = COPY , P  = right!0 → COPY , Q  = left?x → COPY .
Fixed-point induction
The following principle – which we will call ﬁxed-point induction – can be used toprove that a recursive deﬁnition meets a speciﬁcation. It has similarities both withlaws BL5 and BL5 above, and also with the principle of unique ﬁxed points. As
with both of these, we can state a simple version for a single process, and a more
involved one for vectors of processes deﬁned by mutual recursion.
Fixed-point induction (single recursion)3 If P = F (P ) is any recursive definition such that either it is guarded/constructive or it defines a divergence-freeprocess, and Q is such that Q FD F (Q), then we may conclude Q FD P . In thecases of F and T this principle holds without the need to assume the either/or
condition of the recursion.
Note that, since F is always monotone, Q
statementQ

P =⇒ QF (Q) is equivalent to the

F (P )‘if P satisﬁes (the speciﬁcation) Q, then so does F (P )’.
For example, if F (BUFF  ) FD BUFF  for a well-behaved function F (·),
then the process deﬁned by P = F (P ) is a buﬀer. Consider the process
B + = left?x → (B + >> right!x → COPY )deﬁned in the previous chapter. If we accept the argument given there that thisrecursion is constructive, then ﬁxed-point induction and our buﬀer laws easily proveit to be a buﬀer. Suppose P is a buﬀer, then3 For the proof that this and similar rules are valid, see Section 9.2.

5.1

Pipes and buﬀers

125• P >> COPY is a buﬀer by BL1, which implies• left?x → (P >> right!x → COPY ) is a buﬀer by BL4.
• This proves what is required for ﬁxed-point induction; we can infer that B +is a buﬀer.
Fixed-point induction (mutual recursion) If P = F (P ) is any recursive
definition of a vector of processes which, as above, is either guarded/constructive
or makes each component divergence-free, with indexing set Λ, and Q is such that
Qλ FD F (Q)λ for all λ ∈ Λ, then we may conclude that Qλ FD Pλ for all λ ∈ Λ.
Again, in the cases of F and T this principle holds without the need to assume
one of the definedness conditions of the recursion.
As an example of this rule in action, consider the mutual recursive process∞B
deﬁned in Section 1.1.3. We asserted earlier that this is a buﬀer, a claim thatcan now easily be justiﬁed. We prove thatBs∞  BUFF s

for all ﬁnite sequences s.

To do this (since the B ∞ recursion is guarded) it is suﬃcient to prove that
BUFF

F (BUFF )where F is the function of the B ∞ recursion. This is veriﬁed by examining thedeﬁnition of BUFF , copied here from page 117
BUFF 
BUFF sˆa= left?x → BUFF x 
= ((left?x → BUFF x ˆsˆa )2 right!a → BUFF s

STOP )

Since removing nondeterministic options leads to a reﬁnement, we can conclude
that taking away the underlined option above leads to the inference that
BUFF 
BUFF sˆaleft?x → BUFF x 
(left?x → BUFF x ˆsˆa )2 right!a → BUFF s

which is precisely what was required (since the right-hand side is F (BUFF )).
It should be emphasized that ﬁxed-point induction is a very general techniqueand is certainly not just restricted to proving things are buﬀers.
Exercise 5.1.1 Re-formulate the buﬀer speciﬁcation in terms of the variables tr andref (as used in Exercise 3.3.2).

126

Buﬀers and communication

Take your answer to Exercise 4.1.3 and prove that it works. This isprobably an application of BL5.

Exercise 5.1.2

Show, using the buﬀer laws, that if

Exercise 5.1.3

B >> COPY = left?x → (B >> right!x → COPY )then B is a buﬀer.
Now show that B + >> COPY satisﬁes the recursive deﬁnition of B + and deducethat B = B + >> COPY . Thus complete an alternative proof that B + is a buﬀer.
+

A buﬀer works on the FIFO (ﬁrst in, ﬁrst out) principle. A stack, on
the other hand, is LIFO (last in, ﬁrst out): when non-empty, it will output the object it
contains that was most recently input. Give a failures speciﬁcation of a stack in the samestyle as that of a buﬀer: like a buﬀer it should not be able to reject input when empty or
to refuse to output when non-empty. Hint: you might ﬁnd it helpful to deﬁne the conceptof a stack trace recursively, based on the principle that whenever a stack outputs, the value
output was input as the ﬁrst member of a ﬁnal subsequence (suﬃx) s of the trace containing
equal numbers of inputs and outputs, and where s without its ﬁrst and last elements is itself
a stack trace.

Exercise 5.1.4

Show that COPY is a stack as well as a buﬀer. Are there any other processes
satisfying both speciﬁcations?

Exercise 5.1.5
Implement an inﬁnite stack using the enslavement-based recursive
scheme used for the SET recursion. It is easiest to do this using an isempty event in asimilar way. Since the stack speciﬁcation does not allow such an event, it must be bannedat the outermost level of the recursion only by parallel composition with STOP. Thus,
your result should look like
STACK STOP

where STACK  is recursively deﬁned.

{isempty}

Do the same thing without the isempty event: you should end up with a programthat is no longer but perhaps a little more subtle. You might or might not ﬁnd it helps here
to think about how one might eliminate the iszero event from the process Zero // deﬁned
on page 110.
A bag is a process that behaves in the same general way as buﬀers
and stacks, except that it can always output any object it contains (rather than being
restricted to FIFO or LIFO, for example). Give a failures speciﬁcation of a bag, and show
it is reﬁned by those for buﬀers and stacks. Hint: you will ﬁnd it helpful to construct orassume a function bag(t) that maps a sequence t ∈ T ∗ to the bag or multiset of elements
in it: the order of t is lost in bag(t) but the multiplicity of elements is retained. There are
obvious analogues of the usual set-theoretic operations over bags.

Exercise 5.1.6

5.2

Buﬀer tolerance

127

Exercise 5.1.7 If P1 and P2 are (i) buﬀers, (ii) stacks and (iii) bags, which of thefollowing compositions must have the same property? (a) P1 ||| P2 , (b) P1 >> P2 , and(c) P1P2 . Give brief reasons for your answers.
{|lef t,right|}

Suggest analogues of BL1–BL5 for bags using ||| rather than >>.
Which of them do you think is true?

Exercise 5.1.8

Suppose µ p.F (p) is a constructive recursion and it is conjectured that
F (P ) is deadlock-free whenever P is. What reﬁnement check is necessary to establish thisfact? Why would this prove that the recursive process is deadlock-free?

Exercise 5.1.9

Consider the two diﬀerent combinations of COPY with itself under the generalized parallel operator considered in Exercise 2.4.2. These can be chained
together in two ways: prove that one is a buﬀer and show that the other is not.

Exercise 5.1.10

5.2

Buﬀer tolerance

Consider the eﬀect of placing a buﬀer on a channel connecting two CSP processes. It
makes sense to do this on any channel which is used for communicating information
one way, though it may very well alter the behaviour of the overall system even inthis case: for example a buﬀer placed on the internal channel in COPY >> COPY
will still be a buﬀer (as is easily proved by BL1) but with increased capacity. This isa relatively subtle eﬀect which one probably would not mind in most circumstances,but (i) clearly it should not be allowed in any context where we are relying on abuﬀer capacity of two or less and (ii) there are other examples where inserting a
buﬀer in this way would have a much more signiﬁcant eﬀect.
The extent to which a given channel is buﬀer tolerant is a measure of whether,and how much, it relies on the CSP model of handshaken communication. It isfrequently desirable to make any channel that has to operate over a long distancebuﬀer tolerant since implementing the ﬂow-control necessary to avoid introducing
some buﬀering can be expensive.
A given channel may be buﬀer tolerant in an absolute sense, meaning thatthe semantics of the overall process does not change at all, or more likely, relative tosome overall speciﬁcation. Thus, COPY >> COPY is buﬀer tolerant relative to thespeciﬁcation of being a buﬀer! Sometimes a channel may be tolerant of buﬀering
up to some given limit or of any ﬁnite buﬀer but not inﬁnite capacity ones.
In the COPY >> COPY example any buﬀer which is placed on the internal
channels can clearly become full however large it is. Other examples, however, only
use a ﬁxed ﬁnite quantity of buﬀering no matter how much is provided. You cancharacterize such behaviour by testing whether one of the weak buﬀer processes

128

Buﬀers and communication

WBUFF n can safely be placed on the channel (the parameter n, of course, capturing the maximum amount of buﬀering ever used). If more than n buﬀer places wereever used, this experiment would produce a divergent process. For an example ofthis type of behaviour, see Exercise 5.2.2.
It is easier to understand the concept of buﬀer tolerance than to provide
general criteria under which it is true. Usually it is possible, with experience, toget a feel for whether a given system has this property: speciﬁc instances, at least
for small buﬀer sizes, can often be checked using tools like FDR.
The type of circumstances in which it does and does not tend to hold are
well illustrated by attempting to generalize the COPY >> COPY example to thefollowing general rule. It would be very convenient if the following plausible ‘buﬀer
law’ were true:
If P >> R and Q are both buﬀers, with the type of Q matching the ‘internal’
type of P >> R, then P >> Q >> R is also a buﬀer.
Unfortunately, this is not universally valid because of the possibility that R
might input selectively from P . As a simple example, suppose COPY 2 and COPY 3
are respectively deﬁned over the types T2 = {0, 1} and T3 = {0, 1, 2}. Then setting
P
Q
R= COPY 2 2 (right!2 → STOP )= COPY 3= COPY 2

gives a counter-example to the above (the internal type being T3 ): R has the good
sense to reject the oﬀer of 2 in the combination P >> R, which therefore behaves
exactly like COPY 2 >> COPY 2 . Putting Q in the middle, however, allows P to
make its fatal output and deadlock. If we take away the possibility of R controlling
what P outputs to it, the law becomes true:
BL6. Suppose P >> R is a buﬀer, where the internal type is T (i.e., the typecommunicated by right in P and left in R), and that(a) Q is a buﬀer of type T ,(b) if sˆleft.x  ∈ traces(R) and y ∈ T , then sˆleft.y ∈ traces(R), and(c) if (s, X ) ∈ failures(R) then {| right |} ⊆ X ⇒ left.T ∩ X = {},then P >> Q >> R is a buﬀer.
The side conditions (b) and (c) here avoid the possibility that we are relying on inﬂuence passing backwards (via handshaking) along the channel in question in orderto get the original system to work. They will automatically be satisﬁed provided

5.2

Buﬀer tolerance

129

R is deadlock-free and the only way it can communicate on left is by unrestricted
input. Inﬂuence of this sort more or less excludes the possibility of buﬀer tolerance
in any example. When looking to see whether there is such inﬂuence, you shouldbear mind that it can be much more subtle than in the COPY 2 /COPY 3 example
above, especially when there are other communication routes between the processes
connected by the channel in question: see Exercise 5.2.1. (Needless to say, buﬀer
tolerance makes sense over a much wider range of ways of connecting channels thanjust the >> operator.)
Notice how BL6 supports the concept of a layered protocol discussed on
page 105. If we have designed some pairs of processes (Ti , Ri ) such that eachTi >> Ri (i > 0) is a buﬀer, and it can be shown that T0 >> M >> R0 is a buﬀer forsome communication medium M , then BL6 and induction imply that
Tn >> Tn−1 >> . . . >> T1 >> T0 >> M >> R0 >> R1 >> . . . >> Rn−1 >> Rn
is one too, provided the Ri satisfy the no-selective-input criteria of BL6 and thetypes match up in the obvious way.
Exercise 5.2.1 (a) We can deﬁne a pair of processes that alternately use two channels to communicate as follows:
Divide=left?x → mid .1!x → Divide 

Divide =left?x → mid .2!x → Divide

Merge

=

mid ?n?x → right!x → Merge

DandM

=

(Divide{|mid|}

Merge) \ {| mid |}Plainly DandM acts as a two-place buﬀer: you can prove this easily with BL5 if you
interpret mid as a single channel and note that the above combination is then equivalenttoDivide[[right /mid ]] >> Merge[[left /mid ]]Do this and hence show that DandM is (relative to the buﬀer speciﬁcation) tolerant of
buﬀer of type {| mid |}.
(b) What would happen if we were to re-interpret mid as an array of two separate
channels and place buﬀers on each? Show clearly why the result need not be a buﬀer.
(c) Replace Merge with another process with the same alphabet so that the new
system is still a two-place buﬀer but is tolerant of separate buﬀers on mid .1 and mid .2.

130

Buﬀers and communication
The following processes carry messages alternately between two users:

Exercise 5.2.2
SwapL

=

leftin?x → to!x → SwapL

SwapL

=fro?x → leftout!x → SwapL

SwapR

=

to?x → rightout!x → SwapR 

SwapR =rightin?x → fro!x → SwapR

LandR

=

(SwapL{|to, fro|}

SwapR) \ {| to, fro |}Find a sequential process that LandR is equivalent to, and show that a copy of WBUFF 1
can be inserted onto both the internal channels without changing this value.
By adapting this example, ﬁnd a pair of processes connected by a pair of channels, one in each direction, that implement a buﬀer which is tolerant of the insertion of
WBUFF 1 onto both channels.
How does your answer to Exercise 5.2.1 (c) react to having this weak buﬀer inserted
onto either or both channels?
Show that if a channel is tolerant of WBUFF n then it is tolerant of
n+1
WBUFF  (relative to any behavioural speciﬁcation). Find an example of a system thatis tolerant of WBUFF 2 but not of WBUFF 1 .

Exercise 5.2.3

5.3

The alternating bit protocol

Earlier in this chapter we saw how to overcome the corruption of at most one inevery three messages. It is similarly possible (though harder, particularly in thecase where the ‘messages’ are just bits: see Exercise 4.1.4) to overcome bounded
loss, duplication or even a combination of all three together. By ‘similarly’ here, wemean that the overall system maintains the structure S >> E >> R.
In practical terms the sort of techniques used in these cases probably only
make sense in cases where very low level information (i.e., bits or little more) is
being transmitted, almost certainly between hardware components. Since there is
only a one-way passage of information there is no way R can let S know that a
particular message has got through, and so S must put as much redundancy into
the transmission of every message as is necessary to overcome the worst assumed
behaviour of the communication medium.
There are more advanced techniques that can be used in cases where larger
and more structured values can be passed as messages, and particularly where it ispossible to implement an acknowledgement channel (albeit faulty in the same sense
as the forward channel) back from R to S . When this channel cannot be implemented (or is impractical because of time delay – for example with the transmission

5.3

The alternating bit protocol

a
in -

131

-

b

C1

S

R



d

C2



out

-

c

Figure 5.1 The process structure of the alternating bit protocol.
delay, due to the ﬁnite speed of light, back from a remote space probe) the appropriate technology is a branch of mathematics called error correcting codes which isbeyond the scope of this book but which allows one to get the same sort of error
correction under corruption as was illustrated earlier, only with much greater eﬃciency. For various values of (n, k , d ) (for example (23, 12, 3)) one can ﬁnd ways ofcoding a k -bit message into n > k bits in such a way that the result can be decodedeven after up to e bits are corrupted. See [90] for a comprehensive introduction tothis subject.
When we can implement the acknowledgement channel there are a number ofprotocols that can be used to exploit it. It is usual to restrict attention in that case toa medium that can lose messages, or perhaps duplicate them, but cannot corrupt
them. This is, like so much else, an abstraction of what is really implemented:
it is likely that the protocols we are looking at are built on top of mechanisms
for inserting checksum-like information into messages and rejecting (i.e., ‘losing’)
messages which fail the corresponding tests when delivered.
We might want to implement a buﬀer between two distant points but only
have unreliable channels available. By this, we mean error-prone channels that canlose or duplicate as many messages as they wish – though not an inﬁnite consecutive
sequence – but preserve the value and order of those they do transmit. There are anumber of protocols available to overcome this sort of error, the simplest of which
is known as the alternating bit protocol (ABP). In fact, there are (as we will see inthis and later chapters, where we will frequently use it as an example to illustrate
new ideas) a number of variants of this protocol, but the basic idea is the same inall of them. The structure of the network used is shown in Figure 5.1, where thetwo error-prone channels are C 1 and C 2.
The basic idea is to add an extra bit to each message sent along the leaky
channels which alternates between 0 and 1. The sending process sends multiple
copies of each message until it is acknowledged. As soon as the receiving process
gets a new message it sends repeated acknowledgements of it until the next message
arrives. The two ends can always spot a new message or acknowledgement because

132

Buﬀers and communicationof the alternating bit.
This is usually described using real-time features such as time-outs (for deciding when to re-send messages and acknowledgements; we will return to this in
Section 14.5), but in fact with a little care it is possible to construct a version whose
correctness is independent of timing details. Below we present sender (S ) and receiver (R) processes which can readily be proved to work, in the sense that if C 1
and C 2 behave as described above, then the complete system behaves like a reliablebuﬀer.
Very general error-prone channel processes are described by the following,where no limit is placed on the number of losses or duplications:
C (in, out) = in?x → C  (in, out, x )(correct transmission)C  (in, out, x ) = out!x → C (in, out)
out!x → C (in, out, x ) (potential duplication)
C (in, out)(loss of message)
With the channels implied by Figure 5.1, we get C 1 = C (a, b) and C 2 = C (c, d ).
This sort of erroneous medium may lose as many messages as it likes, andrepeat any message as often as it wishes. While we can reasonably hope to createa system using such media which works as long as they do not commit an inﬁnite
unbroken series of errors (so that only ﬁnitely many messages actually get throughin an inﬁnite time), any such system will inevitably be subject to divergence caused
by inﬁnite message loss or repetition. One can easily change the deﬁnition so thatat least one correct action is performed every N as follows:
CN (in, out, r ) = in?x → C  (in, out, x , r )CN (in, out, x , 0) = out!x → CN (in, out, N )CN (in, out, x , r ) = out!x → CN (in, out, N )out!x → CN (in, out, x , r − 1)
CN (in, out, r − 1)

if r > 0

While this deﬁnition looks (and is!) very similar to that of E0 in the previous
section, there is the signiﬁcant diﬀerence that this time we are designing a protocolthat works independently of which N is chosen. The only function the limit N
actually performs should be to prevent divergences. In Chapters 10 and 12 we willmeet techniques that allow us to assume what we really want here, namely thatneither of the medium processes ever commits an inﬁnite sequence of errors.
The sender and receiver processes are now deﬁned as follows: S = S (0) and5.3

The alternating bit protocol

R = R(0){|b,c|}

133

Q, where for s ∈ {0, 1} and x in the set of messages:

S (s) = in?x → S  (s, x )S  (s, x ) = a.s.x → S  (s, x )2d .s → S (1−s)
2d .(1−s) → S  (s, x )R(s) = b.s?x → out!x → R(1−s)
2b.(1−s)?x → R(s)2c!(1−s) → R(s)If we were simply to set R = R(0) then the system could diverge even when
C 1 and C 2 were error-free, because it could get stuck communicating over C 1 orC 2 exclusively. (For example, the transmission of some message might happen
inﬁnitely without it ever getting acknowledged.) Therefore we have introduced
the extra process Q, with alphabet {| b, c |}, in parallel with it to ensure it issuﬃciently well-behaved to avoid these types of divergence. Because of the way
the two processes are combined in parallel, its eﬀect is to restrict R(0)’s possible
behaviours. Q is any process that is always either willing to perform any input
on b or any output on c (or both) but which will not allow an inﬁnite sequence ofcommunications on one channel to the exclusion of the other (a fairness condition).
The most obvious such Q is µ q.b?x → c?x → q, which makes the two channels of
R alternate. This illustrates a use of the parallel operator to impose constraints,
and is related to the discussion in Section 2.5 about the use of parallel operators as
conjunction over trace speciﬁcations.
There is no implication that R would be implemented as a parallel process –we would reﬁne the parallel combination into a sequential one. (One satisfactory
sequential R, equivalent to the parallel composition of R(0) and the alternatingprocess above, is one that accepts messages on b and sends appropriate acknowledgements on c in strict alternation.)
We will argue the correctness of this protocol informally but suﬃciently rigorously that it should be clear how a formal proof would go. Let ABP denote thecomposition of S , C 1, C 2 and R (with R being any version well-behaved in thesense described above and C 1 and C 2 being of the form that avoids the simple
inﬁnite-error divergences).
Livelock is impossible because of the introduction of Q and because neither
C 1 nor C 2 commits an inﬁnite series of errors. The latter means that each of C 1
and C 2 eventually transmits any message that is input to it repeatedly, and thatprovided they are not blocked from outputting they will eventually accept any input
they are oﬀered. In short, since any divergence clearly involves an inﬁnite number

134

Buﬀers and communicationof communications by either C 1 or C 2, inﬁnitely many messages must (in thedivergence) be either getting through from S to R or vice-versa. But R can neither
receive inﬁnitely many messages without transmitting one, nor send inﬁnitely many
without receiving one. We can therefore conclude that R both sends and receives
inﬁnitely many messages in the divergence and (by the properties of C 1 and C 2)
so does S – all this in a sequence where neither S nor R communicates externally.
It easily follows from the deﬁnition of S that all the messages from S to R are
repetitions of s.x for some ﬁxed bit s and packet x . The fact that R ignores these(as it must, for it does not generate any external communication) means it must be
in state 1 − s and therefore that the acknowledgements it is sending back are all s.
But, of course, since these are received by S they would necessarily interrupt thetransmission of the s.x ’s. Thus the system cannot diverge.
Nor can it deadlock. We will study deadlock in much more depth in Chapter
13 (and see Exercise 13.2.1), but the basic argument for this system rests on the fact
that, except when it can communicate externally (which certainly precludes deadlock), S will always both accept any incoming communication on d and be willingto output on a. Hence neither C 1 nor C 2 can be waiting for S in a deadlock state,
and it follows they are both waiting for R. But unless R is willing to communicate
externally it can always communicate with C 1 or C 2, so one (at least) of the tworequests coming into it is accepted, meaning that the system is not deadlocked. Because it can neither deadlock nor diverge, it follows that, whatever state it reaches,it always eventually comes into a stable state where all it can do is to communicate
externally (input on left, output on right or perhaps both).
In order to study the transmission of messages it is easiest to consider thesequences of messages on a, b, c and d in which any message following anotherwith the same tag bit is removed, as are any initial messages on c and d with tag
bit 1. Call these stripped sequences a, b, c and d . The structures of the processes
involved then imply the following facts:• C 1 implies that #a ≥ #b: the stripping process clearly removes any duplication.
• R implies that #b ≥ #c: R can only change the bit it outputs along c in
response to a change in the input bit on b. It only initiates the ﬁrst memberof c in response to the ﬁrst 0 in b.
• C 2 implies that #c ≥ #d .
• S implies that #d ≥ #a − 1: S can only change the bit it outputs along ain response to a change in the input bit on d .

5.3

The alternating bit protocol

135

We can piece all of these together to get#a ≥ #b ≥ #c ≥ #d ≥ #a − 1
or, in other words, these four sequences are, in length, all within one of each other.
From this it is implied that C 1 must, at each moment, have transmitted at least
one of each equal-bit block of outputs sent by S except perhaps the current one (forit to have completely lost one would imply that #b is at least two less than #a).
This, the structure of S , and the fact that R outputs a member of each block it
receives on right, imply that each trace s of the protocol satisﬁess ↓ right ≤ s ↓ left

and #(s ↓ left) ≤ #(s ↓ right) + 1

or, in other words,
COPY

T ABP

The facts that ABP is deadlock- and divergence-free, and clearly never selects between its inputs, combine with this to imply that it is failures/divergences
equivalent to COPY .
It can be shown fairly easily by modifying the above arguments that ABP
is tolerant of any ﬁnite buﬀer on its internal channels. Placing an inﬁnite buﬀer on
one or more of them could lead to divergence.
The alternating bit protocol is too simple and ineﬃcient to be used muchin practice. The ideas it uses are, however, to be found in many that are. Theinterested reader can ﬁnd some more advanced protocols both in the example ﬁleson the web site accompanying this book and in texts such as [25].
Exercise 5.3.1 Assume that R is the version of the receiver in which received messages
and acknowledgements alternate. Estimate the worst-case performance of the resulting
ABP when C 1 and C 2 are each obliged to commit no more than N consecutive errors(in terms of internal communications per message transmitted). Can you improve this bymodifying R? Would the answer to this last question be changed if C 1 and C 2 lost theability to duplicate messages (retaining the possibility of loss)?
The version of the protocol in the text leaves S free to send andreceive messages arbitrarily, but restricts R to behave ‘fairly’. What would happen (i) if
these roles were reversed and (ii) if they were both restricted to be fair?

Exercise 5.3.2

136

5.4

Buﬀers and communication

Tools

It is usually much easier to analyze and prove things about the sort of systems wehave seen in this chapter using a mechanical tool like FDR rather than by hand.
The examples we have dealt with here are extremely simple compared to thosethat can be handled mechanically. Notice that laws like BL5 and BL5 essentiallywork by enumerating the states of a chained system, and it is certainly true thatcomputers do this sort of work better than humans.
As with the work in the previous chapter, the absence of direct support for >>in the machine-readable version of CSP means that the ‘plumbing’ of such networks
has to be done in other ways such as the P[c <-> d]Q construct.
You should bear in mind, though, that current tools can only prove things
about speciﬁc processes, and then only ones that are ﬁnite state.4 Thus, we cannot
use FDR to prove laws like BL1–BL6 and cannot directly prove that B + (an inﬁnitestate process) is a buﬀer. Nor can it prove general buﬀer tolerance except wheresome WBUFF n works. Remember, however, that it may be required that the
speciﬁcation be ﬁnite state also, implying the need to use some of the restricted orapproximate speciﬁcations discussed in the ﬁrst section of this chapter.
An exception to the rule that one can only prove things about ﬁnite state
implementations arises from ﬁxed-point induction. The point is that, even though
the process deﬁned by a recursion P = F (P ) (like that of B + ) may be inﬁnite state,
it is quite likely that F (Q) will be ﬁnite state if Q is. Thus, if the characteristic
process of the speciﬁcation Q we are trying to prove of P is ﬁnite state, the main
proof obligation of ﬁxed-point induction, namely
Q

F (Q)

is likely to be something one can verify automatically.
For example, one can prove for any chosen N (that is small enough to allow
FDR to deal with the resultant state spaces) that B + satisﬁes any of the weak
buﬀer speciﬁcations WBUFF N
 . You cannot ask the same question about the full
speciﬁcation BUFF  because the resulting right-hand side is inﬁnite state. An+
attempt to prove any of the ﬁnite buﬀer speciﬁcations BUFF N
 will fail because B
does not satisfy these (but it would nevertheless be interesting to reassure yourself
that this is so by attempting the checks).
4 With the version of FDR available at the time of writing it is not possible to have an inﬁnitestate process like BUFF  as a speciﬁcation. It is likely that future versions will be able to deal
with these, by exploring only those parts of the speciﬁcation that are necessary – employing lazy
exploration and normalization. It will therefore be possible to prove that a ﬁnite-state process is abuﬀer without guessing its maximum size. However, this is likely to carry a performance penalty
so it will probably remain a good idea to keep most speciﬁcations ﬁnite state.

5.5

Notes (2005)

137

It is an obvious limitation on this type of tool that they cannot take the stepfrom proving that B + satisﬁes WBUFF N
 for any chosen N to proving it is true for
all N . (This comes under the category of ‘general results’ that are unobtainable asdiscussed above.)
It is worth while pointing out one category of ‘general results’ that are obtainable using ﬁnite-state checking which tends to be particularly relevant to communications protocols. This relates to the notion of ‘data-independence’. Manyof the process deﬁnitions in this chapter were, or could have been, deﬁned so thatthey transmitted data values taken from a completely arbitrary type. These values
are input and passed around and manipulated uninspected within the program:the nature of the underlying data type is completely irrelevant to the operation of
the program. It is frequently possible to infer results about how such a program
behaves for general types based on their behaviour for very small ones (often size
one or two). This concept is developed, together with two case studies, in Section
15.3.

5.5

Notes (2005)

Over the past year the author has worked a great deal on buﬀer tolerance and now
have far more results than are presented here. This work should appear on my
website during the ﬁrst half of 2005.
Some interesting ﬁnitary methods for checking if a ﬁnite-state process P isa buﬀer have recently come to light. One class of methods can be found in [112].
Say a process with one output and one input channel is output deterministic if, after any trace s, it cannot both oﬀer and refuse any output action o, andfurthermore it has at most one output event possible after s. A ﬁnitary characterisation of being a buﬀer (taken from the work on buﬀer tolerance discussed above)is that our P is a buﬀer if and only if both
• COPY >> P is output deterministic, and• COPY = P  COPY ∗ , whereΣ

COPY ∗ = (left?x → right!x → COPY ∗ ) 2 right ?x → STOP
In essence the ﬁrst of these conditions checks that the output depends monotonicallyon the stream of inputs; the second checks that the correct things, and only thecorrect things, come out.

Chapter 6

Termination and sequential
composition

6.1

What is termination?

In many programming languages there is a sequential composition operator: P ; Q
runs P until it terminates and then runs Q. In CSP we would expect to see all of
P ’s communications until it terminates, and for it then to behave like Q. Thereis no conceptual problem with this provided we understand just what terminationmeans.
So far we have come across two sorts of process which can communicate no
more: on the one hand, a deadlocked process such as STOP or a deadlocked parallel
network; on the other, the divergent process div. Neither of these can be said tohave terminated successfully, since both represent error states. Indeed, divergence isin principle undetectable in a ﬁnite time in general, as a result of the unsolvabilityof the halting problem. It is natural to want to associate P ; Q with a form of
termination which happens positively rather than by default.
The process which terminates immediately will be written SKIP. We will
think of the act of terminating as producing the special event  (usually pronounced‘tick’). Thus, SKIP can be identiﬁed with the process  → STOP . You can thinkof a process communicating  as saying ‘I have terminated successfully’. The
identiﬁcation of termination with an event is often convenient, but the analogy
should not be taken too far – for example,  is always the ﬁnal event a process
performs.  is not (in this presentation of CSP) a member of Σ – emphasizing that
it is very special. It is not permitted to introduce  directly: SKIP is the only
way it arises; for example the syntax  → STOP used above is illegal because it
mentions . Σ will denote the extended alphabet Σ ∪ {}Thus SKIP; P = P for all P , since all SKIP does is terminate successfully
and pass control over to P . In contrast, STOP ; P = STOP , since STOP does not140

Termination and sequential composition

terminate, merely come to an ungraceful halt. Similarly div; P = div. Notice thatthe  of the SKIP in SKIP ; P is hidden from the environment – this simply meansthat we cannot see where the join occurs from the outside, and means that we do
not confuse the occurrence of the ﬁrst  with overall termination. Because of thisconcealment parts of the theory of sequential composition bear some similarity tothat of hiding and, in particular, it turns the ﬁnal  of the ﬁrst process into a τ(invisible action).
A formal tabulation of the laws of these new constructs is delayed to a later
section. However, we would expect ; (sequential composition) to be associative anddistributive, and(?x : A → P ); Q

= ?x : A → (P ; Q)

amongst other laws (noting that  cannot, by the assumptions above, be an elementof A).
This ‘law’ brings up an interesting point in the interpretation of ‘state’ identiﬁers in CSP processes, the identiﬁers that represent objects input or used in parameterized recursions such as COUNT or B ∞ . For consider the ‘identity’(?x : A → SKIP ); x → STOP

= ?x : A → (SKIP ; (x → STOP ))In the right-hand side, it is quite clear that the second x must be the same event as
the ﬁrst, while on the left-hand side this would require the value of x communicatedﬁrst to be remembered outside the preﬁx choice construct that introduced it, andacross the sequential composition ; . This raises the important question of how thevalues and scopes of identiﬁers are to be interpreted. The real question we need toresolve in order to decide this is whether CSP is an imperative language, where thevalue of an identiﬁer can be modiﬁed (and the input ?x : A is taken to modify anexisting value), or a declarative language, where it cannot. We take the declarative
view that a construct like ?x : A → P creates a new identiﬁer called x to hold the
input value in P and that this value is not remembered once P has terminated,since we have left x ’s scope. An identiﬁer gets its value at the point where it isdeclared and keeps the same value throughout that scope. If there are any otheridentiﬁers called x created by input or otherwise within P , then these simply createa hole in scope in the same way as in many programming languages. Thus, the ﬁnal
x in the term
?x : A → ((?x : A → SKIP ); (x → STOP ))will always be the one created by the ﬁrst input.
It is this decision which allows us to identify all terminations with the single
event , and also allows us to avoid the question of how an assignable state is shared6.1

What is termination?

141

over a parallel construct. Note how this decision is consistent with the observation
made in the Introduction (Chapter 0) about process algebras discarding standard
programming language constructs such as assignment.
In conclusion, the law above is only valid if the term Q does not containan unbound (i.e., free) reference to an identiﬁer called x . If it does, then it would
simply be necessary to change the name of the bound identiﬁer so that it no longer
clashes with any free in Q.
In examples, sequential composition can be used to improve the modularity
of descriptions – allowing one to separate out diﬀerent phases of behaviour. It
also permits us to express some deﬁnitions ﬁnitely which normally require inﬁnite
mutual recursion. Recall the inﬁnite mutual recursion deﬁning COUNT n for n ∈ N.
There is a very clear sense in which this describes an inﬁnite-state system, for all
the diﬀerent values that n can take lead to essentially diﬀerent COUNT n . We cansimulate this behaviour using sequential composition as follows:ZERO= up → POS ; ZERO,

POS= up → POS ; POS
2 down → SKIP

where

The intuition here is that POS is a process that terminates as soon as it has communicated one more down’s than up’s. Thus ZERO, which is intended to behave
like COUNT 0 , initially only accepts an up, and returns to that state as soon as thenumber of subsequent down’s has brought the overall tally into balance.
We will prove this equivalence when we are equipped with enough laws.
Iteration
Now that we have a sequential composition operator it is natural to want waysof repeating a process. The simplest repetition operator is inﬁnite iteration: P *means the repetition of P for ever with no way of escaping. This is not a constructthat makes sense in many programming languages, since in a standard language an
inﬁnitely repeated program would simply send one’s computer into a useless loop
(divergence). In CSP, of course, a process is measured by what it communicates as
it goes along, so that the deﬁnition
P* = P; P*
makes sense. For example, (a → SKIP )* is simply a process that communicates an
inﬁnite sequence of a’s; it is indistinguishable from µ p.a → p. We can similarly
write
COPY = (left?x → right!x → SKIP )*142

Termination and sequential composition

However, the declarative semantics of identiﬁers means that no information can be‘remembered’ from an input in one P to a later one in P * . Thus a two-place buﬀer
cannot be written as neatly: the best we can do is to create a two-place temporary
buﬀer that terminates when emptied:TB= left?x → TB  (x )TB  (x ) = right!x → SKIP
2 left?y → right!x → TB  (y)IterBuﬀ 2= TB *

Because of the way the values x and y are intertwined in this deﬁnition, there
is no hope of writing TB or TB  (x ) as an iteration. To do so we would require an
external place to store values: see Exercise 6.1.2.
The declarative semantics also means that there can be no direct analogue
of a WHILE loop: this depends on being able to evaluate a boolean whose valuechanges with the state of the process – something that makes no sense when an
identiﬁer’s value does not change within its scope.
It would, however, be possible to deﬁne an analogue of a FOR loop: thismight be
FOR n = a, b DO P

= SKIP <I a > b>I
P [a/n]; (FOR n = a + 1, b DO P )since the identiﬁer of this type of loop is declared in the construct itself. Indeed
many of the traditional inelegancies of imperative programming with FOR loops(such as assigning to the loop identiﬁer or changing the values of the bounds within
the body) become impossible in a declarative semantics. The FOR loop is not,however, part of usual CSP syntax.
Deﬁne a process PHOLE representing a pigeon-hole: it can communicate empty when empty, when it will also accept in?x and become full. When full it
can only accept out .x for the appropriate x , which empties it. You should give both adeﬁnition as an ordinary recursion and one as Q * where Q contains no recursion.

Exercise 6.1.1

Show that the two processes you have deﬁned are equivalent.

Exercise 6.1.2Find a process P such that the two-place buﬀer equals(P * //{|in,out,empty|} PHOLE )and P contains no form of recursion. [Hint: P should, on each of its cycles, communicate
ﬁrst with its slave.]

6.2

6.2

Distributed termination

143

Distributed termination

Having introduced the concept of termination we have to understand how it relates
to the other CSP operators, and in particular the parallel operators. If we treated like any other event, then we would say that P X Y Q has the following cases
for determining termination:• If  ∈ X ∪ Y then it can never terminate.
• If  ∈ X  Y then it will terminate whenever P does.
• If  ∈ Y  X then it will terminate whenever Q does.
• If  ∈ X ∩ Y then it terminates when both P and Q do.
The middle two of these are somewhat problematic, for they leave behind the question of what to do with the process which has not terminated. We might assertthat it is closed down by some powerful mechanism which, if we are really expecting
a distributed parallel implementation, seems to have to act instantaneously over a
distance. On the other hand, the other process might continue, creating the embarrassment of a system which communicates after ‘terminating’. Realizing thattermination is really something that the environment observes rather than controls,
the ﬁrst case (and the non-terminating halves of the second and third) cannot realistically prevent the arguments from terminating, but can only fail to report this tothe outer environment. Given this observation, there is really no sensible use of theﬁrst item ( ∈ X ∪ Y ) above, since all that it can achieve is to turn what would
have been termination into deadlock.
The route we take is to assert that the ﬁnal clause always holds implicitly:
there is no need to include  in the alphabets X or Y , for after all  is not amember of Σ, but the combination P X Y Q always behaves as though it were in
both. In other words, a parallel combination terminates when all of the combined
processes terminate. This is known as distributed termination. This reading makes
it sound as though the various processes have to synchronize on termination, as they
do on normal events in X ∩ Y . In fact the best way of thinking about distributed
termination is that all of the processes are allowed to terminate when they want
to, and that the overall combination terminates when the last one does. The factthat termination is the last thing a process does means that these two views are
consistent with each other: in P X Y Q, neither process can communicate after it
has terminated but the other has not.
If A is a set of events which we wish to communicate in any order and thenterminate, then this can be expresseda∈A (a → SKIP , {a})144

Termination and sequential composition

We will see in Section 13.2.2 that this method of combining communications can be
useful in avoiding deadlock.
The principle of distributed termination is extended to all other parallel
operators.1 The view that distributed termination means waiting for all processes
to terminate, rather than actively synchronizing ’s ﬁts far better with the notionthat ||| has distributed termination.
The fact that  is being interpreted diﬀerently from other events – mainly
in its ﬁnality – means that we must protect it from confusion with other events.
This is helped by our assumption that  ∈ Σ, but we should explicitly mention
that  may not be hidden by the usual hiding operator, and nor may it be aﬀectedby renaming. Any renaming aﬀects only members of Σ, and implicitly maps  andonly  to .

6.3

Laws

We will present two sections of laws: one which could be said to describe how SKIP
and sequential composition behave in themselves, while the other shows how theyinteract with other (mainly parallel) operators.
Sequential composition is distributive and associative, and has unit SKIP .
(Q; R)

; -dist-l

(6.1)(P ; R); -dist-r

(6.2)

P ; (Q; R) = (P ; Q); R; -assoc

(6.3)

SKIP; P = P

; -unit-l

(6.4)

P ; SKIP = P

; -unit-r

(6.5)

(P

Q); R = (P ; R)

P ; (Q

R) = (P ; Q)

The last of the above laws, though intuitively obvious, requires a good deal of care inmodelling to make it true. A consequence of this care is the next law, which at ﬁrst
sight is far less obvious. Normally one would not write a process like P 2 SKIP ,2
1 There are good arguments for doing something diﬀerent with enslavement. We might think
that, when P terminates, P //X Q should terminate irrespective of Q’s state. This would havethe disadvantage that enslavement would no longer be expressible in terms of other operators,
and would also (arguably) be an opportunity for untidy programming: insisting on distributed
termination of P //X Q essentially means that P has to tidy up after itself before it terminates.
2 It looks so unnatural that Hoare banned it, something I am reluctant to do because (i) even
if it is banned, it is impractical to ban more elaborate processes that happen to equal it such as(a → SKIP ) \ {a} 2 Q and (ii) it is hard to make the algebraic semantics work without it.

6.3

Laws

145

since the concept of oﬀering the environment the choice of the process terminating
or not is both strange in itself, and ﬁts most uneasily with the principle that  issomething a process signals to say it has terminated. The best way to deal withthis process, given that we are forced to consider it, isP 2 SKIP = P  SKIP

2-SKIP resolve

(6.6)

Remember that P  Q (equivalent to (P STOP ) 2 Q and Q (P 2 Q)) is theprocess that can choose to act like Q but can oﬀer the initial choices of P . Thislaw says that any process that has the option to terminate may choose to do so andthere is nothing the environment can do to stop it: it is reﬁned by SKIP.
It is not too hard to show the link between this law and ; -unit-r. If P =(a → STOP ) 2 SKIP meant one had the choice of a and  – so by oﬀering
only a we could be sure that would be accepted and that the process would notterminate – then P ; SKIP would behave diﬀerently from P (invalidating the law).
For, in P ; SKIP , the  from P is allowed to proceed without the agreement of theenvironment, which cannot stop it happening. The eﬀect of this composition would
be just like((a → STOP ) 2 (b → SKIP)) \ b
since the hidden b here is exactly like the  from P that gets hidden by ; . While
this process might accept a it need not.
When a process cannot oﬀer an initial , the situation about how it acts
under sequential composition is simple, we just get the law already discussed: provided x is not free in Q,(?x : A → P ); Q = ?x : A → (P ; Q)

; -step

(6.7)

We need a law that extends this and ; -unit-l to take account of processes
that can either terminate or oﬀer other events. We can assume that such a process
has already had the law 2-SKIP resolve applied to change this choice into the form. Thus the appropriate law is that, when x is not free in Q,((?x : A → P )  SKIP ); Q = (?x : A → (P ; Q))  Q

SKIP-; -step(6.8)

Sequential composition has many left ‘zeros’: if P is any process that cannever terminate then P ; Q = P for any Q.
Since we are not allowed to hide or rename , SKIP is unchanged by any
hiding or renaming construct.
SKIP \ X = SKIP

SKIP -hide-Id

(6.9)

146

Termination and sequential composition
SKIP-[[R]]-Id (6.10)

SKIP [[R]] = SKIP

In order to deal with distributed termination, we need two extra laws foreach parallel construct: one to deal with the case when both operands are SKIP ,and one to deal with the case where one of them is. The ﬁrst group are remarkably
similar.
SKIP X Y SKIP = SKIPX Y -termination (6.11)

SKIP  SKIP = SKIP  -termination (6.12)

X

X

SKIP >> SKIP = SKIP

>>-termination (6.13)

SKIP //X SKIP = SKIP

//-termination (6.14)

The other group reﬂect the diﬀering modes of synchronization in the operators. Since the asymmetry of these operators makes the laws more numerous, andin any case the required laws can be derived from the ones relating to the operators
out of which they are built, we omit the laws for X Y , >> and //X here.
SKIP  (?x : A → P ) = ?x : A  X → (SKIP  P )X

XSKIP ||| P = P  -preterm (6.15)
X

|||-unit (6.16)

Note the particularly simple law for interleaving – SKIP is the unit of |||.
As an application of the laws we will prove, by the principle of unique ﬁxed
points, that the process ZERO deﬁned earlier is equivalent to COUNT 0 . To do this
we prove that the vector of processes Zn | n ∈ N, deﬁned
Z0 = ZEROand Zn+1 = POS ; Zn(an inductive deﬁnition rather than a recursive one), has the property that Zn =COUNT n for all n. We will demonstrate that Z is a ﬁxed point of the constructive
recursion deﬁning COUNT , proving this claim. Trivially Z0 = up → POS ; Z0 =

6.4

Eﬀects on the traces model147

up → Z1 , and
Zn+1= (up → POS ; POS
2 down → SKIP ); Zn= (up → POS ; POS ; Zn )2 (down → SKIP; Zn )by ; -step etc.

= (up → POS ; POS ; Zn )2 (down → Zn )by ; -unit-l= up → Zn+2
2 down → Zn
Exercise 6.3.1
The recursive deﬁnition of POS and ZERO can be modiﬁed easily torepresent, instead, an unbounded stack process. The process Sx behaves like a temporary
stack containing (only) the value x (i.e., it can have any value pushed onto it, or x popped
oﬀ it) and terminates when all its contents are removed; while Empty is an empty stack
which never terminates.
Deﬁne an unbounded, tail recursive, stack process Stack  as a parameterized recursion very like Bs∞ , which behaves like Empty. Prove Empty = Stack  , modelling yourproof on the one that ZERO is equivalent to COUNT 0 .

6.4

Eﬀects on the traces model

The presence of the special object  in traces, subtly diﬀerent from other events,
means that some of the traces deﬁnitions given up to this point have to be extended
to deal with . In the traces model T we will now identify a process with a nonempty, preﬁx-closed subset ofΣ∗ = Σ∗ ∪ {sˆ | s ∈ Σ∗ }simply reﬂecting our assumption that any  in a trace is ﬁnal.
The earlier deﬁnitions of the traces of STOP , preﬁxing and preﬁx choice,internal and external choice, hiding and synchronous parallel remain unaltered.
Obviously we need deﬁnitions for the two new constructs:
traces(SKIP ) = {, }traces(P ; Q) = (traces(P ) ∩ Σ∗ )∪ {sˆt | sˆ ∈ traces(P ) ∧ t ∈ traces(Q)}Notice how the second of these conceals the  which terminates P and starts Q,
leaving only any ﬁnal  of Q visible.

148

Termination and sequential composition

The semantics of the various renaming operators only needs modifying to
make sure that ’s are preserved. Since both the functions and relations used are
purely over Σ, we need to extend the ‘liftings’ of these to traces to deal with ’s.
In each case this takes the obvious form, for example
f (a1 , . . . , an , ) = f (a1 ), . . . , f (an ), 
Most of the parallel operators have to be changed to reﬂect distributed termination. In alphabetized parallel we simply ‘add’  to the alphabets of bothprocesses from the point of view of the deﬁnition:
traces(P X Y Q) = {s ∈ (X ∪ Y )∗ | s  (X ∪ {}) ∈ traces(P )∧ s  (Y ∪ {}) ∈ traces(Q)}while in the other two we extend the deﬁnitions of the underlying operators on
traces: if s, t ∈ Σ∗ , then s ||| t and s  t are as before, andXs ||| tˆ = {}s  tˆ = {}Xsˆ ||| tˆ = {uˆ | u ∈ s ||| t}sˆ  tˆ = {uˆ | u ∈ s  t}
X

X

The deﬁnitions of the process-level parallel operators then remain as before (using
the modiﬁed trace-level ones).
Exercise 6.4.1

Calculate the traces of the process(a → SKIP ||| a → b → SKIP )*Use the laws to ﬁnd a tail-recursive process equivalent to it.

6.5

Eﬀects on the failures/divergences model

The introduction of  means that we have to look carefully at what a process canrefuse (immediately) before and after this special event, and similarly at its eﬀect
on possible divergence.
The easy part of this is what goes on after : nothing. In the last section
we made the assumption that a process communicates nothing after  (since its
traces are in Σ∗ ). It therefore makes sense to assume it refuses everything (i.e.,Σ ) after any trace of the form sˆ, and cannot diverge. We will make theseassumptions, with the modiﬁcation that we allow divergence traces of the form

6.5

Eﬀects on the failures/divergences model

149sˆ provided they are implied by the assumption that all extensions of divergences
are divergences. What really matters, in fact, is that all processes look alike after, rather than the precise value we put them all equal to. The essential thing isthat once a process has terminated by communicating , we should be free to turn
our attention elsewhere.3
We certainly want to distinguish between the processes SKIP and SKIP
STOP , even though they have the same traces. The ﬁrst one certainly terminates
successfully, the second one only might. If we put them in sequence with a second
process P , the ﬁrst one gives P , while the second might deadlock immediately
whatever P is. The obvious way to make this distinction is to include  in refusal
sets: then the failure (, {}) belongs to SKIP
STOP (because it belongs to
STOP ) but not SKIP , which cannot refuse to terminate. Thus, when recording
a process’s failures we will take note of when it can refuse to terminate as well asother events.
It turns out, however, that  is not quite on a par with other potential members of refusal sets (i.e., ones that are members of Σ). This is because, as discussed
earlier in this chapter,  is not something a process expects its environment toagree to, it is simply a signal to the environment that it is terminating. Thus noprocess will ever oﬀer its environment the choice of  or events in Σ. In otherwords, any process that can terminate must be able (on the appropriate trace) torefuse every event other than ; if a process has the trace sˆ, it has the failure(s, Σ). This is discussed further in Chapters 7 and 8.
The unnatural process SKIP 2 Q – the subject of law 2-SKIP resolve(6.6) – apparently oﬀers its environment the choice of  and the initial events of Q,
in contravention of the above principle. In fact, since the environment’s co-operation
is not required for the event , this process can decide to terminate whatever theenvironment. In other words, it can refuse all events other than  despite the way
it is built. For example, SKIP 2 a → STOP has failures{(, X ) |  ∈ X } ∪ {(a, X ), (, X ) | X ⊆ Σ }You can view this as a consequence of 2-SKIP resolve, since this law proves theabove combination equivalent to(SKIP 2 a → STOP )SKIP

which can clearly refuse everything other than .
3 In some ways the best approach would be not to bother to include any refusals after a.
The only problem with this (and the reason why we have not followed it) is that, since even adivergence-free process’s traces would not then be the trace-components of its failures, a process
could not be represented by its failures and divergences: the termination traces (at least) would
have to be included as a separate component.

150

Termination and sequential composition

The precise way in which failures are extracted from a process’s transition
system, allowing for possible  actions, is described in Section 7.4.1. See Section 8.3
for full details of the way the failures/divergences semantics of processes composes,
including taking account of the SKIP 2 Q issue.

Part II

TheoryChapter 7

Operational semantics

7.1

A survey of semantic approaches to CSP

There are at least three distinct ways of gaining a rigorous mathematical understanding of what a CSP program ‘means’. These are operational, denotational, andalgebraic semantics. We have already seen all of these in action:• The operational semantics interprets programs as transition diagrams, withvisible and invisible actions for moving between various program states: wehave frequently used these to describe informally how processes (and operators over them) behave. Operational semantics, as the name suggests, arerelatively close to implementations: we might deﬁne an operational semantics
as a mathematical formalization of some implementation strategy.
• A denotational semantics maps a language into some abstract model in such a
way that the value (in the model) of any compound program is determinabledirectly from the values of its immediate parts. Usually, denotational semantics attempt to distance themselves from any speciﬁc implementation
strategy, describing the language at a level intended to capture the ‘innermeaning’ of a program. There are several denotational semantics of CSP, allbased on things like traces, failures and divergences; the value of any program
just being some combination of its sets of these things.
• An algebraic semantics is deﬁned by a set of algebraic laws like the ones
quoted for the various operators in this book. Instead of being derived theorems (as they would be in a denotational semantics), the laws are the basic
axioms of an algebraic semantics, and process equivalence is deﬁned in termsof what equalities can be proved using them. In some ways it is reasonable154

Operational semantics
to regard an algebraic semantics as the most abstract type (where ‘abstract’is meant in its informal, rather than its formal, sense).

While any one of these ﬂavours of semantics is enough to describe CSP, it is far
preferable to understand something of them all and how they complement eachother. This is why we have used all three, sometimes informally, to describe it in
the preceding chapters. For most people using CSP there is no need to delve deeply
into the sometimes diﬃcult mathematics which underpins it, but for those who areinterested this chapter and the following four give formal expositions of the threesemantic styles, and show how they relate to each other.
Of these, the material in the rest of this chapter is probably the easiest fora non-mathematician to follow and the most important for using existing tools.
Many of the ideas in it have already been seen in earlier chapters, at a lower levelof formality.
The main purpose of CSP is, of course, to describe communicating and interacting processes. But in order to make it useful in practice we have added quite
a rich language of sub-process objects: anyone who has used FDR will realize that
CSP contains a functional programming language to describe and manipulate things
like events and process parameters. Of course, any complete semantics of the language would have to take account of this other facet: in eﬀect, we would need to givethis sublanguage a semantics too. But this would take a lot of extra space, taking
the focus oﬀ the main thing we want to do which is to understand the semantics ofcommunication, and is complex in its own right. Thus, just as in the rest of thisbook we have focused on the main purpose of CSP, in this and the other chapterson semantics we will deliberately ignore the details of how the calculation of subprocess objects ﬁts in.1 Therefore we will tend to ignore the detailed syntax andevaluation of sub-process objects, just treating them as values. This ‘glossing-over’is made a good deal less dangerous because we are assuming CSP has a declarative(pure functional) semantics, meaning that values are never changed by assignment.
The only real problem occurs when the evaluation of a sub-process object fails toterminate or produces some other sort of error. Error-handling is an important, if
occasionally irritating, part of the construction of any formal semantics, but in thespirit of our simpliﬁed treatment of sub-process objects we will not deal with thesetypes of error in this book. These also are discussed in [126].

1 Operational and denotational semantics taking these details into account can be found in
Scattergood’s thesis [126] and (in a more sophisticated form), in Lazić’s work [64, 68].

7.2

7.2

Transition systems and state machines

155

Transition systems and state machines

In Part I we frequently referred to the transition system of a process: a graphshowing the states it can go through and actions from Σ,τ that it takes to getfrom one to another. The operational semantics presented in this chapter is just aformal way of computing these graphs. In this section we investigate the behaviourof transition systems, whether or not derived from a process.
Formally speaking, a labelled transition system (LTS) is a set of nodes and,afor each event a in some set, a relation −→ between nodes. It is a directed graphwith a label on each edge representing what happens when we take the action which
the edge represents. Most LTSs have a distinguished node n0 which is the one weare assumed to start from.
The operational interpretation of an LTS is that, starting from any nodesuch as n0 , the process state is always one of the nodes, and we make progress byperforming one of the actions possible (on outward-pointing edges) for that node.
This set of the initial actions of node P will be denoted P 0 . The only things thatmatter are the actions each node has: if the nodes do carry some annotation thenthis cannot be observed during a run.
In interpreting CSP we usually take the set of possible labels to be Σ,τ =Σ ∪ {, τ }. Actions in Σ are visible to the external environment, and can only
happen with its co-operation. The special action τ cannot be seen from the outsideand happens automatically. Thus, if the process is in a state with no actions outsideΣ (a stable state) it might have to wait there for ever; when it is in an unstable state(τ ∈ P 0 ) we assume that some action must occur within a short time. (The eventthat occurs may be visible or τ .), as discussed in Chapter 6, is a special signal representing the successful
termination. It is – as we saw in Chapter 6 – diﬀerent from other events, not least
because it is presumably always the last event that happens. It is certainly visible
to the environment, but it is better to think of it as an event that does not require
the environment’s co-operation: it is in one way like τ and in another like ordinary
members of Σ. A state P that has  ∈ P 0 is not stable, because the environment
cannot prevent it from happening. (Note that the previous discussion of stablestates, in Section 3.3, was before we had met .) We will be careful to give  thisintermediate interpretation, unlike most earlier works (where it has been treatedlike a member of Σ).2
Where a state has a range of visible actions we assume, especially when the2 This means that a few of the operational semantic rules in this book are diﬀerent from earlier

versions. Our more careful treatment of is designed to make the law ; -unit-r (6.5) (P ; SKIP =P ) true, which it is not if is assumed to be like any other event. The implications of this decision
for the structure of failure-sets were discussed in Section 6.5.

156

Operational semantics

A
a

τ
b

B

D
τ

τ

a

a
C

a

E

Figure 7.1 Example of a labelled transition system.
state is stable, that the environment has a free choice of which (if any) of the events(i.e., distinct labels) to choose. If there is more than one action with a given label
a, the environment has no control over which is followed if it chooses a. In otherwords, this is a source of nondeterminism.
We assume that only ﬁnitely many actions (visible or invisible) can happen
in a ﬁnite time.
To explain these ideas we will consider two LTSs. The one shown in Figure
7.1 displays most of the possible types of behaviour without .
• In state A, the environment has the choice of either a or b, and since thisis a stable state, nothing can happen until one of these is selected. The
process then moves into state B or D, this being determined by which event
is chosen.
• The only action available to state B is an internal one. Therefore the process
takes this action and moves to state C .
• In state C , there is only one event available, a, and the process must wait
until the environment communicates it. There are two possible states that
can then arise, and the environment has no control over which one the process
moves to.
• In state D, internal and external actions are both possible. The environment
might be able to communicate the a action, but cannot rely on this. It
can, however rely on the process moving to either A or C if this a does not
happen. As in the previous case, the environment has no control over which.

7.2

Transition systems and state machines

157

B
a
C
τ

Ω
D

τ
A

τ
E

Figure 7.2 A labelled transition system with  actions.
• State E has no actions: it is deadlocked. Once the process reaches this state
it is doomed to remain there for ever.
The one in Figure 7.2 enables us to see the eﬀects of . This transition systemfollows the obvious convention that  is always the last event and leads to an end
state Ω. (If forced to interpret a transition system where this was not true we would
just ignore anything that could happen after .)• The easiest state to understand is A: the only thing it can do is terminate.
It behaves like the process SKIP .
• B can either terminate or perform the event a. Since it does not need theenvironment’s co-operation to terminate, this is certain to happen unless theenvironment quickly oﬀers a, in which case either can happen (nondeterministically).
• C either terminates or performs a τ , the choice being nondeterministic.
• D has a τ action to A, which gives it the ability to terminate. Indeed a τaction to a state that can only terminate like A is always equivalent, fromthe point of view of externally observable behaviour, to its having a  actionof its own. Either can be chosen, from any state that has it, independentlyof the environment and leads to inevitable termination.
Even though the only visible action that can ever happen to a process instate D is , its behaviour is diﬀerent from A since it can follow the τ action

158

Operational semantics
to E and become deadlocked. In other words, D can refuse to terminate
while A cannot.

An LTS can be ﬁnite or inﬁnite (in terms of its set of nodes), and it is clearly
the case that only those parts reachable from a node n (via ﬁnite sequences ofactions) are relevant when we are describing the behaviour of n. In particular, we
will usually assume that all the nodes are reachable from the distinguished node n0 .
A process is said to be ﬁnite state if it can be represented by a ﬁnite LTS.
An LTS is not – by itself – a very good way to describe a process if you
want to capture the essence of its behaviour, since there are many diﬀerent waysof representing what any reasonable person would agree is essentially the same
behaviour. For example, any LTS can be expanded into a special sort of LTS, a
synchronization tree, where there are no cycles and a unique route from the root toevery other node, in the manner illustrated in Figure 7.3. (The distinguished root
nodes are indicated by open circles.) But notice that even two synchronization trees
can easily represent the same behaviour, as all the original LTSs – and hence all
their diﬀerent expansions – represent behaviours we might suspect are essentiallythe same. If one does want to use operational semantics as a vehicle for deciding
process equivalence, some sort of theory is required which allows us to analyze which
process descriptions as an LTS represent the same behaviour.
In CSP, the main mode of deciding process equivalence is via failures, divergences etc., which are not primarily based on transition systems, but some otherprocess algebras (most notably CCS) take the approach of deﬁning the basic meaning of a process to be an LTS and then deciding equivalence by developing a theoryof which LTSs are essentially the same. Thus, getting this analysis right can be
extremely important.
Many diﬀerent equivalences over LTSs (and the nodes thereof) have been
proposed, most of which are speciﬁc to a given view, but the most fundamental
one is valid in them all (in the sense that if it deﬁnes two nodes to be equivalentthen so do the others). This is the notion of strong bisimulation, which takes theview that the only thing we can detect about a given process state is what events
it can do, and that to be equivalent two processes must have the same set of events
available immediately, with these events leading to processes that are themselves
equivalent. Another way of looking at this is that no experiment which is based on
exploring the behaviour of two nodes by examining and performing available events(including τ and  on an equal basis to all the others) can tell them apart.
Since the notion of weak bisimulation (a weaker notion of equivalence used
for CCS) is less relevant to CSP,3 we will usually drop the word ‘strong’.
3 This is because weak bisimulation fails to make enough distinctions about divergent processes.

7.2

Transition systems and state machines

159

a
a

a

a

τ

a

a

a

a
a

a
a

(i)

a

a

a
a

a

a
a a

a
a

a a

τ
a

(ii)

a

(iii)

Figure 7.3 Unfolding LTSs to synchronization trees.
Definition If S is an LTS, the relation R on the set of nodes Ŝ of S is said to bea (strong) bisimulation if, and only if, both the following hold:∀ n1 , n2 , m1 ∈ Ŝ . ∀ x ∈ Σ,τ .
xx
n1 R n2 ∧ n1 −→ m1 ⇒ ∃ m2 ∈ Ŝ .n2 −→ m2 ∧ m1 R m2
∀ n1 , n2 , m2 ∈ Ŝ . ∀ x ∈ Σ,τ .
xx
n1 R n2 ∧ n2 −→ m2 ⇒ ∃ m1 ∈ Ŝ .n1 −→ m1 ∧ m1 R m2
(Note that, though there is no requirement that a bisimulation is symmetric, theabove deﬁnition is symmetric so that R −1 is a bisimulation if R is.)Two nodes in Ŝ are said to be bisimilar if there is any bisimulation which
relates them. It is a theorem (see Exercise 7.2.4) that the relation this deﬁnes on
the nodes of an LTS is itself a bisimulation: the maximal one. This is always an160Operational semantics
A

B

X

C
Y

E

D

G
Z

F

Figure 7.4 Bisimulation equivalence.
equivalence relation: reﬂexive, symmetric and transitive – it partitions the nodes
into the sets whose members’ behaviours are indistinguishable from each other (seeExercise 7.2.5).
Consider the systems in Figure 7.4, where for simplicity all the actions havethe same label (a, say). In the left-hand system, it should not come as a surprisethat E , F and G are all bisimilar, since none of them can perform any action atall. All the others can perform the event a, and are therefore not bisimilar to thesethree. This means that A cannot be bisimilar to any of B , C , D, as all of thesecan become one of E , F , G after a and A cannot: the deﬁnition of bisimulation
states that if A is bisimilar to B then it must be able to move under a to somethingbisimilar to E . On the other hand, all of B , C and D are bisimilar – each of themcan perform an a either to a member of the same set or to one of E , F , G. The
partition produced by the maximal bisimulation is shown in the ﬁgure.
It makes sense to say that two nodes in diﬀerent LTSs (with the same underlying alphabet) are bisimilar, because we can embed the two systems in one larger
one (whose nodes are the union of disjoint copies of the nodes of the two we aresumming). In this sense all the nodes of both versions of systems (i) and (ii) of
Figure 7.3 are bisimilar. They are not, however, bisimilar to those in the right-handones – since the latter can perform τ actions. This shows the chief weakness of(strong) bisimulation as a technique for analyzing process behaviour: its inability

7.2

Transition systems and state machines

161

A

a
B

a

a

a
a

C

b

b

b

D

a

E

a

F
G

a

a
H

a

Figure 7.5 Which nodes are bisimilar (see Exercise 7.2.2)?
to distinguish between the diﬀerent eﬀects of visible and invisible actions.
Having found the maximal bisimulation on an LTS, we can produce another
LTS with one node for each equivalence class, and an action a from class C1 to class
C2 just when the nodes in C1 have a actions to C2 (they all will if and only if onedoes). This factoring process is shown in Figure 7.4, with the system on the rightbeing the one derived from the one we have already examined. It is always the casethat the nodes of the new system are bisimilar to the members of the classes they
represent, and that no pair of the new system’s nodes are bisimilar (see Exercise
7.2.6).
Exercise 7.2.1

No pair of nodes in the LTS of Figure 7.1 are bisimilar. Prove this.

Exercise 7.2.2 Which pairs of nodes are bisimilar in the LTS shown in Figure 7.5?
Exercise 7.2.3
Draw an LTS describing a game of tennis between players A and
B , with the alphabet {point.A, point.B , game.A, game.B }. (The intention is that theappropriate event game.X occurs when player X has won.) Recall that successive points
take either player through the scores 0, 15, 30, 40, game except that the game is not won

162

Operational semantics

if a player scores a point from 40-all (deuce), but rather goes to an ‘advantage’–‘deuce’
cycle until one player is two points ahead. Which scores are bisimilar?
Let V be any LTS. We can deﬁne a function Ψ from (V̂ × V̂ ) (therelations on the nodes of V ) to itself as follows: (n, m) ∈ Ψ(R) if and only if

Exercise 7.2.4∀ n  ∈ Ŝ . ∀ x ∈ Σ ,τ .
xxn −→ n  ⇒ ∃ m  ∈ V̂ .m −→ m  ∧ n  R m and∀ m  ∈ Ŝ . ∀ x ∈ Σ ,τ .
xxm −→ m  ⇒ ∃ n  ∈ V̂ .n −→ n  ∧ n  R m 
Show that Ψ is monotonic and that its pre-ﬁxed points (i.e., relations R such that R ⊆Ψ(R)) are precisely the bisimulations. Deduce from Tarski’s theorem (see Appendix A)that there is a maximal bisimulation on V (i.e., one that contains all others) and that it
is a ﬁxed point of Ψ.
Show that the equality relation ‘=’ is a bisimulation, and that if R
and R  are bisimulations then so is their relational composition R ◦ R  .

Exercise 7.2.5

Deduce that the maximal bisimulation is an equivalence relation.
Let S be any LTS, let ≡ be the maximal bisimulation over it, and
let S /≡ be the factored version of S described on page 161 and illustrated in Figure 7.4.
Show that if we form an LTS S + consisting of separate copies of S and S /≡, then theequivalence relation on Sˆ+ in which each equivalence class of S (i.e., a node of S /≡) isdeemed equivalent to each of its members and nothing else, is the maximal bisimulation
on S + .

Exercise 7.2.6

7.3

Firing rules for CSP

The operational semantics of CSP treats the CSP language itself as a (large!) LTS.
It allows us to compute the initial events of any process, and what processes it
might become after each such event. By selecting one of these actions and repeating
the procedure, we can explore the state space of the process we started with. The
operational semantics gives a one-state-at-a-time recipe for computing the transition
system picture of any process.
It is now traditional to present operational semantics as a logical inference
system: we use this system to infer what the actions of a given process are. A
process has a given action if and only if that is deducible from the rules given.
There are separate rules for each CSP operator, to allow us to deduce what theactions of a process are in terms of its top-level operator (often depending on theactions of its syntactic parts).

7.3

Firing rules for CSP

163

The rules themselves are all simple, and correspond closely to our existing
intuition about the operators they relate to.
Because the process STOP has no actions, there are no inference rules forit. It has no actions in the operational semantics because there is no possibility ofproving it has any.
SKIP , on the other hand, can perform the single action , after which itdoes nothing more.
SKIP −→ ΩThe fact that there is nothing above the horizontal bar here means that no assumptions are required to infer the action described. The special process term Ω(which we are adding to the language/LTS for convenience) is intended to denoteany process that already has terminated. The result state after a  action is neverimportant (its behaviour is never looked at) and it is sometimes helpful to have astandardized way of representing the result of termination in the LTS of processes.
The main way communications are introduced into the operational semantics
is via the preﬁxing operation e → P . In general, e may be a complex object, perhaps
involving much computation to work out what it represents. There is a choice inwhat to do about computations like this in an ‘operational’ semantics. Clearly a real
implementation would, in general, have to go through a procedure to work out thisand other types of sub-process objects. One could include these steps (as τ actions
or perhaps some other sort of invisible action) in the operational semantics, but thiswould make them much more complex both to deﬁne and to analyze. In the spiritof the discussion at the start of this chapter, we will ignore these computation steps(taking the values as given) and concentrate only on ‘actions’ which arise directlyfrom CSP rather than from lower-level behaviour.
The preﬁx e may represent a range of possible communications and bind one
or more identiﬁers in P , as in the examples?x : A → P

c?x ?y → P

c?x !e → P

This leads to one of the main decisions we have to make when constructing an
operational semantics for CSP (and many other languages): how do we deal with
the identiﬁers in programs that represent data values, other processes, etc.? For
it is clearly the case that the behaviour of a program with a free identiﬁer (onewhose value is not created within the program itself) might depend on the value ofthe identiﬁer. The simple answer to this problem is to deal only with closed terms:
processes with no free identiﬁers. Using this it is possible to handle most of thesituations that can arise, making sure that each identiﬁer has been substituted bya concrete value by the time we need to know it. Because of its simplicity, this is
the approach we will take.

164

Operational semantics

This simple approach does create some problems when handling some moreadvanced aspects of CSP, which means that another style is preferable if one wishes
to give a complete operational semantics covering every nuance of the language.
This is to introduce the concept of an environment 4 : a mapping from identiﬁers to
the values (which might either be data or processes) they represent. Environments
are then added to the state space of the LTS we are deﬁning with the operationalsemantics: instead of transitions being between processes, we now have transitions
between process/environment pairs. This alternative style makes very few diﬀerences to the individual semantic clauses except where a value is being looked up in
the environment. Full details can be found in [126].
To implement the simpler approach we will assume the existence of functionscomms and subs.
• comms(e) is the set of communications described by e. For example, d .3
represents {d .3} and c?x :A?y represents {c.a.b | a.b ∈ type(c), a ∈ A}.
• For a ∈ comms(e), subs(a, e, P ) is the result of substituting the appropriate
part of a for each identiﬁer in P bound by e. This equals P if there are no
identiﬁers bound (as when e is d .3). For example,subs(c.1.2, c?x ?y, d !x → P (x , y)) = d !1 → P (1, 2)
The transition rule for preﬁx is then easy to state:ae → P −→ subs(a, e, P )(a ∈ comms(e))

It says what we might expect: that the initial events of e → P are comms(e)and that the process then moves into the state where the eﬀects of any inputs inthe communication have been accounted for. Note the way the limitation on events
was introduced: via a side condition to the inference rule. A side condition simply
means that the deduction is only valid under the stated restriction.
This is the only transition rule for preﬁxing, which means that the only actions of the process e → P are those deducible from it. The initial actions of e → P
are thus independent of whatever P can or cannot do (in that initials(e → P ) =comms(e) and this process is always stable). There are only two other operators ofwhich this can be said. One of these is nondeterministic choice, which is modelled
by a choice of τ actions, one to each process we are choosing between:PτQ −→ PPτQ −→ Q

4 This use of the word ‘environment’ has an entirely diﬀerent meaning to the idea of an environment that the process communicates with, discussed elsewhere.

7.3

Firing rules for CSP

165

This easily translates to the generalized notion of choice over a non-empty set ofprocesses:
τS −→ P(P ∈ S )It is important to remember the restriction that S is non-empty since even though
the above rule makes sense, in itself, when S = {} the value of {} it predicts
does not (no value makes sense in the failures/divergences model for this object,since it would have to (i) be a unit for in the sense that P X = P for all P ,and (ii) reﬁne every process even though, as we will see in the next chapter, thefailures/divergences model does not have a greatest element).
The only other case where the initial actions are determined completely by
the operator itself is recursion. It is a good idea to introduce a τ action to representthe ‘eﬀort’ of unfolding a recursive deﬁnition via the following rule5
τµ p.P −→ P [µ p.P /p]
This τ action never causes any harm, since the externally visible behaviour of any
process P is unchanged by the addition of an extra starting state with a τ action to
P . This process has no option but to take this invisible action and behave like P .
The τ action in recursion is there to avoid the diﬃculties caused by under-deﬁned
recursions such as µ p.p and µ p.(p 2 Q). The most natural symptom of this typeof process is divergence, and this is exactly what the introduction of the τ achieves.
In fact, for well-constructed recursions, the τ is not really needed, though it still
makes the mathematical analysis of the operational semantics good deal easier.6
All the other operators have rules that allow us to deduce what actions aprocess of the given form has from the actions of the sub-processes. Imagine thatthe operators have some of their arguments ‘switched on’ and some ‘switched oﬀ’.
The former are the ones whose actions are immediately relevant, the latter theones which are not needed to deduce the ﬁrst actions of the combination. (All thearguments of the operators seen above are initially switched oﬀ.) This idea comes
across most clearly in the construct P ; Q (whose operational semantics can be
5 The µ p.P style of recursion is the only one we will deal with in this operational semantics,

since a proper treatment of the more common style of using names in a script to represent (perhaps
parameterized, and perhaps mutual) recursive processes requires the introduction of environments.
The rule we are introducing here extends simply to that context: it is then the act of looking up
a process identiﬁer that generates a τ .
6 FDR does not introduce τ actions of this sort because the only eﬀect they have on wellconstructed deﬁnitions is to increase the size of the state space. If you are using a tool where suchactions are not used, the result is likely to be that an attempt to use a recursion like µ p.p will
make the tool diverge. Thus, if you need to create a representation of div in such a tool where it
is not built in as primitive, it is necessary to use a term like (µ p.a → p) \ a or µ p.SKIP ; p.

166

Operational semantics

found below), where the ﬁrst argument is switched on, but the second is not as its
actions do not become enabled until after the ﬁrst has terminated.
Both the arguments of external choice (2) are switched on, since a visible
action of either must be allowed. Once an argument is switched on, it must beallowed to perform any τ or  action it is capable of, since the argument’s environment (in this case the operator) is, by assumption, incapable of stopping them.
There is, however, a diﬀerence between these two cases since a τ action is invisible
to the operator, which means that there are always rules like the followingττP −→ P 

Q −→ Q 

P 2 Q −→ P  2 Q

P 2 Q −→ P 2 Q ττwhich simply allow the τ to happen without otherwise aﬀecting the process state.
(In some cases these rules are implied by more general ones.) These rules simply
promote the τ action of the arguments to τ actions of the whole process. On theother hand, the  event is visible, so (as with other visible actions) the operator
can take notice and, for example, resolve a choice. With 2, there is no diﬀerence inhow  and other visible events are handled:aP −→ P a

P 2 Q −→ P aQ −→ Q (a = τ )a

P 2 Q −→ Q (a = τ )Of course, the place where  is most important is in the sequential composition operator ; . Here, the ﬁrst operand is necessarily switched on, while the second
is not. In P ; Q, P is allowed to perform any action at all, and unless that actionis  it has no eﬀect on the overall conﬁguration.
xP −→ P x

P ; Q −→ P  ; Q(x = )If P does perform , indicating it is terminating, this simply starts up Q, with theaction itself being hidden from the outside – becoming τ .
∃ P  .P −→ P τP ; Q −→ Q
It is semantically important that the second argument of ; and the process argumentof e → P are switched oﬀ, for if they were not, they would be allowed to perform anyτ actions so that if they could diverge, so could the overall process. And the process
STOP ; div could never get into a stable state even though it is supposed to beequivalent to STOP . This shows that any argument which is switched on is always
one in which the operator is divergence-strict (i.e., maps immediately divergent

7.3

Firing rules for CSP

167

processes to immediately divergent processes). There is, of course, a considerable
interplay here between what is reasonable in the operational semantics and what is
possible in the denotational semantics.
The rules for hiding and renaming have much in common, since both simply
allow all the actions of the underlying process but change some of the names of theevents. Any event not being hidden retains its own name under \ B , but when thisevent is  we need a separate rule to respect our convention that the result process
is always then Ω.
x

P −→ P 

P −→ P (x ∈ B ∪ {})xP \ B −→ P  \ B



P \ B −→ Ω

Events in B are, on the other hand, mapped to τ .
aP −→ P τ

P \ B −→ P  \ B(a ∈ B )Renaming has no eﬀect on either τ or  actions:τP −→ P 

P −→ P 

P [[R]] −→ P  [[R]]P [[R]] −→ ΩτOther actions are simply acted on by the renaming:aP −→ P b

P [[R]] −→ P  [[R]](a R b)

We have seen a wide range of parallel operators, but they could all be expressed in terms of the operator  , which takes two processes and enforces synchroX

nization on the set X ⊆ Σ. Because of this we will only give operational semantics
for  – all the others being deducible. Since both the arguments are necessarilyXswitched on, we need rules to promote τ actions:ττP −→ P 

Q −→ Q ττP  Q −→ P   Q
X

P  Q −→ P  Q 

X

X

X

There are three rules for ordinary visible events: two symmetric ones for a ∈ X
aP −→ P a

P  Q −→ P   Q
X

X(a ∈ Σ  X )168

Operational semanticsaQ −→ Q (a ∈ Σ  X )a

P  Q −→ P  Q 
X

X

and one to show a ∈ X requiring both participants to synchronizeaaP −→ P  Q −→ Q aP  Q −→ P   Q 
X(a ∈ X )X

The handling of  events in the parallel operator7 requires care, because of
the following two facts:• We decided earlier that this operator must have distributed termination: thecombination P  Q terminates when both P and Q do.
X• Since both arguments are switched on in P  Q, the parallel operator canX

not prevent either P or Q terminating if it wants to. Thus, the left-handargument of SKIP  Q can terminate even if Q cannot.
X

The way to handle this is for the parallel operator to communicate  when both
its arguments have – the intuition we developed when introducing the idea of distributed termination. The terminations of the two arguments are turned into τ ’smuch as in the ﬁrst argument of P ; Q.
P −→ P 

Q −→ Q τP  Q −→ Ω  Q
XXτP  Q −→ P  Ω
XX

Once one of its arguments has terminated and become Ω, all the rules above for Xstill apply, bearing mind that Ω itself has no transitions (being basically equivalent
to STOP ) so that P  Ω can only do those of P ’s actions not in X . After theXsecond argument has terminated the composition will have become Ω  Ω: it canX

now terminate using the following rule.
Ω  Ω −→ ΩX

7 This is the only place where the operational semantics in this book diﬀers signiﬁcantly fromearlier operational semantics for CSP. Previous treatments have considered
to be an event thatthe environment can refuse from a process, and therefore simply required synchronization on theevent between the two processes. Some simply allowed the termination of one of either process(especially under |||) to terminate the combination.

7.3

Firing rules for CSP

169

That completes the operational semantics of the main operators of CSP. All
the other operators we have seen can have their operational semantics derived fromthe ways they can be written in terms of the operators above. The only case thisproduces an unnatural answer to is the time-out operator P  Q, deﬁned as being
equivalent to (PSTOP ) 2 Q. A better operational semantics is produced by
the following three rules, which more accurately refect our intuition about how thisoperator works: allowing P to decide the choice with any visible action, but with thecertainty of a transition to Q if this does not happen. Since P is initially switched
on, we need to promote any τ it performs. (Since it is natural to expect Q to be
initially oﬀ, there is no need to do this for the second argument.)τP −→ P τP  Q −→ P   Q
Any visible action from P decides the choice in its favouraP −→ P a

P  Q −→ P (a = τ )while at any moment (as we have no way of modelling time directly in this semantics)
the combination can time out and become Q.
τP  Q −→ Q
This deﬁnition always produces a process with the same traces, failures and divergences as the derived deﬁnition but gives a much more natural transition diagram,as is shown by Figure 7.6 which contrasts the operational semantics of P   Q  withthose of (P  STOP ) 2 Q  , where P  = a → P and Q  = b → Q.
Example 7.3.1 To show the operational semantics in action we will see how toderive the transitions of a simple process, namely
COPY >> COPY =(COPY [[right, mid /mid , right ]]{|mid|}COPY [[left, mid /mid , left ]]) \ {| mid |}where
COPY = µ p.left?x → right!x → p
and the type of the various channels is {0, 1}, meaning that we can assume
Σ = {left.x , mid.x , right.x | x ∈ {0, 1}}170

Operational semantics

τ

a

τ

τ

P

b
a

b

b
b

Q

P

Figure 7.6 Operational semantics of P   Q  and (P 

Q

STOP ) 2 Q  .

• Consider ﬁrst the initial state P0 = COPY >> COPY . Since none of therules associated with the operators  , \ B or renaming allows us to infer any
Xaction not produced by an action of an argument process, the only initialactions of P0 are those associated with progress by the two COPY processes.
These, in turn, can each perform only a τ action to become
COPY τ

= left?x → right!x → COPYThis τ action is promoted by each of renaming, parallel (both arguments)and hiding, so two τ actions are possible for P0 , to the processes
P1
P2= COPY τ >> COPY
= COPY >> COPY τ• In P1 , the second argument has exactly the same τ available as it did in P0(because it was not used in the move to P1 ), so this can still be promoted toa τ action from P1 toP3= COPY τ >> COPY τ

COPY τ has initial actions left.0 and left.1 leading respectively to the states
COPY (0) = right !0 → COPY
COPY (1) = right !1 → COPY
These are promoted unchanged by the renaming [[right, mid /mid , right ]]. They
because they do not belong toare allowed by the parallel operator{|mid|}{| mid |}, and by the hiding operator \ {| mid |}, so P1 has actions left.0

7.3

Firing rules for CSP

171

and left.1 toP4 (0) = COPY (0) >> COPY
P4 (1) = COPY (1) >> COPY
• In P2 , the ﬁrst argument still has the same τ available as it did in P0 , so
this can be promoted to a τ action from P2 to P3 . The actions available to
the right-hand argument are the same ones ({| left |}) as were available tothe left-hand one in P1 . This time they are promoted to mid actions by therenaming operator, and prevented by the parallel operator since actions on
mid require a synchronization (which is not possible). Thus P2 only has the
single τ action.
• In P3 = COPY τ >> COPY τ , the actions of the two arguments are obviously
the same. As in P1 , the two left actions of the left-hand one are promoted
to actions with the same name leading to respectively
P5 (0) = COPY (0) >> COPY τ
P5 (1) = COPY (1) >> COPY τ
while the corresponding actions of the right-hand one are prevented as in P2 .
• In P4 (x ), the right-hand argument only has a τ action available, which is
promoted by the rules to a τ action to P5 (x ). The left-hand argument has
only the action right.x , which is renamed to mid .x and prevented by theparallel operator since the right-hand process cannot synchronize.
• The unique action of COPY (x ) is promoted by renaming, in P5 (x ), to mid .x .
The two left actions of the right-hand argument are also promoted to mid .
 ) on the action mid .x ,This time synchronization is possible (under{|mid|}

which becomes a τ action of the overall process because of the hiding operator. The resulting process is
P6 (x ) = COPY >> COPY (x )• In P6 (x ), the left-hand process has a τ to COPY τ , which can be promoted
to a τ action toP7 (x ) = COPY τ >> COPY (x )and the right-hand one has the action right.x to COPY , which promotes tothe same action leading back to P0 .
• In P7 (x ), the right-hand process can communicate right.x , which again promotes to the same action, leading to COPY τ >> COPY , in other words, P1 .

172

Operational semantics

a
b
c
d
e
f
g
h

P0
P1
P2
P3
P4 (0)
P4 (1)
P5 (0)
P5 (1)

i
j
k
l
m
n
o
p

P6 (0)
P6 (1)
P7 (0)
P7 (1)
P8 (0, 0)
P8 (0, 1)
P8 (1, 0)
P8 (1, 1)

Table 7.1 States of Figure 7.7.
The left-hand process can communicate left.0 or left.1, which promote to thesame events and the overall state
P8 (y, x ) = COPY (y) >> COPY (x )for the chosen y.
• The ﬁnal state we have to consider is P8 (y, x ), where both components canonly output. The right-hand one’s right.x communication promotes to thesame action externally leading to P4 (y). The reason why no more states
have to be considered is simply that all the states discovered during our
exploration have already been examined.
Taking account of all the variation in x and y, there are 16 states altogether inthe resulting LTS, which is shown in Figure 7.7. The states that the labels a–p
in the ﬁgure denote are shown in Table 7.1. You should compare the LTS derived
carefully here with the one, for essentially the same system, described in Figure 2.3
on page 60. The only diﬀerences are hiding the intermediate communications, thepresence of the τ actions produced by unfolding recursions, and the fact that wehave taken individual account of the values held in the buﬀer rather than showing
them symbolically. Evidently this creates considerably more complexity! (End of
example)Exercise 7.3.1 Compute the LTSs resulting from evaluating the operational semanticsof the following processes:(a) (a → b → STOP) 2 (c → d → STOP)(b) ((a → b → STOP) 2 (c → d → STOP)) \ {a, c}(c) (a → b → STOP) \ {a} 2 (c → d → STOP) \ {c}7.3

Firing rules for CSP

173aright.0bleft.0right.1

τleft.1

e

f

τ

τ

τ

left.1hττright.0cdleft.0g

right.1

τ

τ

i

j

τ

right.0τright.1 right.1

right.0kleft.0mlleft.1

left.1
left.0nopFigure 7.7 The full state space of COPY >> COPY .
Your answers to (b) and (c) should show rather diﬀerent externally observed behaviour.
What is it about the rules for 2 that causes this?

Exercise 7.3.2

Draw the LTSs corresponding to the recursively deﬁned processes(a) (µ p.(a → SKIP ) 2 (b → p)); (a → SKIP )(b) µ p.(a → STOP)  ((b → STOP)  p)(c) ZERO (see page 141)

Exercise 7.3.3

Give a set of rules for computing the operational semantics of P ||| Q,174

Operational semantics

derived from those of. Describe the LTS resulting from the processX(a → b → SKIP ) ||| (a → c → SKIP )Give a set of rules for the operational semantics of P >> Q directly, rather than going
through the series of inferences through renaming, parallel and hiding illustrated in theexample above.

7.4

Relationships with abstract models

7.4.1

Extracting failures and divergences

It was already pointed out in Section 3.3 that there are two quite separate ways towork out a process’s traces, failures and divergences: either by using the inductive
semantic rules for piecing these together (and which we will be studying in the next
chapter), or by examining the process’s transition system.
It is easy to formalize the extraction of these values from an LTS C .
We ﬁrst deﬁne two multi-step versions of the transition relation. The ﬁrst justallows us to glue a series of actions together into a single sequence. If P , Q ∈ Ĉ andss = xi | 0 ≤ i < n ∈ (Στ )∗ we say P −→ Q if there exist P0 = P , P1 , . . . , Pn = Q
xksuch that Pk −→ Pk +1 for k ∈ {0, 1, . . . , n − 1}.
This ﬁrst version includes τ actions (invisible to environment) in the sequencesshown. The second ignores these τ ’s: for s ∈ Σ∗ we write P =⇒ Q if there existssss  ∈ (Στ )∗ such that P −→ Q and s  \ τ = s. The following properties of =⇒ ands
−→ are all obvious.




s

t

sˆt

s

t

sˆt

(a)

P =⇒ P ∧ P −→ P(b)P =⇒ Q ∧ Q =⇒ R ⇒ P =⇒ R(c)

P −→ Q ∧ Q −→ R ⇒ P −→ R(d)P =⇒ R ⇒ ∃ Q.P =⇒ Q ∧ Q =⇒ R(e)

P −→ R ⇒ ∃ Q.P −→ Q ∧ Q −→ R

sˆt

s

t

sˆt

s

t

It is easy to extract the set of a node’s ﬁnite traces using the above relations:s

traces(P ) = {s ∈ Σ∗ | ∃ Q.P =⇒ Q}
Suppose C is a transition system and P ∈ Ĉ . We say P can diverge, writtenτP div , if there exist P0 = P , P1 , P2 , . . . such that, for all n ∈ N, Pn −→ Pn+1 .
sdivergences(P ) = {sˆt | s ∈ Σ∗ ∧ t ∈ Σ∗ ∧ ∃ Q.P =⇒ Q ∧ Q div }7.4

Relationships with abstract models

175

Notice that we have said that sˆt is a divergence trace whenever s is. This is areﬂection of the decision, discussed in Section 3.3, not to try to distinguish what canhappen after possible divergence. It would, of course, be easy to avoid this here, but
it is much harder to get things right in the denotational semantics without it. Noticethat minimal divergences (i.e., ones with no proper preﬁx that is a divergence) do
not contain . This is because we are not concerned with what a process does after
it terminates. Our inclusion of divergences of the form sˆ, where s is one, issimply a matter of taste.
In Section 3.3, we said that the only states that give rise to refusals are stableones, since a τ action might lead to anything, in particular to a state that accepts
an action from whatever set is on oﬀer. Since then the notion of a stable state has
been complicated a little by the intermediate nature of , and so, inevitably, arethe criteria for extracting refusals.
• A stable state (one without τ or  events) refuses any set of visible events(perhaps including ) that does not intersect with the state’s initial actions.
• We are interpreting  as an event that cannot be resisted by the environment.
Thus any state with this event amongst its initial actions can decide toterminate, plainly refusing all events other than . So any state with a action (even such a state with τ actions) can be held to be able to refuse any
subset of Σ. To help understand this, remember the discussion of Figure 7.2,
where we commented that any state with a  action is equivalent, so far as
external observation is concerned, to one with a τ to state A (one with onlya  action). If we made this transformation, it would be this ‘A’ state that
introduces this refusal.
We can formally deﬁne P ref B (B ⊆ Σ ) if and only if either P is stable andB ∩ P 0 = {} or there is Q with P −→ Q and B ⊆ Σ.
We can then extract the failures by combining this with the traces, taking
account of the convention that a process refuses anything after .
failures(P ) =s{(s, X ) | ∃ Q.P =⇒ Q ∧ Q ref X }sˆ∪{(sˆ, X ) | ∃ Q.P =⇒ Q}
As we saw brieﬂy in Chapter 3, and will study more in Section 8.3.1, it issometimes necessary to ignore details of what a process does after possible divergence. Sets of traces and failures with post-divergence detail obscured are given by
the deﬁnitions
traces ⊥ (P ) = traces(P ) ∪ divergences(P )failures ⊥ (P ) = failures(P ) ∪ {(s, X ) | s ∈ divergences(P )}176

Operational semantics

7.4.2

Inﬁnite traces and inﬁnite branching

There is one further important type of process behaviour that can be extracted from
LTSs in much the same way that we have seen done for ﬁnite traces, divergences
and failures. This is the inﬁnite traces, the inﬁnite sequences of communications
a process can engage in – an obvious extension of the idea of ﬁnite traces. Theuunotations −→ and =⇒ can be extended to inﬁnite u, though they now become
unary rather than binary relations on the nodes in an LTS:
• If u = xi | i ∈ N ∈ (Στ )ω (the set of inﬁnite sequences of members of Στ ),
xi
u
Pi+1
we say that P −→ if there exist P0 = P , P1 , P2 , . . . such that Pi −→for all i .
uu• If u ∈ Σω then P =⇒ if and only if there exists u  ∈ (Στ )ω such that P −→
and u = u  \ τ .
’s, being ﬁnal, play no part in inﬁnite traces. Note that not all u  ∈ (Στ )ω haveu  \ τ inﬁnite – the others all have the form sˆτ ω and give rise to divergences.
Inﬁnite traces have more in common with divergences than with ﬁnite traces,in the sense that both take an inﬁnite amount of time to unfold and result fromthe process performing inﬁnitely many actions (in the case of divergence, all but
ﬁnitely many being τ ’s). This means that, as with the set of divergences, there is
no reasonable way to model, in the denotational semantics, what goes on in theinﬁnite traces after potential divergence. The set of inﬁnite traces we extract froman LTS therefore closes up after potential divergence, rather than oﬀering a choiceof two functions as with ﬁnite traces and failures.
uinﬁnites(P ) = {u | P =⇒} ∪ {sˆu | s ∈ divergences(P ) ∩ Σ∗ ∧ u ∈ Σω }It makes a lot of sense, of course, to combine ﬁnite and inﬁnite traces into asingle set
Traces(P ) = traces ⊥ (P ) ∪ inﬁnites(P )This set is, naturally, always preﬁx closed like traces(P ) and traces ⊥ (P ). Thus,
every ﬁnite preﬁx of an inﬁnite trace is also in this set. Studying inﬁnite traces only
conveys extra information about a process if the reverse of this can fail: if there canbe u not in inﬁnites(P ) all of whose ﬁnite preﬁxes are in Traces(P ), for otherwise
Traces(P ) = traces ⊥ (P )where A = A ∪ {u ∈ Σω | {s | s < u} ⊆ A}. We will say that Traces(P ) is closed
when this happens.

7.4

Relationships with abstract models

177

There is a large and important class of LTSs where this identity always holds:
ones with the following property:
Definition The LTS C is said to be ﬁnitely branching if for all nodes P and eachx ∈ Σ,τ , the setx{Q | P −→ Q}
is ﬁnite.
This says that there are only ﬁnitely many nodes we can reach from a given
one under a single action. This means that, if we know what action or sequenceof actions have occurred, there is only ﬁnite uncertainty, or nondeterminism, about
what state the process has reached. If Σ is inﬁnite, because the above condition
only restricts the size of the set that is reached after a single event, it is possiblethat a node of a ﬁnitely-branching LTS might have inﬁnitely many successors.
The proof that nodes in ﬁnitely-branching LTSs have closed Traces(P ) is acorollary of the following standard result, which we will want to use a number oftimes in the mathematical analysis of CSP.
Theorem 7.4.1 (König’s lemma) Suppose Xi is, for each i ∈ N, a non-empty
finite set and that fi : Xi+1 → Xi is a (total) function. Then there is a sequencexi | i ∈ N such that xi ∈ Xi and fi (xi+1 ) = xi .
Proof We can compose the individual functions together to get, for r > s, functions fr ,s : Xr → Xs :fr ,s = fs ◦ . . . ◦ fr −1
Fix s in N. It is easy to see that fr ,s (Xr ) is a decreasing series of subsets of
Xs for r > s (i.e., fr ,s (Xr ) ⊇ fr +1,s (Xr +1 ) for all r ), since
fr +1,s (Xr +1 )= fr ,s (fr (Xr +1 ))⊆ fr ,s (Xr )But any decreasing sequence of ﬁnite sets must be eventually constant, and since
the members of the sequence are all non-empty we have thatXs∗ =r >s fr ,s (Xr )is non-empty and equals fr ,s (Xr ) for all suﬃciently large r .
∗) = Xs∗ . The Xs∗ ,From this it follows that when we vary s, we have fs (Xs+1
and the functions fs restricted to these sets, thus satisfy the assumptions of thelemma and have the additional property that the restricted fs are onto.

178

Operational semantics

f1
X0

f2
X1

f3
X3

X2

Figure 7.8 The proof of König’s lemma.
∗
Now simply pick x0 ∈ X0∗ , and for each s let xs+1 be any member of Xs+1
such that fs (xs+1 ) = xs . This must exist by what we observed above.

Figure 7.8 illustrates a simple example of this proof. A few of the decreasing
subsets fr ,1 (Xr ) of X1 are illustrated. The elements in black are those which, on
the evidence before us, are candidates for the Xr∗ .
König’s lemma is often stated in graph-theoretic terms: a ﬁnitely-branchingtree with nodes at every (natural number) depth below a root r has an inﬁnite pathfrom r . The sets Xi just become the nodes reachable in i steps from r , and thefunctions fi map each node to the one from which it was reached.
We can now use this result to establish the result about ﬁnitely-branching
LTSs.
Theorem 7.4.2 If C is a finitely-branching LTS, and P ∈ Ĉ , then Traces(P ) is
closed.
Proof Let u ∈ Σω be such that {s ∈ Σ∗ | s < u} ⊆ traces ⊥ (P ). We can assume
that none of these s’s is in divergences(P ), for then u ∈ inﬁnites(P ) by deﬁnition.
The proof works by applying König’s lemma to the nodes reachable from P on
traces that are preﬁxes of u. We can formally deﬁne sets and functions for thelemma as follows:s• Xn = {(Q, s) | Q ∈ C ∧ s ∈ (Στ )n ∧ P −→ Q ∧ s \ τ < u}s

• If (Q, sˆx ) ∈ Xn+1 then there must be R ∈ C such that P −→ R andx
R −→ Q. Necessarily (R, s) ∈ Xn . Let fn (Q, sˆx ) be any such (R, s) (R isnot necessarily unique, but this does not matter).

7.4

Relationships with abstract models

a

179

τ
a

τ

a
a

τ

a
τ

a

a

a
a

a

Figure 7.9 The role of divergence in Theorem 7.4.2.
The sets Xn are all ﬁnite by induction on n, using the assumption that C is ﬁnitely
branching: if (Q, s) ∈ Xn , then the set of its successors in Xn+1 is contained in theﬁnite setτa{(R, sˆτ ) | Q −→ R} ∪ {(R, sˆa) | Q −→ R}
where a is the unique element of Σ such that (s \ τ )ˆa < u. That the Xn are
all non-empty is an easy consequence of the assumption that s ∈ traces ⊥ (P ) for alls < u.
König’s lemma then gives a sequence (Pi , si ) such that fi (Pi+1 , si+1 ) =(Pi , si ). The structure of the Xi and the fi imply that there is an inﬁnite sexi
Pi+1 .
quence u  = xi | i ∈ N ∈ (Στ )ω such that si = x0 , . . . , xi−1  and Pi −→The fact that si \ τ < u for all i implies u  \ τ ≤ u. In fact, u  \ τ = u sinceotherwise (contrary to our assumption) a preﬁx of u is in divergences(P ).
Figure 7.9 shows how a ﬁnitely nondeterministic system can (for the inﬁnite
trace a, a, a, . . .) depend on the divergence-closure of inﬁnites(P ) to make thisresult true.
On the other hand, as soon as we allow inﬁnite branching, the set of inﬁnite
traces does convey important information. For example, consider the two systems

180

Operational semantics

Figure 7.10
a.)Inﬁnite branching makes inﬁnite traces signiﬁcant. (All actions are

in Figure 7.10: they clearly have the same sets of failures, divergences and ﬁnite
traces, but the one on the left has the inﬁnite trace aω while the other does not.
We will study the consequences of distinctions like this, and the extra power inﬁnite
traces give us for speciﬁcations, in Chapter 10.
The above result makes it important that we understand which CSP terms
produce ﬁnitely-branching operational semantics. Every one of the operators, if
applied to a term that already has inﬁnite branching, is capable of producing inﬁnite
branching itself. But fortunately only three operators are capable of introducing
inﬁnite branching, or unbounded nondeterminism as it is often called.
• The choice operator
when S is inﬁnite.

S clearly introduces inﬁnite branching (of τ actions)• If the set X is inﬁnite, then P \ X can branch inﬁnitely (on τ ) even if P doesnot. For example, the process Q = (?n : N → P (n)) \ N is operationallyequivalent to {P (n) \ N | n ∈ N}.
• If the relation R is such that {x | x R y} is inﬁnite for any y, then therenamed process P [[R]] can branch inﬁnitely on y when P is ﬁnitely branching.
For example, the functional renaming f [Q] where f (n) = 0 for all n ∈ N
introduces inﬁnite branching.
The last two of these can only happen when Σ is inﬁnite, but there is no such
limitation on the ﬁrst.
We could easily prove that avoiding these three things guarantees ﬁnite
branching. The proof comes in two parts:

7.5

Tools

181

• Show by structural induction8 that the initial actions of any CSP term not
involving one of these three constructs are ﬁnitely branching.
x• Show that if P does not involve them, and P −→ Q, then neither does Q.

Exercise 7.4.1 Use your answer to Exercise 7.3.2 and the functions deﬁned in thissection to determine traces(P ), failures(P ) and divergences(P ) for each of the processes
refered to in that earlier exercise. Is any of them inﬁnitely nondeterministic?
Exercise 7.4.2

7.5

Can (

{COUNT n | n ∈ }) \ down diverge? What are its failures?

Tools

The role of an animator like ProBE is to bring the operational semantics to life:
it will let you carry out the actions of a process as derived from the operationalsemantics. It may well allow you to see how the rules of the operational semantics
have derived each action of a compound process from the actions of its parts.
8 Structural induction is a technique for proving properties of objects in syntactically-deﬁned
sets such as the set of all CSP terms CSP. It says that if you can prove a property R of each term
T of a syntax on the assumption that R holds of all the immediate subterms that T is built from(e.g., assuming it holds of P and Q to prove it holds of P 2 Q) then it holds for all members of thesyntax. Over most programming languages one can justify this principle easily, because structural
induction is implied by ordinary mathematical induction over the size of programs. But a careful
examination of what we allow as CSP terms reveals this argument does not work here, since wehave inﬁnite mutual recursion as well as the inﬁnitary constructs
S and ?x : A → P , meaningthat there are terms with no ﬁnite ‘size’ in the ordinary sense. Structural induction can still bejustiﬁed provided we assume that the syntax is well-founded, meaning that there is no inﬁnite
sequence of terms each of which is a subterm of its predecessor. This means we cannot have terms
likea 1 → a2 → . . . → ai → . . .
actually in the language, though there is nothing wrong with achieving the same eﬀect using an
inﬁnite mutual recursion Pi = ai → Pi+1 .
Well-foundedness corresponds to the natural assumption that the language generated by a syntax
is the smallest set of terms which is closed under all the constructs of the syntax. This leads to atrivial proof of the principle of structural induction: the assumptions of that rule imply that theset of terms in the language that satisfy R is itself closed under all the constructs, and therefore
contains the smallest set.
Readers with the necessary mathematical background might like to note that, in order to makethe inﬁnitary syntax of CSP well deﬁned, it is necessary to put some bound on the size of sets that
can haveapplied to them. This can be any inﬁnite cardinal number κ, which can be chosen toaccommodate all the nondeterministic choices required for a given theory. (The necessity of thisbound is tied up with Russell’s paradox and the non-existence of a set of all sets.)

182

Operational semantics

You can use a tool like this both to help you understand the operationalsemantics and to apply these semantics to allow you to experiment with complex
process deﬁnitions.
FDR is heavily dependent on the operational semantics. This is discussed inAppendix C.

7.6

Notes

Historically, the operational semantics of CSP was created to give an alternative
view to the already existing denotational models rather than providing the intuitionin the original design as it has with some other process algebras such as CCS.
The style of presenting an operational semantics as an inference systemevolved at about the same time as CSP, the main inﬂuence being Plotkin’s notes[94] which set out the general style used here. The operational semantics of CSP
ﬁrst appeared in something like their present form in Brookes’s thesis [15], thoughessentially the same semantics in LTSs using diﬀerent notations (more remote from
Plotkin’s) were present in [18, 101]. In providing CSP with an operational semanticsof this form we were certainly heavily inﬂuenced by the earlier work on CCS, thestandard treatment of which is now [82].
The version in [15] did not use the τ -expansion rule for recursion unfolding.
This ﬁrst seems to have appeared in print in [87], though it had certainly been in
use for several years by then. This rule is interesting because it shows up one of the
major diﬀerences between CSP and those other process algebras which, like CCS,
give semantic signiﬁcance to a single τ action. If it were not the case that, for anyτnode P , another node Q whose only action is Q −→ P is equivalent to P , then theunwinding rule would be much more controversial.
The semantics presented in this book diﬀer from the earlier versions in theway , and hence the distributed termination of parallel constructs, are interpreted.

Chapter 8

Denotational semantics

8.1

Introduction

CSP has been given a number of denotational semantics, mainly based on sets of
behaviours such as traces, failures and divergences. It is not necessary to understand a lot of diﬃcult mathematics to use the behaviours as a tool for describingor specifying processes, especially when equipped with automated tools for evaluating which behaviours a process has. Indeed, the sets of behaviours of processes
can equally and equivalently (thanks to congruence theorems) be extracted fromoperational semantics. However, it is possible to gain a much deeper insight into
the language by investigating these notions of equivalence and the properties of themodels they generate. In this chapter we set out the main ideas and methods ofdenotational semantics, or at least the ones important to CSP, and show how threemodels for CSP each give an interesting semantics.
In building a denotational semantics – a function1 S[[·]] from a programming
language L into a mathematical model M – there are a number of things we must
always seek to do. The following paragraphs set out these aims.
Natural but abstract relationship between model and language
Ideally the construction of M should have a close relationship to a natural languagefor describing the ‘essence’ of programs in L. This makes it easier to devise andjustify the semantic clauses for the diﬀerent operators and to use the semantic valueof a program as a vehicle for specifying properties of it.
1 The special style of brackets [[·]] is commonly used in denotational semantics to separate pro-gram syntax from abstract semantics. They have no formal signiﬁcance, but give a useful visualsignal. In fact we will not generally use them when it comes to dealing with CSP except in places
where a clear distinction between syntax and semantics is vital.

184

Denotational semantics

Natural notion of process equivalence
The equivalence over process terms induced by the semantics should be a naturalone, in the sense that for all terms P and Q, S[[P ]] = S[[Q]] if and only if P and Q
behave equivalently in some clearly deﬁned sense. Depending on the way the model
is built this may be obvious, or it may be rather more subtle. One of the best waysof demonstrating this is to identify a very few (rarely more than one or two) simple tests based on simple speciﬁcations (such as ‘does not immediately deadlock’,‘does not immediately diverge’ or ‘does not have the trace fail’) which are uncontroversial reasons for deciding two processes are diﬀerent, and then showing that
S[[P ]] = S[[Q]] if and only if, for all process contexts C [·], C [P ] and C [Q] satisfy
the same selection of these tests. If one can prove a result like this we say that thesemantics S[[·]] is fully abstract with respect to the chosen selection of properties.
We will study this idea in depth in the next chapter.
Model must be a congruence
The semantics has to be a congruence, in that for each operator ⊕ in the language,
it is possible to compute S[[P ⊕ Q]] in terms of S[[P ]] and S[[Q]] (with obvious
modiﬁcations for non-binary operators). It is quite possible to propose what looks
like a good model for a language only to discover that this property fails for some
operator. For example, we might design a model for CSP in which a process wasmodelled by (traces(P ), deadlocks(P )), where deadlocks(P ) is the set of traces on
which P can deadlock, as a simpliﬁcation of the failures model. We would then ﬁnd
it possible to give semantic clauses for deadlocks(P ) for most CSP operators, forexampledeadlocks(STOP )= {}

deadlocks(a → P )= {aˆs | s ∈ deadlocks(P )}deadlocks(P 2 Q)=

deadlocks(P= deadlocks(P ) ∪ deadlocks(Q)Q)

deadlocks(P ; Q)=((deadlocks(P ) ∪ deadlocks(Q)) ∩ {s | s = })∪ (deadlocks(P ) ∩ deadlocks(Q))(deadlocks(P ) ∩ Σ∗ )∪ {sˆt | sˆ ∈ traces(P ) ∧ t ∈ deadlocks(Q)}But this breaks down for parallel operators involving synchronization, such as  .
XIf, for exampleP= (a → P )(b → P )R= (a → R) 2 (b → R)

8.1

Introduction

185

P and R have exactly the same sets of traces ({a, b}∗ ) and deadlock traces ({}).
But, while R  R still cannot deadlock, the process P  P can (on any trace)
{a,b}

{a,b}

because the left-hand P can opt only to accept a and the right-hand one can opt
only to accept b. Thus it is impossible, in general, to predict the semantics of S  T
Xfrom those of processes S and T , so our proposed semantics is not a congruenceand must be rejected.
Fixed-point theory
Just as we need to be able to combine semantic values accurately under all of thebasic operators of our language, we also need to be able to compute the valuesof recursively deﬁned processes. While you can think of recursion as just anotheroperator that is applied to process terms (turning P into µ p.P ), it is conceptuallya quite diﬀerent thing to operators like a →, 2 and  . What µ p.P represents is aXsolution to the equation
A = P [A/p]
Since the denotational semantics is a congruence, the semantic value S[[P [A/p]]] isa function of the value S[[A]], in the sense that if S[[A]] = S[[B ]], then S[[P [A/p]]] =S[[P [B /p]]]. Thus S[[µ p.P ]] is a ﬁxed point of this function. You can think of theterm P as a context in which the identiﬁer p represents the process argument.
Giving a denotational semantics to recursively deﬁned processes thus reduces
to ﬁnding ﬁxed points of the functions from M to itself that are generated by processcontexts. This means that every appropriate function over M must have a ﬁxed
point – not something that is true for most mathematical structures. And, of course,
there may be more than one ﬁxed point, in which case we have to make a rational
choice of which one to select.
Just as the semantics of recursion is stylistically very diﬀerent from the semantic clauses of more ordinary operators, so too are the methods available forproving properties of recursively deﬁned process. We need ways of proving properties of the objects extracted by whatever mechanism is chosen to pick ﬁxed points.
Such proof methods, the main ones seen so far being the UFP rule and ﬁxed-point
induction, are inevitably intimately tied up with whatever mathematical theory isused to prove the existence of the ﬁxed points.
In the later sections of this chapter we formalize several denotational semantics for CSP and show how they meet the aims set out above.
Two diﬀerent theories, partial orders (with Tarski’s theorem) and metricspaces (with the contraction mapping theorem) for proving the existence of ﬁxed
points are commonly used in denotational semantics. Both of these are used in CSP

186

Denotational semantics

and we use them widely in this and subsequent chapters. A tutorial introduction
to both can be found in Appendix A, and readers not familiar with one or bothshould study that before continuing with the present chapter.

8.2

The traces model

We have already deﬁned the traces model and the semantics of each individual
operator over it. T is the set of non-empty, preﬁx-closed subsets of Σ∗ . This,
as is shown in Section A.1.1, is a complete lattice under the reﬁnement order T(which equates to reverse containment). But, since any complete lattice is also acomplete lattice when turned upside down, we actually have three diﬀerent choicesof theories to get us the ﬁxed points required for recursions: the two senses of theorder, or metric spaces. In this section we discover which of these is the right answer
by looking carefully at the properties of the model and the CSP operators over it.
It is instructive to examine the ways that the various operators are deﬁned
over T . (Their deﬁnitions can be found in Section 1.3.1 and with later deﬁnitionsof operators.) In every case, it is possible to restructure them so that instead ofbeing functions from sets of traces to sets of traces, they are lifted in a natural
way from relations over traces. This is well illustrated by considering the sequential
composition operator P ; Q. We can derive its traces from two relations: one(binary) between traces of P and output traces and one (ternary) between tracesof P , traces of Q and output traces. These are describeds[; ]1 u(s, t)[; ]1,2 u⇔⇔s ∈ Σ∗ ∧ u = s∃ s0 .s = s0ˆ ∧ u = s0ˆtThus, we get one relation describing the overall behaviours that the ﬁrst argument
can produce without the help of the second, and one describing the behaviours inwhich both arguments are active. There are two further relations we might needfor a binary operator ⊕: [⊕]2 for the second argument acting alone and [⊕]• for theset of behaviours that can be produced without either playing a part; but in thecase of ‘;’ these are both empty. In general we then get
traces(P ⊕ Q)

= {u | ∃ s ∈ traces(P ), t ∈ traces(Q).(s, t, u) ∈ [⊕]1,2 }∪ {u | ∃ s ∈ traces(P ).(s, u) ∈ [⊕]1 }∪ {u | ∃ t ∈ traces(Q).(t, u) ∈ [⊕]2 }∪ [⊕]•For a unary operator we similarly need two relations: one for behaviours involving
its argument and another for those that do not. The following give clauses for mostof the other main CSP operators. Where a relation is not speciﬁed it is empty.

8.2

The traces model187[a →]• = {}[a →]1 = {(s, aˆs) | s ∈ Σ∗ }[2]1,2 = {(s, , s), (, s, s) | s ∈ Σ∗ }[ ]• = {}[ ]1 = {(s, s) | s ∈ Σ∗ }[ ]2 = {(s, s) | s ∈ Σ∗ }[  ]1,2 = {(s, t, u) | u ∈ s  t} where s  t is as deﬁned in Section 2.4 andXXextended to deal with  on page 148.

X[\ X ]1 = {(s, s \ X ) | s ∈ Σ∗ }[ [[R]] ]1 = {(a1 , . . . , an , b1 , . . . , bn ), (a1 , . . . , an , , b1 , . . . , bn , ) |∀ i .ai Rbi }It is interesting to note that the relations given above for and 2 are diﬀerent,
even though these operators are identical over trace sets. On one hand, this showsthat the choice of relations to achieve a given eﬀect is not unique. On the other,
the precise forms chosen have been inﬂuenced by the very diﬀerent operationalsemantics of the two (see Section 7.3): in P Q it is never the case that both P
and Q have ‘run’, while in P 2 Q they may both have executed internal actions
before the choice was resolved.
Perhaps the most important consequence of this relational representation isthat it automatically yields important structural results about the semantics.
Theorem 8.2.1 Any operator ⊕ over T definable as the lifting of a family of trace
relations is fully distributive in each of its arguments, in the sense that F ( S ) ={F (P ) | P ∈ S } for each non-empty S (where F (·) represents any unary function
produced by fixing all arguments of ⊕ other than the one we are studying).
Proof Suppose ﬁrst that ⊕ is unary. Then there are no other arguments to ﬁx,
and soF(S)

= [⊕]• ∪ {u | ∃ s ∈ S .(s, u) ∈ [⊕]1 }
= [⊕]• ∪ {{u | ∃ s ∈ P .(s, u) ∈ [⊕]1 } | P ∈ S }={[⊕]• ∪ {u | ∃ s ∈ P .(s, u) ∈ [⊕]1 } | P ∈ S }{F (P ) | P ∈ S }=the equality between the second and third lines following because S is non-empty.
If ⊕ were not unary then ﬁxing all arguments but one means we can divide
the relations into those which involve the chosen one and those that do not, andderive a unary and a binary relation to use in the above proof. For example, if we188

Denotational semantics

are studying the ﬁrst argument of a binary operator and ﬁx the second argument
to be Q ∈ T then the cross-section F (P ) = P ⊕ Q gives relations[⊕Q]•= [⊕]• ∪ {u | ∃ t ∈ Q.(t, u) ∈ [⊕]2 }[⊕Q]1= [⊕]1 ∪ {(s, u) | ∃ t ∈ Q.(s, t, u) ∈ [⊕]1,2 }This completes the proof.
This gives another view of the distributive laws that hold of CSP operators
and also proves (i) that they are all monotonic with respect to the reﬁnement orderand (ii) that under the subset order (i.e., the reverse of reﬁnement) they are allcontinuous. The former is because we know P
Q is equivalent to P Q = P ,and so F (P ) F (Q) = F (P ) for distributive F (·). The latter is because continuity
under that order is equivalent to distributivity over directed sets.
It is also informative to consider continuity in the other direction. Now, itturns out, not all operators are continuous. An example that fails is hiding an
inﬁnite set X = {a1 , a2 , . . .}, since, if we pick b ∈ X , the processes
Pn = STOP{ai → b → STOP | i ≥ n}form an increasing sequence underPn \ X = STOP

T with limit STOP . However, for every n,

b → STOPso that the limit of applying \ X to the sequence:{Pn \ X | n ∈ N}
equals this value, which of course is not equal to STOP \ X .
The key to which operators are continuous lies in the relations that represent
them. The crucial feature of \ X (whether or not X is inﬁnite, though it may not
be empty) is that for any trace u not including a member of X , the set {s ∈ Σ∗ |(s, u) ∈ [\ X ]1 } is inﬁnite: if we are told that s ∈ traces(P \ X ), there are inﬁnitely
many potential reasons for this and as we go through an inﬁnite reﬁning sequenceof processes these reasons can disappear just as in the example above until there
are none left in the limit.
Except for hiding, the only relation described above that can have this inﬁnitary property is the one for renaming P [[R]] when the R used is inﬁnite-to-one(i.e., it relates an inﬁnite set of before-renaming events to a single after-renaming
one).

8.2

The traces model

189

Consider, for example, the case of ;. The fact that there are two2 diﬀerent
relations generating traces is irrelevant since if there were an inﬁnity of diﬀerent
reasons for a given trace, inﬁnitely many of these would have to come from one
or other. [; ]1 is obviously ﬁnitary since it is a subset of the identity relation –each trace has at most one precursor here. [; ]1,2 is more interesting since the tracea1 , . . . , an  has precursors{(a1 , . . . , ak , , ak +1 , . . . , an ) | k ∈ {0, . . . , n}}which, though always a ﬁnite set, grows in size with the length of trace.
Formally, we deﬁne an n-ary relation R to be ﬁnitary if, for all v in thedomain of its ﬁnal component,{(x1 , . . . , xn−1 ) | (x1 , . . . , xn−1 , v ) ∈ R}

is ﬁnite

The following result shows the importance of these ideas to continuity.
Theorem 8.2.2 If ⊕ is any operator of finite arity, which can be represented bya family of relations all of which are finitary, then it is T -continuous in eachargument.
Proof The reduction of this problem to the case where ⊕ is unary is essentiallythe same as in the previous proof, its ﬁnite arity being needed simply so that the
number of representing relations is also ﬁnite. So we will restrict out attention tothat case, so that ⊕ is generated by the relations [⊕]• and [⊕]1 where the latter is
ﬁnitary (there being no question that a unary relation like [⊕]• can fail to be). We
are therefore considering the function
F (P ) = [⊕]• ∪ {u | ∃ s ∈ P .(s, u) ∈ [⊕]1 }To prove it is continuous it is suﬃcient (thanks to its known monotonicity) to show
F(

∆)

T

{F (P ) | P ∈ ∆}or, equivalently,
F(

∆) ⊇

{F (P ) | P ∈ ∆}for any directed ∆ ⊆ T . So suppose u is a trace belonging to the right-hand side.
We can dispose of it immediately if u ∈ [⊕]• for it is then trivially in the left-hand
2 In the case of there being infinitely many relations, as there would be forthis would be of concern if the ranges of the relations overlap.

S with S inﬁnite,

190

Denotational semantics

side; so we can assume u ∈ [⊕]• . If u did not belong to the left-hand side, it follows
that each member of the ﬁnite set
pre⊕ (u) = {s | (s, u) ∈ [⊕]1 }is absent from ∆. For each such s we can choose Ps ∈ ∆ such that s ∈ Ps .
Finiteness and the fact that ∆ is directed then implies that there is a P ∗ ∈ ∆ suchthat Ps T P ∗ for all such s. Necessarily then, P ∗ ∩ pre⊕ (u) = {} and henceu ∈ F (P ∗ ) contradicting what we assumed above. This completes the proof.
This, of course, only proves continuity for each individual CSP operator. As
you will ﬁnd in studying Appendix A, the composition of continuous (monotone)
operators is itself continuous (monotone), which means that the above result easily
yields the continuity of any expression built out of continuous operators. One
important point that is often forgotten about in this type of explanation is thepossibility of there being one recursion inside another, as inµ p.(a → (µ q.p 2 b → q))
The fact here is that, in order to deﬁne the meaning of the µ p recursion, we haveto think of the inner recursion as a function of p (i.e., the ﬁxed point varies withp). Fortunately Lemma A.1.8 (page 508) tells us that this causes no problems, but
it is important that you understand clearly why it is needed.
T can be given a metric structure based on the system of restriction functions
P ↓ n = {s ∈ P | #s ≤ n}which are closely analogous to, and satisfy the same collection of properties as, thefamily introduced in Section A.2 for individual traces. Following the same approach
set out there gives the distance functiond (P , Q) = inf {2−n | P ↓ n = Q ↓ n}
If the sequenceP0 , P1 , P2 , . . .satisﬁes Pn+1 ↓ n = Pn , then it is easy to see that P ∗ = {Pn | n ∈ N} satisﬁes
P ∗ ↓ n = Pn . Thus T is (following the deﬁnitions in Section A.2) a complete
restriction space and so the metric is complete.
The restriction functions, and hence the complete metric structure, extend
easily to the product spaces used to reason about mutual recursions. If Λ is any
non-empty indexing set, we restrict a vector P ∈ T Λ componentwise:(P ↓ n)λ = Pλ ↓ n

8.2

The traces model191

It is the metric/restriction structure which is at the heart of the theoryof guardedness/constructiveness that we ﬁrst met in Chapter 1. For we can now
precisely deﬁne what it means for a function F to be constructive with respect to
T : for all processes P , Q and n ∈ N
P ↓ n = Q ↓ n ⇒ F (P ) ↓ (n + 1) = F (Q) ↓ (n + 1)
As discussed in Section A.2, it is useful to deﬁne a corresponding concept of nondestructive function:
P ↓ n = Q ↓ n ⇒ F (P ) ↓ n = F (Q) ↓ n
As shown in there, a function is constructive if and only if it is a contraction
mapping with respect to the associated metric and is non-destructive when it isnon-expanding in the metric space.
This immediately means that a constructive function has a unique ﬁxed point(thus justifying the UFP rule for analyzing recursions that we have used frequently
through this book).
In Section 1.3.1 we declared that a recursion was ‘guarded’ if every recursive
call was directly or indirectly guarded by a communication, but when we met thehiding operator in Section 3.1 we had to exclude recursions in which hiding wasused. Both of these steps are easily explained when we examine how the individual operators behave with respect to the restriction functions. The following resultsummarizes the position and is easy to establish; combining it with the compositional rules for constructive/non-destructive functions justiﬁes the earlier claims.

Lemma 8.2.3 Each of the operators, 2,  , renaming and ; is non-destructive
Xover T in each argument. The prefix operators a → and ?x : A → are constructive.
We could prove most of these in terms of the relational representations of
the operators: if an operator can be represented by relations that are all nondestructive in the sense that the result trace of each tuple is never shorter than anyof the others, then it is easily shown to be non-destructive, and if the other traces
are always strictly shorter then it is constructive. The only relations amongst thosedeﬁned above that are not non-destructive are [\ X ]1 (as one might expect) and[; ]1,2 which contains tuples like (a, , , a). That ; is non-destructive despite
this observation follows because any trace that results from such a ‘destructive’
triple also results from [; ]1 as the contribution of the second process to [; ]1,2 mustbe  in such a case.
There are, as we saw in Chapter 4, useful classes of recursion that do involve hiding because of the way they create dynamic networks using piping and192

Denotational semantics

enslavement. It is possible to ﬁnd ones that actually behave properly despite notbeing constructive at all, but most can be shown constructive using careful analysis.
Recall the recursive deﬁnition of an inﬁnite buﬀer:
B + = left?x → (B + >> right!x → COPY )When we introduced this on page 106 we saw an informal argument for the composition (P >> right!x → COPY ) being non-destructive as a function of P because
the process on the right of the >> is built so that it compensates for all the events
that get hidden. We now have the mathematics to analyze this situation, in clause(a) of the following lemma, whose proof is left as an exercise.
Lemma 8.2.4 (a) If Q satisfies
s ∈ traces(Q) ⇒ #(s ↓ left) ≤ #(s ↓ right)
then the function F (P ) = P >> Q is non-destructive.
(b) If Q satisfies
s ∈ traces(Q) ⇒ #(s ↓ right) ≤ #(s ↓ left)then the function F (P ) = Q >> P is non-destructive.
(c) If, for each s ∈ traces(Q) and i ∈ {1, . . . , k }, we have#(s \ {| m1 , . . . , mk |}) ≥ #(s ↓ mi )then the function F (P1 , . . . , Pk ) = Q//m1 :P1 // . . . //mk :Pk is non-destructive in eachof its arguments.
Where the metric ﬁxed point theory works it is, by virtue of the uniqueness of
the ﬁxed points it produces, certain to agree with those produced by both directionsof the partial order (which, of course, then agree with each other). Virtually all
well-behaved recursions ﬁt within it, and in Section 9.2 we will see evidence that
all other well-behaved ones (ones not introducing divergence) force there to be aunique ﬁxed point. Nevertheless it is preferable to be in a position to interpretbadly-behaved ones too, such as the three set out below.
• Z0 = Z0• Z1 = a → (Z1 \ {a})8.2

The traces model

193• Z2 = (up → (AZ //u:Z2 )) 2 (iszero → Z2 ), whereAZ= down2 up

AZ→ (u.iszero → AZ 
2 u.down → u.down → AZ )→ u.up → u.up → AZ

= iszero → AZ 
2 up → AZ

Z2 is an interesting recursion closely modelled on the enslavement version of
the counter process, seen on page 110, but which increments and decrements
its slave by two rather than one. This violates Lemma 8.2.4 (c) since it
frequently requires its slave to have communicated a longer trace than it
has, and though the well-behaved counter is a ﬁxed point, it is not the only
one. Others are BCOUNT and PCOUNT , where
BCOUNT=iszero → BCOUNT
2 up → (down → BCOUNT
2 up → (up → STOP 2 down → STOP ))PCOUNT=iszero → PCOUNT
2 up → (down → PCOUNT
2 up → MANY )

MANY

=

down → MANY
2 up → MANY

Both of these get confused when they reach the number 2 (which is thepoint where the slave counter gets raised to the same level as the overall one,leading to ill-deﬁnedness). BCOUNT reacts by deadlocking soon after, while
PCOUNT loses track and accepts any number of down events.
And we are in a position to interpret arbitrary CSP-deﬁned recursions, for
we have both the T and ⊆ orders. The only problem is to decide which, if either,is the right one to use.
• If we identify a recursion with the least ﬁxed point with respect to
we have to accept that the simple formula

T then∞rr =0 F (⊥)

for the least ﬁxed point does not always hold because F is not always continuous. In this order, ⊥ is Σ∗ . The ﬁxed point produced will always be theone with as many traces as possible, consistent with its being a ﬁxed point.

194

Denotational semantics
Essentially, with this choice, we start out with the assumption that all behaviours are possible for a recursively deﬁned process, and the constructionof the ﬁxed point is the determination of which of these traces are impossible
based solely on the information that it is a ﬁxed point.
• If we identify a recursion with the ⊆-least ﬁxed point then the above formula(with ⊥ now being STOP = {}) will always hold and we will always get
the process with as few traces as possible. With this choice, the constructionof the ﬁxed point establishes which traces are certainly in any ﬁxed point.

Now, in fact, the operational semantics given in Chapter 7 gives precisely
the traces corresponding to the second choice (we will examine this fact further in
Section 9.4). The only reasons to pick the ﬁrst option would be (i) if one were
proposing an alternative operational semantics in which some under-deﬁned recursion could produce some other trace and (ii) somehow to express our disapproval ofunder-deﬁned recursions by cluttering up their semantics with traces that may wellmake the process fail some safety speciﬁcation. The ﬁrst of these seems unlikely tothe author, and the second really represents muddled thinking: in the traces model
we can only expect to reason about safety properties and it is not possible accurately to model divergence (the natural way in which an under-deﬁned recursion
such as any of the above manifests itself at the point where the under-deﬁnedness‘bites’) without expressly including it in the model.
Therefore the correct choice for T is to identify every recursion µ p.F (p) withits ⊆-least ﬁxed point which, because of the continuity of all operators with respect
to this order, is just the set of all traces which some F n (STOP ) can perform. For
the examples Z0 , Z1 and Z2 above these are respectively {}, {, a} and thetraces of BCOUNT .
The identiﬁcation of a diverging process like Z0 (or, indeed, a straightforward
example like (µ q.a → q) \ {a}, about which there is no ambiguity in the calculationof the ﬁxed point) with the most reﬁned process of T is simply a reﬂection of thedeﬁciencies of this model for reasoning about anything other than safety properties.
This is similar to the phenomenon that identiﬁes the deadlocked process STOP
with the same value. As we will see in the next section, as soon as we model both
safety and liveness in the same model, there is no most reﬁned process.
Exercise 8.2.1 Find sequences of processes of the form P0 T P1 T P2 T . . .
illustrating failures of T -continuity of (i) hiding a single event \ {a} and (ii) inﬁnite-toone renaming.
Exercise 8.2.2

Prove that the relation [ ]1,2 is ﬁnitary.
X

8.3

The failures/divergences model

195

Show that if a unary operator ⊕ satisﬁes (s, t) ∈ [⊕]1 ⇒ #t > #s,
then ⊕ is constructive.

Exercise 8.2.3

Exercise 8.2.4
Prove Lemma 8.2.4 (c), and hence show that the Zero // recursion
given on page 110 is constructive.
Suppose Σ is inﬁnite. Use renaming to ﬁnd a CSP-deﬁnable functionthat is constructive but not continuous with respect to T .

Exercise 8.2.5

8.3

The failures/divergences model

8.3.1

Building the model

As we have already speciﬁed in Section 3.3, in the failures/divergences model eachprocess is modelled by the pair (failures ⊥ (P ), divergences(P )), where, as formallyset out in Section 7.4.1,• divergences(P ) is the (extension-closed) set of traces s on which P can diverge, in the sense that an inﬁnite unbroken sequence of τ actions can occur
after some s  ≤ s.
• failures ⊥ (P ) consists of all stable failures (s, X ) (where s is a trace of P and
X is a set of actions P can refuse in some stable (unable to perform a τ or) state after s, or results from a state after s which can perform  andX ⊆ Σ), together with all pairs of the form (s, X ) for s ∈ divergences(P ).
This model has long been taken as the ‘standard’ equivalence for CSP, and withgood reason. It allows us to describe safety properties (via traces) and to assertthat a process must eventually accept some event from a set that is oﬀered to it(since stable refusal and divergence are the two ways it could avoid doing this, andwe can specify in this model that neither of these can happen). Although, as we will
see in Sections 8.4 and 10.1, it is possible to reason about either (stable) failures ordivergences in the absence of the other, neither alone provides a suﬃciently complete
picture of how processes behave.
It is important to notice that if s is a trace that process P can perform thencertainly either P diverges after s or reaches a stable state or one that can perform. Thus, the failure (s, {}) always belongs to failures ⊥ (P ), either because of theclosure under divergence or because any stable (or ) state obviously refuses theempty set of events. It is, therefore, in general true that traces ⊥ (P ) = {s | (s, {}) ∈failures ⊥ (P )}, and we will use this identity without comment in what follows.

196

Denotational semantics

Recall that in the traces model we identiﬁed processes with non-empty, preﬁxclosed sets of traces in Σ∗ . Similarly, in the failures/divergences model we needa number of ‘healthiness’ conditions to identify which pairs of the form (F , D)(F ⊆ Σ∗ × P(Σ ) and D ⊆ Σ∗ ) can reasonably be regarded as processes. We
formally deﬁne the model N to be the pairs P = (F , D) of this form satisfying thefollowing (where s, t range over Σ∗ and X , Y over P(Σ )):F1. traces ⊥ (P ) = {t | (t, X ) ∈ F } is non-empty and preﬁx closed.
F2. (s, X ) ∈ F ∧ Y ⊆ X =⇒ (s, Y ) ∈ F
This simply says that if a process can refuse the set X , then it can also refuse
any subset.
F3. (s, X ) ∈ F ∧ ∀ a ∈ Y .sˆa ∈ traces ⊥ (P ) =⇒ (s, X ∪ Y ) ∈ F
This says that if P can refuse the set X of events in some state then thatsame state must also refuse any set of events Y that the process can neverperform after s.
F4. sˆ ∈ traces ⊥ (P ) =⇒ (s, Σ) ∈ F
This reﬂects the special role of the termination event/signal  (see Section
7.2) and says that if a process can terminate then it can refuse to do anything
but terminate.
D1. s ∈ D ∩ Σ∗ ∧ t ∈ Σ∗ =⇒ sˆt ∈ DThis ensures the extension-closure of divergences as discussed brieﬂy above.
D2. s ∈ D =⇒ (s, X ) ∈ F
This adds all divergence-related failures to F .
D3. sˆ ∈ D =⇒ s ∈ D
The eﬀect of this axiom is to ensure that we do not distinguish between
how processes behave after successful termination. Already obliged not tocommunicate again (as  is always ﬁnal) and therefore to refuse all events(by F3), D3 states that the only way a trace sˆ can get into D is via
the implication in D1. Since  is a signal indicating termination, after thatevent there is no possibility of the process carrying on and diverging.
Our earlier assertion that the set of traces of any process is just the set{s ∈ Σ∗ | (s, {}) ∈ F } is justiﬁed for any pair (F , D) satisfying the above, becauseof F2.
It is fairly easy to see that the abstraction functions deﬁned in Section 7.4.1
for deducing (failures ⊥ (P ), divergences(P )) for a member P of an LTS give a pairsatisfying the above. That these conditions cannot be strengthened any further isdemonstrated

8.3

The failures/divergences model

197(a) by the fact that, as demonstrated in Exercise 9.4.3, there is a member of an
LTS mapping to any pair (F , D) that satisﬁes them, and(b) by the facts that, under various sets of assumptions, it can be shown thatevery member of N is the image of a CSP process: see Sections 9.3 and 10.2.
Recall that reﬁnement is deﬁned over this model by reverse containment:(F , D)
FD (F , D ) ≡ F ⊇ F ∧ D ⊇ D

Any immediately divergent process such as div is identiﬁed with the bottom
element of N :⊥N = (Σ∗ × P(Σ ), Σ∗ )for notice that, thanks to conditions D1 and D2,  ∈ divergences(P ) implies that
all of these behaviours are present.
The greatest lower bound for any non-empty subset of N is just given bycomponentwise union:
S = (



{F | (F , D) ∈ S }, {D | (F , D) ∈ S })which is naturally identiﬁed with the nondeterministic choice over S and easily
shown to be a member of N (see Exercise 8.3.3).
If s is a trace of P = (F , D), then P /s (P after s) is the pair({(t, X ) | (sˆt, X ) ∈ F }, {t | sˆt ∈ D})
which simply represents the possible behaviour of P after s has been observed.
Conditions D1 and D2 ensure that if s ∈ D ∩ Σ∗ then P /s = ⊥N . We can similarly
extract the initials and refusals of P from its failures/divergence representation:
initials(P ) =refusals(P ) ={a ∈ Σ | a ∈ traces ⊥ (P )}{X ⊆ Σ | (, X ) ∈ F }Clearly ⊥N FD P for all P , so this process is the least reﬁned underfailures/divergences reﬁnement. There is no single most reﬁned process, unlike T
where STOP was most reﬁned. It would have been worrying if there had been one,since P FD Q can be interpreted as saying that Q is more deterministic than P ,and it is implausible for there to be a single most reﬁned process in a model thatclaims to provide a complete description of processes. If there were we could put
programmers out of a job and use it every time! The maximal processes of N are

198

Denotational semantics

those that cannot diverge and can only refuse those sets implied by condition F3.
These, satisfying the following
divergences(P ) = {} ∧∀ s, a.¬(sˆa ∈ traces ⊥ (P ) ∧ (s, {a}) ∈ failures(P ))are the deterministic processes we met in Section 3.3. Let D denote the set ofdeterministic processes. We will discuss these in Section 9.1, including showingthat they are, indeed, the maximal elements of N .
When Σ is ﬁnite, N is signiﬁcantly easier to analyze and better-behaved.
The following result illustrates this.
Theorem 8.3.1 If Σ is finite then N is a complete partial order (cpo) under therefinement order and the least upper bound of any directed set ∆ of processes is
simply the componentwise intersection
P † = (F † , D † ) = ( {F | (F , D) ∈ ∆},{D | (F , D) ∈ ∆})Proof To prove this we have to show that (F † , D † ) satisﬁes all of F1–D3. All ofthese other than F3, which is the only one actually requiring the directedness of ∆,are straightforward, so we will concentrate on that one.
If (s, X ) and Y meet the conditions of F3 for the failure-set F † , we have toshow that (s, X ∪ Y ) ∈ F for every (F , D) ∈ ∆ as that would imply it is in theintersection F † . Let us ﬁx on a speciﬁc P0 = (F0 , D0 ). As P varies over ∆, the set
initials(P /s) = {a | sˆa ∈ traces ⊥ (P )}varies in such a way that
P

FD P



⇒ initials(P /s) ⊇ initials(P  /s)

As we are assuming Σ (and hence P(Σ )) to be ﬁnite, it follows that the above setsform a ﬁnite directed set under reverse containment, which means that there is a
P ‡ = (F ‡ , D ‡ ) ∈ ∆ such that it is minimum in the sense that (P ‡ /s)0 ⊆ (P /s)0 for
all P ∈ ∆. Directedness of ∆ also lets us assume that P ‡  P0 for if the one we pickﬁrst does not satisfy this we may pick one which reﬁnes both the original and P0 .
It follows easily that initials(P † /s) = initials(P ‡ /s) and so (s, X ∪ Y ) ∈ F ‡ ⊆ F0
as required.
The use of directed ﬁnite sets in this proof is essentially a re-working inrather diﬀerent language of the argument in Theorem 7.4.1 (König’s lemma). It isinteresting to compare them.

8.3

The failures/divergences model

199

This proof depends crucially on the ﬁniteness of Σ, for the result does nothold when Σ is inﬁnite. We should not be too surprised at this, since moving froma ﬁnite to an inﬁnite alphabet means that N contains processes that are fundamentally inﬁnitely, or unboundedly, nondeterministic in the sense that they cannot
be represented by a ﬁnitely nondeterministic LTS or by CSP syntax without oneof the constructs ( S for inﬁnite S , inﬁnite hiding and inﬁnite-to-one renaming –note that the last two of these can only exist in the context of inﬁnite Σ) known
to introduce it. Since reﬁnement is equated with the restriction of nondeterministic choice, if we start oﬀ (at some point in a process) with a ﬁnite range of options
then – as shown in the proof above – any directed set of reﬁnements must eventually
settle down to a ﬁxed non-empty subrange of these options, for a directed (underreverse inclusion) set of non-empty ﬁnite sets always has non-empty intersection.
On the other hand, a similar directed set of inﬁnite non-empty sets may have empty
intersection, the simplest example being, perhaps,{{0, 1, 2, . . .}, {1, 2, 3, . . .}, {2, 3, 4, . . .}, . . . , {n, n + 1, . . .}, . . .}This example can be translated directly to one showing that N is not a cpo
when Σ is inﬁnite; assume we have identiﬁed a distinct element ai ∈ Σ for eachi ∈ N. Now let
Pn ={ai → STOP | i ≥ n}

Clearly Pn FD Pn+1 for all n and (, Σ) ∈ failures ⊥ (Pn ) for any n. If thisincreasing sequence were to have an upper bound P † , it would have to have thefollowing properties:• (, Σ) ∈ failures ⊥ (P † ) because P † must reﬁne the Pi , and• traces(P † ) = {} since every trace other than  is absent from Pn for
suﬃciently large n.
But these two properties are inconsistent because of condition F3.
This, of course, means that it is easier to justify the existence of ﬁxed points
for recursive deﬁnitions when Σ is ﬁnite. A number of techniques3 have been de3 In this case it is possible to ﬁnd a diﬀerent and stronger partial order which is complete andwith respect to which the operators of CSP are all monotonic. This order asserts that P ≤ Q
only when divergences(Q) ⊆ divergences(P ) and whenever s ∈ traces(P ) divergences(P ) thenrefusals(P /s) = refusals(Q/s) and initials(P /s) = initials(Q/s). Thus, non-divergent behaviourof P cannot be ‘reﬁned’ any further and the divergence-free processes are all maximal in the order.
For details of this order, the reader should consult [104]. We will see further applications of thisorder in Section 9.2. Other techniques for proving the existence of ﬁxed points, with more generalapplicability, include comparison with the operational semantics [105] and the identiﬁcation andmanipulation of a complete sub-order [5, 7]. We will discuss these further in Chapter 10.



200

Denotational semantics

veloped for establishing their existence over the type of incomplete order causedby considering unbounded nondeterminism. These can be used to show that any
CSP-deﬁnable function over N always has a least ﬁxed point whether Σ is ﬁnite ornot.
Thus, the incompleteness arising from inﬁnite alphabets is more a mathematical inconvenience than a real problem. Nevertheless, the possibility of inﬁnite
nondeterminism (whatever the size of Σ) does create a real diﬃculty with the accuracy of N as we will see in the next section.
In order to extend the notions of constructiveness and non-destructivenessto N we need to deﬁne restrictions P ↓ n with the same properties as those alreadystudied over T . Various deﬁnitions would work, but the following one is perhaps
the best since it identiﬁes P ↓ n with the FD -minimal process in the subset of N
we would wish to identify with P based on n-step behaviour. (F , D) ↓ n = (F  , D  ),
where
D
F

= D ∪ {sˆt | (s, {}) ∈ F ∧ s ∈ Σn }= F ∪ {(s, X ) | s ∈ D  }In other words, P ↓ n behaves exactly like P until exactly n events have occurred,
at which point it diverges unless it has already terminated.
Lemma 8.3.2 These functions form a restriction sequence satisfying the conditions
laid out on page 512, and furthermore(i) For each P ∈ N , P ={P ↓ n | n ∈ N}.

(ii) If Pn is a sequence of processes such that Pn+1 ↓ n = Pn for all n, thenP † = {Pn | n ∈ N} exists and is such that P † ↓ n = Pn .
Hence the metric generated by these functions is complete.

Exercise 8.3.1 List all the members of N whose traces are {, a, b}, and ﬁnd a
CSP process corresponding to each.
Exercise 8.3.2 Axiom D3 states that any divergence must appear before successful
termination. Reformulate the model so that divergence-sets are now subsets of Σ∗ (i.e.,
do not contain ), in such a way that the new version is order-isomorphic to the original.
It is a somewhat arbitrary decision which version to choose. We have chosen the version
in which ’s can appear in divergences because it simpliﬁes some operator deﬁnitions in
the next section slightly.

8.3

The failures/divergences model

Exercise 8.3.3

201Show that componentwise union of any non-empty subset S of N isa member of N .
Find an example to show that the intersection of two members of N need not bein the model. What can you say about the intersection of two processes with the same
traces?

Exercise 8.3.4

Prove Lemma 8.3.2 above (establishing that N is a complete restric-tion space).

8.3.2

Calculating the semantics of processes

Throughout Part I we generally gave the trace semantics of each operator as we
introduced it. In this section we show how to calculate the failures/divergences semantics in the same way, thereby giving the building blocks of another denotationalsemantics.
The following clauses show how to calculate the failures and divergences ofcombinations under a number of operators where the deﬁnitions are all fairly obvious
extensions of the corresponding traces deﬁnitions.
failures ⊥ (STOP) = {(, X ) | X ⊆ Σ }divergences(STOP ) = {}failures ⊥ (SKIP) = {(, X ) | X ⊆ Σ} ∪ {(, X ) | X ⊆ Σ }divergences(SKIP) = {}failures ⊥ (a → P )= {(, X ) | a ∈ X }∪ {(aˆs, X ) | (s, X ) ∈ failures ⊥ (P )}divergences(a → P ) = {aˆs | s ∈ divergences(P )}failures ⊥ (?x : A → P ) ={(, X ) | X ∩ A = {}}∪ {(aˆs, X ) | a ∈ A ∧(s, X ) ∈ failures ⊥ (P [a/x ])}divergences(?x : A → P ) = {aˆs | a ∈ A ∧ s ∈ divergences(P [a/x ])}failures ⊥ (PQ) = failures ⊥ (P ) ∪ failures ⊥ (Q)Q) = divergences(P ) ∪ divergences(Q)failures ⊥ ( S ) = {failures ⊥ (P ) | P ∈ S } for any non-empty set S ⊆ Ndivergences( S ) = {divergences(P ) | P ∈ S }
failures ⊥ (P ) if b evaluates to true
failures ⊥ (P <I b>
I Q) =
failures ⊥ (Q) if b evaluates to false
divergences(P202

Denotational semantics
divergences(P <I b>I Q) =

divergences(P ) if b evaluates to true
divergences(Q) if b evaluates to false

As one would expect, in this model we can distinguish P Q from P 2 Q.
The diﬀerence is, that on , P 2 Q cannot refuse a set of events just because P or
Q does, they both have to. The obvious deﬁnitions aredivergences(P 2 Q)
X

failures ⊥ (P 2 Q)

= divergences(P ) ∪ divergences(Q)= {(, X ) | (, X ) ∈ failures ⊥ (P ) ∩ failures ⊥ (Q)}∪ {(s, X ) | (s, X ) ∈ failures ⊥ (P )∪ failures ⊥ (Q) ∧ s = }The divergences clause is correct, but the failures one potentially breaches conditions
D2 and F4. D2 fails, for example, on div 2 a → STOP , since the above deﬁnitions
tell us that this process can diverge immediately but cannot refuse {a} after theempty trace. Of course this process does not have the stable refusal {a}, but we haveto remember that failures ⊥ (P ) does not just contain the stable failures. F4 fails
because in compositions like SKIP 2 a → P the deﬁnition does not take accountof the special status of : we decided in Section 6.3 that SKIP 2 P had to be
specially interpreted, and this must be reﬂected in the semantics. We can correctthese two ﬂaws by fairly obvious additions to the above deﬁnition
divergences(P 2 Q) = divergences(P ) ∪ divergences(Q)failures ⊥ (P 2 Q) = {(, X ) | (, X ) ∈ failures ⊥ (P ) ∩ failures ⊥ (Q)}∪ {(s, X ) | (s, X ) ∈ failures ⊥ (P )∪ failures ⊥ (Q) ∧ s = }∪ {(, X ) |  ∈ divergences(P ) ∪ divergences(Q)}∪ {(, X ) | X ⊆ Σ ∧  ∈ traces ⊥ (P ) ∪ traces ⊥ (Q)}Several later deﬁnitions will need similar additions to preserve the divergence conditions D1 and/or D2, but this is the only place the special treatment of F4 isrequired.
Since the parallel operators can all be deﬁned in terms of the interface parallel
operator  , we only have a formal need to give the deﬁnition for that one. P  Q can
X

Xrefuse an event in X when either P or Q can because they both have to participate
in it. On the other hand, since they can independently perform events outside X ,these can only be refused when both P and Q do, much as on the empty trace in
P 2 Q.  is, for the purposes of calculating refusals, treated as though it werein X because of distributed termination (Section 6.2; recall that this is built into
the deﬁnition of the trace-level parallel operator s  t which produces the set of allX

8.3

The failures/divergences model

203

traces that could arise if P and Q respectively communicate s and t).
divergences(P  Q)X

= {uˆv | ∃ s ∈ traces ⊥ (P ), t ∈ traces ⊥ (Q).
u ∈ (s  t) ∩ Σ∗X

∧ (s ∈ divergences(P ) ∨ t ∈ divergences(Q))}
failures ⊥ (P  Q)
X

= {(u, Y ∪ Z ) | Y  (X ∪ {}) = Z  (X ∪ {})∧ ∃ s, t.(s, Y ) ∈ failures ⊥ (P )∧ (t, Z ) ∈ failures ⊥ (Q)∧ u ∈ s  t}
X

∪ {(u, Y ) | u ∈ divergences(P  Q)}
X

The hiding operator is the most subtle and diﬃcult one to deal with in
the failures/divergences model; this is because it turns visible actions into τ ’s andthus (i) removes stable states and (ii) potentially introduces divergences. It is
straightforward to deal with the ﬁrst of these diﬃculties once we observe that thestable states of P \ X correspond precisely to stable states of P that cannot perform
any element of X , which is equivalent to saying that they can refuse the whole of
X . In general,
failures ⊥ (P \ X )={(s \ X , Y ) | (s, Y ∪ X ) ∈ failures ⊥ (P )}∪ {(s, Y ) | s ∈ divergences(P \ X )}It is the second problem that presents the greater diﬃculty and which will
ultimately impose a bound on the accuracy of the semantics. Hiding introduces adivergence in P \ X when P can perform an inﬁnite consecutive sequence of eventsin X . The diﬃculty we have is that our model only tells us about ﬁnite traces of P ,not about inﬁnite ones. Our only option is to try to infer what the inﬁnite traces
are in terms of the information to hand. As we saw in Section 7.4.2, thanks toKönig’s lemma, if P has a ﬁnitely-branching LTS as its operational semantics thenTraces(P ) (P ’s ﬁnite and inﬁnite traces traces ⊥ (P )∪inﬁnites(P )) equals traces ⊥ (P )(the closure which includes those inﬁnite traces whose ﬁnite preﬁxes are all there).
In that case we therefore know thatdivergences(P \ X )= {(s \ X )ˆt | s ∈ divergences(P )}∪ {(u \ X )ˆt | u ∈ Σω ∧ (u \ X ) ﬁnite∧ ∀ s < u.s ∈ traces ⊥ (P )}If P ’s LTS is not ﬁnitely branching then it simply is not possible to be surewhat the inﬁnite traces are when we are told the ﬁnite ones, and therefore what the204

Denotational semantics

divergences of P \ X are. The simplest example is provided by the two processes
A∗
A∞={An | n ∈ N} and= AS{An | n ∈ N}

where A0 = STOP , An+1 = a → An and AS = a → AS . A∗ and A∞ haveidentical representations in N , but clearly only one of them can actually perform
an inﬁnite sequence of a’s and hence diverge when we hide {a}.
We must therefore conclude that it is not, in general, possible to determine
the correct value in N of P \ X from that of P when P is unboundedly nondeterministic. In other words, N unfortunately fails to be a congruence for the full CSP
language, though it is when we forbid the operators that can introduce unbounded
nondeterminism. All we can do in the general case is to assert
divergences(P \ X )⊆ {(s \ X )ˆt | s ∈ divergences(P )}∪ {(u \ X )ˆt | u ∈ Σω ∧ (u \ X ) ﬁnite∧ ∀ s < u.s ∈ traces ⊥ (P )}so that a denotational semantics that uses the right-hand side as its deﬁnition ofdivergences(P \ X ) will give a conservative approximation of the true value, in thesense that the true value always reﬁnes it.
As we will see in Chapter 10, there is a straightforward solution to the problems we have just encountered, namely to include inﬁnite traces explicitly in the
representation of a process. Given this, the author recommends the adoption of thefollowing principle:
N should be regarded as the standard model for giving semantics
to finitely nondeterministic CSP (that is, for processes not involving
infinite hiding, infinite-to-one renaming or infinite nondeterministic
choices). It should not be used for giving denotational semantics toprocesses that do use these constructs.
Before leaving this topic, it is worth considering brieﬂy an example which
illustrates one of the arguments for including axioms D1 and D2 (the ones thatsay that we do not attempt to distinguish behaviour after potential divergence).
Consider the process P0 , wherePn= b → Pn+1
2 c → Anand the An are as above. Plainly P0 \ {b} (a process that uses no inﬁnitely
nondeterministic construction) can diverge and so D1 and D2 force us to identify

8.3

The failures/divergences model205

it with ⊥N . If, however, we were tempted to use a version of the model without
D1 then the only divergence of P0 \ {b} would presumably be . It would have, asﬁnite traces,{} ∪ {cˆan | n ∈ N}
in other words, all ﬁnite preﬁxes of c, a, a, a, a, . . ., so that applying the abovedeﬁnition of hiding would predict that (P0 \ {b}) \ {a} could diverge after c. In
fact, it cannot, since P0 plainly cannot perform an inﬁnite consecutive sequence ofa’s. Thus, discarding axiom D1 would lead us to a position where the semantics ofhiding is not even accurate for ﬁnitely nondeterministic CSP. What is, if anything,more disturbing about this example is that the semantics would (correctly) notpredict that (P0 \ {a}) \ {b} could diverge after c; this means that the standard
and obvious laws hide-sym (3.2) and hide-combine (3.3):(P \ X ) \ Y = (P \ Y ) \ X = P \ (X ∪ Y )would fail. The real problem we are encountering here is that even ﬁnitely-branching
LTSs can exhibit unbounded nondeterminism after potential divergence when we
take into account the invisibility of τ actions. As P0 \ {b} diverges it gives theinﬁnite choice of how many a’s follow any c. In Theorem 7.4.2, we did not prove thatan inﬁnite trace was possible in a ﬁnitely branching LTS where every ﬁnite preﬁx
was possible, rather that either it was possible or a ﬁnite preﬁx was a divergence.
Note the similarity between the present example and Figure 7.9.
There are still two operators waiting to be given their failures/divergences
semantics. The ﬁrst of these is renaming. This creates few problems, though we dohave to close up under D1 and D2 since not all traces may be in the image of therenaming relation.
divergences(P [[R]])={s ˆt | ∃ s ∈ divergences(P ) ∩ Σ∗ .s R s  }failures ⊥ (P [[R]])={(s  , X ) | ∃ s.s R s  ∧ (s, R −1 (X )) ∈ failures ⊥ (P )}∪ {(s, X ) | s ∈ divergences(P [[R]])}

Here, R −1 (X ) = {a | ∃ a  ∈ X .(a, a  ) ∈ X } is the set of all events that map to X
under R. In the above we use R extended to traces and so that R , as previously
discussed.
If and when P terminates in P ; Q, the  signalled by P is hidden from theenvironment since the overall process has not yet terminated. This means that it istreated in essentially the same way for the calculation of failures as an event hidden
in P \ X . We do not get into the same trouble with divergence because there is

206

Denotational semantics

never more than one hidden  in any run of P ; Q.
divergences(P ; Q) = divergences(P ) ∪{sˆt | sˆ ∈ traces ⊥ (P ) ∧ t ∈ divergences(Q)}failures ⊥ (P ; Q) = {(s, X ) | s ∈ Σ∗ ∧ (s, X ∪ {}) ∈ failures ⊥ (P )}∪ {(sˆt, X ) | sˆ ∈ traces ⊥ (P ) ∧ (t, X ) ∈ failures ⊥ (Q)}∪ {(s, X ) | s ∈ divergences(P ; Q)}
The properties of these operators over the reﬁnement order are, as over T ,largely viewable as consequences of the fact that they can be reformulated as relations over behaviours. Actually deﬁning the relations is rather dull, since we now
have to worry about the interplay between two diﬀerent types of behaviour as wellas the combinations of diﬀerent arguments. For example, consider renaming P [[R]],where we get a relation from failures to failures{((s, R −1 (X )), (s  , X )) | s R s  }one from divergences to divergences{(s, s ˆt) | s ∈ Σ∗ ∧ s R s  }and one from divergences to failures{(s, (s ˆt, X )) | s R s  ∧ (s ∈ Σ∗ ∨ t = )}In every case except one this is possible, simply because each behaviour that
results from applying an operator is inferred from at most one behaviour from eachof the arguments. The exception is, of course, hiding because we had to infer thepresence of a hiding-induced divergence from an inﬁnite set of traces. Thus, we
generally have to use a diﬀerent type of argument when reasoning about hiding.
Lemma 8.3.3 Each of the operators other than \ X is fully distributive (and hencemonotonic) over N in every argument. \ X is not fully distributive but does satisfy(P Q) \ X = (P \ X ) (Q \ X ) (which also implies monotonicity).
Proof In every case except hiding, the distributivity follows from the existenceof a relational representation, as it did over T .
We should not be surprised at the failure of full (i.e., inﬁnite) distributivity for \ X , because we have already noted that N loses accuracy for inﬁnitely
nondeterministic processes. That it does fail can be seen from( {An | n ∈ N}) \ {a} ={An \ {a} | n ∈ N}

8.3

The failures/divergences model

207

where the An are as on page 204.
It is ﬁnitely distributive because if each ﬁnite preﬁx of the inﬁnite trace u
is a trace of P
Q, then either inﬁnitely many come from P or inﬁnitely many
come from Q. Whichever of these happens, it then follows by preﬁx closure of
trace-sets that they all come from the chosen argument (though this does not, ofcourse, preclude the possibility that some or all of them might also come from theother one).
We again have to decide on the semantics of recursion, in other words how
to extract ﬁxed points. The status of the metric theory (of constructive recursions)is exactly the same as over T , namely that it works for at least 99% of well-behaved
recursions one typically meets, and, when it does, it says that there was not reallya choice at all. Again, the only issue is what value to give to badly constructedrecursions such as those on page 192. Whether or not Σ is ﬁnite meaning that
N is complete, it can, as we discussed earlier, be shown that every CSP-deﬁnable
function has a least ﬁxed point in the reﬁnement order FD .
It is, at ﬁrst sight, by no means obvious that this will give the right answer
since we ended up choosing the opposite order in T – a choice we no longer havesince there is no least element of N under the subset or anti-reﬁnement order. In
particular, it will deﬁnitely give us a diﬀerent set of traces for most under-deﬁned
recursions like µ p.p (mapped to {} in T and to ⊥N over N which has all traces).
The crucial point is the distinction between traces(P ) (the value computed over T )and traces ⊥ (P ) (the traces of P ’s representation in N ), since the latter includes
all extensions of divergent traces. Now the only thing (the operational semanticsof) µ p.p does is diverge, which accounts precisely for the diﬀerence here, and ingeneral, you can characterize an ill-deﬁned recursion as being one where, after somespeciﬁed trace, the next step behaviour is not resolved no matter how often therecursion is unwound. In other words, an ill-deﬁned recursion is one where theunwinding of the recursion creates a divergence, which means that the right value
for it (after the given trace) is ⊥N .
Recall that on page 194 we characterized the two possible choices of order
to use for computing least ﬁxed points in terms of the existence of a proof thata given behaviour was not in any ﬁxed point ( ) or had to be in any ﬁxed point(⊆). The latter works for T because all the behaviours recorded in the model occur
in a ﬁnite time, so some ﬁnite number of unwindings of a recursion are bound todemonstrate their presence (if a given behaviour over the operational semantics
of a recursive process contains n actions, then its derivation never requires morethan n unwindings simply because each unwinding introduces a τ action). It would
not work for a behaviour that, like a divergence, takes an inﬁnite amount of time
to appear. The proof-of-absence idea still makes sense, however. Consider therecursion µ p.a → p: after unfolding this recursion n times we have a proof that

208

Denotational semantics

divergence can never begin before the trace an , so that for any ﬁnite trace there
is a proof of absence of divergence. A trace of µ p.F (p) will thus be considered adivergence if there is no proof that it cannot be one. This always gives the rightanswer because an inﬁnitely unfolding recursion results in divergence (see Section
9.4 where these arguments are explored in more detail).
We might therefore suspect that a CSP model in which all behaviours reveal
themselves ﬁnitely will have a positive (⊆) ﬁxed-point theory, whereas a model
which has some inﬁnite observations like divergences will require the negative ( )theory. Perhaps the most persuasive argument for the principle of ignoring postdivergent behaviour (axioms D1 and D2) is that it makes this negative ﬁxed-point
theory work.
The least ﬁxed point of the under-deﬁned counter recursion Z2 on page 192
isZ2= iszero → Z2
2 up → Z2

Z2

= down → Z2
2 up → ⊥N

which is exactly what you might expect operationally. After up, up the recursion
unfolds inﬁnitely since as soon as one of the cells AZ reaches this point it promptly
drives its slave to exactly the same one, creating a divergence as this cascades down
the inﬁnite master/slave chain. All three of the processes identiﬁed earlier as trace
ﬁxed points of this recursion are actually failures/divergences ﬁxed points as well.
All are maximal since they are deterministic; and, as we would expect, they all
reﬁne the value Z2 deﬁned above.
Since we are using the order for ﬁxed points over N , it makes the questionof which operators are continuous with respect to that order more important4 thanover T . Since N is not even a cpo when Σ is inﬁnite, we will only consider the casewhen it is ﬁnite.
For operators represented as relations over behaviours, the continuity analysis closely parallels that over the reﬁnement order over T , namely any operator
represented by ﬁnitary relations is automatically continuous thanks to essentiallythe same proof as that seen on page 189. Our assumption that Σ is ﬁnite greatly
simpliﬁes this analysis, since it means that the number of possible refusal sets attaching to a given trace is also ﬁnite. Thus any relational representation of an
operator that is ﬁnitary on traces is automatically ﬁnitary on failures.
4 Except for making the ﬁxed-point formula simpler and perhaps more believable, the diﬀerence
between monotonic and continuous has surprisingly little impact, given the importance that is
usually placed on continuity.

8.3

The failures/divergences model

209

Using this fact, and the observation that the relations which introduce divergences/failures based on a divergent preﬁx are ﬁnitary because each trace only
has ﬁnitely many preﬁxes, it is straightforward to derive the following result.
Lemma 8.3.4 If Σ is finite, then each of the operators a → ·, 2,,  , ; andX

renaming is continuous.
In fact, hiding (necessarily ﬁnite because of the restriction on Σ) is also
continuous under this assumption, though the proof is rather diﬀerent. This isinteresting because it did not hold over T for the order; the diﬀerence lies in ourtreatment of divergence. Close examination of the following proof, as well as the
behaviour over N of any example which demonstrates the lack of continuity overT , reveals that any failure of continuity over T is masked by axioms D1 and D2.
Lemma 8.3.5 If Σ is finite, then the hiding operator \ X is continuous over N .
Proof The main components of the proof are as follows. Firstly, whenever P
is such that the set pre\X (P , t) = {s ∈ traces ⊥ (P ) | s \ X ≤ t} is inﬁnite, thent ∈ divergences(P \ X ) since by an application of König’s lemma very like that on
page 179 this set of traces must contain all the preﬁxes of some inﬁnite trace.
Secondly, if ∆ is a directed set of processes and t ∈ {divergences(P \ X ) |P ∈ ∆}, then t ∈ divergences( ∆ \ X ), because if this were not so then (by thelast observation) we would have thatM = pre\X ( ∆, t)
is ﬁnite, and clearly contains no element of divergences( ∆). Let
M  = {sˆa | s ∈ M ∧ sˆa \ X ≤ t}  M
the set of all extensions of elements of M by either an element of X , or the next
member of t, that are not themselves in M . For each s ∈ M there is certainly
Ps ∈ ∆ such that s ∈ divergences(Ps ), and for each s ∈ M  there is Ps ∈ ∆ suchthat s ∈ traces ⊥ (Ps ). But M and M  are both ﬁnite sets, so following the usual
directed set argument yields a FD upper bound P † ∈ ∆ for all the Ps and Ps .
This must satisfy
pre\X (P † , t) = M
for if not there would be a preﬁx-minimal element s in pre\X (P † , t)  M . But
then s ∈ M  , contradicting the construction of P † . Since plainly, then, we have

210

Denotational semanticst ∈ divergences(P † \ X ), this contradicts our original assumptions. We can thus
conclude that t ∈ divergences( ∆ \ X ).
Thirdly and ﬁnally, when t ∈ divergences( ∆ \ X ), the arguments in theprevious paragraphs show that suﬃciently far through ∆ the behaviour of the hiding
operator is eﬀectively ﬁnitary. The proof that it preserves the limit of this ∆ (fortrace t) then follows more-or-less the same pattern as those for operators withﬁnitary relational representations.
Thus every5 function deﬁnable in ﬁnitely nondeterministic CSP is continuous
over N for ﬁnite Σ.
The lists of operators that are constructive and non-destructive over N are
identical to those that applied over T .
Lemma 8.3.6 Each of the operators, 2,  , renaming and ; is non-destructive
Xover N in each argument. The prefix operators a → and ?x : A → are constructive.
Again these facts are usually elementary consequences of relational representations, and the only one to be interesting is the left-hand side of sequencing (;)
because of the eﬀective hiding of . For this, the precise form of the restriction
operator P ↓ n is moderately important. If s is a trace of length n, then whethers ∈ traces ⊥ (P ) can be established by looking at P ↓ n, but the further details abouts, namely whether a pair (s, X ) ∈ failures ⊥ (P ) or whether s ∈ divergences(P ), canonly be established by looking at P ↓ (n + 1). This means that all failures anddivergences of P ; Q that can be created by P performing the trace sˆ have
depth, in this sense, of at least n + 1 (the length of sˆ).
(a) Prove carefully that N is closed under (i) the preﬁx operator
Exercise 8.3.5
a → P and (ii) external choice P 2 Q. (For the model to be closed under an operationmeans that, if the arguments to the operator belong to the model then so does the result.
Another way of stating this is to say that the operator is well-deﬁned over the model.
While it is plainly tedious to have to prove such results for all operators, they are clearlya basic well-formedness check that has to be done either by someone or some theorem
prover!)(b) Give direct proofs, for the same operators, that they are distributive (over )and continuous.

Exercise 8.3.6

Prove that the following laws are valid over N :(a) -2-dist (1.13)
5 The properties of continuous operators detailed in Appendix A are needed to combine theresults about the basic operations into this general statement, in particular their closure undercomposition.

8.4

The stable failures model

211(b) |||-step (2.6)(c) ; -step (6.7)

Exercise 8.3.7

Give relational representations of the following operators over N :(a) Preﬁxing a → P .
(b) Nondeterministic choice P  Q(c) External choice P 2 Q
In each case you will need relations to generate both failures and divergences; in the lastcase the set of relations generating failures have to take account of divergences.
Find expressions, in the style of those on page 201, for the failuresand divergences of P >> Q for any P and Q all of whose non-divergent traces lie in the set{| left, right |}. (You can ﬁnd an expression for the traces on page 104.)

Exercise 8.3.8

Use this to prove BL1 (if P and Q are buﬀers, so is P >> Q). (All of the buﬀer laws
except BL5 and BL5 can be proved fairly straightforwardly from the failures/divergences
semantics of >>. These other two require rather sophisticated versions of the recursion
induction rule.)

8.4

The stable failures model

The failures/divergences model gives us perhaps the most satisfactory representation of a process for deciding questions of liveness, since by excluding both divergence and the stable refusal of a set of events we can guarantee that a member of theset will eventually be accepted. It is possible to devise models which combine traces
either only with divergences or only with stable refusals, but it must be emphasized
that, in using either, one must appreciate the important information one is leaving
out. There is not much to say about the ﬁnite traces/divergences model, except
the obvious fact that the representation of any process can be found by dropping
the refusal components in the failures from its representation in N . The semantic
clauses for the CSP operators are similarly derived from those over N , noting thatsince refusal (as opposed to trace and divergence) information never inﬂuences thetraces or divergences of any of the operators over N , there is no problem in computing the values accurately. This model, like N , uses the reﬁnement order to computethe values of recursions, and needs to adopt axioms like D1 and D2. It has the same
restriction to ﬁnitely nondeterministic CSP to make the semantics accurate.
The model in which we record traces and stable refusals (where ‘stable’ refusals include the ones generated by states that can perform , or, in other words,
the ones postulated by axiom F4) is more interesting for three reasons.

212

Denotational semantics• Firstly, some authors have long considered the imposition of axioms D1 andD2 on N unfortunate because they have an obscuring eﬀect. It turns outthat by ignoring divergences completely one can, to some extent, satisfy their
desires.
• Secondly, the calculations required to determine if a process diverges are
signiﬁcantly more costly than those for deciding other aspects of reﬁnement.
Therefore it is advantageous if tools like FDR have a model they can usethat does not force the calculation of divergences.6• Thirdly, it is sometimes advantageous to analyze a divergence-free process P
by placing it in a context C [P ] in which it may diverge as the result of hiding
some set of actions. This only works when the traces and stable failures that
result are not obscured by D1 and D2.

The ﬁrst thing to appreciate about only recording stable failures is that it
is by no means inevitable that every trace of a process has one: it may neverstop performing τ actions. Therefore, unlike the case with N , it is necessary
to record the traces separately, and so each process is represented as the pair(traces(P ), failures(P )) rather than just failures(P ). The stable failures model, F,
thus consists of those pairs (T , F ) (T ⊆ Σ∗ and F ⊆ Σ∗ × P(Σ )) satisfying thefollowing healthiness conditions
T1. T is non-empty and preﬁx closed.
T2. (s, X ) ∈ F ⇒ s ∈ Tplus conditions F2, F3, and F4 (with T replacing traces ⊥ (P )) as for N . We need afurther condition which, like D3, serves to standardize how processes look after :
T3. sˆ ∈ T ⇒ (sˆ, X ) ∈ F
All of these are obvious, given our previous discussions. The fact that they
are suﬃcient to characterize what processes look like will be shown in Section 9.3.
F has both top and bottom elements with respect to the reﬁnement orderP

F Q≡ traces(P ) ⊇ traces(Q) ∧ failures(P ) ⊇ failures(Q)The minimal, or least-deﬁned process, is ⊥F = (Σ∗ , Σ∗ × P(Σ )): as one would
expect, the process that can perform any behaviour within the domain under consideration. The maximal process is a more surprising object, F = ({}, {}), which
6 In most cases one will combine such a check with a proof of divergence freedom, from which
one can infer that reﬁnement holds over N .

8.4

The stable failures model

213

satisﬁes all the axioms above. A little thought reveals that this represents the process div which simply diverges immediately without the possibility to do anythingelse. What has happened is that by omitting to model divergence, we have pushed
processes that do diverge (as opposed to other things) upwards under the reﬁnement order. Rather like the case with T (and the traces/divergences model, which
also has STOP as its maximal element), you should regard the existence of a top
element under reﬁnement as a strong indication that the model only presents apartial picture of processes.
under

As with T and N , any non-empty subset of F has a greatest lower boundS = (T + , F + ), where
F given by componentwise union:
T+
F+


=
{T | (T , F ) ∈ S }
={F | (T , F ) ∈ S }Since F is the greatest lower bound of the empty set, this means that every subset
has one, and hence (thanks to Lemma A.1.1) we immediately get the following.
Theorem 8.4.1 F is a complete lattice under both the refinement order and thesubset order.
This is a much stronger result than with N , particularly since it applies
whether or not Σ is ﬁnite. The least upper bounds generated under the reﬁnement
order are not always particularly intuitive, since this new model can and does create
its upper bounds for sets of processes that are inconsistent over N by introducing
behaviour like the top element F . Thus, the least upper bound of{a → a → STOP , a → STOP }is a → F = ({, a}, {(, X ) | a ∈ X }); the inconsistent behaviour after a
being resolved to F .
Noticing that the ﬁrst component of a process’s representation in F is its
representation in T , it follows:• that the clauses for calculating that component of each operator are identicalto the corresponding clauses in T , and• that to get the right value for recursively deﬁned processes we should takeﬁxed points with respect to ⊆ rather than . Note that the existence of the
F top, which is the bottom under ⊆, supports this, as does the simple formof least upper bounds under ⊆.
The latter may seem surprising since it is the opposite to N , but the crucial distinction between F and N is that the former, like T , only records ﬁnitely observable

214

Denotational semantics

behaviours so (bearing in mind our discussions about the calculation of ﬁxed points
over N ) we neither need reverse-inclusion to allow inﬁnite behaviours into ﬁxed
points, nor have the special properties of divergence to make the reverse-inclusion
ﬁxed point accurate.
As one might expect, the clauses for calculating the failures component are
essentially the same as those over N except that there is no need to close underaxioms D1 and D2.
failures(STOP) = {(, X ) | X ⊆ Σ }failures(SKIP) = {(, X ) | X ⊆ Σ} ∪ {(, X ) | S ⊆ Σ }failures(a → P )= {(, X ) | a ∈ X }∪ {(aˆs, X ) | (s, X ) ∈ failures(P )}failures(?x : A → P ) = {(, X ) | X ∩ A = {}}∪ {(aˆs, X ) | a ∈ A∧ (s, X ) ∈ failures(P [a/x ])}Q) = failures(P ) ∪ failures(Q)failures( S ) = {failures(P ) | P ∈ S } for S a non-empty set of processes
failures(P ) if b evaluates to true
failures(P <I b>I Q) =
failures(Q) if b evaluates to false
failures(Pfailures(P 2 Q) = {(, X ) | (, X ) ∈ failures(P ) ∩ failures(Q)}∪ {(s, X ) | (s, X ) ∈ failures(P ) ∪ failures(Q) ∧ s = }∪ {(, X ) | X ⊆ Σ ∧  ∈ traces(P ) ∪ traces(Q)}failures(P  Q)
X

= {(u, Y ∪ Z ) | Y (X ∪ {}) = Z (X ∪ {})∧ ∃ s, t.(s, Y ) ∈ failures(P )∧ (t, Z ) ∈ failures(Q)∧ u ∈ s  t}X

failures(P \ X ) = {(s \ X , Y ) | (s, Y ∪ X ) ∈ failures(P )}failures(P [[R]]) = {(s  , X ) | ∃ s.s R s  ∧ (s, R −1 (X )) ∈ failures(P )}failures(P ; Q)

= {(s, X ) | s ∈ Σ∗ ∧ (s, X ∪ {}) ∈ failures(P )}∪ {(sˆt, X ) | sˆ ∈ traces(P ) ∧ (t, X ) ∈ failures(Q)}We have lost the clause that caused diﬃculty over N (namely the inference ofdivergence under hiding), and all the operators thus have relational representations
that are simpliﬁcations of those for N . The arguments in Section 8.2 thus apply toyield the following result.

8.4

The stable failures model

215

Theorem 8.4.2 All CSP operators are monotonic and continuous over F withrespect to the subset order, and are fully distributive.
In some ways F is better thought of as a reﬁnement of T than as an approximation to N : equivalence of processes over F implies equivalence over T , whereas
no such relationship exists between N and F. It is, however, vital that we understand how a process’s representations in N and F are related. The following
paragraphs attempt to set this out.
• It is important to realize that, while you can sometimes tell from the shape ofa member of F that it must diverge after a trace (speciﬁcally, when there areno failures associated with the trace), you can never infer that it must not.
In particular, any simply divergent process like div, µ p.p or µ p.SKIP ; p is
identiﬁed with F , and P F = P for all P .
• This same example shows the type of process for which F gives more distinctions than N : since P div can diverge immediately it is identiﬁed with ⊥Nover N . In other words, F lets us see the details of behaviour after possible
divergence, whereas axioms D1 and D2 force us to obscure this in N .
• We previously noted that the denotational semantics for CSP over N is only
accurate for ﬁnitely nondeterministic processes. Since the problem whichcaused that restriction does not arise over F, neither does the restriction.
• Since, for divergence-free processes, failures(P ) = failures ⊥ (P ), it follows
that the representations of such processes in the two models are congruent in
the obvious sense. It is this fact that leads to the most common use of F with
FDR, namely that if the processes Spec and Imp are known, or postulated,
to be divergence-free, then the reﬁnement check Spec F Imp is equivalent
to the less eﬃcient Spec FD Imp.
It is the fact that F lets us see past potential divergence that gives it someuses which are more interesting than as a way of speeding up certain checks over N .
The ﬁrst is in situations where divergence is diﬃcult to exclude, and it is natural
to build a system which is correct in other respects before addressing it. Here it
may be natural to formulate and establish correctness conditions over F (dealing
with safety properties and stable refusals), before making some ﬁnal reﬁnement to
exclude divergence. (This is another application of the idea of stepwise reﬁnement:see page 47.) A good example of this is in dealing with communications protocols
which, like the Alternating Bit Protocol (Section 5.3), are designed to deal with
arbitrary message loss, and perhaps duplication. In our earlier presentation of that
protocol we built a model of the lossy communication medium which placed a ﬁxed
bound on how many consecutive messages can be lost and how many times one

216

Denotational semantics

can be duplicated, using the processes CN (in, out) to model the channels. Even
though the protocol is designed to work for arbitrary but ﬁnite loss or duplication.
For any N , the above medium is obviously a reﬁnement of the process C (in, out)
as deﬁned on page 132 which can misbehave as much as it likes. An alternative andequivalent deﬁnition of this is:
C (in, out) = in?x → C  (in, out, x )C  (in, out, x ) = out!x → C  (in, out, x )in?y → C  (in, out, y)
If you replace the CN medium processes by C in the system, which we
can term ABP N , deﬁned in Section 5.3 (constrained, as described there, to avoid
divergence in the absence of error), the result is a process ABP ∞ that can diverge,
but which satisﬁes the speciﬁcation COPY (i.e., a one-place buﬀer) over F:
COPY

F ABP ∞

If checked on FDR, this will have substantially fewer states than does ABP N foreven small values of N .
This proves very cleanly that unless ABP ∞ diverges, it does what we want.
The monotonic and transitive properties of reﬁnement imply that this remains true
whenever the C∞ processes are replaced by reﬁnements such as CN . So(i) all that remains to be proved for such a reﬁnement is divergence freedom,and(ii) it demonstrates that the only reason any limit is needed on the misbehaviourof the medium processes in the ABP is to avoid divergence.
The steps we have gone through in the above argument are summarized
below, hopefully showing how it should be reworked for other examples.
• First build a system ABP ∞ such thatCOPY

F ABP ∞• Then ﬁnd a divergence-free ABP  such that
ABP ∞

F ABP



(established in this case by properties of reﬁnement)

8.4

The stable failures model217• This allows us to infer that
COPY

FD ABPThe second distinctive use of F arises when we want to establish a property
of a divergence-free process P by analyzing not the process itself, but some context
C [P ] which involves hiding and can therefore potentially introduce divergence. Aslong as you are well aware of the existence of such divergences and what theymean, they frequently do not represent an undesirable behaviour of the underlying
process P . Usually the context and hiding represent some mechanism whereby
events irrelevant to the speciﬁcation can be abstracted away. Abstraction is a very
important subject, and Chapter 12 is devoted to it, including some uses of the idea
we are now investigating. We will therefore content ourselves with a simple but
important one here.
In Section 13.1.1 it is stated that a process P is deadlock-free if and only
if P \ X is, though the hiding can introduce divergence. Operationally, this isclearly true since all we care about there for deadlock freedom is that each reachable
state has an action available: it does not matter what the name of the action is.
Nevertheless this result is not one of N , since in that model the introduction ofdivergence results in the assumption of deadlock via D2. It is, however, true in F
and should therefore be regarded as a statement in that model. The most interesting
X to try in the above statement is Σ. No matter what P is, there are four possible
values for P \ Σ:• F , indicating that P \ Σ must diverge, or in other words P can neither
deadlock nor terminate;• ({}, {(, X ) | X ⊆ Σ }) (equivalent in F to STOP ) indicating that P
cannot terminate, but can reach a deadlock state;• SKIP , indicating that P can terminate and cannot deadlock before it hasdone so (though since P \ Σ might diverge, this does not imply that it must
eventually terminate); and• SKIP

STOP , meaning that P can deadlock and can terminate.

The statement ‘P is deadlock-free’ is thus equivalent to the assertion SKIP F P \Σ. In the majority of cases where there is no possibility of P terminating, this canbe replaced by F F P \ Σ. Of course, this is curious since what we are in eﬀect
doing here is stipulating that a process (P \ Σ) must diverge, so we have moved
a long way from the treatment of divergence over N . It is also of great practicalimportance since in FDR one usually gets much better compression of processes
when events are hidden than without the hiding (see Section C.2).

218

Denotational semantics

The deﬁnition and theory of restriction operators over F are similar to thoseover N : (T , F ) ↓ n = (T  , F  ), where
T
F

=
=

{s ∈ T | #s ≤ n}{(s, X ) ∈ F | #s < n ∨ (s = s ˆ ∧ #s = n)}

P ↓ n thus contains all the traces of length ≤ n and, like with N , only identiﬁes therefusals of strictly shorter traces except for the special case dealing with condition
T3.
Exercise 8.4.1

Find an example of a process such that {s | (s, X ) ∈ failures(P )} is

not preﬁx closed.
Find a single CSP process which is mapped to the bottoms (under) of T , N and F by the respective semantics.

Exercise 8.4.2

Exercise 8.4.3

Find the least upper bound in F of the processes(a → STOP) 2 (b → STOP)anda → STOP

Find its representation in the model and a CSP expression with the given value.
Suppose P is any process whose traces are contained in Σ∗ (i.e., it is-free). What can you say about the traces and failures of the process P ||| div?

Exercise 8.4.4

Harder: Achieve the same eﬀect for a process P that can terminate (though, if it helps,
you can assume there is a given a ∈ Σ that P never communicates).

8.5

Notes

The central role given to semantic models such as those seen in this chapter is thething that most characterizes the theoretical treatment of CSP in relation to thoseof other process algebras. In a sense that will be made formal in the next chapter,the CSP semantic models each deﬁne a congruence which is the coarsest possible
subject to some natural criterion. Other process algebras have found their own way
to capture failures-style equivalences, most notably the testing equivalences for CCS
described by Hennessy and de Nicola [32, 51].
The traces model of CSP was introduced by Hoare in [55]. This was reﬁned
into the failures model developed by Hoare, the author and Brookes in [18]. Thatmodel was basically N without the divergence component, and used the reﬁnement(reverse containment) order to compute ﬁxed points: it identiﬁed µ p.p with Chaos .
That model failed to give a consistent model of divergent processes, leading, forexample, to the failure of a few of the basic laws. This was corrected with theintroduction of the divergences component in [101], [15] and [19].

8.5

Notes

219

The formulation of the model in this book is diﬀerent in two ways from thatin these papers (the latter also being essentially the same one that Hoare used in
his text [56]). The ﬁrst is that the early version either speciﬁed that all refusal
sets are ﬁnite (even over inﬁnite Σ) or speciﬁed that an inﬁnite refusal set waspresent whenever all its ﬁnite subsets were (which was, of course, eﬀectively thesame assumption). This was necessary to make the model a cpo under the reﬁnement order (corresponding to the observation we made on page 199 that N overinﬁnite Σ is incomplete). It meant that the model could not handle unboundedly
nondeterministic operators like inﬁnite hiding at all. This assumption has been
dropped in this book because (i) the later development [104] of the strong orderreferred to on page 199 means that we do not need N to be complete underto get ﬁxed points and (ii) the development of the inﬁnite traces extension of N
that we will meet in Chapter 10 means that we can now unequivocally deal withunbounded nondeterminism and it is nice to have the projection function from thericher model cleanly deﬁned. (Neither of the two equivalently powered restrictions
on refusal sets mentioned above makes any sense over the inﬁnite traces model. So
to use them over N would leave us with a real problem when it came to deciding
which member of N was the image of a general member of the other model.)The second change is in the handling of termination . The early models
and CSP semantics did not special-case this nearly so much as we have done. The
consequences of this were that sequential composition did not have some desirable
properties such as P ; SKIP = P and that some semantics did not make all ’s
ﬁnal. So axioms F4 and D3 are new here. It has long been recognized that thetreatment of termination in CSP was something of a compromise: the recent paper[129] points out one problem with the old approach (as well as providing a mostinteresting study of the automated proof of many theorems about CSP models andsemantics). See [1] for an alternative approach to representing termination in aanother process algebra.
The eﬀects on the semantics and models of a move to an imperative (i.e., nondeclarative) view of process state can be seen in [102] (where occam is considered).
The primary eﬀect is on the representation of termination, since a process now has
to be able to pass its state to its successors upon terminating.
The stable failures model F is a much more recent development. The author
has seen a number of attempts (generally unsuccessful) over the years at eliminating
the divergence-strictness of N . Characteristically this involved interpreting a divergence as equivalent to a refusal of the whole alphabet, but discarding the axiom D1
which enforces extension-closure of divergence sets. That approach does not work
because it is hard to compute ﬁxed points accurately and various standard laws areinvalidated. The idea of simply ignoring divergence was suggested to the author
in 1992 by Lalita Jategoankar and Albert Meyer, and the model F as described in220

Denotational semantics

this book is a result of that conversation and subsequent collaboration between theauthor and these two people. A very similar model was described by Valmari in[132].
2005: Over the past few years there has been interest in a wider range of CSP
models. Christie Bolton showed how non-standard CSP-like equivalences could be
used for capturing notions such Z reﬁnement. There has been more interest in therefusal testing model of CSP [86] (based on [91]). New and interesting equivalences[116] have just come to light (based on work by Rehof and Rajamani) in which aprocess is modelled by its deadlock traces, its revivals (namely triples (s, X , a) where(s, X ) is a stable failure and a is an event that can be performed from the same state
where X is refused, and either traces or (strict) divergences.

Chapter 9

Analyzing the denotational models

In this chapter we look in a bit more detail at the structure of the denotationalmodels we saw in the previous chapter, especially that of N . The aim is to convey
somewhat deeper understanding of the models and how they represent CSP.

9.1

Deterministic processes

The deterministic processes D, (as a subset of N ) are important both for practicaland theoretical reasons. The most obvious practical beneﬁt from having a deterministic process is that it is, in some sense, testable because its behaviours, whenused over and over again, do not vary unless it is given diﬀerent external stimuli.
We will see in Section 12.4 that the concept can be applied in characterizing suchproperties as information ﬂow.
The full expressive power of N is required to judge whether or not a process
is deterministic. Practically no useful information can be obtained from the tracesmodel T , and the stable failures model F is inadequate because it does not model
divergence and will equate P F with P whether P is deterministic or not. Of
course, for processes known to be divergence-free, one can1 test for determinism
in F since the representation is then eﬀectively the same as the one in N . Moregenerally, we can deﬁne a process to be F-deterministic if its representation in F
satisﬁes the obvious condition:tˆa ∈ traces(P ) ⇒ (t, {a}) ∈ failures(P ))This set of processes is closed under reﬁnement and includes F . Since it does allow
1 In practice it is usually better to test a process for divergence freedom and then (assuming
this works) for determinism over F .

222

Analyzing the denotational models

some usually undesirable processes, this condition is mainly of technical interest,
but it does have at least one practical use – see page 330.
We have already seen that members of D play a special role in N because, as
stated in Section 8.3.1, they are the maximal elements under the reﬁnement order.
In this section we establish this and other important properties of D. We ﬁrst showthat every member of D is maximal; the proof that they are the only maximal
elements will follow later.
Lemma 9.1.1 Every member of D is maximal (under) in N .

Proof Suppose F are the failures of one member of D, and F  ⊆ F are the failuresof another process (we do not have to worry about divergences since deterministic
processes do not have any). We have to show that F  = F ; ﬁrst we show traces(F ) =traces(F  ). If not, there is sˆa of minimal length in traces(F )  traces(F  ) (notingthat thanks to condition F1 the empty trace does not have this property); by thisminimality we have (s, {}) ∈ F  , so by condition F3 of F  we then have (s, {a}) ∈ F  ;but since F  ⊆ F we also have (s, {a}) ∈ F , contradicting determinism of F . Thus
the trace-sets are equal; it follows by F2 that if F = F  there is (s, X ) with X = {}such that (s, X ) ∈ F  F  . We know (s, {}) ∈ F  ; if a ∈ X then (s, {a}) ∈ F
by F2 and hence sˆa ∈ traces(F ) by determinism. It follows that X ⊆ {a |sˆa ∈ traces(F  )} which together with condition F3 yields a contradiction to ourassumption that (s, X ) ∈ F  .
A deterministic process is completely characterized by its traces, because
once we know initials(P /s) we know refusals(P /s). Not quite all members of T giverise to a deterministic process, because of the special treatment of : a deterministic
process that can decide to terminate immediately must do so, and so cannot oﬀer
any other choices of event.
Lemma 9.1.2 The deterministic processes are in 1–1 correspondence with the subset T d of T consisting of those members satisfyingsˆ ∈ P ⇒ ¬ ∃ a ∈ Σ.sˆa ∈ P
in the sense that traces ⊥ (P ) ∈ T d for every P ∈ D, and there is exactly one such
P for every member of T d .
Proof The fact that traces ⊥ (P ) ∈ T d is an immediate consequence of the axiomsof N : if sˆ and sˆa were both members of traces ⊥ (P ) (for s ∈ Σ∗ and a ∈ Σ)
then (s, {a}) ∈ failures ⊥ (P ) by axioms F4 and F2, in contradiction to determinacyof P .

9.1

Deterministic processes

223

If Q ∈ T d , we have to ﬁnd a member of D with this as its set of traces. Thisis det(Q) = (F , {}), whereF = {(s, X ) | s ∈ Q ∧ X ⊆ Σ  {a | sˆa ∈ Q}}
It is easy to show that this has the required property. Since the failures in det(Q)are precisely the ones implied by axiom F3 for the given set of traces, it follows thatdet(Q). Since weany other process P  with the same set of traces satisﬁes P know that deterministic processes are maximal, it follows that P  ∈ D, establishingthat det(Q) is the only one with the given set of traces.
Now, if P is any member of N , it is not hard to see thatP

det({s ∈ traces ⊥ (P ) | (s  < s ∧ s ˆ ∈ traces ⊥ (P )) ⇒ s = s ˆ})The set of traces on the right above are those of P which do not result as continuations of traces on which P could also terminate. Thus every process has adeterministic reﬁnement, and in particular we can easily deduce the following.
Lemma 9.1.3 If P is a-maximal element of N , then P ∈ D.

When we introduced CSP operators in earlier chapters we often said either
that they could, or could not, introduce nondeterminism. This idea can now begiven a precise meaning: an operator can introduce nondeterminism just when it
can produce nondeterministic results when applied to member(s) of D. In eachcase the result corresponds to the intuition we developed earlier: preﬁxing (a → ·)and preﬁx choice (?x : A → ·) both preserve determinism, as do 1–1 renaming,
alphabetized parallel (P X Y Q) and sequential composition (P ; Q). The lastof these holds because a deterministic P never has any alternative to the event when the latter is possible. The rest of the standard operators can introduce
nondeterminism:• (a → STOP ) 2 (a → a → STOP ) is nondeterministic because the initials of
the two deterministic arguments are not disjoint. In general, if P and Q are
deterministic,  ∈ initials(P )∪initials(Q) and initials(P )∩initials(Q) = {},then P 2 Q is deterministic.
• The nondeterministic choice operator
ism!

obviously introduces nondetermin-• A non-injective renaming can introduce nondeterminism when it identiﬁes
two visible actions from some state: for example, if f (a) = f (b) = a thenf ((a → STOP ) 2 (b → b → STOP ))224

Analyzing the denotational models
is nondeterministic.
• A parallel operator that, for any event a, allows either argument to perform
a independently of the other, can introduce nondeterminism because when
we see a we cannot be sure which side it came from. Thus, for example,(a → STOP ) ||| (a → b → STOP )is nondeterministic because, after the trace a, the event b may be either
accepted or refused.
• Hiding introduces nondeterminism because it turns visible choices into internal actions, and can thus, amongst other things, emulate the behaviour of:(a → c → STOP )2 (b → d → STOP )\ {a, b} =c → STOP
d → STOPD is a closed subset of the metric space N , because whenever a process P
fails to be deterministic, there is some trace s which is either a divergence or, after
which, P has the choice of accepting or refusing some action a. Thus if n = #s + 1then
Q ↓n=P ↓n⇒ Q is nondeterministic

The rule of metric ﬁxed-point induction, which we will meet shortly (page 229) canthen be applied to deduce the following result.
Lemma 9.1.4 If µ p.F (p) is a constructive recursion such that, whenever Q is deterministic then so is F (Q), then the unique fixed point of F is also deterministic.
Furthermore, any constructive mutual recursion P = F (P) such that eachcomponent of F (Q) is deterministic when all components of Q are, has all components of its fixed point deterministic.
What this basically shows is that guarded recursion does not introduce nondeterminism. Thus, any process deﬁnition using only
• deterministic constant processes (such as STOP and SKIP),• operators that preserve determinism,• other operators in cases that do not introduce nondeterminism, and• constructive recursions

9.1

Deterministic processes

a

a

a

225

a

τ

τ

a

a

Figure 9.1
ministic.

Two examples of ‘nondeterministic’ LTSs whose behaviour is deter-is guaranteed to create a deterministic process.
The deﬁnition of determinism over N takes a broad view of a process, in thesense that it looks at its set of observable behaviours rather than the way it evolves
operationally. It is easy to devise rules which ensure that a labelled transition
system behaves deterministically, and one such set follows. Except for the lastcondition you can determine their truth or falsity by examining the transitions ofindividual nodes.
• No node has multiple branching on any action (visible or invisible); thusxx
P −→ Q and P −→ Q  implies Q = Q  .
• If a node P has a τ or  action, then it is the only action of P .
τ• There is no inﬁnite sequence Pi of nodes such that Pi −→ Pi+1 .
The result of mapping any node of such a system to N is certain to be deterministic,
but the reverse is far from the truth. In other words, there are LTSs whose local
structure looks nondeterministic but which actually create processes that behave
deterministically. Trivial examples are shown in Figure 9.1. A much more complex
one is provided by communication protocols such as the Alternating Bit Protocol(Section 5.3) in which the eﬀects of a nondeterministic communication medium arefactored out by the way it is used, creating an overall deterministic eﬀect. An
important application of this possibility will be found in Section 12.4.
So it is not possible to decide whether a process is deterministic or not justby looking at the individual nodes of an LTS. There is an interesting algorithm
for deciding this question, however, which takes advantage of the maximality ofdeterministic processes under reﬁnement. This is set out below, both for its intrinsic
importance and because it helps to illustrate some of the other ideas in this section.

226

Analyzing the denotational models

Suppose we have a process P , presented as a ﬁnite-state LTS (V , →, P0 ), andwe want to know whether or not it is deterministic. By (perhaps partially) exploring
the LTS we attempt to select a subsystem (V  , → , P0 ) (with the same root node)
representing a process P  which reﬁnes P and which meets the conditions quoted
above for being a deterministic LTS. This is done as follows:• Initially we place P0 in V  and begin the search there.
• If we have to explore the node Q, then if it is stable (has no τ or  action)a
we select for each action a ∈ initials(Q) a single node Q  such that Q −→Q  , add this transition to the subsystem and add Q  to the search if it is
not already in V  . This choice means that the initial actions of Q in thesubsystem are the same as they were in the original, but that all possibilityof nondeterminism arising from ambiguity has been removed.
x• If a node Q is not stable then select a single τ or  action Q −→ Q  andmake this action the only action of Q in the subsystem. This Q  is added tothe search if not already in V  .
• If a loop of τ actions is thus encountered, we have discovered a divergenceand so can abandon the search since P is not deterministic.
This search will either eventually be abandoned because the last case arises, or
terminate because all the nodes added to V  have been explored. If it does terminate
then the subsystem it produces is deterministic by construction and the processrepresented by each node reﬁnes the corresponding node in (V , →, P0 ).
The algorithm above sometimes leaves a great many choices open about how
to resolve a process’s nondeterminism, meaning that from a given system (V , →, P0 )it might choose many diﬀerent subsystems, perhaps with large diﬀerences in sizeand shape. This is illustrated in Figure 9.2, where two diﬀerent selections (B andC) are made from a process (A) that is, in fact, deterministic. Thus the existenceof these choices does not indicate that the original process P was nondeterministic.
What we can guarantee, in any case, is that we have a deterministic process P  suchthat P FD P  .
If P is deterministic then P = P  (even though the transition systems representing these members of N may be very diﬀerent) because deterministic processes
are maximal. If P is not deterministic then P = P  and hence P  FD P . Thus P isdeterministic if, and only if, P  FD P , something we can decide with a reﬁnement
checker like FDR. Indeed, this is the method FDR uses to decide whether a process
is deterministic.

9.2

Analyzing ﬁxed points

227

a
A
b
a

a

a

a

τ

τ
a

B

C
b

a

b
a

a
τ

τ

τ
Figure 9.2
one.

9.2

Two diﬀerent ‘deterministic’ LTSs extracted from a ‘nondeterministic’

Analyzing ﬁxed points

In this section we see how understanding the structure of semantic models allows
us to justify existing rules for proving properties of recursions and derive new rules.
At various points we have found it useful to be able to apply rules suchas ﬁxed-point induction and UFP for inferring properties of processes. We havealready seen how UFP is justiﬁed using metric spaces, but have not proved theﬁxed point induction rule set introduced in Section 5.1.
Fixed-point induction If P = F (P) is any recursive definition of a vector ofprocesses which is either constructive or makes each component divergence-free,with indexing set Λ and Q ∈ N Λ is such that Qλ FD F (Q)λ for all λ ∈ Λ, then

228

Analyzing the denotational models

we may conclude that Qλ FD Pλ for all λ ∈ Λ. In the cases of F and T
this principle holds without the need to assume the constructiveness or divergencefreedom of the recursion.
The above is a good starting point for our discussion, since it is really a
combination of several results requiring quite diﬀerent proofs. We will look at three
diﬀerent approaches to ﬁxed point analysis.
Order-theoretic analysis
Sometimes one can simply use the fact that a recursive process is identiﬁed withthe least ﬁxed point of a monotonic function f in some cpo (M , ≤). The following
is a list of a few simple arguments which can often be applied. See Appendix A for
more discussion and their proofs.
• If x ≥ f (x ) then µ f ≤ x .
• If x ≤ f (x ) then f has some ﬁxed point y (not necessarily the least) suchthat x ≤ y.
• If µ f is maximal in M , then it is the unique ﬁxed point.
An immediate application of the ﬁrst of these is the proof of the ﬁxed-point
induction rule for T and F. For there the reﬁnement order is the reverse of theF (Q) is equivalent to Q ≥ F (Q). This
one used to compute ﬁxed points, so Q
implies µ F ≤ Q, which is equivalent to µ F  Q, justifying the rule for thesemodels.
Metric methods
The Banach ﬁxed point theorem, with its ability to force convergence to the uniqueﬁxed point from any point in the underlying space, often makes it possible to achieve
more powerful results about constructive recursions than about general ones. In thecase of ﬁxed-point induction, it allows us to formulate a rule which applies to a muchwider class of properties than that speciﬁed in the deﬁnition of the rule above.
Let X be any space with a family of restriction operators deﬁned over it thatgive a complete metric (a complete restriction space). In general, a predicate R(·)
on X (i.e., a function from X to {true, false}) can be thought of as a subset Y of X
(the members of X satisfying it). If Y is both closed (in the metric space) and nonempty, then it is a complete metric subspace of X . If f : X → X is constructive,
and f (Y ) ⊆ Y , then we can regard f as being a contraction map from Y to itself,
which implies that f has a ﬁxed point in Y . But since f only has one ﬁxed point9.2

Analyzing ﬁxed points

229

in the whole of X , it must be the same one. (See Exercises A.2.1 and A.2.2 foranother view of this.)
The subset Y is closed (see the Appendix) if and only if any x ∈ Y can beseen not to be a member by some ﬁnite depth of the restriction process. This canbe paraphrased as follows:
Definition The predicate R(·) on the complete restriction space X is continuous
if, whenever ¬R(x ), there exists n ∈ N such that, for all y ∈ X , y ↓ n = x ↓ nimplies ¬R(y).
The demonstration that the ﬁxed point of f , under suitable assumptions,belongs to Y then immediately implies the truth of the following rule:
Metric fixed-point induction Suppose R is a continuous, satisfiable (i.e., {x |R(x )} is non-empty) predicate on the complete restriction space X . Then if theconstructive function f is inductive in the sense that, for all x ∈ X ,R(x ) ⇒ R(f (x ))then R(y), where y is the unique fixed point of f .
This justiﬁes the ‘constructive’ case of the original ﬁxed point rule, since, for
any Q ∈ N Λ the predicate
R(P  ) ≡ Q

FD P



is continuous. To see this, notice that if Q FD P  there must be a λ ∈ Λ and abehaviour of Pλ not belonging to Qλ ; you can choose any n larger than the length of
this behaviour. Note that the predicate above is always satisﬁable (being satisﬁedby Q) and inductive by the assumptions of the rule and monotonicity.
Whereas the standard ﬁxed-point induction rule only allows us to prove behavioural properties, the metric rule allows us to address properties that do nothave a characteristic process. This generalization is frequently unnecessary sincemost properties one typically wants to prove are behavioural, but it does allow us
to deal with abstract speciﬁcations such as ‘deterministic’, as we saw on page 224.
Suppose R and f satisfy the conditions of the metric ﬁxed-point
induction rule and that Q is the ﬁxed point of f . Let P be any process satisfying R.
Prove by induction that f n (P ) ↓ n = Q ↓ n, and hence use the deﬁnition of a continuous
predicate to show that R(Q) holds. (This gives a more direct proof of the validity of therule than the one which explicitly uses the properties of metric spaces.)

Exercise 9.2.1

Fixed-point induction, stated informally, might be ‘if a recursive process meets some speciﬁcation R on the assumptions that all recursive calls do, then it meetsthe speciﬁcation unconditionally’. There are, however, three conditions that are required

Exercise 9.2.2

230

Analyzing the denotational modelsof the recursion/speciﬁcation pair to make this valid: the speciﬁcation must be satisﬁable,
the speciﬁcation must satisfy some continuity condition, and the recursion must satisfy
some well-formedness condition (such as being constructive).
The ﬁrst of these is trivially necessary: without it, the rule would prove the predicate ‘false’ true of any recursion! Find examples to show that the other two are needed
as well.
Show that, over N , the predicates R1 (P ) ≡ P  Q, R2 (P ) ≡ P  Q
and R3 (P ) ≡ P = Q are all continuous when Q is any process. Show that R4 (P ) ≡ P = Q
is only continuous if Q = Q ↓ n for some n.

Exercise 9.2.3

Exercise 9.2.4(a) Suppose that R is a continuous predicate and that G and G  are non-destructivefunctions (all over one of the models T , N or F ). Show that the predicates R(G(P ))and G(P )  G  (P ) are continuous.
(b) Hence show that if F is a constructive function, and H a subset of Σ, such that
P ||| RUN H ∈ D ⇒ F (P ) ||| RUN H ∈ D(remembering that D is the set of deterministic processes) then Q ||| RUN H ∈ D,
where Q is the ﬁxed point of F . An important application of this result will become
apparent in Sections 12.4 and 12.6: we will ﬁnd that the predicate being used here
can be read ‘P is secure’.
(c) Similarly show that the predicate on P
STOP) ||| RUN E  P ||| RUN E(PE

is continuous. In Chapter 12 this predicate will be interpreted as ‘P is fault tolerant’:
see Sections 12.3 and 12.6.
The speciﬁcations quoted in parts (b) and (c) share with pure determinism the property
of not being behavioural speciﬁcations. You may like to convince yourself of this now, or
wait until studying them properly in Chapter 12.

The strong order on N
When we discovered in Section 8.3.1 that N over an inﬁnite Σ is not a complete
partial order, it was stated in a footnote that you could use an alternative andstronger order, which was complete, to calculate the ﬁxed points. Given (i) that N
cannot model inﬁnite nondeterminism properly, (ii) that inﬁnite nondeterminism
is unnatural to avoid with inﬁnite Σ (because of hiding) and (iii) that there is
no problem modelling these things in the inﬁnite traces model that we will see in9.2

Analyzing ﬁxed points

231

Chapter 10, it can be argued that this application of the strong order is mainly ofacademic interest. However, the existence of the order is worthy of note, particularly
since it both reveals much about how recursions converge to their ﬁxed points in N
and allows us to prove, inter alia, the ﬁnal part of the ﬁxed-point induction rule.
Much more detail on the strong order, as well as proofs of results quoted in thissection, can be found in [104].
The strong order on N asserts that P ≤ Q only when divergences(Q) ⊆divergences(P ) and whenever s ∈ traces(P )  divergences(P ) then refusals(P /s) =refusals(Q/s) and initials(P /s) = initials(Q/s). Plainly P ≤ Q implies P FD Q,
because the only traces on which the two processes can diﬀer are ones where P candiverge and thus has all behaviours, though there are many cases where the reverse
does not hold. In a sense, this order takes the principles enshrined in axioms D1
and D2 to the extreme and says that not only is divergent behaviour undeﬁned butthat it is the only behaviour that can be ‘reﬁned’ in moving up the order. One
can replace any divergence with non-divergent behaviour, but cannot subsequently
alter the result. The following summarizes some results about ≤.
Lemma 9.2.1 (a) ≤ is a partial order on N which is stronger thansense that P ≤ Q ⇒ P FD Q.

FDin the(b) ⊥N is the least element of N under ≤.
(c) If ∆ is a ≤-directed set, thenand the two are equal.

≤ ∆ exists; in this case∆ also exists(d) The maximal elements of N under ≤ are precisely the divergence-freeprocesses.
The most curious feature of ≤ is that it turns out to be interchangeable withforthe purpose of calculating ﬁxed points: all CSP operators are monotone, theFDﬁnitely nondeterministic ones are continuous, and each CSP-deﬁnable function has
identical least ﬁxed points in the two orders. For details, see [104]. An immediate
consequence of this (using (d) above) is the following result:Lemma 9.2.2 If P = F (P ) is a CSP-defined recursion with indexing set Λ, andeach component of the least fixed point P is divergence-free, then it is the uniquefixed point.
This extends the class of recursions where you can use the UFP rule toessentially all well-behaved ones.
This lemma easily disposes of the last part of the ﬁxed-point induction rulein the case where Σ is ﬁnite, since if Q FD F (Q) then F must have a ﬁxed pointP  such that Q FD P  . Obviously it must be the unique ﬁxed point.

232

Analyzing the denotational models

The case where Σ is inﬁnite is more diﬃcult since we cannot argue that since
the set{P  ∈ N Λ | Q

FD P }

is a cpo under FD , and F preserves this set, there must be a ﬁxed point in it –for it is no longer complete.
It can still be justiﬁed, but (so far as the author is aware) only using arguments based on topology. The predicate R(P  ) = Q FD P  represents a closed
set with respect to the δ-topology deﬁned in [104, 107]. Results in those papers establish the rule. These same two papers, especially the second, give a rather fuller
exposition of the mathematics and methods of ﬁxed-point induction.

9.3

Full abstraction

The concept of full abstraction addresses the question of how good a semantics isfor a programming language. The deﬁnition is frequently divided into two aspects.
• The semantics S[[·]] should distinguish two programs P and Q if, and only
if, they are distinguished by some natural criterion. Usually this criterion isthe existence of some context such that one of C [P ] and C [Q] passes, andthe other fails, some simple test.
• The model M being used should not contain large classes of elements thatare not in the image of S. Speciﬁcally, the aim is usually to show that theexpressible elements of the model are dense, in the sense that every element
is the limit of a directed set of expressible ones.
While the second of these is clearly a desirable aim in itself – the existence ofidentiﬁable classes of inexpressible elements in a semantic model would seem to
imply a mis-match with the language – the main reason for incorporating it under
the heading of full abstraction is that it is frequently important in establishing theﬁrst. For having classes of elements of M that are distinct from all expressible ones
can result in problems for program terms with free process identiﬁers because theymight create functions only diﬀerent on inexpressible values. We will study the two
aspects below.
Of necessity the constructions used in this section often get rather detailed.
The author hopes that even though some readers may not want to study all the
intricacies involved, they will try to understand what full abstraction is and what
the roles of the various constructions are.

9.3

Full abstraction

233

Expressibility
Provided we take a reasonably liberal view of what the CSP language contains,demonstrating the expressibility of the members of our semantic models usuallypresents no problem.
The liberality referred to is in using rather non-constructive mathematicalobjects to do things like index mutual recursions and use as input sets. Thus the
CSP we create here falls well outside the domain of ‘eﬀective computability’. We
are thinking here of CSP as a mathematical language for describing communicatingprocesses rather than a programming language.
Proving an expressibility result like those that follow establishes that theaxioms (such as F1–F4 and D1–D3, in the case of N ) used to deﬁne the model are
strong enough, because they do not allow anything to be considered a process whichshould not be. Let us deal with each of our models in turn.
Traces model
If s is any trace in Σ∗ , it is straightforward to deﬁne a CSP process Ts which has
trace s and as few others as possible:
traces(Ts ) = {t ∈ Σ∗ | t ≤ s}This is done by giving Ts one of the forms
a1 → a2 → . . . → ak → STOPanda1 → a2 → . . . → ak −1 → SKIP

depending on whether s has last member .
It follows that if S ∈ T , then S = traces( {Ts | s ∈ S }) which meansthat every member of T is represented by a CSP process, albeit one using a rather
artiﬁcial and inﬁnitary nondeterministic choice construct.
We will term the process constructed above Int TS , because in some sense it
interprets the process S .
Stable failures model
Suppose (T , F ) ∈ F. A similar, though slightly more involved, construction createsa CSP process with this value.
The trace component T can be dealt with in much the same way as in T ,except that we cannot use the simple Ts processes used above since they give rise
to stable failures that will not, in most cases, be appropriate. They need to beadapted so that failures(Ts ) contains nothing that is not implied by the presenceof s. In other words, we need to create processes Ts that are maximal under F234

Analyzing the denotational models

subject to containing s. These are as below, bearing in mind that we can express
the value F as any simply divergent process.

T

T

Taˆs= F= SKIP= F 2 a → Ts

(a = )The situation with the failures component is slightly trickier, since there isusually no maximal process containing a failure (s, X ). For example, consider the
failure (a, {}) in the context of the processes a → STOP and a → a → STOP
discussed on page 213. They both have this failure, but they have no common
reﬁnement that does.
It is necessary to concentrate on the failures which are complete in the sensethat axiom F3 does not add anything (i.e., (s, X ) such that {a ∈ Σ | sˆa ∈ T } ⊆
X ). The structure of the processes Ttˆcreated above mean that we can assume∗
that s ∈ Σ and that  ∈ X . (All other complete members of F are failures of.) For such (s, X ) we can deﬁne processes F(s,X ) inductively as follows:Tsˆ
F(,X )F(aˆs,X )= ?x : Σ  X → F
= F 2 a → F(s,X )Notice that the only failures of F(s,X ) occur on trace s and are of subsets of X ,and that its traces are all in T .
It is then always true that (T , F ) = (traces( S(T ,F ) ), failures( S(T ,F ) )),where S(T ,F ) is the following set of processes (noting that the ﬁrst component isalways non-empty because T is):{Ts | s ∈ T } ∪ {F(s,X ) | (s, X ) ∈ F ∧ {a ∈ Σ | sˆa ∈ T } ⊆ X∧ s ∈ Σ∗ ∧  ∈ X }We will term this nondeterministic choice Int F(T ,F ) .

So, again, every element of F is expressible as the nondeterministic choice ofa rather artiﬁcially created set of processes.

Standing back from the constructions used for T and F, and looking at just
how the processes we have constructed to model arbitrary elements of them actually
behave, is an excellent way of understanding the limitations of these models. Afterall, these processes must be considered useless for any practical purpose! This will
be illustrated shortly.
The failures/divergences modelWith T and F we were able to deal with each constituent behaviour very nearlyon an individual basis and form a process as a nondeterministic choice at the end.

9.3

Full abstraction

235

This was possible largely because of judicious use of the -top processes in thetwo models (STOP and F ), something that is not possible over N . The use of
an inﬁnite nondeterministic choice operator would, in any case, be of questionabletaste over N since we have already seen that this model does not treat unbounded
nondeterminism accurately.
and the other inﬁnitely nondeterministic operaIt turns out that, without
tors, it is impossible to model every member of N in CSP when Σ is inﬁnite. There
are some patterns of refusal behaviour which are allowed by the model axioms thatcannot be created without inﬁnite nondeterminism. In fact the only ones that canbe created with ﬁnite nondeterminism are ones where, for every trace s,refusals(P /s) = {X | ∃ Y ∈ R.X ⊆ Y }for some non-empty ﬁnite subset2 R of P(Σ ) (which can vary with s).
Therefore we will only deal with the case of ﬁnite Σ here. What we can thendo is to deﬁne a mutual recursion over the whole of N : in other words, we deﬁne
one process for each (F , D) ∈ N .
⎧⎪⊥N if  ∈ D, and otherwise
⎪
⎪
⎪
⎪
⎪
⎨ ({?x : Σ  X → Int N(F ,D)/x  |NInt (F ,D) =X maximal in refusals(F , D) ∧  ∈ X }
⎪
⎪
⎪
⎪
∪
{(SKIP<I (, {}) ∈ F>
I STOP )⎪⎪⎩2?x : initials(F , D) {} → Int N(F ,D)/x  })where ‘maximal’ means maximal under ⊆ (noting that any such refusal set iscomplete in the sense described earlier that it includes all impossible events, andthat maximal refusals must be present because of our assumption that Σ is ﬁnite).
In the interest of brevity, the above deﬁnition uses the general nondeterministic
choice operator , but only over ﬁnite sets of processes where it could have been
replaced by the binary .
You can think of this curious recursion as an ‘interpreter’ of members of N
into CSP: at any stage the process’s state is (F , D)/s, where (F , D) is the initialvalue of the process and s is the current trace. The recursion is constructive, whichleads to the following remarkable argument for its correctness. We can form a vector
2 Obviously this condition has to be satisﬁed when Σ is ﬁnite, since then È(Σ ) is also ﬁnite.
We could, of course, have included the above property as an additional axiom for N . This would
have made it a cleaner model for ﬁnitely nondeterministic CSP at the expense of losing the ability
to model unboundedly nondeterministic CSP at all and making N ’s links with other models alittle more obscure.
The special properties ofand axiom F4 mean that not all such R produce an allowable setof refusal sets.

236

Analyzing the denotational models

Id N of processes, indexed by N itself (i.e., a member of N N ), in which each member
is mapped to itself. This vector is easily seen to be a ﬁxed point of the recursion
and hence, by the UFP rule, equals Int N(F ,D) | (F , D) ∈ N , and soN(failures ⊥ (Int N(F ,D) ), divergences(Int (F ,D) )) = (F , D)

In contrast to the two models dealt with earlier, the processes Int N(F ,D) areusually a reasonable reﬂection of how one would expect a process with the given
value to behave. As a simple example, consider the process P = a → P . If thiswere interpreted in the three models and we then applied the three constructions
to the results, the processes obtained would behave as follows.
• Int TT gives a process which performs any number of a’s and then stops. It is
the same as the process A∗ seen on page 204.
• Int F
(T ,F ) gives a process which makes a choice, over all n, of oﬀering n a’s
unstably in turn and then oﬀering a again, stably, before ﬁnally simply diverging, and additionally has the option of oﬀering any ﬁnite number of a’s
and never becoming stable (again, diverging after the last).
• Int N(F ,D) behaves identically to the original P , simply oﬀering a’s stably forever.

Distinguishing processes
The second thing we have to do is ﬁnd what criteria for distinguishing processes best
characterize each of our models. It is certainly reasonable to argue that the simple
construction of the models from process behaviours makes this unnecessary3 : thesets of behaviours are easy to understand and processes are identiﬁed if and only ifthey have the same ones. But these criteria can be simpliﬁed yet further if we use
the full power of how full abstraction is formulated: P must equal Q if and only
if C [P ] and C [Q] always (i.e., for all contexts C [·]) either both satisfy or both failthe tests.
Hopefully the following arguments will help the reader to understand theconcept of full abstraction, as well as further exploring the expressive power of
CSP.
3 The concept of full abstraction is more vital on semantics using models which have a moresophisticated structure than simple sets of behaviours, frequently being applied to ones recursively
deﬁned using domain theory. There are some languages, such as the typed λ-calculus, for which
it is famously diﬃcult to ﬁnd a fully abstract semantics.

9.3

Full abstraction

237

Traces model
Select any member of Σ. It is convenient to give it a suggestive name such as fail.
We can then formulate a simple test on processes: they fail it when they have thetrace fail and pass it otherwise. Call this test T1 .
Since T1 is formulated in terms of traces, and the traces model calculates
the traces of any CSP process accurately, it is obvious that if traces(P ) = traces(Q)then C [P ] and C [Q] either both pass or both fail it. In order to establish that thetest is strong enough to distinguish all pairs of processes, we need to show thatwhenever traces(P ) = traces(Q) there is a context C [·] such that one of C [P ] andC [Q] passes, and the other fails, it. We can achieve this by ﬁnding, for any traces, a context CTs [·] such that CTs [P ] fails T1 precisely when s ∈ traces(P ). There
are various ways to do this; one is set out below.
• When s = s ˆ, a simple context that does what we want is
CTs [V ] =(V  Ts ) \ Σ; (fail → STOP )Σwhere Ts is the same process used on page 233 in exploring expressibility. The point is that the process on the left-hand side of the sequential
composition can only terminate when V has completed the trace s.
• For s ∈ Σ∗ , we can use the context
CTs [V ] =((V  Ts )[[a/x | x ∈ Σ]]  FAIL(#s)) \ {a}Σ{a}where again Ts is as used for expressibility, a is any member of Σ distinct
from fail , and FAIL(m) is deﬁned
FAIL(m) = (fail → STOP )<I m = 0>I (a → FAIL(m − 1))This context, much as with the more obvious ﬁrst case, works by only allowing
the trace s to occur in V and, like the ﬁrst one, communicating fail only
when it is complete and its contents hidden.
This establishes that the traces model is, indeed, fully abstract with respect
to the simple test chosen.
Stable failures model
One might expect the tests used for F to be a reﬁnement of the method used above,and in order to distinguish processes on the basis of refusals it is clearly necessarythat some aspect of the tests involves more than observing traces. We have two

238

Analyzing the denotational models

types of behaviour to handle: traces and failures. It is possible to combine two
separate forms of test, one for each type, into one by disjoining them: let us deﬁnetest T2 to fail if a process either can communicate fail as its ﬁrst action or deadlocks
immediately (i.e., stably refuses the whole of Σ ).
Clearly the semantics of CSP in F can accurately calculate whether any
process fails T2 , and so all we have to do to establish full abstraction is to showthat if (T , F ) = (T  , F  ) are the representations of processes P and Q then there
is a context that distinguishes them (with respect to T2 ).
Suppose ﬁrst that T = T  . Then the context we use is a slightly modiﬁed
version of the one used for T . For any trace s ∈ Σ∗ , letCTs [V ] = CTs [V ] ||| FThis has identical traces but, since it is never stable, will never fail T2 becauseof deadlock. Thus CTs [Q] fails T2 exactly when CTs [Q] fails T1 , which is whens ∈ traces(Q). This form of context thus allows us to distinguish two processes
with unequal trace sets.
We can thus assume that T = T  and F = F  . So let s be a trace such that
refusals(P /s) = refusals(Q/s). It is easy to show that s is not of the form s ˆ.
Without loss of generality we can assert there is a refusal set X such that
• (s, X ) ∈ F  F • {a ∈ Σ | sˆa ∈ T } ⊆ X•  ∈ X , because if sˆ ∈ T , then by F4 the sets of refusals of P and Q not
containing  are identical.
Consider the context
CF(s,X ) [V ] = ((V ; F )  F(s,Σ  X ) ) \ ΣΣwhere F(t,Y ) is the process used when investigating expressibility that has thefailures (t, Y  ) for Y  ⊆ Y and no other. Since we are hiding the entire alphabet ina process that cannot terminate, there are only two possible values for CF(s,X ) [V ]:F or STOP , the latter being one that can deadlock and hence fail T2 . CF(s,X ) [P ]can fail T2 because P has the failure (s, X ), hence so does P ; F (using  ∈ X ),and so the parallel combination has the failure (s, Σ ). If CF(s,X ) [Q] could fail itthen you can argue in reverse to show Q must have a failure (s, X  ) for X  ⊇ X , but
it cannot by our assumptions and axiom F2. Thus contexts of the form CF(s,X ) [V ]allow T2 to detect diﬀerences between failure-sets.

9.3

Full abstraction239

It is reasonable to hope that T2 might be simpliﬁed further to just testingfor immediate deadlock, but unfortunately the standard CSP language does notallow us to construct contexts that are strong enough to tell diﬀerences between
trace-sets by this means. The problem is that if P and Q are two members of N ,neither of which can either terminate or become stable (i.e., they both have theform (T , {}) for T ⊆ Σ∗ ) then there is no context that can distinguish them on thebasis of deadlock. There is no way for P to make a signiﬁcant contribution to the
behaviour of C [P ], and for the context subsequently to become stable, for none of
the standard operators of CSP can ‘switch oﬀ’ P .
It is easy to add an operator to CSP which rectiﬁes this situation: an interrupt operator which allows one process Q to take over from another P . This iseasiest to understand for a speciﬁed event i being the signal for Q to start: P i Q.
The semantics of this operator over F are:traces(Pi Q)= traces(P )∪ {sˆi ˆt | s ∈ traces(P ) ∩ Σ∗ ∧ t ∈ traces(Q)}failures(Pi Q)= {(s, X ) ∈ failures(P ) | s ∈ Σ∗ ∧ i ∈ X }∪ {(s, X ) | sˆ ∈ traces(P ) ∧  ∈ X }∪ {(sˆ, X ) | sˆ ∈ traces(P )}∪ {(sˆi ˆt, X ) | s ∈ traces(P ) ∩ Σ∗
∧ (t, X ) ∈ failures(Q)}Given this operator, it is not too hard to devise a context that will allow
C [P ] to deadlock immediately, precisely when P has a speciﬁed trace s ∈ Σ∗ , andto deal with traces of the form sˆ using sequential composition in a similar way.
This then leads quickly to the aimed-for full abstraction result. The details are left
as an exercise. See Exercise 9.3.2 for an investigation of a related result.
We can learn an important lesson from this: adding or removing constructs
from a language, even when the semantic model is unchanged, can greatly aﬀect
full abstraction properties.
Failures/divergences modelWith N there seems to be no option but to use a disjunctive test in the same
spirit as T2 . This is T3 , which a process fails if it either immediately diverges orimmediately deadlocks. Following in the footsteps of the earlier models, to showthat T3 is strong enough we need to ﬁnd a context to distinguish any pair P , P  ofdiﬀerent elements of N .
Let a be any member of Σ. For s ∈ Σ∗ , then the context
CTs [V ] = (V  Ts ) \ Σ ||| (a → STOP )Σ240

Analyzing the denotational models

can diverge immediately if and only if s ∈ traces ⊥ (V ), where

T

Tbˆs= ⊥N= b → TsThe role of the event a in this deﬁnition is to prevent the process deadlocking
immediately and thereby failing T3 in an unexpected way.
Thus, if P and P  diﬀer in whether they have this trace, they can be distinguished. Traces of the form s ˆ can be dealt with similarly (see Exercise 9.3.1).
We can thus use T3 to distinguish P and P  if their trace-sets diﬀer.
If s is a divergence of one process and not the other, then by D3 we canassume s ∈ Σ∗ . After replacing the process ⊥N by STOP in the deﬁnition of Ts ,we can use the same context as for traces, since the divergence that trips the test
then comes from V rather than Ts .
So we can assume that our two processes have identical trace and divergencesets, and (without loss of generality) (s, X ) ∈ failures ⊥ (P )  failures ⊥ (P  ). Clearlyno preﬁx of s is a divergence, and exactly as over F we can assume  ∈ X and that
X includes all impossible events. We use a context similar to that used for failures
over F, the important diﬀerence being that we have to use a diﬀerent method to
avoid it deadlocking until the chosen failure is reached. It is built in two stages.
We have to deal separately with the cases X = {} and X = {}. In theﬁrst case letC(s,X ) [V ] = (V  Tsˆ ); (a → STOP )where again a is any member of Σ.
In the second case let a ∈ X {} and deﬁne AS = a → AS . The following
is a simpliﬁed version of the F(s,X ) seen earlier:F(,X)
F(bˆs,X )= ?x : Σ  X → STOP
= b → F(s,X)

Now deﬁneC(s,X ) [V ] = (V ; AS )  F(s,ΣX)ΣIn either case C(s,X ) [V ] behaves as follows:• Until it has completed s (or diverged in the process, something which will
not happen when s is not a divergence of V ) its trace is always a preﬁx of s.

9.3

Full abstraction

241• It may or may not be able to deadlock on proper preﬁxes of s.
• On the complete trace s it can deadlock if, and only if, V has the refusal(s, X ).
What we have to do is place this process in a context which generates an immediate
deadlock from any deadlock of the above after s, but not from any other trace, anddoes not introduce a divergence. One way of doing this is
CFD(s,X ) [V ] = ((C(s,X ) [V ][[a, b/x , x | x ∈ Σ]])



{a,b}

W (#s)) \ {a}

where
W (0)
W (n)
CS

= b → CS= (a → W (n − 1)) 2 CS

(n > 0)= c → CSand a, b, c are arbitrary members of Σ.
The process W (#s) keeps track of how many events C(s,X ) [V ] has performed, and only allows it to deadlock the combination when this number is exactly#s, meaning that C(s,X ) [V ] has actually performed s. (The double renaming of
events to both a and b, coupled with the structure of W (n), means that only eventsfrom the trace s get hidden. Thus the behaviour of V up to trace s is brought forward to the empty trace of the combination, but anything beyond is not. This useof one-to-many renaming appears to be essential.4 ) It follows that CFD(s,X ) [V ]fails T3 if and only if (s, X ) ∈ failures ⊥ (V ).
CFD(s,X ) [V ] can then be used to distinguish P and P  , as desired.
We can summarize the results of this section in the following result:
Theorem 9.3.1 (i) The traces (T ) semantics of CSP is fully abstract with respect
to T1 (failed on the immediate occurrence of a chosen event).
(ii) The stable failures (F) semantics is fully abstract with respect to T2(failed on immediate occurrence of a chosen event or immediate deadlock), andwith the addition of an interrupt operator this test can be weakened to immediate
deadlock.
(iii) The failures/divergences (N ) semantics of finitely nondeterministic
CSP is fully abstract with respect to T3 (failed on the process immediately deadlocking or diverging) provided Σ is finite.
4 The construction given here is a correction from that in the ﬁrst edition, which did not use

the double renaming and which was wrong because it hid the events of a process accepting an
event from Σ X as well as the ones in the trace leading up to it. The author is grateful to Antti
Valmari for pointing out this error.



242

Analyzing the denotational models

Another consequence of full abstraction properties like these is that eachmodel generates the weakest congruence (i.e., identiﬁes most processes) which allows
us to tell whether a process satisﬁes the relevant test. Thus T gives the weakest
congruence on CSP allowing us to tell whether a process has the trace fail, andso on.
Recall that the context CTs [·] is used to distinguish processes in N
on the basis of traces. The version deﬁned on page 239 was only for s ∈ Σ∗ . Find adeﬁnition that works for traces of the form sˆ .

Exercise 9.3.1

Notice that axiom T3 implies that all traces of the form sˆ  aretraces of failures. The only semantic clause for standard CSP operators over F in which
the failures component depends on the input traces is P ; Q, in which only traces of thisform are used. Show that this means it is possible to give a semantics for CSP in a purestable failures model in which a process is represented only by failures(P ) rather than(traces(P ), failures(P )).

Exercise 9.3.2(a) Show that axioms F2, F4 and a much weakened F3 (dealing only with two casesthat can occur in connection with ) suﬃce to create a model whose members
are exactly the failure-sets that arise in F . We no longer get the full version of
F3 because it relates refusal sets to successor traces, and by leaving out the tracecomponent it thus becomes impossible to include this particular ‘sanity check’.
(b) Prove that this model is fully abstract for the standard CSP language with respect
to the test for immediate deadlock.
(c) Find two processes that are identiﬁed over this new model but distinguished overboth T and F . What are the advantages of using F rather than the pure version?
Are there any disadvantages?

9.4

Relations with operational semantics

We have two methods of working out the representations of CSP processes in ourabstract models: either following the route of Chapter 7 and calculating the operational semantics and then extracting behaviours via abstraction functions, orthat of Chapter 8 and doing it by directly using denotational semantics. There is aclaim implicit in this, namely that both ways calculate the same value. We are, inother words, claiming that the operational semantics is congruent with each of thedenotational ones. This is something that needs to be proved, and in this section
we outline some of the methods that can be used to do this.
Firstly, one must remark that in order to keep the discussion clear we will
have to be a little more formal than hitherto about the distinctions between thesyntax of CSP and functions deﬁned over it. The language of terms in CSP (i.e., the9.4

Relations with operational semantics

243

set of well-formed terms in the language that may contain free process identiﬁers)
will be denoted CSP, and the closed terms (ones with no free identiﬁers) will bedenoted CSP. Naturally, when referring to a function like failures ⊥ (P ) we will
have to make it clear which of the two supposedly equal values this is.
The operationally-based versions of these functions deﬁned in Section 7.4.1
provide us with functions to the models from any LTS V : for each node σ of V
ΦT (σ) =ΦF (σ) =ΦN (σ) =traces(σ)(traces(σ), failures(σ))(failures ⊥ (σ), divergences(σ))

These can, of course, be used to compute one set of interpretations of CSP
from the LTS generated by the operational semantics. The second set are producedby the denotational semantics given in Chapter 8: let us call these ST [[·]], SF [[·]] andSN [[·]].
A variety of techniques have been used over the years to establish the equivalence of pairs of these interpretations. Invariably the proofs have been by some
sort of structural induction over the syntax of a CSP program and come in threeparts: a series of lemmas dealing with basic operators other than recursion, a morediﬃcult argument to handle the recursive case, and overall ‘glue’ to put all thesepieces together. Presenting detailed arguments for each of the models here would
be much too long and complex, so we will concentrate on the simplest model, T ,and indicate brieﬂy at the end how things change for the others.
A CSP term can, in general, have free process identiﬁers. Even if we startwith a closed term (one with none), if we want to establish results about it bystructural induction we may well have to consider sub-terms which are not closed.
In proving congruence between an operational and a denotational semantics it istherefore necessary to use notation capable of interpreting general terms5 and toformulate our inductive congruence results accordingly.
It is mathematically superior to formulate each of the denotational semantics
with environments giving a binding of each free process identiﬁer to an element of
the underlying semantic model. (This type of environment was previously discussed
on page 164.) Thus, we can deﬁne
Env T = Ide → T
to be the set of T -environments, so that the type of the semantic function becomes
ST : CSP → Env T → T
5 As remarked previously (for example in Chapter 7), we have avoided doing this formally up to
now. This was because the gain in terms of completeness and making the semantics of recursion
tidier would have been outweighed by the notational and conceptual clutter.

244

Analyzing the denotational models

and, for a process term P and environment ρ ∈ Env T , ST [[P ]]ρ is the value of P
when its free identiﬁers have the trace sets assigned to them by ρ. The reason why
it is superior is because, when we are faced with a recursive term such as µ p.P ,we can present the function that P represents cleanly: in a given environment ρ itmaps α ∈ T to ST [[P ]]ρ[α/p].
The natural operational semantic analogue of an environment is a substitution ξ that maps each identiﬁer to a closed CSP term:ξ ∈ Subst : Ide → CSP
ξ then converts any CSP term P into a closed one subst(P , ξ) by replacing each free
identiﬁer p by ξ(p). The full statement of the congruence result is now that, for allξ ∈ Subst and all terms P ∈ CSP,ΦT (subst(P , ξ)) = ST [[P ]]ξ
where ξξ:T

T

is the member of Env T produced by applying ΦT to each component ofTξ (p) = ΦT (ξ(p))
It is this result we prove by structural induction over P (for all ξ simultaneously).
The claim is trivially true for all ‘base’ cases of the induction: P being either
a process identiﬁer p or one of the constant processes STOP and SKIP .
The proof then follows the same pattern for each non-recursive operator.
Consider, for example, 2. We can assume P and Q are two terms both satisfying
the claim for all ξ. We havesubst(P 2 Q, ξ) = (subst(P , ξ)) 2 (subst(Q, ξ)),ST [[P 2 Q]]ξT

= ST [[P ]]ξ

T

2T ST [[Q]]ξ

andT

where 2T is the representation of this operator over T , in this case ∪ (union). Thus,
by induction, it is suﬃcient to prove that for any closed CSP terms R and S ,ΦT (R 2 S ) = ΦT (R) 2T ΦT (S )This result, and corresponding ones for all the other operators, can be provedby analyzing how the operational semantics behaves. Speciﬁcally, in this case, it iseasy to show that, for any R and S ,






• If R =⇒ R  and S =⇒ S  then R 2 S =⇒ R  2 S  .

9.4

Relations with operational semantics
s

245
s

s

• If s =  and either R =⇒ T or S =⇒ T then R 2 S =⇒ T .
s• The above are the only pairs (s, V ) such that R 2 S =⇒ V .
This, of course, establishes what we want.
Now consider the case of a recursion µ p.P . What we have to show is that,for any ξ, ΦT (subst(µ p.P , ξ)) is the least ﬁxed point of the function Υ mappingT
α ∈ T to ST [[P ]](ξ [α/p]). The inductive assumption makes it easy to show that it
is a ﬁxed point. Let P  be the term in which all free identiﬁers of P other than p
have been substituted by ξ, so that subst(µ p.P , ξ) = µ p.P  . ThenΦT (subst(µ p.P , ξ)) =
=
=
=
=
=

ΦT (µ p.P  )ΦT (P  [µ p.P  /p])ΦT (subst(P , ξ[µ p.P  /p]))

(a)
(b)

ST [[P ]]ξ[µ p.P  /p]

(c)

T

T



ST [[P ]](ξ [ΦT (µ p.P )/p])Υ(ΦT (subst(µ p.P , ξ)))(d)(a) follows because of the operational semantics of recursion:τµ p.P  −→ P  [µ p.P  /p]τ

and because if A is a node of an LTS whose only action is A −→ B then ΦT (A) =ΦT (B ). (b) follows by deﬁnition of P  , (c) comes by induction on the term P whichTis simpler than µ p.P , and (d) by deﬁnition of ξ .
Recall that, for T , we chose to identify recursions with the subset-least ﬁxed
points of the associated functions, arguing that this was natural because all the
behaviours recorded in this model always appear ﬁnitely. To show that this was theright decision, given the above argument, it is suﬃcient to show that every traceof ΦT (subst(µ p.P , ξ)) belongs to Υn ({}) for some n. (Containment in the otherdirection comes from the fact that ΦT (subst(µ p.P , ξ)) is a ﬁxed point of Υ, and so
is greater than the least one.)
If s is such a trace then there must be some s  ∈ (Στ )∗ and Q such thatss  \ τ = s and subst(µ p.P , ξ) −→ Q. If N = #s  , then during the derivation of
the behaviour s  , the recursion cannot possibly be unfolded more than N times,
since every time it is unfolded a τ action is generated which must be present in s  .
Consider the following two mutual recursions deﬁning the processes p0 and q0 .
pn=P  [pn+1 /p]

qn
qN

=
=

P  [qn+1 /p] n ∈ {0, . . . , N − 1}
STOP

n∈N

246

Analyzing the denotational models

where P  is as above. The ﬁrst of these clearly has exactly the same behaviour as
subst(µ p.P , ξ), in the sense that the operational semantics are exactly alike exceptthat the multiple names of the identiﬁers in the mutual version keeps track of how
many times the recursion has been unfolded. The process q0 behaves exactly like p0
until after the N th unfolding, which means that it has the behaviour s  ; this meansthat s ∈ ΦT (q0 ).
On the other hand, ΦT (qN ) = {}, ΦT (qN −1 ) = Υ({}) etc., until ΦT (q0 ) =TΥN ({}), because ΦT (subst(P , ξ[Q/p])) = ST [[P ]]ξ [ΦT (Q)/p] for every closed
term Q. Hence s ∈ ΥN ({}), which is what we wanted to show.
This completes our sketch of the proof of congruence between the operationalsemantics and the trace semantics. The proof for F goes through exactly the same
steps, except that one obviously has to keep track of failures as well as traces andit is necessary to allow the q0 recursion to unfold N + 1 times rather than N .
With N there is little diﬀerence with the overall structure of the proof or
the cases for non-recursive operators. The recursive case is diﬀerent because wehave to handle inﬁnite behaviours (divergences) and use what is really the opposite
ﬁxed point. We have to show that the eﬀects of divergence lead to the operationalsemantics mapping under ΦN to the N -least ﬁxed point, bearing in mind thatthe same basic argument applied over T (page 245) shows that any recursive term
maps to a ﬁxed point of the associated function.
Perhaps the easiest way of proving minimality uses König’s lemma (applicablesince we are in any case restricted to ﬁnitely nondeterministic CSP). For any traces ∈ Σ∗ , one shows that either the tree of states reachable from a process such as
R = subst (µ p.P , ξ) on preﬁxes of s is ﬁnite, or there is a divergence in the tree.
In the second case, axioms D1 and D2 mean that every behaviour on s gets into
ΦN (R), while in the ﬁrst case you can limit the number N of times the recursion
has to be unfolded to be the depth of the ﬁnite tree, and then a similar argument
to that applied over T can be used to show that the operational and denotationalsemantics must agree on behaviours that are preﬁxes of s.
Exercise 9.4.1

Prove that, for any closed term P , ΦT (P \ X ) = ΦT (P ) \T X .

Exercise 9.4.2 Repeat the previous exercise for (i) the stable failures model F and(ii) the failures/divergences model N , the latter under the assumptions that the term P
is ﬁnitely nondeterministic and X is ﬁnite.
Exercise 9.4.3
The results on expressibility in Section 9.3 imply that, in each of thecases considered, the function ΦM is surjective as a function from the closed CSP terms
CSP to the model M. Show that there is a transition system V on which the function ΦNis surjective when Σ is inﬁnite (i.e., the one case not dealt with by the previous remark).

9.5

9.5

Notes

247

Notes

The main properties of deterministic processes have been well known since failurestype models were ﬁrst developed [15, 18, 19, 101].
The results of Section 9.2 are derived mainly from [101, 104, 107]. The last
two of these contain the details omitted here of the purely topological approach to
CSP ﬁxed-point induction.
The notion of full abstraction evolved in the 1970s and early 1980s: see[79, 92] for example. The full abstraction result for N has been known for many
years: it is implicitly present in [51], for example (which also contains mush othermaterial on full abstraction). The full abstraction results for F, like the other results
about this model, arose from the collaboration between the author, Jategoankar andMeyer, and are closely related to independent results of Valmari [132].
The ﬁrst congruence proof between operational and denotational semantics
of CSP appears (rather brieﬂy) in Olderog’s important paper [87] with Hoare. A
more complete presentation of a proof appears in [135] and [22]. The diﬃculty insuch proofs comes mainly from the radically diﬀerent ways in which denotationaland operational semantics handle recursions. The above two references handle thisin diﬀerent ways; the author later developed a further way of handling this (encompassing unbounded nondeterminism and discontinuous functions) in [105] – thelater is the style of proof he presently prefers.
2005: Some interesting results have been proved about the properties which
can be expressed by CSP reﬁnement in its most general form:
F (P )G(P )for F and G being CSP contexts [115, 112]. It turns out that the ones which can be
expressed by a natural class of contexts are exactly the properties which are closed
in the usual metric space on the failures/divergences model provided the alphabet Σis ﬁnite. This can be viewed as a sort of higher-order full abstraction result.

Chapter 10

Inﬁnite traces

We have seen (Section 8.3.2) that the failures/divergences model is deﬁcient in theway it models inﬁnitely nondeterministic processes. The solution is to include theset of a process’s inﬁnite traces in the model. An inﬁnite trace is a member of Σω ,the sequences of the form ai | i ∈ N. It represents a complete (i.e., throughout alltime) communication history of a process that neither pauses indeﬁnitely without
communicating nor terminates.
In this chapter we see how this is done and get an idea of the extra expressive
power it gives us.

10.1

Calculating inﬁnite traces

Our aim is to represent each process by the triple(failures ⊥ (P ), divergences(P ), inﬁnites(P ))recalling that inﬁnites(P ) already, by deﬁnition, contains all extensions of divergences.
Bear in mind that we know (thanks to the argument in the proof of Theorem
7.4.2 on page 178) that for any ﬁnitely nondeterministic process
inﬁnites(P ) = traces ⊥ (P )  traces ⊥ (P )where S = S ∪ {u ∈ Σω | ∀ t < u.t ∈ S }. Thus, the extra component will only
convey extra information outside this category of process.
If we are to follow the route taken in Chapter 8 we should now axiomatize which triples (F , D, I ) are allowable, investigate the model’s properties (ordertheoretic and otherwise) and then use it to give the semantics. It is entirely possible

250

Inﬁnite traces

to build such a model, and indeed we will do so later in this chapter, but it turns outthat the relationship in it between failures and inﬁnite traces is remarkably subtle
and creates problems which there is no overriding need for us to meet yet.
One can, at least temporarily, avoid these diﬃculties thanks to the following
observations:• The stable failures failures(P ) are accurately calculated, even for inﬁnitely
nondeterministic CSP, by the semantics over the stable failures model F.
• If one examines the way that CSP operators generate behaviours, it turns
out that the stable failures of component processes never inﬂuence any ofﬁnite or inﬁnite traces or divergences.
It therefore makes sense to introduce inﬁnite traces via a simpler model in which aprocess is modelled as(traces ⊥ (P ), divergences(P ), inﬁnites(P ))We can still work out failures ⊥ (P ) from a combination of the second componentsof this representation and the semantics over F.
I, the inﬁnite traces/divergences model, consists of the triples (T , D, I ),where T , D ⊆ Σ∗ and I ⊆ Σω , meeting the following conditions:
T1. T is non-empty and preﬁx closed.
D1. s ∈ D ∩ Σ∗ ∧ t ∈ Σ∗ ⇒ sˆt ∈ D
D2 . D ⊆ T
D3. sˆ ∈ D ⇒ s ∈ D
D4. s ∈ D ∩ Σ∗ ∧ u ∈ Σω ⇒ sˆu ∈ I
I1 . u ∈ I ∧ s < u ⇒ s ∈ T
I is a complete lattice under both I (deﬁned, of course, to mean reverse
inclusion on all three components) and its reverse, the subset order. For I =({}, {}, {}) (the representation of STOP ) is the greatest I -lower bound of theempty set, and the greatest lower bound of any non-empty set is given, as usual, bycomponentwise union:
S = (T ∗ , D ∗ , I ∗ ), where
T∗
D∗
I∗


=
{T | (T , D, I ) ∈ S }
={D | (T , D, I ) ∈ S }
={I | (T , D, I ) ∈ S }10.1

Calculating inﬁnite traces

251

The least reﬁned element is ⊥I = (Σ∗ , Σ∗ , Σω ), representing any process thatcan diverge immediately.
It is easy to give clauses for calculating inﬁnites(P ) for all the standard CSP
operators.
inﬁnites(STOP)= {}inﬁnites(SKIP)= {}inﬁnites(a → P ) = {aˆu | u ∈ inﬁnites(P )}inﬁnites(?x : A → P ) = {aˆu | a ∈ A ∧ u ∈ inﬁnites(P [a/x ])}inﬁnites(P 2 Q)

= inﬁnites(P ) ∪ inﬁnites(Q)inﬁnites(PQ)= inﬁnites(P ) ∪ inﬁnites(Q)inﬁnites(P  Q)

= {u ∈ Σω | ∃ s ∈ Traces(P ),Xt ∈ Traces(Q).u ∈ s  t}X

∪ {sˆu | s ∈ divergences(P  Q) ∩ Σ∗ ∧ u ∈ Σω }X

inﬁnites(P ; Q)

= inﬁnites(P )∪ {sˆu | sˆ ∈ traces ⊥ (P ) ∧ u ∈ inﬁnites(Q)}inﬁnites(P [[R]])= {u  | ∃ u ∈ inﬁnites(P ).u R u  }∪ {sˆu | s ∈ divergences(P [[R]]) ∩ Σ∗ ∧ u ∈ Σω }inﬁnites(P \ X )= {u  ∈ Σω | ∃ u ∈ inﬁnites(P ).u \ X = u  }∪ {sˆu | s ∈ divergences(P \ X ) ∩ Σ∗ ∧ u ∈ Σω }Recall that Traces(P ) is an abbreviation for traces ⊥ (P ) ∪ inﬁnites(P ). The trace
constructs  , \ X and renaming have been extended in the natural ways to encomX

pass inﬁnite traces. Of course, to give a denotational semantics to CSP you needclauses for the other components, traces ⊥ (P ) and divergences(P ), of the representation. In all but one case, the clauses for divergences(P ) are the same as they wereover N because knowledge of a process’s inﬁnite traces does not aﬀect what thedivergences are when applying the respective operators. The exception is hiding,since we no longer have to attempt to infer what the inﬁnite traces are from theﬁnite ones and can directly deﬁne:divergences(P \ X )= {(u \ X )ˆt | u ∈ inﬁnites(P )∧t ∈ Σ∗ ∧ u \ X is ﬁnite}∪ {(s \ X )ˆt | s ∈ divergences(P ) ∩ Σ∗ ∧ t ∈ Σ∗ }The deﬁnitions for the ﬁnite traces component traces ⊥ (P ) are identical tothe mappings on traces that can be extracted from the failures clauses for N . These

252

Inﬁnite traces

diﬀer from the clauses for the ﬁnite traces model T only in the cases where it isnecessary to close up to preserve axiom D2/D2 , so for example
traces ⊥ (P \ X )= {s \ X | s ∈ traces ⊥ (P )}∪ {sˆt | s ∈ divergences(P \ X ) ∩ Σ∗ ∧ t ∈ Σ∗ }All the resulting semantic clauses are both universally accurate and representable as relations over behaviours: we have eliminated the problem which caused
the semantics over N to break down for inﬁnitely nondeterministic CSP. It is now
possible to prove the lemmas of an operational/denotational congruence proof (likethat for 2 and T on page 244) for every one of the operators. For example, theprocesses A∗ and A∞ deﬁned on page 204 are now clearly distinguished by thesemantics, which correctly predict that A∞ \ {a} can diverge and that A∗ \ {a}cannot.
The fact that they are representable by relations implies (as in Section 8.2)
that they are all monotonic, fully distributive, and continuous in the ⊆ order. Let us
consider the question of continuity in the order. The argument for the continuityof hiding over N no longer applies because of the diﬀerent way we are calculating
divergence. One would not expect the argument to apply when we reason about
inﬁnitely nondeterministic CSP, since it relied on König’s lemma, which in turnrequires ﬁnite branching. And, in fact, hiding is not continuous over I. When Σ is
inﬁnite, the same example as used on page 188 works. An example for ﬁnite Σ isprovided by the processes Qn deﬁned below (hiding {a, b} makes each Qn diverge,
but not their limit A∗ ). Indeed, the incorporation of inﬁnite traces, which eachcontain an inﬁnite amount of information, leads to several other relations becoming
inﬁnitary and the corresponding operators discontinuous. This applies to sequential
composition, parallel and ﬁnitary renaming.
For example, let R be a renaming that maps events a and b to b, and let Pn
be the process that performs n a’s and then an inﬁnite sequence of b’s:PnBS

= a → . . . → a → BS
= b → BS

Obviously Pn [[R]] = BS for all n. If we deﬁne Qn = {Pm | m ≥ n} then theseform an increasing sequence under I whose limit is actually A∗ (it can perform
any ﬁnite sequence of a’s, but has no inﬁnite trace). But we then have{Qn [[R]] | n ∈ N} = BS = ( {Qn | n ∈ N})[[R]]demonstrating the failure of continuity.
In Chapter 8 we established a rule of thumb that one should identify a recursion with either the or ⊆ least ﬁxed point depending on whether or not one’s10.1

Calculating inﬁnite traces

253

model incorporates inﬁnite behaviours. On this principle we must expect the rightanswer for I to be , and indeed it is, despite the fact that it means a large-scale
abandonment of continuity and the resulting simple formula for ﬁxed points. The
need to use rather than ⊆ can now be demonstrated not only from under-deﬁned
recursions such as µ p.p, (which diverges and so must be mapped to ⊥I rather thanto I ), but also from very ordinary ones such as µ p.a → p.
For ({an | n ∈ N}, {}, {}) (which is the value in I of the process A∗ ), isthe ⊆-least ﬁxed point of the function F (·) derived from the recursion µ p.a → p.
This is plainly not the right value, since it does not contain the inﬁnite trace thatthe process self-evidently has. The problem is that F (P ) can never have an inﬁnite
trace when P does not, so starting an iteration from I (which itself has no inﬁnite
traces) will never yield one. On the other hand, the -least ﬁxed point (and greatest⊆ one) is ({an | n ∈ N}, {}, {aω }), the correct answer.
In the case of µ p.a → p, there are only the two ﬁxed points quoted above,
but in only slightly more complex cases, such as µ p.(a → p) (b → p), there canbe inﬁnitely many. In this second example also it is clear that the correct answer
is the -least one, which contains all inﬁnite traces made up of a’s and b’s.
Even ‘constructive’ recursions can fail to reach their least ﬁxed points via
the simple formula
µf =

∞
n
n=0 f (⊥)

This is illustrated by the recursionµ q. ((a → q)  A∗ ){a}where A∗ is as above. For this recursion, F n (⊥I ) has the inﬁnite trace aω for allnn (because an is a divergence), and hence so does ∞n=0 F (⊥I ) which equals({an | n ∈ N}, {}, {aω })However, this value is neither a ﬁxed point of this recursion, nor does the operationalsemantics of the recursion have the inﬁnite trace aω . The least ﬁxed point, whichis also the operationally correct value, is A∗ . It is clear, both from this and themultiplicity of ﬁxed points we saw above, that the proof that you always get theoperationally right answer is more critical than over previous models.
The argument we saw for T in Section 9.4 still applies when it comes toproving that the operational semantics of any recursion maps to some ﬁxed point of
the associated function. But the proof that it is always the least one seems to require
subtlety and mathematical machinery well beyond what we can present here. Theinterested reader can consult [105].

254

Inﬁnite traces

But the important thing is that the result, and hence the congruence theorem
with the operational semantics, can be proved and so is true. This establishes thatthe denotational semantics for CSP, derived from the above operator deﬁnitions andleast ﬁxed points for recursions, does give the correct value for every process.
The demise of metrics
The major gain we have made from the move to incorporate inﬁnite traces in ourmodel is the ability to calculate a satisfactory semantics for general CSP (i.e.,
incorporating unbounded nondeterminism) denotationally. The attentive reader
may already have noticed what is the greatest practical loss, and one of the best
reasons for not using inﬁnite traces all the time. The recursions µ p.a → p andµ p.(a → p) (b → p) are certainly constructive in every reasonable sense, and yet
we have seen that they do not have unique ﬁxed points. This is because no family ofrestriction functions based (as all those for other models have been) on describing
what a process does up to some ﬁnite length of trace, can discriminate between apair P , P  which only diﬀer in inﬁnite traces.
Thus the UFP rule, and the ﬁxed-point induction principles relying on constructiveness as deﬁned in Section A.2, are not in general valid over I or othermodels using inﬁnite traces. We will be able to repair the damage somewhat, but it
is better to do this after we have studied the incorporation of failures information
into our model as this can signiﬁcantly aﬀect the situation.
Exercise 10.1.1 Suppose Σ is inﬁnite (containing, say, {ai | i ∈ }). Find ﬁnitely
nondeterministic processes P1 , P2 , Q1 and Q2 , a set X and a renaming relation R suchthat
• traces ⊥ (P1 \ X ) = traces ⊥ (P2 \ X ) but inﬁnites(P1 \ X ) = inﬁnites(P2 \ X ).
• traces ⊥ (Q1 [[R]]) = traces ⊥ (Q2 [[R]]) but inﬁnites(Q1 [[R]]) = inﬁnites(Q2 [[R]]).
The existence of such examples demonstrates that inﬁnite hiding and inﬁnitary renaming
can introduce unbounded nondeterminism.

Exercise 10.1.2 Find the relations which generate inﬁnites(P ; Q) in the relational
representation of this operator. Show by means of example that they are not all ﬁnitary.
Find a process Q and a directed subset ∆ of I (with respect to ) such that(∆); Q ={P ; Q | P ∈ ∆}This shows ; to be discontinuous in its ﬁrst argument; is it also discontinuous in its second
argument?

10.2

10.2

Adding failures

255

Adding failures

We now know that, for any CSP process, we can calculate its divergences, traces
both ﬁnite and inﬁnite, and (stable) failures. In fact, we know how to do thesethings two ways since we can either get them from the operational semantics orby using a combination of two denotational models. It is nevertheless interesting
to try to combine all of these types of behaviour into a single model, because only
by doing this can we understand what ‘the space of all processes’ looks like, andestablish results like full abstraction. We want to build the failures/divergences/inﬁnite traces model U consisting of sets of triples (F , D, I ).
The main issue in understanding which (F , D, I ) can represent the(failures ⊥ (P ), divergences(P ), inﬁnites(P ))of some process P is the way in which failures and inﬁnite traces interact, for theother relationships have all been established in studying I and N .
Their relationship is analogous to axiom F3, which can be read as statingthat when an event a is not refusable after trace s, then sˆa is a ﬁnite trace.
Carrying on this argument to inﬁnity will lead to inﬁnite traces; we will investigate
this by studying the two recursions used as examples in the previous section:RaRab= a → Ra= (a → Rab )(b → Rab )It is easy to see thatFa
Fab= failures ⊥ (Ra )= failures ⊥ (Rab )= {(an , X ) | a ∈ X }= {(s, X ) | s ∈ {a, b}∗ ∧ {a, b} ⊆ X }In the model I, both of the recursions have solutions with no inﬁnite traces,
but that would be inconsistent with the failure information since, if we always oﬀer
either process the set {a, b}, then it is certain to perform an inﬁnite trace. A processwith no inﬁnite trace is certain, if we always oﬀer it the whole of Σ, eventually todeadlock or terminate; neither of these processes can do either.
So in fact the Ra recursion does have a unique ﬁxed point when we take into
account the additional information from failures, since the set of inﬁnite traces fromthe ‘wrong’ one of the pair seen on page 253 can now be discounted.
We can be sure that any set of inﬁnite traces to be paired with Fa has
the trace aω because this inﬁnite trace can be forced from a known ﬁnite one.
Speciﬁcally, if s is a ﬁnite trace of the process P , and u > s is in Σω , andwhenever s < tˆa < u we have (t, {a}) ∈ failures ⊥ (P ), then u must belong

256

Inﬁnite traces

to inﬁnites(P ). This implies that whenever F is the failure-set of a deterministic
process in N then there is only one set of inﬁnite traces consistent with F , namely
traces ⊥ (F )  traces ⊥ (F ).
As inﬁnite traces tell us nothing interesting about processes in U whose
projection into N (the ﬁrst two components) appear deterministic, we can takeexactly the same deﬁnition for ‘deterministic’ over U as over N .
Unfortunately the story is not quite as simple with Rab , for there are stillinﬁnitely many sets of inﬁnite traces consistent with the failures. Furthermore,
there is no speciﬁc inﬁnite trace you can be sure is there. If I is any subset of{a, b}ω with the property that for all s ∈ {a, b}∗ there is u ∈ I with s < u, it turns
out that we can create a CSP process with value (Fab , {}, I ).
If v is any inﬁnite trace, let Tv be the process that simply communicates themembers of v in turn (akin to the processes Ts for ﬁnite traces used on page 233).
Then
NI =

{Tv | v ∈ I }is the process we want: it obviously has the correct inﬁnite traces, and our assumption implies it has the right failures since if s ∈ {a, b}∗ then there are va and vb
in I with sˆa < va and sˆb < vb . The processes Tva and Tvb give to NI all the
failures of Fab for this s.
These are precisely the sets of inﬁnite traces consistent with Fab . For weknow that every ﬁnite trace is possible, and if after the trace you oﬀer a processwith failures Fab the set {a, b} for ever, you are bound to get an inﬁnite extension ofs. Not all I of this form give rise to ﬁxed points of our recursion, though inﬁnitely
many of them do (see Exercise 10.2.3), but that is not relevant to the issue of
determining what it means for a set of inﬁnite traces to be consistent with a set of
failures.
Whatever formula captures the general relationship between inﬁnite traces
and failures is inevitably going to be more complex than previous axioms suchas F1–F4 since it evidently relates the entire sets of these behaviours rather than
individual ones. A variety of formulations of an axiom relating F and I have been
discovered, but all of them rest ultimately on something very like the following
ideas.
Imagine that you are about to experiment on a process. Now there may well
be some nondeterminism in the implementation, and on any run it will then haveto make decisions to resolve this. From the experimenter’s point of view there is no
way of telling whether the decisions are being made in ‘real time’ as the experiment
proceeds, or have all been pre-ordained. If all the decisions have been made inadvance, then the process you are actually dealing with is a reﬁnement P  of P that

10.2

Adding failures257

is at least nearly deterministic.1 The reasons why the procedure in the footnote
may not deliver a deterministic result are divergence and the events that are left asalternatives to an internal action. It is certainly closed in the sense that
Traces(P  ) = traces ⊥ (P  )Since every recordable behaviour of P is present in one of these P  it follows
that
P =

{P  | PP  ∧ P  is closed}This identity is the key to deciding when sets of failures and inﬁnite traces
are consistent. For there can be no doubt that if (F , D) is a member of N then its
closure(F , D) = (F , D, traces(F )  traces(F ))must be included in the failures/divergences/inﬁnite traces model U. A construction
identical to that for N on page 235 (which now requires unbounded choice since Σ
may be inﬁnite) creates a process with these behaviours. And it is clear that for any(F , D, I ) ∈ U, (F , D) is a member of N , so that the closed processes are precisely
N , the set of closures of members of N .
Thus the model U equals{

S | {} = S ⊆ {(F , D) | (F , D) ∈ N }}and the way we have derived this fact equips U with the expressibility half of a full
abstraction result.
There is no reason, of course, why you should not take the above as thedeﬁnition of U. But one can get back to the earlier, directly axiomatized, style byextracting what this says about inﬁnite traces into a suitable formula.
We can thus deﬁne U to consist of those triples (F , D, I ) satisfying F1–F4,
D1–D4, the following property slightly reformulated from I1 of I
1 You can imagine this choice procedure as being applied to an LTS which has been unrolled

into a tree, as in Figure 7.3 on page 159, so that no node is visited more than once, recognizing that
diﬀerent decisions may be made each time a node is visited. There is then an ‘implementation’of it that is produced by a method like the algorithm for extracting a deterministic reﬁnement
described on page 225, except that you should select one representative for each label leading froma node irrespective of whether it is stable or not. This is because we have to recognize that theprocess is allowed to accept visible alternatives to internal actions and that if such alternatives
were always ignored then there would be legitimate behaviours of the LTS which would not appear
in any of the ‘implementations’.

258

Inﬁnite traces

I1. u ∈ I ∧ s < u (for s ∈ Σ∗ ) implies s ∈ traces(F )and one more property, I2. A wide range of formulations, as well as some plausible
alternatives that fail, can be found in [105] and especially in [12]. The axiom canbe stated in terms of game theory and via logical formulae with inﬁnitely deeply
nested quantiﬁcations, but the most understandable are probably those closer inspirit to the discussion above. The following version simply states that from any
point a process can reach, we can pre-resolve the nondeterministic choices it will
make thereafter so that it acts deterministically:I2.

s ∈ traces(F ) ⇒ ∃ T ∈ T d .(F , D)/s∧ {sˆu | u ∈ T } ⊆ I

FD det(T )The more refusal sets a process has (relative to a ﬁxed set of ﬁnite traces),the less inﬁnite traces it need have. This is because, in the above, the sets T canbe smaller when F is able to refuse more. Thus, for the failure-set Σ∗ × P(Σ )and divergence-set {}, any set of inﬁnite traces is permissible. In particular, you
can have the empty set of inﬁnite traces, creating the interesting process FINITE Σwhich can be written{Ts | s ∈ Σ∗ }with Ts , as before, being the process which simply communicates the trace s.
The semantic clauses for computing how CSP operators behave over U caneasily be put together from those of earlier models. Those for divergences andinﬁnite traces are identical to those over I, while those for failures are identical2 to
those over N . Every one has a relational representation and so is monotonic andfully distributive. Just as over I, many fail to be continuous.
You should always remember that if P is a ﬁnitely nondeterministic term(or, indeed, a node in a ﬁnitely nondeterministic LTS) then its value in U is always
simply the closure of its value in N .
Full abstraction
Our ﬁrst expression for U as a set of nondeterministic compositions equips it withthe expressibility half of its full abstraction result.
The second half serves to emphasize that U is the natural extension to unboundedly nondeterministic CSP of the failures/divergences model N , since except
2 Those, especially \ X , that refer to divergence-sets, of course now mean the ones derived from

I.

10.2

Adding failures259

for the larger language the testing criterion is identical. U is fully abstract withrespect to the test for immediate deadlock or divergence (T3 , see page 239). Exactly the same contexts as over N distinguish processes on the bases of ﬁnite traces,
failures and divergences, so all we need is to ﬁnd contexts that distinguish them on
the basis of inﬁnite traces. If Tu is, as above, the process that simply performs thetrace u thenCu [V ] = ((V  Tu ) \ Σ) ||| a → STOPΣ

can diverge if and only if u ∈ inﬁnites(V ). As with ﬁnite traces, the last part of thecontext is included to avoid any possibility of immediate deadlock and so ‘diverge’
can be replaced by ‘fail T3 ’ here.
Partial order properties
The reﬁnement order on U is exactly what we would expect:(F , D, I )


 



U (F , D , I ) ≡ F ⊇ F ∧ D ⊇ D ∧ I ⊇ IThis order has a bottom element, the one representing any process that candiverge immediately:⊥U = (Σ∗ × P(Σ ), Σ∗ , Σω )Like N , it has no top element but many maximal elements which are exactly thedeterministic processes{det(T ) | T ∈ T d }The nondeterministic choice operator, as over other models, corresponds to
the greatest lower bound operator over arbitrary non-empty subsets of U and tocomponentwise union.
It should not come as a great surprise that the reﬁnement order fails to becomplete over U, since we have seen there is a close correspondence between ﬁnite
nondeterminism and the attractive properties of completeness and continuity. If A∗
is, as before, the process that can perform any ﬁnite number of a’s but not inﬁnitely
many, then the following series of reﬁnements hold:A∗∗
U a →A∗U a →a →AU ...

since preﬁxing A∗ with a simply removes its ability to perform no a’s. However,this sequence has no upper bound since any such bound could never refuse a but

260

Inﬁnite traces

would be unable (as all the members of the sequence are) to perform the forceable
trace aω .
Whereas over N for inﬁnite Σ the incompleteness of could be got round by
introducing the strong order ≤, no such remedy exists3 here since one can actually
prove (see [105]) that any order which makes CSP operators monotone and whichﬁnds the same ﬁxed points for them as U is incomplete.
Nevertheless, it turns out that every CSP deﬁnable function does have aleast ﬁxed point, and that ﬁxed point is the correct (judged by congruence with
operational semantics) value for it. There are two known ways of proving thisresult, the outlines of which are sketched below.
It is this diﬃculty in ﬁnding ﬁxed points, added to the subtlety needed tobuild and understand the model in the ﬁrst place, that led us to look at the inﬁnite traces/divergences model I before U. We observed there that a failures/
divergences/inﬁnite traces representation for every process could be computed fromits values in I and F (see page 250). There is no guarantee, just because we havepieced together a member of I and one of F that the result will be one of U, sincein general the failures and inﬁnite sets produced need not satisfy I2. However, thecongruence theorems of the two models with the operational semantics do imply
it is in U, since the combined value is guaranteed by these to be the abstraction
into U of (the operational semantics of) the process in question. A little analysis
then shows it is a ﬁxed point, and indeed the least ﬁxed point, of the corresponding
operator over U.
This is a simple proof given the earlier congruence theorems, and indeed it
establishes the extremely important congruence theorem for U as a bonus. It is,however, worth bearing in mind (i) that the results on which it rests, especially the
congruence for I, are highly non-trivial and (ii) that it has the curious property of
being a proof entirely stated in one domain (the denotational semantics in U) which
rests on detailed analysis of another one (the operational semantics).
There is an elegant proof, discovered by Geoﬀ Barrett [5, 7], whose overall
diﬃculty is considerably less and which does not rely on analyzing the operationalmodel. The following is an outline of his work.
Say a process (F , D, I ) ∈ U is pre-deterministic if it behaves deterministicallywhenever it does not diverge. In other words,s ∈ traces(F )  D ∧ sˆa ∈ traces(F ) ⇒ (s, {a}) ∈ F
The combination of axioms D1, D2, I1 and I2 ensures that each pre-deterministic
3 The strong order can be deﬁned on U: (F , D, I ) ≤ (F  , D  , I  ) if and only if (F , D) ≤ (F  , D  )in N and I ⊇ I  . All CSP operators are monotone with respect to this order, but it fails to becomplete.

10.2

Adding failures261

process is closed. In fact, the pre-deterministic processes P form a complete partial
order under U , and have the property that every member of U is reﬁned by oneof them. The maximal members of P are, of course, the deterministic processes D.
Now it is easy to show that if a monotonic function f over U has a ‘post-ﬁxed’
point (one such that f (x ) U x ) then it has a least ﬁxed point. For we can use theproof of Tarski’s theorem for complete lattices on page 496: the crucial point hereis that the set of post-ﬁxed points (upon which the proof is based) has a greatest
lower bound as it is non-empty and every non-empty subset of U has one.
Barrett proved that every CSP deﬁnable function f has a pre-deterministic
post-ﬁxed point by ﬁnding a monotonic function f  from P to itself such thatf (P ) U f  (P ) for all P ∈ P. This has the desired consequence because thenf  (being a monotonic function from a cpo to itself) has a ﬁxed point µ f  , andf (µ f  )U f

(µ f  ) = µ f He built the f  by replacing each CSP operator by a reﬁnement that preserves
determinism in a systematic way. Essentially, he modiﬁed the operators so thateach way described on page 223 for them to introduce nondeterminism was avoided.
For example, P  Q = P and P 2 Q always behaves like P where an ambiguous
ﬁrst event is chosen.
Exercise 10.2.1 Show that any process P ∈ N such that Traces(P ) consists only ofﬁnite traces can either deadlock or terminate. Hence prove from I2 that if s ∈ traces ⊥ (Q)for Q ∈ U , then either there is u ∈ inﬁnites(Q) with s < u, or Q can either deadlock or
terminate on some s  ≥ s.
Exercise 10.2.2 Recall the Rab recursion on page 255. Find a set of inﬁnite traces I
that is consistent with Fab but such that (Fab , {}, I ) is not a ﬁxed point of the recursion.
If u is any inﬁnite trace in {a, b}ω , let ∆(u) be the subset of {a, b}∗consisting of those sequences obtainable by a ﬁnite sequence of additions and deletions
from u: {sˆv | s ∈ {a, b}∗ ∧ ∃ t ∈ {a, b}∗ .u = tˆv }. Even though there are inﬁnitely manymembers of each ∆(u) and v ∈ ∆(s) ⇔ u ∈ ∆(v ), there are inﬁnitely4 many diﬀerent∆(u) and each satisﬁes the identity ∆(u) = {aˆv , bˆv | v ∈ ∆(u)}.

Exercise 10.2.3

Show that, for any u, N∆(u) (as deﬁned on page 256) is a solution to the Rab
recursion.
Find a sequence In of subsets of {a, b}ω such that (Rab , {}, In ) ∈ U for all n,
In ⊇ In+1 , but {In | n ∈ } = {}. This leads to a U increasing sequence of members
4 There are, in fact, uncountably many since {a, b}ω is uncountable and each ∆(u) is countable.
Since any union of countable sets is countable, there must be uncountably many diﬀerent such
sets.

262

Inﬁnite tracesof U which diﬀer only in their inﬁnite traces, but which has no upper bound. This showsthat the strong order ≤ (deﬁned in a footnote on page 260) is incomplete.
Prove that the deterministic processes are precisely the U maximal
elements of U . Hint: use the characterization of U as the nondeterministic compositionsof closed processes, and the corresponding result over N .

Exercise 10.2.4

10.3

Using inﬁnite traces

It is controversial whether an inﬁnitely nondeterministic system could really be(fully) implemented. Any implementation would have to include a mechanism whichguaranteed to select between an inﬁnity of choices in a ﬁnite time. You cannot do
this by repeatedly performing a ﬁnitely nondeterministic activity such as tossing acoin or throwing dice, since König’s lemma implies that any such procedure that
has inﬁnitely many outcomes can go on for ever. For example, if you toss a coinand count how many successive heads are seen before the ﬁrst tail, there remains
the possibility that the series of heads will go on for ever. On the other hand, if
a system made a choice dependent on the value of some inﬁnitely varying physicalquantity such as time ...
Whatever you believe about this, the ability to model inﬁnite nondeterminism has a number of practical applications. Many of these occur when we want
either to specify or to assume some property, which requires inﬁnite nondeterminism to express it, of a process even though the process may well only be ﬁnitely
nondeterministic. This can quite legitimately lead to us reasoning about inﬁnitely
nondeterministic processes, even if you take a conservative position in the debate
above. This having been said, you should always bear in mind that there is no need
to use U when you are dealing with a ﬁnitely nondeterministic CSP term and wantto prove a property of it that can be expressed in one of the weaker models.
10.3.1Inﬁnitary speciﬁcations and fairness

Recall the speciﬁcation of a buﬀer B from Section 5.1: divergences(B ) = {} and(i) s ∈ traces(B ) ⇒ s ∈ {| left, right |}∗ ∧ s ↓ right ≤ s ↓ left(ii) (s, X ) ∈ failures(B ) ∧ s ↓ right = s ↓ left ⇒ X ∩ {| left |} = {}(iii) (s, X ) ∈ failures(B ) ∧ s ↓ right < s ↓ left ⇒ {| right |} ⊆ X
This allows a buﬀer to input inﬁnitely without ever outputting. We might wish to
insist that our buﬀer is always ﬁnite, in the sense that it never accepts an inﬁnite
sequence of inputs without outputting. To express this naturally requires an inﬁnite
trace speciﬁcation:

10.3

Using inﬁnite traces

263(iv) u ∈ inﬁnites(B ) ⇒ u \ {| left |} is inﬁnite
Clearly each of the explicitly bounded buﬀer processes BUFF N
 meets this∞does not. It remains true, of course, thatspeciﬁcation, but the inﬁnite buﬀer B
any satisﬁable behavioural speciﬁcation can be identiﬁed with the most nondeterministic process satisfying it (its characteristic process, the nondeterministic choiceof all processes satisfying it). Naturally, BUFF  , the characteristic process of thebasic buﬀer speciﬁcation, does not satisfy the stronger ﬁnite buﬀer speciﬁcation.
It is interesting to construct an explicit CSP representation FinBUFF  of thisprocess: see Exercise 10.3.6.
Even if you believe it is impossible actually to build an inﬁnitely nondeterministic system, it can still be sensible to include an inﬁnitely nondeterministic
component in a model of an implementation. For there may be a component process which is either outside your control or which you may wish to vary: in eithercase it is appropriate to replace the component by a speciﬁcation it is assumed tomeet, and this speciﬁcation may well be inﬁnitely nondeterministic.
A good example of this can be found in the Alternating Bit Protocol as
discussed in Sections 5.3 and 8.4. Recall that this protocol is designed to work
(i.e., transmit successive pieces of data correctly) provided that neither of the two
error-prone channels used either loses an inﬁnite sequence of consecutive messages
or duplicates any message inﬁnitely. In the ﬁrst discussion (Section 5.3) we had tochoose some ﬁxed bound on the number of consecutive errors, while in the second
we saw that the protocol could be proved correct for arbitrary loss/duplication
conditional on any reﬁnement that removes the divergence. The channel processes
we really want (which are, indeed, reﬁnements of those C (in, out) used in Section
8.4) can only be modelled accurately in models incorporating inﬁnite traces.
What we want to assert about the channels is that they cannot output inﬁnitely without inputting (for that would constitute inﬁnite duplication), nor input
inﬁnitely without outputting (which would be inﬁnite loss). We call such a conditiona fairness assumption. A fair arbiter between two non-empty and usually disjoint
sets A and B of events is a process which repeatedly chooses between allowing A
and B , but which never chooses either side inﬁnitely without the other. The mostgeneral fair arbiter between A and B isFair (A, B )= LFair (A, B )RFair (A, B ),where

LFair (A, B )={NLeft(n, A, B ) | n ∈ {1, 2, . . .}}RFair (A, B )={NRight (n, A, B ) | n ∈ {1, 2, . . .}}NLeft(n, A, B )= RFair (A, B )<I n = 0>I ?x : A → NLeft(n − 1, A, B )NRight(n, A, B )= LFair (A, B )<I n = 0>I ?x : B → NRight(n − 1, A, B )264

Inﬁnite traces

since this repeatedly chooses one of A and B a non-zero ﬁnite number of times, andthen goes back and starts on the other. Fair (A, B ) is divergence-free, has as its
ﬁnite traces (A ∪ B )∗ and for each trace has (when A ∩ B = {}) maximal refusalsΣ  A and Σ  B . What makes it special is its set of inﬁnite traces, which can be
written, in a natural extension of existing notation,A∗ (B B ∗ A A∗ )ω
The asymmetry in this expression is immaterial, since switching all A’s and B ’s
leaves the set unchanged.
You can use processes like Fair (A, B ) to add fairness into systems by making them replace existing (unfair) choice mechanisms like those in C (in, out).
The deﬁnition of C∗ (in, out) below simply replaces the nondeterministic choices
of C (in, out) by external choices, thus leaving them to be made by the parallel
composition with the arbiter.
C∗ (in, out) = in?x → C∗ (in, out, x )C∗ (in, out, x ) = out!x → C∗ (in, out, x )2 in?y → C∗ (in, out, y)Cfin (in, out) = C∗ (in, out)  LFair ({| in |}, {| out |})Σ

Notice that we use the version of the arbiter that guarantees that its ﬁrst choice
will go to the left, because C∗ needs to input ﬁrst.
Cfin (in, out) has identical failures to C (in, out), but has just the restriction
on its inﬁnite traces we want. Using it to model the channels in the alternating
bit protocol eliminates the divergences that occur when you use C (in, out), thoughof course you need the power of U to express this formally. The mathematicalargument would just paraphrase the informal one for lack of divergence in Section
5.3. One could then either prove directly in U that the resulting system is equivalent
to COPY , or deduce it from the analysis done in Section 8.4 over F.
What we have managed to capture over U are the ‘real’ assumptions on thecommunication medium that are required to make the protocol work. Of course,
having done this, any medium that reﬁnes the Cfin model is also guaranteed towork.
Fairness is a diﬃcult subject, both because it is inextricably linked withunbounded nondeterminism and because interpretations of what it means for asystem to be ‘fair’ vary widely depending on just how one has chosen to model
systems and on authors’ opinions. See, for example, [16, 40, 77, 89]. Diﬀerent
notions of fairness are couched in terms:

10.3

Using inﬁnite traces

265• of one or more speciﬁc internal decisions inside the program, as was the one
above;• of the complete pattern of internal decisions, one example being ‘angelic
nondeterminism’: if, whatever decisions are made, it always remains possible
to attain some desirable state, then eventually that state must be reached;• of the pattern of ‘enabled actions’ – if an action is enabled inﬁnitely then it
will occur; or• of ‘fair parallel’: ensuring that each side of a parallel composition is treatedfairly in terms of being allowed to make progress.
In CSP one has to be careful about how to deﬁne fairness because of the basic modelof communication: no action can occur unless the environment is willing to perform
it. Thus a process like µ p.(a → p) 2 (b → p) cannot enforce fairness between aand b, even though each is always enabled, and nor does it make sense to say thatthe equivalent process µ p.a → p ||| µ p.b → p necessarily behaves as a fair parallel
construct, since in either case the environment can insist on an unfair trace such as
a, a, a, . . ..
For clarity, and because it corresponds directly to perhaps the most widelyused notion of fairness in the literature, the only form we will consider directly is
the ﬁrst. The most natural way to introduce this into CSP would seem to be a fairnondeterministic choice operator F that behaves like except that it guarantees
to make its choices fairly. There is no reason why you should not use this as ashorthand, but it cannot be treated as a CSP operator like all others. One problem
is that, as a binary operator over CSP models, and F are indistinguishable, andyet in a recursive context they mean very diﬀerent things.
Where there are multiple fair choices in a program, these have to be treatedas separately fair, in the sense that if any one of the choices is made inﬁnitely
often it is made fairly, but there is no linking property between the ways in which
combinations of choice are made. This creates curious programs like(µ p.(a → p)

F (b → p))



{a,b}

(µ p.(a → p)

F (b → p))

Obviously this can deadlock, for the two sides can immediately, or after any ﬁnite
trace, pick diﬀerent actions. The interesting question is whether it must eventually
deadlock. On a global view of fairness (perhaps along the lines of angelic fairness)
one is tempted to say ‘yes’ (it being too much of a coincidence if they always pickthe same event), but actually the two sides of the parallel are allowed to makeexactly the same fair decisions (behaving, perhaps, like µ p.a → b → p) since there
is no link between the fairness conditions. Indeed it is quite likely that if we take

266

Inﬁnite tracesa fair choice mechanism oﬀ the shelf it will, in fact, always follow the same patternsuch as strict alternation. Thus the answer under our model of fairness is ‘no’.
A very similar phenomenon creates a second problem in trying to view
as an ordinary operator. Consider the ‘identity’(PQ); (R

F S)= (P ; (RF S ))(Q; (RFF S ))

which should be provable by the left distributive law of ; . But the right-handside has two F operators while the left-hand side has one, and this makes a big
diﬀerence to how the two sides behave when put in a context such as the inﬁnite
iteration P * that forces inﬁnitely many choices to be made.
• If the ordinary nondeterministic choice on the left-hand side alternates between P and Q, there is nothing to stop the fair choice alternating between
R and S , so that R always follows P and S always follows Q.
• On the other hand, the diﬀerent pattern of F ’s on the right-hand side meansthat each of P and Q, if picked inﬁnitely often, must be followed by a fairchoice between R and S . The alternating pattern P ; R, Q; S ω is thus notallowed.
Fair choices are thus much more context sensitive than other CSP constructs.
As said above, F should really be thought of as shorthand rather than as an
operator in its own right. To implement processes involving this ‘operator’ we
simply delegate the choices to separate fair arbiters for each occurrence of F ,rather like the modelling of Cfin above. This can be done by transforming the CSP
deﬁnition of your process. Invent two new events for each occurrence of F (a.iand b.i for the i th, say) and replace the i th P F Q by a.i → P 2 b.i → Q.
The new events should not be synchronized, hidden or renamed in the transformed
deﬁnition. Then take the ﬁnal transformed process T and place it in parallel withfair arbiters for each choice:(T{|a,b|}(Fair ({a.1}, {b.1}) ||| . . . ||| Fair ({a.n}, {b.n}))) \ {| a, b |}This transformation is incorrect if there is any possibility of the original process
terminating (), since the fair arbiter(s) prevent the transformed one terminating.
A more elaborate transformation is then required (see Exercise 10.3.3).
We might well want fair choices between more than two options. When
there are ﬁnitely many (the only case we consider here) it can accurately be doneby composing the binary version: executing a program with the construct
P1

F (P2

F . . . (Pn−1

F Pn ) . . .)

10.3

Using inﬁnite traces

(1,M)

267

?

(N,M)

(N,1)

(1,1)

Figure 10.1 A counter moving across an N × M board.
implemented as above, allows just those behaviours in which all of the Pi are chosen
inﬁnitely often if any is. Obviously one could deﬁne a more than two-way fair arbiter
and use it to implement a multi-way fair choice more directly. For example,
Fair (A, B )  Fair (B , C )B

has (for A and C disjoint) exactly the behaviour we want of Fair (A, B , C ). Make
sure you understand why the asymmetry of this deﬁnition does not matter.
Example 10.3.1 (fair counter) Fairness is generally used to ensure progress ofsome sort in a system. For example, imagine a counter sitting on a rectangularboard as in Figure 10.1. The counter c, when sitting at co-ordinates (i , j ), can do
one of three things:• It can choose not to move, and communicate the event procrastinate.c.
• It can try to move up (to (i , j +1)) by communicating with the target square.
• It can try to move right (to (i + 1, j )) by communicating with the target
square.
Let’s assume that after requesting permission to move to a square it receives either
an ok or ref signal, indicating that it can move or not, and that we ensure that if
it asks to leave the board (oﬀ the top or right edges) then it always gets the refusal(ref ) response.

268

Inﬁnite traces
CTR(c, i , j ) =procrastinate.c → CTR(c, i , j )(req.i .j + 1.c →(ref .i .j + 1.c → CTR(c, i , j )2 ok .i .j + 1.c → enter .i .j + 1.c →leave.i .j .c → CTR(c, i , j + 1)))
(req.i + 1.j .c →(ref .i + 1.j .c → CTR(c, i , j )2 ok .i + 1.j .c → enter .i + 1.j .c →leave.i .j .c → CTR(c, i + 1, j )))Clearly if no fairness is assumed in the way it makes these choices, then it
need never move, no matter where it starts, since it can always take the ﬁrst option.
If the board is programmed in the obvious way so that a square, when empty, willallow a counter to move onto it, etc., then if these choices are made fairly a system
consisting of a single counter on an N × M board will eventually have the counterreach the top right-hand corner (N , M ) no matter where it starts.
This naturally leads to the question of how one speciﬁes the concept of ‘eventually’ in CSP. To specify that a system P must eventually (unless deadlocked by
the environment) communicate a speciﬁc event a, all you have to specify is
a → div

P \ (Σ {a})over either N or U as appropriate to the constructs used. For this says that theprocess P can neither diverge nor engage in an inﬁnite sequence of non-a actions
before communicating a, and neither can it deadlock or terminate before doing so.
This has much in common with the timing consistency check described on page 393.
One can obviously compose variations on this theme.
In this case you can either show that eventually our counter seeks to move to(N + 1, M ) or (N , M + 1) (since it has to be on (N , M ) to do so), or, better, to look
for the event the counter communicates when entering (N , M ). In other examples
you might well have to add a ‘success’ event explicitly into the program, and look
for that.
It is interesting to consider the case where there are two or more tokens on
the board. At ﬁrst sight you would probably expect that the fair counter deﬁnition
will inevitably result in the counters becoming huddled together at and around(N , M ). But this is not so, since no fairness is imposed regarding the speed ofdiﬀerent counters. If there are, initially, counters at (1, M ) and (2, M ) then there isnothing to say that the left-hand one cannot perform inﬁnitely many actions while
the right-hand one does nothing. This, of course, would lead to no counter moving
since the left-hand one is blocked by the top edge and the right-hand one. Whatis required is essentially the fair parallel composition discussed brieﬂy earlier. This

10.3

Using inﬁnite traces269

only makes sense if we remove from the environment the ability to choose whichcounter communicates next. The appropriate way to do this is to place the system
in parallel with a fair arbiter whose job it is to choose which counter acts. If
choices(c) = {procrastinate.c, req.i .j .c | i , j ∈ N}
then for counters c1 and c2 , you can use the arbiter Fair (choices(c1 ), choices(c2 )).
(End of example)
Exercise 10.3.1 Complete the programming of the system in the example above by
deﬁning a Square(i, j ) process, any others you need, and putting the complete network
together.
Exercise 10.3.2 If instead of moving just up and right, the counter chooses fairly
between trying to move up, down, left and right, need it ever leave the board?
The implementation of F given in the text does not work for potentially terminating processes. Put this right as follows:

Exercise 10.3.3(a) Revise the deﬁnition of Fair (A, B ) to produce a process TFair (A, B , tk ) (for tk ∈
Σ (A ∪ B )) whose behaviour is identical except that it is always willing to communicate tk (as an alternative to its current choice of A or B ), upon which it
terminates.

(b) In transforming a program with F ’s in, as on page 266, sequentially compose theprevious result with tk → SKIP for some new event tk .
(c) Put together the resulting process with TFair processes, synchronizing appropriately, and explain why the result behaves as you would wish.
The process Cfin (in, out) can both lose and duplicate messages.
Deﬁne (in CSP) the most general process Efin (in, out) that acts like a one-place buﬀer
except that it can lose any message as long as it does not lose an inﬁnite consecutive
sequence of them (i.e., it behaves like Cfin (in, out) except that it never duplicates). What
reﬁnement relation, if any, holds between the Cfin (in, out) and Efin (in, out)? Hint: deﬁne
the process using F and then use the transformation implementing this.

Exercise 10.3.4

Exercise 10.3.5

The process

SemiFair (A, B ) = RUN A ||| Fair (A, B )always allows any event in A and need never allow B , but speciﬁcally does not permit
an inﬁnite trace unless it contains inﬁnitely many events from A. Compute its sets offailures and inﬁnite traces and ﬁnd a direct deﬁnition of this process in the style of thatof Fair (A, B ) on page 263.
Construct the process which, for three disjoint sets A, B and C , may at any time
select between them, and which does not allow inﬁnitely many of either A or B without

270

Inﬁnite traces

the other, and which does not allow inﬁnitely many C without inﬁnitely many each of A
and B .

Exercise 10.3.6
Use a fair arbiter (using the F to introduce it, if you wish) toconstruct the most general ﬁnite buﬀer FinBUFF  discussed on page 263.

10.3.2

Fixed-point induction over U

As we saw on page 254, it is not possible to use restriction functions to generatecomplete metrics over models incorporating inﬁnite traces, and indeed constructivefunctions often have multiple ﬁxed points. These facts are as true over U as overI. This is a great pity since the UFP rule and ﬁxed-point induction (whose proofs
in Section 9.2 depend on constructiveness and the uniqueness of ﬁxed points) arevery important tools for establishing facts about recursively deﬁned processes.
It is possible to establish weak versions of ﬁxed-point induction and the‘unique’ ﬁxed point rule over U and I. To do this we have to deﬁne what a constructive function is via a family of restriction functions: over U these are deﬁned(F , D, I ) ↓ n = (F , D) ↓ n where the restriction on the right-hand side is thatdeﬁned over N , with a similar deﬁnition over I. Though these do not generatea metric (there are pairs of distinct processes they cannot separate), we can stilldeﬁne ‘constructive’ and ‘non-destructive’ functions exactly as before, and exactly
the same collections of the standard operators are respectively one or the other (see,for example, Lemma 8.2.3).
While a constructive function over U may not have a unique ﬁxed point, it iseasy to show that all ﬁxed points have identical projections into N . This is because
you can inductively prove that if P and Q are two ﬁxed points then P ↓ n = Q ↓ nfor all n. This argument leads to the following result.
Lemma 10.3.1 Suppose F : U → U is constructive, monotonic and has a least
fixed point µ F , and P ∈ N (a closed member of U) is such that P U F (P ). ThenP U µF
Proof By induction on n it is easy to prove that
P

U F

n

(P ) andF n (P ) ↓ n = (µ F ) ↓ n

Suppose b is a ﬁnite-length behaviour of µ F (i.e., a failure or divergence). Choosingn to be any number greater than its length we thus have that b is a behaviour ofF n (P ) and hence of P . Hence
failures ⊥ (µ F ) ⊆ failures ⊥ (P )divergences(µ F ) ⊆ divergences(P )

(+)

10.4

Notes

271

We thus haveinﬁnites(µ F )⊆ traces ⊥ (µ F )⊆ traces ⊥ (P )= Traces(P )

(1)
(2)
(3)

Here, (1) is a consequence of axiom I1, (2) is by (+), and (3) is because of ourassumption that P ∈ N . This implies thatinﬁnites(µ F ) ⊆ inﬁnites(P )completing the proof that P

U µF.

This result means that the rule of ﬁxed-point induction (Sections 5.1 and 9.2)
is valid over U provided the property you are proving is ﬁnitely nondeterministic
and the function is constructive.
Of course, both the above lemma and the conclusion regarding ﬁxed-point
induction extend easily to mutual recursions (i.e., functions in U Λ → U Λ ). It also
leads to the following weak analogue of the UFP rule since under the assumptionsof the following rule we have P U µ F by the lemma, but µ F is the least ﬁxed
point.
Unique closed fixed point rule Suppose F : U Λ → U Λ is a constructive, CSP
definable function, and that P ∈ (N )Λ is such that F (P) = P . Then P = µ F .
Thus, if a ﬁnitely nondeterministic process satisﬁes a constructive recursion,
it is always the value of the recursion. There are, of course, recursions that do nothave a closed solution like this, an example is µ q.(a → q)  A∗ which we studied{a}earlier.

10.4

Notes

The role of inﬁnite traces in modelling unboundedly nondeterministic constructs
such as fairness was well understood before CSP was invented. They were notincorporated into the semantic models for some years, however, because of technicaldiﬃculties they introduce such as incompleteness and discontinuity.
U was introduced in [105], which also is the main reference for the basic
properties of this model. It proves the existence of ﬁxed points of recursions via
operational congruence. Barrett’s alternative proof can be found in [5, 7], and isanalyzed further in [84]. Some ﬁner properties of the model can be found in [6, 12].
Our understanding of the axioms of U (especially I2) owes much to the work of
Stephen Blamey.

272

Inﬁnite traces

2005: The author has now shown [114] that it is possible to build an inﬁnite
traces which is not divergence-strict. A vestige of this strictness remains in thatinﬁnite traces which are the limits of divergent ﬁnite traces are always included.
Otherwise it only includes real traces, failures, divergences and inﬁnite traces. The
penalty for this is an elaborate ﬁxed-point theory.

Chapter 11

Algebraic semantics

11.1

Introduction

Throughout the introductory chapters we used algebraic laws to help explain themeanings of the various operators of CSP. Laws of this type have historically played
an important role in the ﬁeld of process algebra (the very name of which suggeststhis).
An algebraic semantics for a programming language is one where the notionof process equivalence is derived from a set of laws. Some authors proposing process algebras have regarded algebraic semantics as the most basic means of deﬁning
process equality, in that they propose a given set of laws and set about investigating what equivalence they produce. The theory most closely associated withthis approach is ACP (see, for example, [9, 10]). This gives a remarkable degree of
freedom, since essentially any set of laws will create an equivalence on the set ofprocess terms. There is no constraint on one’s choices that is nearly as sharp as therequirement that a denotational model induce a congruence.
Simply quoting a set of laws does bring the dangers of not identifying processes that you had intended should be equal, or, more worryingly, identifying far too
many. See Exercises 11.1.1, 11.4.5 and 11.5.3 for examples of the latter. Therefore
the equivalence induced by a proposed set of laws must be thoroughly investigatedto make sure it has the intended eﬀect.
Since we already have a well-established concept of equivalence between CSP
processes, our approach will be to attempt to characterize that. In other words, wewill attempt to capture the equivalences induced by the various denotational models
for CSP described in Chapter 8. Obviously all laws used must be theorems of theequivalence under consideration: if the semantics we are attempting to duplicate is274

Algebraic semantics

written S[[·]], this just involves proving a series of simple lemmas such as
S[[P 2 Q]]
S[[SKIP ; P ]]S[[P ||| (Q ||| R)]]= S[[Q 2 P ]]= S[[P ]]= S[[(P ||| Q) ||| R]](in each case for all processes P , Q and R). It is usually not hard to ﬁnd a large
number of true laws with respect to a sensible notion of equivalence. Provided
all your laws satisfy this basic ‘sanity’ stipulation, and all rules which you use inconjunction with them are valid also, it is plain that they can never prove a pair of
inequivalent processes equal. In the usual logical sense of the word, such a theory
is sound.
The real challenge is in ﬁnding, and being able to show you have found,enough laws to be able to prove any pair of equivalent processes equal; in otherwords, creating a complete algebraic theory. This chapter shows how you can do
this. We will deal only with the semantics of ﬁnitely nondeterministic CSP with
Σ ﬁnite. We will also, for now, deal only with the fragment of the CSP language
without SKIP or sequential composition since these require special cases that would
unnecessarily complicate an introductory view of the way algebraic methods work.
Most attention is given to the equivalence induced by N , since that is the main
denotational model for ﬁnitely nondeterministic CSP.
All the laws given names (e.g., ‘hide-dist (3.1)’) in earlier chapters are true
under all the equivalences generated by the models described in Chapters 8 and 10.
Since each of our models equates some pairs of processes that are discriminated in
at least one of the others, a set of laws true in all three models cannot be suﬃcient
to capture any one of the model-based equivalences completely, but, as we will see,they require very few additions.
Examples of such pairs of processes are
P

=

div

P

=

div ||| a → STOP

Q

=

STOP



=

STOP

Q

div

(equivalent to P in N but not in T )(equivalent to Q in T and F but not in N )Our existing laws thus cannot prove the equivalences
P =N P 

and Q =T Q 

since any such proofs would contradict the inequivalences
Q =N Q 

and

P =T P 

11.2

Operational semantics via algebra275

A certain text ([53]1 ) proposes the following laws for CSP (amongst

Exercise 11.1.1
many others)

⊥

=

⊥

STOP

=

STOP

(3)

P

Q

=

Q

(4)

⊥Q

=

⊥

(5)

STOP  Q

=

Q

P

(1)
P

(2)

P

Which of these are true, and which false, over N on the assumption that ⊥ is identiﬁed
with div? Show that these laws alone (and hence any superset) are suﬃcient to provethat P = Q for all processes P and Q.

Exercise 11.1.2

Prove that the following laws are all valid in the semantics of CSP

over N :(a) ; -assoc (6.3), (b) hide-step (3.6), (c) hide-combine (3.3).

11.2

Operational semantics via algebra

An operational semantics does not have to follow the pattern set out in Chapter
7: all we require is a formally-based method of implementing a language. You cando this via systematic algebraic transformations: a reduction strategy very much
like those used for functional programming. A way of implementing CSP in thisfashion is to calculate the selections of initial actions a process can communicate bytransformation to a process of the form2
Ni=1?x : Ai → Pi

where, of course, the Pi are terms that can depend on the identiﬁer x . By analogy with functional programming, an appropriate name for this is head normal
form (hnf)3 . To execute a process, you thus transform it into this form and make1 An amazing proportion of the ‘laws’ stated in [53] are false, and it is possible to ﬁnd many
distinct combinations which prove all processes equal. Three disjoint such sets can be found in
this exercise and Exercises 11.4.5 and 11.5.3 in this chapter. Some of the laws given in that bookmake even less sense than simply being false: for example ‘P ||| Q ∧ Q ||| R ⇒ P ||| R’ which istrivially ill-typed since processes are not truth values.
2 Here,N
i=1

Qi is an abbreviation for Q1(Q2. . . (QN −1

QN ) . . .), though in what

follows we will not go explicitly through the transformations required to turn more arbitrarily
constructed nondeterministic compositions into this precise, right-associated, form. This can, ofcourse, be done with the laws  -assoc (1.6),  -sym (1.4) and  -idem (1.2) in such a way as
to guarantee that all the Qi are diﬀerent.
3 The formal deﬁnition of hnf will appear on page 280 and be a little more general than this.

276

Algebraic semantics

an arbitrary selection from the nondeterministic choice of initial selections Ai ofactions which are thereby displayed. If the environment picks one of these, it iscommunicated and we can repeat the procedure on the result process, and so on.
There are four types of laws required to do this:• the distributive laws, for removing nondeterministic choices to the outside;• the step laws, which calculate the ﬁrst-step actions of constructs like P ⊕ Q
in terms of those of P and Q;• the unwinding law of recursion; and• manipulations of the expressions within processes.
Just as in earlier chapters we have avoided going into details about the syntax
and semantic details of sub-process expressions, here we will generally assume that
one of these can always be replaced by an equivalent expression without comment.
The only law as such we will need is one to change the names of input identiﬁers:?x : A → P = ?y : A → P [y/x ]if y is not free in P

input α-cnv (11.1)

While this is frequently needed to perform the transformations below, in describing
them we will simply assume it has been used to unify the names of inputs where
necessary without further comment.
The strategy for reducing an arbitrary process P into hnf is quite simple,
and is as follows:• If P has the form ?x : A → P  , it is already in the required form so we need
do nothing.
• If P has the form P  P  , then reduce each of P  and P  . The resulting
process (P1 P1 , say) is in the required form.
• If P is STOP , then apply the law STOP -step (1.15).
• If P has the form P  ⊕ P  , where ⊕ is any other standard binary operator(i.e., 2,  , ||| or X Y ), then ﬁrst reduce each of P  and P  , to P † and P ‡ ,Xsay. Next, use the left and right distributive laws of ⊕ (in each case the right
distributive law is proved using the left distributive law and the symmetrylaw) to move all the top-level nondeterminism from P † and P ‡ to the outside.
The result then has the form
N
i=1(?x : Ai → Pi† ) ⊕ (?x : Bi → Pi‡ )11.2

Operational semantics via algebra277

In each case the respective step law (2-step (1.14),   -step (2.10), |||-stepX(2.6) or X Y -step (2.2)) transforms this into the required form.
• If P has the form P  [[R]], then very much the same procedure (using [[R]]-dist(3.13) and [[R]]-step (3.15)) is followed.
• If P has the form P  \ X , then applying the same procedure (using hide-distN

Qi where(3.1) and hide-step (3.6)) will result in a process of the form
i=1
the Qi either have the form ?x : Ai → (Qi \ X ), which is what we want, or(?x : Ai → (Qi \ X )) 


{Pi,j
\ X | j ∈ {1, . . . , Mi }}which is not. The second case occurs, evidently, when some of the initialactions of P  are hidden and so do not create initial visible actions of P (inthe operational semantics of Chapter 7 they would have become τ ’s).

\ X , and thenThe strategy in the second case is to reduce the processes Pi,juse the deﬁnition of P  Q = (P 2 Q) Q and 2-step (1.14) to organize
the result into the correct shape. (*)• If P is recursively deﬁned, simply apply µ-unwind (1.23) and reduce theresult. (**)
There is a signiﬁcant problem with this strategy, namely it need not terminate. The problem is that the clauses for reducing P \ X and µ p.P can both resultin inﬁnite regression: the reduction-based operational semantics diverges rather
than produces a term of the required form. In fact, this is just as well, becauseof course there are CSP terms in the language we are considering that are notequivalent in N to any process in head normal form: the ones that can diverge
immediately.
The reduction strategy must therefore certainly fail on any term mapped by
the semantics to ⊥N . This can easily be demonstrated on divergent terms such as(µ p.a → p) \ {a}µ p.pµ p.STOPp

The converse (i.e., the strategy succeeds on any other term) is also true, because itis easy to show that any inﬁnite regression contains an inﬁnite number of uses of (*)
and (**), the application of either of which generates a τ in the original operationalsemantics.
Example 11.2.1 Consider the process (COPY ||| COPY ) \ {| left |}. To transform this to hnf we ﬁrst expand the two recursions: this immediately brings eachof them into the hnf
left?x → right!x → COPY

278

Algebraic semantics

The law |||-step (2.6) then brings the interleaving to the hnf
left?x → ( (right!x → COPY ) |||(left?x → right!x → COPY ))left?x → ( (left?x → right!x → COPY ) |||(right!x → COPY ))which (thanks to |||-sym (2.7) and  -idem (1.2) and re-folding the recursion)
can be simpliﬁed to the hnf
left?x → ((right!x → COPY ) ||| COPY )(Such simpliﬁcations are not a necessary part of the procedure, but help.)
We then apply hide-step to this to transform the complete process (incorporating the external hiding) to{((right!x → COPY ) ||| COPY ) \ {| left |} | x ∈ T }This, of course, is not in hnf since the hiding takes away the visible guard. We
therefore have to re-apply our strategy to the processes((right!x → COPY ) ||| COPY ) \ {| left |}(§)

which yields
right!x → (COPY ||| COPY )2 left?y → ((right!x → COPY ) ||| (right!y → COPY ))for the process inside the hiding. (Bear in mind that in practice it is a lot clearer
to use an appropriate mixture of preﬁx choices such as left?y and external choicesof these to represent a given initial set of actions of a given branch of an hnf, rather
than using the pure preﬁx-choice form used in the deﬁnition, though the latter could
easily be recovered using 2-step (1.14).) Thus (via hide-step again) the process(§) becomesright!x → (COPY ||| COPY ) \ {| left |} {((right!x → COPY ) ||| (right!y → COPY )) \ {| left |} | y ∈ T }This is still not hnf, since we have once again lost some of the guards to thehiding. We now have to re-apply our strategy once more to((right!x → COPY ) ||| (right!y → COPY )) \ {| left |}11.3

The laws of ⊥N

279

which fortunately does now yield an hnf:
right!x → (COPY ||| (right!y → COPY )) \ {| left |}2 right!y → ((right!x → COPY ) ||| COPY ) \ {| left |}(It would really be purer to separate the cases of x = y and x = y as would be doneby 2-dist, but it would be even more complex!) We can now collect together an
hnf for (§): after a little manipulation it is{right!x → (COPY ||| COPY ) \ {| left |}(COPY ||| right!y → COPY )) \ {| left |}2 right!y → (right!x → COPY ||| COPY )) \ {| left |}| y ∈ T}and the hnf for the original process is then just the nondeterministic choice overthis as x varies.
Obviously if we had hidden {| left |} in a buﬀer with no initial bound on how
many inputs it can take, such as BUFF  , then the strategy would not terminate.
(End of example)
Exercise 11.2.1

Reduce the following processes to hnf:(a) COPY \ {| right |}(b) ((a → Pa )  (b → Pb )) ||| ((b → Qb )  (c → Qc ))(c) COPY \ {left.0} where the type T of the channels is {0, 1}

11.3

The laws of ⊥N

Our attempts to reduce divergent processes to hnf failed in the previous section
because the divergence translated itself into non-termination of the reduction algorithm. It is a good idea to include an explicit representation of a divergent process
in the language we reason about algebraically: let div represent this as it did in
Section 3.1. We can then see how a term that is equivalent to a diverging process
behaves algebraically.
As one might expect from the discussions in Chapter 8, it is in the handling of
div that N diﬀers from the models without an explicit representation of divergence(F and T ). The laws for div (equalling ⊥N ) over N are thus often not valid
over these other models: with the exception of preﬁxing and the right-hand side ofsequencing, all operators are strict (in the sense deﬁned on page 496). Notice thatthe names of these laws reﬂect their selective validity. They are called zero laws
because of their similarity to the arithmetic equivalence 0 × x = 0.
div

P = div

 -zeroN  (11.2)

280

Algebraic semantics
div 2 P = div

2-zeroN  (11.3)

div  P = div  -zeroN  (11.4)

X

X

div X Y P = div

X Y -zeroN  (11.5)

div ||| P = div

|||-zeroN  (11.6)

div \ X = div

hide-zero (11.7)

div[[R]] = div

[[R]]-zero (11.8)

div; P = div

; -zero-l (11.9)

These laws mean it makes sense to add the term div as an alternative headnormal form: we can now formally deﬁne a process to be in hnf if• it is div, or• it has the form ?x : A → P , or
• it isN
i=1

Qi for processes Qi in hnf.

The laws mean that if either div appears explicitly in a program or you
can recognize and replace4 some divergent term by it, then you can extend the
reduction strategy to deal with this. Essentially, if div is encountered at any levelin reducing a process P to calculate its initial behaviour, then these laws (together
with symmetry laws to derive the right-zero laws for binary operators other than ;)will reduce the process itself to div.
The deﬁnition of hnf above makes it optional whether to reduce a process inwhich div appears as a choice, such as(?x : A → P )div

to div using  -zeroN . For simplicity, let us assume that we always do make thisreduction.
4 If the replacement is going to form part of our algebraic semantics, then it is clear thatthe means of performing it would have to be formalized, justiﬁed, and incorporated within thesemantics.

11.4

Normalizing

281

The possible outcomes of the reduction strategy are then (i) the original
type of hnf, (ii) the term div and (iii) non-termination of the strategy. There isno complete algorithm for telling if a given CSP term diverges5 or not, and so noeﬀective procedure which will tell us which terms our strategy will fail to terminate
on.
There is a simple and powerful6 algebraically-based method for detecting
divergence, namely:
LoopN If, during an attempt to reduce a process P to head normal form the (syntactic) process P is encountered other than at the root of the reduction,then P is divergent and may be replaced by div.
This is not, of course, a law in the conventional sense of the word, rather arule. To implement this rule it is necessary to keep a record of the tree structurethat results from the attempt to reduce a process, and look for loops (nodes identicalto predecessors). The notation LoopN indicates that this is a valid rule over N ,but not over T or F.

11.4

Normalizing

It is our objective to be able to prove any pair of equivalent processes equal using
an algebraic theory. An obvious approach to this is to identify a normal form: ahighly restricted syntax for processes meeting the following requirements.
• A pair of normal form programs are only semantically equal if they are either
syntactically identical, or perhaps diﬀer in a well-deﬁned and trivial way suchas the name of a bound variable or the order of terms composed under asymmetric and associative operator.
• Every program is equivalent to one in normal form.
• This equivalence can be demonstrated by the algebraic theory.
Let us restrict ourselves, for the time being, to processes that are ﬁnitely
transformable to hnf, as are all successors reached when executing their algebraic
operational semantics. (In other words, processes in which all divergences are either
syntactically explicit, div, or detectable using a rule such as LoopN .)5 This would solve the halting problem.
6 Inevitably, given the previous discussion, it is not complete in the sense of detecting all divergence. It is, however, complete provided the process is ﬁnite state. It then corresponds to adepth-ﬁrst search for loops in the graph of nodes reachable from the chosen root.

282

Algebraic semantics

Our approach will be to reﬁne the concept of head normal form into a fullnormal form, and to show how a program in head normal form can be transformed
using the laws of 2 and into this restricted form.
Given that Σ is ﬁnite, the ﬁrst-step behaviour P ↓ 1 of any process P iscompletely characterized by the following information:• Does P diverge immediately? If not,• what is P ’s set of initial actions initials(P ), and• what are P ’s maximal refusals?
The divergent case of head normal form evidently captures the ﬁrst of these precisely,
but the non-divergent one is too loose in that there are typically many diﬀerent sets
{A1 , . . . , AN } of initial actions that would give rise, inN
i=1

x : Ai → Pi

to exactly the same sets of initial actions and maximal refusals, bearing in mind
that the complements of the Ai are the refusals. For example,{{a, b, c}, {a}, {b}}{{b, c}, {a}, {b}}{{a, b, c}, {a, b}, {a}, {b}}{{a, b, c}, {a, b}, {a, c}, {b, c}, {a}, {b}}all give the same result, and are by no means the only sets that give this particularone. We need to decide on a unique representation of any given collection of acceptance sets7 Ai and provide a way of transforming any non-div head normal form
to this. There are various sensible choices one could make, but the one we opt forhere is to specify that the set {A1 , . . . , AN }7 The concept of an acceptance set is obviously very closely related to that of a refusal set. If wedeﬁne an acceptance set just to be the complement of a refusal set (in Σ ) then clearly we could
have replaced all uses of refusal sets in our models with them, subject to systematic changes indeﬁnitions. This would, however, imply that acceptance sets were superset-closed (as an analogy
to axiom F2), implying there were members of ‘acceptance sets’ that a process could never accept.
Thus an acceptance is arguably better deﬁned to be a set of events which is (a) the complement ofsome refusal and (b) contained in initials(P ). This modiﬁcation means that the translation fromrefusal sets to acceptance sets is not so direct and means that model, operator, etc. deﬁnitions
work better with failures rather than with their acceptance-set analogues. So it seems that inorder to create acceptance-based analogues of the models N and F one either has to compromiseon naturalness or on ease of manipulation. Perhaps the most natural acceptance-set model is that
proposed in [87], which has no superset closure condition at all: modulo divergence, an acceptance
set is the set of all events oﬀered by some stable state. This gives a subtly diﬀerent (and lessabstract) congruence which fails the law  -2-dist (1.13).

11.4

Normalizing

283• has the property that A1 ⊃ Aj for all j > 1 (i.e., A1 is the union of all Ai
and represents initials(P )), and• if i , j > 1 are distinct then Ai ⊆ Aj (i.e., all these Ai represent minimal
acceptances, and hence their complements, the maximal refusals).
Note that in the case where initials(P ) is a (necessarily the only) minimal acceptance, N = 1 and A1 plays a double role.
A simple procedure, which is described below, transforms an arbitrary nondiv head normal form to this format. It rests almost entirely on the laws of 2, ,preﬁxing and conditionals.
You can ensure that each set Ai only appears once in the result by applying
the law input-dist (1.11) repeatedly till all pairs of identical ones are eliminated.
If there is only one Ai remaining after this, there is nothing further to do. If
there are more than one, we have to ensure the collection contains the union andthat all the rest are minimal. Observe that, for any processes P and Q,
PQ=(P Q) 2 (P Q)by 2-idem (1.1)=(P 2 Q) P Q
by 2-dist (1.7),  -idem (1.2), etc.

This argument can (see Exercise 11.4.1) be extended, by induction, to show thatfor any N and processes Qi ,N
i=1

Qi = (2

N
i=1

Qi )

(

N
i=1

Qi )

In the case where Qi =?x : Ai → Pi , the extra process Q1 2 . . . 2 QN can betransformed using 2-step (1.14) to the form
?x : A† → R
where A† =

N

i=1 Ai and such that, for any a ∈ Aj , we have

Pj [a/x ]R[a/x ] = R[a/x ]Any a ∈ A† may appear in several diﬀerent Ai , and the processes Pi [a/x ],which are the possible results of performing it, may all be diﬀerent from each otherand R[a/x ]. What the above does ensure is that R[a/x ] is the most nondeterministic

284

Algebraic semanticsof these choices. Consider the transformation:(?x : A† → R)(?x : Ai → Pi )=(?x : A†  Ai → R 2?x : Ai → R)(?x : Ai → Pi )by 2-step and <I ·>I -idem (1.17)= (?x : A†  Ai → R ?x : Ai → Pi )2 (?x : Ai → R ?x : Ai → Pi )by  -2-dist (1.13)= (?x : A†  Ai → R ?x : Ai → Pi )2 (?x : Ai → (R Pi ))by input-dist (1.11)= (?x : A†  Ai → R ?x : Ai → Pi )2 (?x : Ai → R)
by what we established about R above= (?x : A†  Ai → R 2 ?x : Ai → R)(?x : Ai → Pi 2 ?x : Ai → R)by 2-dist= (?x : A† → R) (?x : Ai → Piby 2-step, etc.

R)= (?x : A† → R) (?x : Ai → R)
by what we established about R above
What this does is to show we can replace all the old result processes Pi by R in theprocess we are transforming, making all the possible results of performing a given aidentical. This is both a vital part of the normalization process itself and is helpful
for the next and ﬁnal part of transforming it to our target shape of hnf, which is theremoval of any non-minimal Ai (other than A† ). This makes use of the following
identity, which is essentially that proved in the last part of Exercise 3.1.5.
(P 2 Q 2 S )P = (P 2 Q 2 S )since we can then, for any Ai ⊂ Aj , set
PQS= ?x : Ai → R= ?x : Aj  Ai → R= ?x : A†  Aj → R

and apply the identity from right to left.

(P 2 Q)

P

11.4

Normalizing

285

What we have managed to do is transform our process P into a one-stepnormal form: a hnf which is either div or satisﬁes the restrictions on its acceptanceset pattern set out above and furthermore has a unique successor process for each
initial action. This gives a complete characterization of the ﬁrst-step behaviourof the original process P , and has the property that (provided P does not equaldiv) for each a ∈ initials(P ) we have P /a = R[a/x ]. If P  were another processequivalent to P in N then it would reduce to a one-step normal form with exactly
the same shape (pattern of Ai , except that the Ai for i > 1 may be re-ordered)and such that its successor process R  is equivalent to R in N (in the sense thatR[a/x ] = R  [a/x ] for all a in the initials set A† ).
This notion of a one-step normal form extends naturally to a full normal
form: the deﬁnition is exactly the same except that, in addition, we insist that eachof the result processes R[a/x ] is also in normal form. (It is in doing these lowerlevel normalizations of the leaf processes of a one-step normal form that we need theassumption that all successor processes can be reduced to hnf.) The argument in
the previous paragraph can easily be extended by induction to show that any pairof normal form programs which are equivalent in N have equivalent normal form
structures and can trivially be inter-transformed by laws. The only things that candiﬀer are things like the order of Ai ’s and the names of input variables.
It would seem that we have attained our goal of completely capturing thedenotational equivalence via algebra. Essentially we have, but not as simply as
it appears on the surface. The problem is how to handle processes that can goon communicating for ever and which therefore fail to have a ﬁnite-depth normal
form. It is evident that we can attempt fully to normalize a process P by ﬁrst
transforming it to one-step normal form and then normalizing each of the result
processes R[a/x ], but this transformation will only terminate and produce a ﬁnitedepth normal form program if the set traces ⊥ (P )  divergences(P ) is ﬁnite (which,under our assumptions, is equivalent to there being a bound on the length of its
members). There are several ways around this diﬃculty, but all mean we have toabandon any hope that all pairs of equivalent CSP processes are inter-transformableby a ﬁnite sequence of law applications.
The ﬁrst approach we can take is to incorporate into our theory the fact thatprocesses P and Q are equivalent in N if, and only if, P ↓ n = Q ↓ n for all n ∈ N,
where the restriction functions ↓ n are as deﬁned on page 200. We can express
P ↓ n directly in CSP8 , it is P  Rest(n) whereΣ

Rest(0) = div
Rest(n) = ?x : Σ → Rest(n − 1) for n > 0
8 The expression given here is dependent on our assumption that P never terminates. For how
to extend this idea to processes that can communicate , see Exercise 11.5.4.

286

Algebraic semantics

Since each P ↓ n always has a ﬁnite normal form, the rule
EquivN If P and Q are any processes in ﬁnitely nondeterministic CSP, deﬁned
without SKIP or sequential composition, then they are equivalent in N
if and only if, for all n ∈ N,
P  Rest(n) = Q  Rest(n)ΣΣleads directly to a decision procedure for equivalence which involves converting
inﬁnitely many processes into ﬁnite normal form and seeing if you get the same
results for each pair. It is complete on processes satisfying our assumptions about
reducibility to hnf.
Another approach is to transform the program into a potentially inﬁnite
normal form tree. It is perhaps easiest to understand this in terms of deriving,from a process P , a recursive deﬁnition of a vector of processes which turns out
to be indexed by T , the set of members of traces ⊥ (P ) other than non-minimal
divergences. If s is such a trace, we can compute Rs , the result process (equivalent
to P /s) derived from applying the one-step normal form transformation down s as
follows.
R
Rsˆa

= P= Q[a/x ],where applying the one-step normal form transformation to Rs yields something of the formN?x : Ai → Q
i=1

Along with this derivation you have produced an expression for each Rs in termsof the Rsˆa : the one-step normal form of Rs . If you now replace the processes
Rs by the corresponding components of a vector N of process variables, the result
is a constructive one-step tail recursion whose unique ﬁxed point in N T is clearlyRs | s ∈ T  = P /s | s ∈ T . If P  is a process equivalent to P then the recursion
produced will be exactly the same, since the one-step normal form of P  /s has thesame shape as that of P /s for all s. So we have managed to transform P and P  tothe same process deﬁnition, albeit using in many cases an inﬁnite number of steps.
When deriving this ‘tree’ expression for the normal form, it may very wellbe the case that the number of distinct values of P /s visited is actually ﬁnite. Thisis always so if P is ﬁnite state and even sometimes when it is not, for exampleµ p.a → (p ||| p)(equivalent to µ p.a → p)

If you can recognize these equivalences (by transformation, for example), then you
can produce a more compact representation of the normal form tree as a ﬁnite graph11.4

Normalizing

287

or as a recursion with a ﬁnite indexing set. Thus you can represent the process
P0 = µ p.(a → a → p)(a → STOP )as the two-state recursionN= a → NaNa

= a → N
STOP

rather than having a component for each member of {a}∗ .
The problem with this is that it re-introduces an element of ﬂexibility into
the way normal form processes are structured: ﬂexibility is just what you do notwant of a normal form. The main source of ﬂexibility is the fact that one may or
may not spot an equivalence between a pair of processes. Consider, for example,
the process
P1 = P0

{a,b}(µ p.a → a → ((a → p) 2 (b → STOP )))This is, in fact, equivalent to P0 , but the ﬁnite-state normal form you would be
most likely to derive for it is
N

=


a → Na


Na

=


a → Na,a
STOP


Na,a

=
a → Na,a,aNa,a,a=
a → Na,a,a,a
STOP
Na,a,a,a=
a → Na,a,a,a,aNa,a,a,a,a

=

a → N
STOP

because the structures of, for example, P1 / and P1 /a, a are suﬃciently diﬀerent
that it is unlikely one would spot or easily prove their equality while transforming
to normal form.
If the above were computed for P1 , then one can no longer establish its equivalence with P0 by the identity of their normal forms. The way around this, though it

288

Algebraic semantics

is not in any obvious sense an algebraic operation, is to factor each normal form you
compute by the maximal bisimulation computed over it9 (see Section 7.2). In the





, Na,a,a,a} and {Na, Na,a,a
, Na,a,a,a,a}
case above this identiﬁes {N , Na,a
resulting in a structure identical to the normal form of P0 (which has no interesting
equivalences between its nodes).
These bisimulated normal forms are in some ways less attractive from apurely algebraic standpoint than the ones with separate components for all traces,
but they are a lot more practical since they are so often ﬁnite. Though they arederived via direct manipulation of the underlying LTS rather than by algebraic
transformations, the normal forms which play a crucial part in FDR’s operations
are essentially the same objects. See Appendix C for more details.
The reader might have noticed the great similarity between the normal forms
described in this section and the recursion deﬁned on page 235 to demonstrate thecoverage of N by the CSP notation. This should not come as a surprise, since ineach case our task was to ﬁnd a standard way of representing a given semantic
value, even if we did have to approach this problem from opposite ends. Except
for the fact that we have, in this chapter, yet to deal with SKIP and sequencing,the only diﬀerence between the recursions Ns deﬁned above and Int N(F ,D) deﬁned
on page 235 is the indexing sets used. In the second case this is, for a given value(F , D) ∈ N ,{(F , D)/s | s ∈ T }where T is, again, the set of traces other than non-minimal divergences. Naturally,in comparing this with the normal form of a process P such that
(F , D) = (failures ⊥ (P ), divergences(P )) = SN [[P ]]it is not hard to prove that the relation over T deﬁneds ≡ s  ⇔ SN [[P ]]/s = SN [[P ]]/s corresponds precisely to the maximal bisimulation over the processes Ns derived
from P . This demonstrates nicely that the result of quotienting the maximal bisim9 This bisimulation can be computed in two ways. The ﬁrst is to use the ordinary bisimulation
relation over the LTS you get from the standard operational semantics of the normal form recursion.
Before bisimulating you would then start with distinct nodes for all the normal form states, andalso extra states (reachable under τ actions from this ﬁrst sort) for the initials sets and maximalrefusals. The second, and much more elegant, way is to consider only the normal form states asnodes of the transition system. The nodes are marked with divergence or with maximal refusal
information which is taken into account when computing the maximal bisimulation: no two nodes
with diﬀerent markings are ever identiﬁed. See Section C.2 for more discussion of this idea.

11.4

Normalizing

289

ulation into any ‘normal form’ of the sort represented by the Ns above gives a true
normal form. In other words, it demonstrates the ‘completeness’ of the method.
To summarize, we have shown that the algebraic laws completely characterize
the semantics of CSP over N , though the procedures we have provided for deciding
equivalence are inﬁnitary. The only remaining issue is our assumption that we candetect all divergent terms and replace them with div. The procedure for reducing aprocess to hnf does, of course, provide an inﬁnitary complete method for this, and we
could argue reasonably that if we are to accept an inﬁnitary procedure for one thing
then it will do for this too! The unfortunate feature is that it leads to one inﬁnitary
procedure (divergence detection) being a frequently-used subroutine in another.
You can get round this (i.e., back to a single level of inﬁnity) by several methods,
perhaps the most frequently used of which is the concept of syntactic approximation
where, instead of comparing the desired pair of processes algebraically, you compare
pairs of recursion-free approximations (where recursions have been unwound a ﬁnite
number of times, and those that remain are replaced by div). For more details of
this, see [45], for example.
It is well worth commenting that the normalization procedure uses a surprisingly small proportion of the laws set out in earlier chapters. The laws of
preﬁxing and choice have been used extensively in normalization, but the only laws
used for other operators have been unwinding and their distributive, step and zero(strictness) laws (with the exception that some symmetry laws are needed to derive
symmetric versions, such as right distributive laws from left ones). The only possible
conclusion is that the rest of the laws must be implied by the ones we used, examples being |||-assoc (2.8), X Y -assoc (2.5), hide-  -dist (3.8), hide-combineX(3.3) and f [·]-  -dist (3.9). None of these is a trivial consequence of the ones weXused in the same sense that hide-sym follows from hide-combine. It is usuallypossible to prove them from the algebraic theory, but the proofs are generally muchharder than those directly using the underlying models. The proofs often make useof the rule EquivN and inductions such as((P ||| Q) ||| R) ↓ n = (P ||| (Q ||| R)) ↓ n
in which, for the inductive step, the two sides are reduced to hnf. See Exercise
11.4.2.
Algebraic semantics also give us (as discussed earlier) the freedom to ask thequestion of what equivalence is induced if we drop one or more of the laws that
actually were necessary to characterize failures/divergences equivalence. The mostinteresting ones to consider dropping are  -2-dist (1.13), which plays a crucial rolein normalization and which is, as discussed at the point of its deﬁnition on page32, somewhat hard to justify on intuitive grounds, and the step laws of parallel

290

Algebraic semantics

operators. But all of this is beyond the scope of this text, and in any case theoccupation of experimenting with sets of laws for its own sake is a great deal more
fascinating theoretically than it is practically useful.
Exercise 11.4.1
N
i=1

Prove, using the laws and induction on N , that for any P1 , . . . , PN

Pi = (2N
i=1Pi )  (

N
i=1

Pi )

Exercise 11.4.2 Using the expression for P ↓ n given in the statement of the rule
EquivN , show by induction on n that for any processes P , Q and R((P ||| Q) ||| R) ↓ n = (P ||| (Q ||| R)) ↓ n
by computing the hnf’s of the right- and left-hand sides in terms of hnf’s of P , Q and R. Do
you think this form of induction would work as easily for proving the law hide-combine?

Exercise 11.4.3
Compute ﬁnitely mutual recursive normal forms for (COPY |||COPY ) \ {| left |}, dealt with in Example 11.2.1 and the process of Exercise 11.2.1
part (c).
Exercise 11.4.4
Recall the interrupt operator described on page 239. P a Q
behaves like P except that at any time a may occur and the process subsequently behave
like Q. Give the failures/divergences semantics of P a Q. Is it strict in P ? and in Q?
Now give a step law that allows the reduction strategy to hnf to be extended
to processes involving a constructs together with the strictness properties above anddistributive laws.
Notice that these laws completely determine the semantics of this new operator.
Do you think a similar principle applies to any new operator?

Exercise 11.4.5 Repeat Exercise 11.1.1 for the following ‘laws’ (also taken from [53]),
though this time only showing all divergence-free processes equal.
(1)

P

RUN

=

P

(2)

P 2 STOP

=

P

(3)

P 2Q

=

Q 2P

(4)

P ||| STOP

=

P

(5)

P ||| RUN=

RUN ⇔ divergences(P ) = {}

11.5

Sequential composition and SKIP

11.5

291

Sequential composition and SKIP

We have not dealt with SKIP, and hence sequential composition, so far because
it necessarily adds cases to the reduction/normalization strategies and to the definitions of the normal forms. This is not only because we are not permitted toinclude  in choice sets Ai but also because  is, as seen in earlier chapters, nottreated like other actions. The law 2-SKIP resolve (6.6) was crucial in explaining
the diﬀerence earlier, and it has a large impact on how the algebraic semantics areaﬀected by .
The crux of the problem is that we now have processes like (a → STOP ) 2
SKIP which can oﬀer an event in Σ transiently before they terminate. In many
ways the behaviour of this process is similar to((a → STOP ) 2 (b → c → STOP )) \ {b}in that both can independently make the decision to remove the choice of doing a
in favour of something else. This latter process has hnf (indeed, normal form)(?x : {a, c} → STOP )c → STOP

In other words, the process with the transient event a has been replaced by a process
deﬁnition without transients which has identical observed behaviour. This is notpossible with the ﬁrst process, because it involves the trick of oﬀering the external
choice of the transient a and the result of the internal choice, and we do not permit
process deﬁnitions like(?x : {a, } → STOP )SKIP

which would be the translation.
There are two reasonable ways to incorporate termination into hnf. In someways the more pleasing is to bring the sliding choice/timeout operator P  Q into
the syntax of hnf, thinking of it as a primitive operator implemented as in the direct
operational semantics for it on page 169 rather than as (P 2 Q)
Q (thoughthe equality over denotational models with this representation would still hold).
However, because some people might ﬁnd this ‘doublethink’ about  confusing,and because it is probably simpler overall, we will add termination by allowing(?x : A → P ) 2 SKIP to be considered an hnf.
The deﬁnition of hnf now becomes:• div is in hnf;
• SKIP is in hnf;

292

Algebraic semantics• ?x : A → P is in hnf;
• (?x : A → P ) 2 SKIP is in hnf;
• if each Qi is a hnf, thenN
i=1

Qi is;

When we want to distinguish this extended form we will refer to it as -hnf.
The idea that reducing to hnf provides an operational semantics easily extends to this larger class. Obviously SKIP terminates, whereas (?x : A → P ) 2 SKIP
may oﬀer the choice of A for a short time before terminating.
Imagine you are reducing a construct like P ⊕Q (⊕ being any binary operator
other than or, with the obvious modiﬁcations, renaming or hiding) to -hnf. The
recipe given earlier calls for us ﬁrst to reduce P and Q. Clearly you need to deal
with the extra cases that arise when one or both of the results, P  and Q  , areof the form SKIP or (?x : A → R) 2 SKIP . The laws of SKIP given in Section
6.3 easily deal with all combinations of SKIP with itself and preﬁx choices. And
SKIP ; Q  and ((?x : A → P ) 2 SKIP ); Q  reduce, for any Q  , via ; -unit-l (6.4)
and ; -step (6.7).
The remaining cases for 2 can be dealt with using existing laws, and the caseof ((?x : A → P ) 2 SKIP )[[R]] by [[R]]-2-dist (3.14) and SKIP-[[R]]-Id (6.10).
The corresponding case for \ X requires a new law which is closely based on its
existing step law:((?x : A → P ) 2 SKIP ) \ X =(?x : A → (P \ X )) 2 SKIP<I A ∩ X = {}>I((?x : A  X → (P \ X )) 2 SKIP
{P [a/x ] \ X | a ∈ A ∩ X }hide-SKIP-step (11.10)

Parallel operators require three new laws each: one each for an input/SKIP combination in parallel with a diﬀerent type of -hnf. (There is no need to introduce
a law to deal with the cases where the other process is a nondeterministic choice or
div since these are reducible by distributive and zero laws respectively.) Becauseof this multiplicity we only give those for  , since each of ||| and X Y are expressX

ible in terms of it. The second and third of these are better and more succinctly
expressed as general principles involving the  construction (bearing in mind thelaw 2-SKIP resolve). These laws make it straightforward to extend the strategy so that it can reduce CSP processes possibly involving SKIP and sequential

11.5

Sequential composition and SKIP

293

composition to -hnf.
((?x : A → P ) 2 SKIP )  SKIP =  -2 SKIP (11.11)

X(?x : A  X → (P  SKIP )) 2 SKIP

X

X

(P  Q)  (R  S ) =X(P  R)  ((Q  (R  S ))XX((P  Q)  S ))  --split (11.12)
X

X(P  Q)  (?x : A → R)) =X?x : A  X → ((P  Q)  R)
X

2 ((P  ?x : A → R)  (Q  ?x : A → R))X  --input (11.13)
XX

if x is not free in P or Q
Given its similarity to the normal form in the SKIP -free case, it is natural
to look to the full abstraction recursion on page 235 for guidance about how toextend the deﬁnitions of one-step and full normal forms. The ﬁrst-step behaviourof any non-divergent process is now characterized by its initial actions (which may
now include ) and the minimal acceptance sets which are subsets of Σ. Minor
extensions to the strategy given in the previous section can transform any -hnf to
one of the following forms:(a) div(b) ?x : A → R(c) (?x : A → R) 2 SKIP(d) (?x : A → R)
subsets of A

(

N
i=1

?x : Ai → R) where the Ai are incomparable properN?x : Ai → R) where the Ai are incompara(e) ((?x : A → R) 2 SKIP ) (i=1
ble subsets (not necessarily proper subsets) of A.
Here, (a) is the representation of a divergent process, (b) of a process which cannot
terminate or behave nondeterministically on its ﬁrst step and (c) of a process which
can terminate immediately and must do so if no member of A is accepted quickly
enough. (d) and (e) add the possibilities of nondeterministic oﬀers of proper subsetsof the initials to the cases in (b) and (c).

294

Algebraic semantics

The most important new transformation required to bring the manipulationof an arbitrary -hnf to one of these forms is developed in Exercise 11.5.1 below.
The above is the extended deﬁnition of one-step normal form, and the methods
and problems associated with converting this to a full normal form are exactly as
for the smaller language in the previous section.
Exercise 11.5.1

Show algebraically that for any P and Q,(P 2 SKIP )  (Q 2 SKIP ) = (P 2 Q 2 SKIP )Why is this useful for transforming a-hnf process to one-step normal form?

Our dealings with the combinations involving P 2 SKIP and parallel
operators would have been simpliﬁed if the distributive law

Exercise 11.5.2(P  Q)

R = (P
XR)  (QX

R)
X

were true. Give an example to show that it is not.
Repeat Exercises 11.1.1 and 11.4.5 for the following ‘laws’ (also takenfrom [53]), proving all processes equal.

Exercise 11.5.3(1)STOP; P

=

STOP

(2)

P ; STOP

=

P

(3)

SKIP ; P

=

P

(4)

P ; (Q; R)=(P ; Q); R

It can be done with, or without, the associative law (4), which is, of course, true.
Recall that on page 285 we showed how to deﬁne restriction over
N for -free processes via a process context. Assuming that there is some event a ∈ Σthat P never communicates on a non-divergent trace, ﬁnd a corresponding way of deﬁning
P ↓ n when P can terminate.

Exercise 11.5.4

Hint: consider P ; (a → SKIP ) in parallel with a well-chosen process.

11.6

Other models

We will not deal with the algebraic characterization of the other models for ﬁnitely
nondeterministic CSP in as much detail, since many of the basic principles are thesame and, as we will see, in some ways the algebraic approach does not work quite
as cleanly for T and F as for N .

11.6

Other models

295Over both F and T we have the lawP -unitT ,F  (11.14)

div = P

which is, of course, radically diﬀerent from the corresponding law over N (namely
 -zeroN ). The characteristic law of T is
P 2Q = PQtrace-equivT  (11.15)

which, together with  -unitT ,F , 2-unit (1.16) and symmetry, can establish thatdiv =T STOP . The fact that div can be replaced by STOP means that the lackof all the div-strictness laws true over N is no handicap over T when it comes totransforming processes involving div to hnf.
The situation over F is more complex because the processes div, P and
P 2 div are all, in general, diﬀerent. This leads to the need for a variety of newlaws in much the same way we needed laws to deal with processes of the form
P 2 SKIP in the previous section. We do not enumerate them here.
An essential ingredient of demonstrating that you have captured one of theother models is, as with N , the creation of normal forms which capture all possible
semantic values in exactly one way. This is always done by creating what is essentially a picture in syntax of the semantic model, but we are still left with choices,which generally increase in weaker models like T .
Given the close correspondence between the normal form for N and theconstruction used for full abstraction in Section 9.3, you might expect the same to
be true for T and F. While their representations in Section 9.3 are perhaps thestarkest imaginable syntactic pictures of the representations of processes, they dohave disadvantages as normal forms. One is the fact that ﬁnitely nondeterministic
processes over ﬁnite Σ would often require a S construct, with inﬁnite S , in theirnormal forms. Another is the fact that the highest-level syntactic structure now
depends not on the ﬁrst-step behaviour of the target process (as it did for N ) but
on all levels. The crucial diﬀerence is in the place where nondeterministic choices
are made: in the N normal form (and its construction in Section 9.3) all choices
are left as late as possible, whereas in the Section 9.3 constructions for T and F achoice is made immediately which eﬀectively determines what the process will dothrough all time.
There is no need for any nondeterministic choices in a normal form for T : aprocess is in one-step normal form if it is either?x : A → P

or (?x : A → P ) 2 SKIP

since all we have to specify of a process is what its initial actions are, and how it296

Algebraic semantics

behaves after each. You can build full normal forms from this one-step form in justthe same way as over N .
The normal form for F is like that for N , though heavily inﬂuenced by theradically diﬀerent role of div: see Exercise 11.6.1.
When we were reducing a process to hnf over N , we could be sure thateither we would succeed or the process was equivalent to div (with this frequently
detectable via the rule LoopN ). How helpful this is can be seen when we look at
the contrasting situation in models such as T which are not divergence-strict.
In T , the fact that a process can diverge does not mean it is identiﬁed withdiv. For example, even though you can immediately deduce that it diverges, theprocessµ p.(a → Q)

p[[R]]

needs its recursion unwound potentially many times (inﬁnitely if Σ is inﬁnite) justto reveal its ﬁrst-step behaviour (its initial actions being the smallest set whichcontains a and is closed under the renaming relation R). The real problem is thatthe procedure for reducing this process to hnf diverges without the simple answer
this inevitably leads to over N .
This means that reduction to hnf (at least, the same hnf) cannot be at thecore of a reduction-based operational semantics which faithfully reﬂects all possible
behaviours predicted by T and F beyond points of possible divergence. In essence,the strategy is certain to diverge on processes like the above which these models
suggest have alternative behaviours. The operational semantics described in Section
11.2 would, if the behaviours they predicted for processes were abstracted into theseother models, yield sometimes proper reﬁnements of the denotational semantics ofthe processes.
The possibility of divergence on reducing a process to hnf also creates problems in reducing an arbitrary process to one-step normal form, since we previously
relied on conversion to hnf ﬁrst. Since these problems do not arise for recursion-freeprocesses, probably the best way of completing the algebraic characterizations of T
and F is via the concept of syntactic approximations discussed on page 289.
Show that every member of F can be expressed in one, and only
one, of the following four ways

Exercise 11.6.1(i) (?x : A → P ) 2 div(ii) (?x : A → P ) 2 SKIP(iii) ((?x : A → P ) 2 div)  ((iv) ((?x : A → P ) 2 SKIP )  (N?x : Ai → P )

i=1
N

i=1

?x : Ai → P )

11.7

Notes

297

where in (iii) and (iv) the Ai are all incomparable subsets of A.
Hence deﬁne a normal form for F .
Calculate the normal form of the process(div 2 (SKIP  a → SKIP )); STOP

11.7

Notes

Algebraic laws have played an important part in the deﬁnition of CSP from its
earliest beginnings, and many of those presented here can be found in [18].
The algebraic semantics for the language was ﬁrst given in Brookes’s thesis[15]. The version presented here deals with a wider range of operators (consequently
requiring more laws) and deals with recursion diﬀerently, but is in most important
respects the same.
A closely related algebraic semantics is that of occam [121], which deals
with parallel language based on CSP with the added complexity of assignable state.
Algebraic approaches to other process calculi may be found in [1, 9, 10, 51, 81](amongst many other works).
The concept of algebraic reduction as an operational semantics has its origins
in the λ-calculus and similar. Hoare and He have advocated their use on moregeneral languages, see [47, 48].
2005: At the time of writing the author is engaged in some work to show how
the laws and normal forms of the algebraic semantics vary with the model we seek
to characterise. This encompasses both models described here and more elaborate
ones. A limited part of it can be found in [116].

Chapter 12

Abstraction

One view of systems is said to be more abstract than another if it hides more detail,thereby identifying more processes. Greater or lesser abstraction can result fromthe choice of model used, where, for example, the traces model T is more abstract
than the stable failures model F. What we will be studying in this chapter are ways
in which one can deliberately abstract detail away from a process by applying CSP
constructs. We will then apply these ideas to formulating a variety of speciﬁcations,
including fault tolerance. Perhaps the most important of these is characterizing
information ﬂow across processes and hence security.
What we will be doing, in other words, is learning both how to build carefully
designed fuzzy spectacles which let us see just that aspect of process behaviour that
may seem relevant and, equally importantly, why this activity can be useful.
One such abstraction mechanism is many-to-one renaming, which allows us
to ignore distinctions between events which may be irrelevant for some purpose. A
typical example of such a renaming might be to ignore the data that passes along achannel by mapping all communications over the channel to a single value. Though
we will be using renaming occasionally in the rest of this chapter, the eﬀects ofrenaming, in itself, as an abstraction are covered in Sections 3.2.2 and 13.6.1 (seeDeadlock Rule 15 on page 384 in particular) and we will study the concept ofdata-independence, which in some respects is similar, in Section 15.3.2.
It is worth remarking that many-to-one renaming often introduces nondeterminism, as is well shown by the routeing node example on page 383. In thisit has something in common with just about all imaginable abstraction mechanisms: in forming an abstraction you deliberately obscure some detail about how
a process behaves and therefore risk losing information about how some choice ismade, though the eﬀects of the choice remain visible. Any example of many-to-one

300

Abstraction

renaming introducing nondeterminism illustrates this, such as((a → c → STOP ) 2 (b → d → STOP ))[[b /a ]]= a → ((c → STOP )(d → STOP ))The rest of this chapter is devoted to abstraction mechanisms with one speciﬁc aim: taking a process P and a set of events X ⊆ Σ and working out what P
looks like to a user who can only see the events X (though there may be other users
interacting with P in the complement of X ).

12.1

Modes of abstraction

Throughout this section we will assume that P is a divergence-free, ﬁnitely nondeterministic process with two users, Hugh and Lois, who respectively communicate
with P in the disjoint sets of events H and L which contain between them all theevents P ever uses, with each user only being able to see his or her own events. If
P could ever terminate () we would have to worry about which of our two users
could see this; to avoid special cases of limited practical use we will assume thatP never does terminate. (This does not, of course, exclude the possibility that thedeﬁnition of P might internally use SKIP and sequential composition.)12.1.1

Lazy and eager abstraction

Given a process P and set of events L, it is tempting to believe that the abstracted
view of P in L is given by P \ (Σ  L). In the traces model T this is the right answer,
but over the richer models the situation is more complex since this deﬁnition does
not necessarily deal with refusal sets and divergences appropriately. The problem isthat the hiding operator P \ X assumes that X has passed out of sight and controlof the entire environment and hence that events from H become τ actions and thus
‘eager’. We will thus identify hiding with eager abstraction1 :EH (P ) = P \ Hthough we will ﬁnd that, outside T , this is of rather limited use as a means ofabstraction.
If, on the other hand, we believe that the events H are under the controlof some other part of P ’s environment (the other user Hugh) but happen to be
1 When choosing the notation for abstraction there is an important choice we have to make,namely whether to make the set parameter either the events we are abstracting from, as done here,
or to, which would have led us to replace the subscript H here by L. Obviously this is arbitrary.

12.1

Modes of abstraction

301

invisible to us (looking at P through Lois’s eyes), then when an event in H becomes
available it may be either accepted or refused by Hugh. Thus Hugh, from Lois’s
perspective, gets to introduce nondeterminism into the system both by the choiceof which action to communicate and also by whether to communicate at all. If, forexample, Hugh decides to refuse absolutely all communications oﬀered to him, P
will appear to act like P  STOP .
H

The most general behaviour of the abstracted environment (Hugh) is Chaos H ,accepting or refusing any event available to him. This suggests that the right way
to form the abstraction is(P  Chaos H ) \ H
Hand indeed this has a lot to recommend it. However, in the failures/divergencesmodel N , this construction will introduce a divergence whenever P can perform
an inﬁnite sequence of events in H even though P is not itself diverging. While
you can imagine that this corresponds to the real possibility of Hugh continuously
oﬀering events to the process which are accepted, thereby excluding Lois from doing
anything, it is, particularly in conjunction with the severe way N treats divergence,
too strong an abstraction for most practical purposes: the divergences typicallymask much L behaviour we should really want to see. It is usually better to assume
either that Hugh is always suﬃciently lazy not completely to use up the process,or equivalently that the implementation is suﬃciently fair between Hugh and Loisthat neither is inﬁnitely excluded simply because of the eagerness of the other.
There are three, largely equivalent but stylistically diﬀerent, ways of constructing
a lazy abstraction LH (P ) which behaves like the above except for not introducing
the divergences.
Our assumptions about P mean that its representations in the three models
N , U and F are essentially the same (entirely characterized in each case by theset of stable failures failures(P )). The following versions of the abstraction exist,
respectively, in these models.
The N version is best deﬁned by direct manipulation of the failures of P .
As P is a divergence-free process, the projection of P into the alphabet L is thedivergence-free process P @L with failure-set{(s \ H , X ) | (s, X ∩ L) ∈ failures ⊥ (P )}The main diﬀerence between this and the deﬁnition of the hiding operator P \ H(see page 203) is that it does not insist that the whole of H is refused before
generating a failure. This is because Hugh can always refuse all the events in H  X .
LN
H (P ) is deﬁned to be P @L.

302

Abstraction
For example, if L = {l1, l2} and H = {h}, we might deﬁne P byP

= l1 → P
2 l2 → h → P
2h→PLN
H (P ) is then equivalent to Q whereQ= l1 → Q
2 l2 → (STOP

Q)

Notice that the (ﬁnite) traces of LN
H (P ) are precisely {s \ H | s ∈ traces(P )},which is what we might have expected and coincides with the abstraction mechanism
for T , namely hiding.
The second version, using the inﬁnite traces/failures/divergences model U,
can be expressed directly using CSP operators, since in that model we can express
fairness properties, as seen in Section 10.3.1. As discussed in Exercise 10.3.5,
SemiFair (A, B ) = RUN A ||| Fair (A, B )is a process which never refuses events in A, allows any ﬁnite combination of A’s
and B ’s, but only allows inﬁnitely many B events to occur if inﬁnitely many A’s doas well.
 SemiFair (L, H )) \ H
LU
H (P ) = (PΣcannot diverge unless P can, as the structure of the inﬁnite traces of SemiFair (L, H )prevents new divergences being introduced by the hiding here. The failures of
LU
H (P ) are exactly the same as those of P @L. The inﬁnite traces are precisely
those inﬁnite traces of P with inﬁnitely many L events, with all H events hidden.
(Obviously the other inﬁnite traces of P cannot be mapped sensibly onto inﬁnite
traces in Lω , since u \ H is then ﬁnite. Naturally, it is then a ﬁnite trace of
LU
H (P ). This is because u will have a ﬁnite preﬁx s such that u \ H = s \ H and
SemiFair (L, H ) does not prevent P performing s.)
It should be remarked that abstraction in U distinguishes more processes thanabstraction in N , since the inﬁnite traces component of the model can vary when
the abstraction construct (which is, itself, inﬁnitely nondeterministic) is applied toﬁnitely nondeterministic processes whose LN
H abstractions are identical. Examples

12.1

Modes of abstraction

303

are Q1 and (Q2; STOP ), where
Q1 = l1 → Q1
h → Q1Q2 = h → (Q2; l1 → SKIP )SKIPUEach of LU
H (Q1) and LH (Q2; STOP ) can perform any number of l1’s before refusing this event, but only the abstraction of Q1 can perform an inﬁnite trace of l1’s,
since the only inﬁnite trace of Q2; STOP is h, h, h, . . .. This is a very reasonabledistinction to make, but it is one which is only possible over U.

The above discussion shows that lazy abstraction should be added to the listof operators which can have the eﬀect of introducing inﬁnite nondeterminism, andtherefore require U as opposed to N for full precision. In fact the extra distinctions
only become an issue if either we need to place lazy abstractions into contexts inwhich they aﬀect the divergence-set via hiding as discussed in Section 8.3.2, or if wewant to prove that they meet speciﬁcations which constrain inﬁnite traces. Noneof the examples we will see in the rest of this chapter does either of these things, so
the extra precision of LU
H (P ) is not something we will need.
As we will see later in this chapter, the case where LH (P ) is deterministic isvery important. If the failures of LU
H (P ) show it to be deterministic then we know(see page 256) that only one set of inﬁnite traces (all those that are limits of ﬁniteNones) is possible. Thus, if LN
H (P 1) = LH (P 2) and this value is deterministic, thenUalso LU
H (P 1) = LH (P 2).
The third, and for practical purposes the best, way of computing the lazy
abstraction is the one over the stable failures model F where divergence is not aconcern for the simple reason that it is not recorded in the model: the value of Chaos H ) \ H
LF
H (P ) = (PH

in this model is precisely(traces(P ) \ H , failures(P @L))
because (s, X ∩ L) ∈ failures(P ) implies that (s, X ∪ H ) ∈ failures(P  Chaos H )Hand hence(s \ H , X ) ∈ failures((P  Chaos H ) \ H )HSince, under our basic assumptions, the traces of LF
H (P ) are exactly those of its
failures, this form of abstraction is identical in strength to LN
H (P ): these two values

304

Abstraction

being trivially inter-translatable. In fact, it is best to think of LF
H (P ) as an alterN
native way of computing LH (P ). Under our assumptions about P ,• the determinism of LF
H (P ) is equivalent to that of the other two versions,and• if S is a divergence-free and ﬁnitely nondeterministic (speciﬁcation) process,then the three reﬁnements
S

F
F LH (P )S

N
FD LH (P )S

U
U LH (P )are all equivalent.
LF
H (P ) is the best form of lazy abstraction in practice simply because it isdirectly computable by FDR for ﬁnite-state P , and the above equivalences meanthat in most cases we are free to choose whichever we want. Together with its
application to the speciﬁcation and automated analysis of deadlock discussed around
page 217 it provides the main ways of applying F to tell us things about divergencefree processes P by putting them in contexts C [P ] which could introduce divergence
if analyzed over N .
Throughout the rest of this chapter we will only use lazy abstraction incircumstances where all three are equivalent, and therefore cease to distinguish between them in our notation: henceforth we will normally simply refer to LH (P ).
Equally, the reﬁnement relation will denote any one of the three generally equivalent versions referred to above (i.e., not T ).
The following results are both easy to prove and show the extent to whichlazy abstraction really does capture an accurate one-sided view of a process.
Lemma 12.1.1 If Σ is partitioned by {H , L} and P = PL ||| PH where PL and
PH are processes satisfying the assumptions of this section whose finite traces arerespectively contained in L∗ and H ∗ , then LH (P ) and LL (P ) respectively equal PL
and PH .
A process that can be factored into two components with disjoint alphabets
like this is called separable. Invariably, separability will be considered relative to a
speciﬁc pair of alphabets.
The proof of this lemma is left as an exercise.
Theorem 12.1.2 If Σ is partitioned by {H , L} and P is any process satisfying thebasic assumptions of this section, thenP  LL (P ) ||| LH (P )

12.1

Modes of abstraction

305

in any of the three models over which lazy abstraction is defined. Additionally, over
the traces model T we have the analogous result:
P T P \ H ||| P \ L
Proof We deal with the result over N , which is equivalent to that over F andimplies that over T . Suppose (s, X ) ∈ failures ⊥ (P ). Then, by deﬁnition of P @A
N(see page 301), (s \ H , X ) ∈ failures ⊥ (LN
H (P )) and (s \ L, X ) ∈ failures ⊥ (LL (P )).
∗Since plainly s ∈ (s \ H ) ||| (s \ L) for any s ∈ Σ (where ||| is the trace version of
the operator deﬁned on pages 67 and 148), it follows from the deﬁnition of ||| overN (see page 203) thatN(s, X ) ∈ failures ⊥ (LN
H (P ) ||| LL (P ))which establishes our result.
The result for U follows because if u is any inﬁnite trace of P , then u \ H
and u \ L are respectively traces (which may be either ﬁnite or inﬁnite) of LU
H (P )and LU
(P
).
u
is
then
an
interleaving
of
these
two.
L
The above theorem cannot be extended to equivalence: the reﬁnement isoften proper, as it is if
P= l →h→P

when L{h} (P ) = l → Chaos {l} and L{l} (P ) = Chaos {h} so that the interleaving of
the two abstractions contains all traces in {l, h}∗ rather than the highly restricted
set of P . This is hardly surprising, since we would rather expect the behaviour of P
visible to Lois to depend on what Hugh does, and vice-versa, and the interleaving
into two abstractions removes all such inﬂuences and hence all linkage between what
they see. The lemma above shows that the reﬁnement turns into equality when there
demonstrably is no linkage because P is separable. The following result gives aninteresting partial converse to this, allowing us to determine when deterministic
processes are separable.
Corollary 12.1.3 P is deterministic and separable (over {H , L}) if and only if
the processes LH (P ) and LL (P ) are both deterministic.
Proof The ‘=⇒’ half of this result follows from the lemma and properties ofdeterminism. For the ‘⇐=’ half, suppose both the abstractions are deterministic.
Then, as the alphabetized parallel operator A B preserves determinism (see page223), so is
LH (P ) L H LL (P ) = LH (P ) ||| LL (P )

306

Abstraction

But we know that P reﬁnes this process, so the two must be equal by maximalityof deterministic processes under reﬁnement.
For example, this shows that the deterministic process P = l → h → P considered above is not separable, since its two abstractions are both nondeterministic.
On the other hand, the process Q(n) deﬁned
Q(n) = h → Q(n)2 ((l → Q(n − 1))<
I n > 0>I STOP )is separable, since its abstractions are respectivelynl → . . . → l → STOPandµ p.h → p

The above series of results, and especially the last, hints at one of the mostimportant uses of abstraction: characterizing when one user of P can inﬂuence what
another user sees. We will return to this in Section 12.4.
12.1.2Mixed abstraction

While lazy abstraction is the one truest to the underlying philosophy of CSP, it issometimes necessary to weaken the assumption that the abstracted user Hugh candelay all events he sees. One quite often builds models of systems in CSP whosealphabets contain some events that the environment really can delay – typically inputs to the system – and some, perhaps outputs, that it would be more comfortableto picture as not really delayable. If Hugh is sitting at a workstation, his keystrokes
would naturally be thought of as delayable actions, but outputs displayed on the
VDU would not. In many respects, undelayable signal events have much in common
with the way the termination signal  is thought of (see Chapter 6).2 As long as
such events remain visible, this is not much of a concern since we can take accountof the diﬀerences between events in specifying and animating the process. But, if
they are to be abstracted, one can get undesirable results if the signal events are
abstracted lazily.
2 It would be possible to take this analogy further and develop models in which Σ was partitioned
into delayable events and signals; the semantic treatment of signals would then be very like that
we have developed for . We have not done so in this book in the interests of purity (sticking
close to Hoare’s original concept of CSP) and simplicity. Without this special modelling, signals
only really make sense at the external interface of a process with its environment unless one isextremely careful to make sure that whatever process context they are placed in does not delay
them. There are close connections between these ideas and some of those we will meet when we
model timed processes in Chapter 14.

12.1

Modes of abstraction

307

The right abstraction to use is then a mixed one, with delayable events treatedlazily and signal events abstracted eagerly (i.e., by ordinary hiding). If S are P ’s
signal events then we deﬁne
MSH (P ) = LH (P \ (H ∩ S ))Essentially, this treats the events in H ∩S exactly as though they are internal
actions of the abstracted process. This is reasonable since they are invisible to Loisand cannot be delayed by anyone. There is a potential problem in this deﬁnition,
namely that the hiding P \ (H ∩ S ) might either introduce divergence or (if thehidden set is inﬁnite) unbounded nondeterminism; either of these take it outside thedomain over which we have deﬁned lazy abstraction. While one should be awareof the second problem, it will rarely occur in practice since in practical examples
process alphabets are usually ﬁnite, and all it would mean in any case is that wewould be forced to compute the two abstractions over U.
Divergence of P \ (H ∩ S ) corresponds to an inﬁnite unbroken sequence of
signal events from P to Hugh. We might well think that this sort of behaviour, which
gives Hugh no opportunity to be lazy and gives Lois a slice of P ’s attention, is morecompellingly identiﬁed with divergence, from her perspective, than the type we so
carefully avoided when deﬁning lazy abstraction. Whatever one thinks, the process
produced by this hiding is not one to which lazy abstraction can be applied, andso we have to stipulate that mixed abstraction is only used for processes where theinner hiding does not introduce divergence. In any case where this is a danger, you
should, if using FDR, establish this divergence freedom separately before computing
the abstracted process MSH (P ) which, as with LH (P ), is then evaluated over F.
Over this model it equals(P Chaos H  S ) \ H

H S

Example 12.1.1 This form of abstraction is often the appropriate one for processes
in which each transaction with a user comprises an input from the user followedby some ﬁnite sequence of responses. Consider, for example, a memory device withthe following speciﬁcation:
Mem(s) =2

write?user ?a?v →(ok .user → Mem(update(s, a, v ))<I a ∈ WriteAddresses(user )>I(reject.user → Mem(s)))
read?user ?a →(value.user !fetch(s, a) → Mem(s)<I a ∈ ReadAddresses(user )>I(reject.user → Mem(s)))

308

Abstraction

The functions update and fetch respectively modify the state s to execute a write,
and look up the value for a read.
Here, we would expect the events in {| write, read |} to be delayable, andS = {| ok , reject, value |} to be the signals. We will, naturally, assume that the setof users is {Hugh, Lois}. If you use lazy abstraction on this, then the abstracted
views can both deadlock immediately because it is assumed that the hidden usermight initiate a read or write and then refuse the response it gets.
Mixed abstraction does not predict these deadlocks. The only way (it says)that either user can aﬀect the other is by writing to variables readable by the other:
if L is the set of Lois’s events, then MSH (Mem(s)) is equivalent to the process ML (s),where
ML (s) = write.Lois?a?v →(ok .Lois → M L (update(s, a, v ))<I a ∈ WriteAddresses(Lois)>I(reject.Lois → M L (s)))
2 read .Lois?a →((value.Lois!fetch(s, a) → M L (s)<I a ∈ WriteAddresses(Hugh)>I{value.Lois!v → M L (s) | v ∈ T })<I a ∈ ReadAddresses(Lois)>I(reject.Lois → M L (s)))
Here, T is the (ﬁnite, to avoid diﬃculties with unbounded nondeterminism) type ofthe values stored in the memory. The nondeterminism in this abstraction relates tothe fact that Lois has no way of knowing, when she reads a value that is writeable-toby Hugh, what the value will be. On the assumption that T has more than one
member, this process will be deterministic if, and only if,
ReadAddresses(Lois) ∩ WriteAddresses(Hugh) = {}It might have been preferable, in formulating the above, to have restricted
the range of memory locations held in the parameter s of ML (s) relative to theoriginal (i.e., only retaining those accessible by Lois). The semantics of the result
would not, however, diﬀer from the version where the full range is retained, provided
of course that everything was done appropriately. (End of example)
Exercise 12.1.1 Find as simple as possible representations, as CSP processes, of thefollowing lazy abstractions.
(i) L{down} (COUNT 0 ) (see page 16)(ii) L{up} (COUNT 0 )12.1

Modes of abstraction

309(iii) L{up,down} (Counter (0, 0)) (see page 26)(iv) LA (COPY ), where A = {left.a, right.a | a ∈ V } for {} = V ⊂ T , T being thetype of left and right.
Which of these processes is separable (in each case relative to the partition of its alphabet
implied by the abstraction quoted above)?

Exercise 12.1.2 Show that LΣ (P ) = STOP and L{} (P ) = P for every P satisfying
the assumptions quoted at the start of this section.
F
F
Show that LF
A (LB (P )) = LA∪B (P ) for any A, B and P .

Let V and A be as in Exercise 12.1.1 (iv) above. Describe thebehaviour, respectively, of the mixed abstractions

Exercise 12.1.3{|right|}(i) MA(ii)(COPY ){|right|}
MA(COPY >> COPY )Which of these is deterministic? How would you expect the same abstraction to behave
applied to an N -fold chaining of COPY (i.e., an N -place deterministic buﬀer)?
Suppose we were to replace the formulation of LU
H (P ) on page 302

Exercise 12.1.4
by the following:L̂U
H (P ) = (PFINITE H ) \ H
Hwhere FINITE H is the process (deﬁned as on page 258) which can communicate any ﬁnite
trace of events from H , but no inﬁnite trace. Show that this always has exactly the same
set of failures as the other lazy abstractions, but can diﬀer from LU
H (P ) in its set of inﬁnite
traces. Find a process P which demonstrates this diﬀerence.
Does any reﬁnement relation hold between the two versions (for all allowable P )?
Find a reason why LU
H (P ) is the better of the two.

Exercise 12.1.5

Prove Lemma 12.1.1 for the failures/divergences model N .

Exercise 12.1.6

Show that, for any P , Q and X , the equivalence

Q)

(P
X

Chaos H = (PH

Chaos H )Hholds in F . Deduce that, if H ∩ X = {}, thenQ) = LH (P )

LH (P
X

LH (Q)
X

and hence that
LH (P ||| Q) = LH (P ) ||| LH (Q)

Chaos H )

(Q
X

H

310

12.2

Abstraction

Reducing speciﬁcations

It is very common to want to prove that a process P meets a speciﬁcation S whichrefers only to a subset of its events. It makes no sense to ask the direct question‘S
P ?’, since we know it will fail. We have either to extend S so that it allows
the extra events of P , without specifying anything about them, or to abstract theextra events away from P .
With traces speciﬁcations, there is little diﬃculty about achieving this either
way. If X are the events of P that we want to ignore, then we should establish
either
S ||| RUN X

T P

or S

T P \XFor example, to prove that a pair a and b of actions alternate, irrespective of any
other events P might do, we could establish the reﬁnementµ p.a → b → p

TP \ (Σ {a, b})

On the whole it is better to take the latter, hiding approach rather than theformer in which we ‘boost’ the speciﬁcation. It is arguably clearer, especially when
examining any failure of the speciﬁcation, but the main argument is in terms ofeﬃciency when running FDR. If the set X is large, the process S ||| RUN X may beslow to normalize, whereas the act of hiding X in P frequently enables the result
to be compressed (as described in Section C.2), thereby substantially speeding up
the check.
When the speciﬁcation S involves failures, we have to worry not only about
how to abstract away from events that P may perform outside the alphabet of S ,but also how to deal with its refusals. Perhaps the most spectacular example ofa failures speciﬁcation abstracted has already been seen in Section 8.4, where wefound that, over F, P is deadlock-free if and only if P \ Σ is. Thus, apparently, we
can reduce deadlock freedom to a speciﬁcation with an empty alphabet! What turns
out to be important here is the way the (many) irrelevant events are abstracted: by
doing so eagerly, we have said that the only relevant refusal sets are those where all
the abstracted events are refused.
To generalize this, over F, with X being the ‘extra’ events as before,S

F P \X

means that, in addition to S T P \ X , whenever (s, Y ∪ X ) ∈ failures(P ) then(s \ X , Y ) ∈ failures(S ). But this says nothing whatsoever about P ’s refusals inany state where it does not reject the whole of X . This may or may not be what we12.2

Reducing speciﬁcations

311

want. For example, it does not allow us to make the speciﬁcation ‘P always oﬀers
either a or b’, since in factµ p.(a → p)(b → p)F

P \ (Σ {a, b})is (for -free P ) another equivalent of ‘P is deadlock-free’.
The obvious alternative is to replace eager abstraction by lazy abstraction
and, indeed,µ p.(a → p)(b → p)LΣ {a,b} (P )says exactly what we wanted, namely that every stable state of P can perform either
a or b. Thus,• we should eagerly abstract X if, as with the deadlock speciﬁcation, we are
only interested in those refusals which occur when every member of X is
impossible, and• we should lazily abstract X if, as is more likely in other situations, we areconcerned about P ’s refusals in the alphabet of S at other times as well.
Given our discussion in the previous section, one would expect that LΣ  X (P )will normally give the right abstraction into the alphabet of S and therefore be thecorrect process to test. Of course, if some of the events in X were signals andtherefore not delayable by the environment, it would be appropriate to use mixed
abstraction instead. We will see some important examples of this in Chapter 14.
Perhaps the right way of looking at the deadlock speciﬁcation is as an extreme
example of this: it is not that we are assuming that the environment cannot delay
any event, only that if it is testing for deadlock then it is reasonable to assume thatit chooses not to.
As discussed in Section 8.4, one of the main advantages of the abstracted
proof of deadlock freedom is the compression it often makes possible when performing a check using FDR. This is brought about by pushing the hiding as far into aparallel system as possible. The formulation of LF
H (P ) on page 303 does not directly
show how to extend these manipulations of lazy abstraction: hide-  -dist (3.8) isX

no longer directly applicable since the entire hidden set P is synchronized (with
Chaos H ) immediately below the hiding. Fortunately, however, it is possible tocombine hide-  -dist with properties of Chaos to establish rules for pushing lazyX

abstraction down through a process: see Exercise 12.2.1.
Example 12.2.1 A token ring is a parallel network organized as a ring. It is
designed so that there are a ﬁxed number of tokens that exist in the ring, each

312

Abstraction

conveying some privilege on the node containing it. For example, if there is only one,ownership of the token might permit the node to perform some critical operation
which must not be simultaneously executed in more than one place at once. (Thisis another view of the mutual exclusion problem, discussed brieﬂy on page 4.)
A very simple implementation of this might be
Empty(i ) = ring.i → Full (i )Full (i ) = ring.i ⊕ 1 → Empty(i )2 start-cr .i → end -cr .i → Full (i )
Ring

=

N −1

i=0 (Full (i )<I i = 0>I Empty(i ), Ai )where Ai = {ring.i , ring.i ⊕ 1, start-cr .i , end -cr .i }and the events start-cr .i and end -cr .i respectively represent the start and end ofi executing a critical region. The intention is that at all times exactly one process
has the token.
We might want to specify this in the alphabet CR = {| start-cr , end -cr |} as
follows:{start-cr .i → end -cr .i → Spec | i ∈ {0, . . . , N − 1}}

Spec =

Interpreted as a failures speciﬁcation, this says that the ring is always able toperform some event in CR, and furthermore the events in this set that do occur
comprise the sequencing of a number of disjoint critical regions. Of course, exactly
which process is allowed to perform start-cr .i will depend on where the token is.
We can test this speciﬁcation of the ring by the abstracted checkSpec

L{|ring|} (Ring)

This is true, and essentially says that however the passing of tokens roundthe ring is managed, Spec holds.
There will be further discussion of token rings in Exercise 13.3.3 and elsewhere. (End of example)
Exercise 12.2.1

Use the results of Exercises 12.1.2 and 12.1.6 to prove that

F
F
F
LF
H (P A B Q) = L(A∩B ∩H ) (L(H ∩A)  B (P ) A B L(H ∩B )  A (Q))

Secondly, prove algebraically thatF
LF
H (P \ X ) = (LH  X (P )) \ X12.3

Abstracting errors: specifying fault tolerance

313

Combine these two principles to produce a rule for pushing LF
H into processes ofthe form (P A B Q) \ A ∩ B .
This question is formulated in terms of F because L has the easiest CSP formulation
over this model.

Exercise 12.2.2
Let S be a divergence-free, ﬁnitely nondeterministic andprocess communicating only in H .
(a)

-free

Show that S  LH (P ) if, and only if,

S ||| Chaos H  P
Hint: use the series of results beginning on page 304 and monotonicity properties.
(b)

Show that S  LH (P ) if, and only if,

S ||| RUN H  P ||| RUN H
Hint: use a similar argument to part (a), plus the result of Exercise 12.1.6.

12.3

Abstracting errors: specifying fault tolerance

CSP is often used for modelling systems with unreliable or potentially faulty components, the intention being to overcome these errors and preserve all, or a deﬁned
subset, of their functionality. The main examples we have seen so far have been
unreliable communication media in Chapter 5, as well as subsequent further investigations of the alternating bit protocol in Sections 8.4 and 10.3.1.
The approach to error modelling used so far has been the most obvious one:
namely to make the occurrence of each error a nondeterministic choice introducedby : see, for example, the deﬁnitions of E0 on page 121 and C (in, out) on page132. In systems with potential faults it is usually the case that, if errors happen in a
totally unrestricted way, then at least some of the intended behaviour is lost. Thisis certainly true of the example designed to overcome message corruption on page
121, where we built our model of the medium so that it commits at most one error
for every three transmissions: if we had allowed the corruption of any message, thenneither the transmitter and receiver deﬁned there nor any others could overcome
this. Even the alternating bit protocol relies on there not being so many errors as
to create an inﬁnite sequence of consecutive losses or duplications. A fault-tolerantsystem created (as is common) by replicating functionality (such as processors) andusing a voting mechanism will only be immune to some ﬁnite limit of errors which
disable individual elements: plainly it will not function if all the processors are
disabled.

314

Abstraction

It is often easier to understand the relationship between the pattern of errorsthat occur and the behaviour of the entire system if the errors appear in traces. In
other words, each fault, when it occurs, is signposted by some event. It is usuallysimple to adapt CSP models of faults to reﬂect this: instead of being selected by anondeterministic choice, errors are triggered by special events placed in the alphabet
specially and not confused with the ‘ordinary’ events of the processes concerned.
Thus the loss/duplication medium C (in, out) for the alternating bit protocol would
become:CE (in, out) = in?x → (out!x → CE (in, out, x )2 loss → CE (in, out))CE (in, out, x ) = dup → out!x → CE (in, out, x )2 CE (in, out)
Each time a message is input it can be lost if loss occurs, and once it has been
output once it can be duplicated arbitrarily often if dup is communicated.
You should imagine that the events E = {loss, dup} are under the controlof some dæmon that can choose whether or not to introduce errors. We could getback to the original medium by abstracting away these events:
LE (CE (in, out)) = C (in, out)
When building a model of a faulty process where the errors are controlled by extra events, you should aim to create one where the lazy abstraction, as above,is equivalent to the version in which the errors occur nondeterministically. Conversely, if you prevent the errors from occurring by synchronizing with STOP , asin CE (in, out)  STOP , you should get a process equivalent to perfect behaviour ofEthe component in question. In this case it is a suitably renamed version of COPY .
When the components with these visible errors are put into the entire network, we can fulﬁl our wish to see directly how the occurrence of faults aﬀects runsof the system. One simply places the erroneous processes into the system and leaves
the error events unsynchronized. In cases like the alternating bit protocol, where
there are several erroneous components, it is a good idea to ensure that the error
events of each are distinct. This is so that the errors in the diﬀerent components
can be distinguished when analyzing the behaviour later. Thus the alternating bit
protocol might become
ABPE = ((S{|a,d|}(C 1E ||| C 2E )){|b,c|}

R) \ {| a, b, c, d |}

12.3

Abstracting errors: specifying fault tolerance

315

where S and R are as previously and
C 1E
C 2E

=
=

CE (a, b)
CE (c, d )[[loss , dup /loss, dup ]]We thus extend E to be {loss, loss  , dup, dup  }.
Having constructed a system with visible errors like this, we can either abstract them immediately or put bounds on the circumstances in which they occur
before doing so. It turns out that the ﬁrst of these options is what is required forthe alternating bit protocol. The lazy abstraction LE (ABPE ) is the natural one tolook at: it is well-deﬁned since ABPE is ﬁnitely nondeterministic and is, provided
R and S are correctly deﬁned as in Section 5.3, divergence-free. This form of abstraction correctly reﬂects our expectations of this protocol, namely that an error
can happen at any time but we should never rely on one happening. The fairness
assumptions built into lazy abstraction also correspond closely to the fact that the
protocol works provided the channels are not permitted to commit an inﬁnite seriesof errors. If S and R are as deﬁned in Section 5.3, it is true that
COPY

LE (ABPE )What this establishes precisely is that the alternating bit protocol reﬁnes this speciﬁcation provided only ﬁnitely many errors of any sort occur between each pair ofvisible actions. Another way of saying the same thing is that, whatever errors haveoccurred in the past, if whatever dæmon is selecting them stops doing so for longenough, the protocol will come into a state where it can make the progress requiredby the speciﬁcation.
This lazy abstraction into non-error events gives what is probably the best
general-purpose picture of the way a system with potential errors can behave under
the assumption that errors do not exclude everything else. However, what we haveshown in this case is not precisely the same as was proved in Section 10.3.1 where we
looked directly at how inﬁnite traces can analyze the protocol. There the inﬁnitary
relation was directly over the two internal channels, whereas here it is between theerrors and the external communications of the entire protocol. While the diﬀerence
does not appear to be of great importance in this example, this is not always so:see Exercise 12.3.3. It teaches us one general lesson, namely that if you want torelate the errors that occur to some internal events of your system, then you mustdelay hiding the latter until after the comparison has been made.
The best way to assume a stronger bound on error behaviour than that
expressed implicitly by lazy abstraction is by putting a constraining process inparallel with either the whole system or an appropriate part of it. Such a boundis likely to take one of two forms: either a limit on the total number of errors

316

Abstractionthat can occur through all time (perhaps with separate limits for diﬀerent types oferrors) or a limit on how many errors can occur relative to some other behaviour, inwhich case, of course, the limitation must be imposed before any of the comparative
actions have been hidden.
Imagine, for example, a supposedly fault-tolerant processor built out of four
identical units enclosed in a context which feeds them all identical inputs and gathers
all their results.3 There are at least two diﬀerent modes of failure of one of theprocessors: they might simply die in such a way that they never communicate
again (i.e., behave like STOP ) or might become corrupted so that they can berelied on for nothing, not even not communicating (the most appropriate model
then being Chaos A where A is the failing processor’s alphabet). In this latter case
we are assuming that a corrupted processor might, either through luck or, in some
applications, malice, do whatever it can to make the surrounding hardware’s job
as diﬃcult as possible. A fault of this second sort is usually termed a Byzantine
failure.
If Proc is a process modelling the correct (and deterministic) behaviour of aprocessor without faults, then(Prochalt STOP )byzantine Chaos A

gives a natural way of adding the potential for faulty behaviour. (Pinterrupt operator deﬁned on page 239.)

a Q is the

Suppose that the result of composing the entire system, together with thesefaulty components and the harness used to manage the distribution and collectionof data to and from the four processors, is FTP (fault-tolerant processor).4 The
important thing from our point of view is that the four sets of fault events are
permitted to occur freely (i.e., they do not synchronize with each other or anythingelse). We will assume that the error events have become
E = {halt.i , byzantine.i | i ∈ {0, 1, 2, 3}}
You would not expect FTP to work once all four processors have beenbrought down by faults. And Byzantine faults are likely to be harder to over3 In any application like this it is vital that the programs running on the processors are deterministic, since otherwise there might be several valid answers that the various copies could
produce, almost certainly leading to confusion in the surrounding voting hardware!
4 The mechanisms used to do this in the general case are really quite complex and would take
too long to describe for this book. One of the major issues is the extent to which the harness itself
has to be fault tolerant, since the advantages of running multiple copies of a processor are clearly
reduced signiﬁcantly if you are dependent on some unreplicated piece of hardware to achieve ‘fault
tolerance’. The mechanisms for achieving fault tolerance frequently use the timed dialect of CSP
described in Chapter 14. Some references can be found at the end of this chapter.

12.3

Abstracting errors: specifying fault tolerance

317

come than halting faults. It is, for example, reasonable to expect it to continue
working when all but one processor has halted, but it could not work when eventwo chaotic faults have appeared since the pair of faulty processors might agree ona diﬀerent answer to a problem than the pair of correct ones; plainly there is no way
for a voting system to distinguish which is right. If we wanted to prove that FTP
was tolerant of one Byzantine, or three halting, faults, the way to do this would be
to prove that
LE (FTP  Halt (3)) andE

LE (FTP  Byzantine(1))
Eboth meet an appropriate speciﬁcation (see later), where, for example
Halt (n) = halt?i → Halt(n − 1)<
I n > 0>I STOP
One of the major applications of the style of error modelling where the number of faults is limited relative to some other set of events is in timed modelling,which we will meet in Chapter 14 and where you can express a bound on how manyerrors occur in a given interval. For example, you could state that no more than 3errors occur in any 13 time units. See page 416 for more on this.
In general, if you are imposing limits on how many errors occur, it will almost
never be appropriate to make an implicit assumption that errors deﬁnitely occur.
This means that if the limit is expressed via the parallel composition
System E

 LimiterA∪E

where A is part of the alphabet of System E , then the process Limiter should neverrestrict which members of A occur. In other words,
LΣ  A (Limiter ) = RUN A
A process which satisﬁes this condition is said to be a monitor for A: its E behaviour
can depend on what it sees in A, but it will never refuse any communication in A.
If, for example, you want Limiter to express the condition that no more thanN errors occur for every M events in A, an appropriate process to use would be
Limit(E , A, N , M ) = Bound (E , A, N )  . . .  Bound (E , A, N ) (M copies)
E

E

where
Bound (E , A, n) = ?a : A → Bound (E , A, N )2 ((?e : E → Bound (E , A, n − 1))<
I n > 0>I STOP )318

Abstractionis the process which prevents more than N error events happening for every A
event. This subtle parallel composition expresses exactly the right condition on
traces via the way it synchronizes only on E : it acts as a monitor on A because
each Bound (N ) does. See Exercise 12.3.4.
The most extreme limitation on errors is to ban them outright. If E is the setof error events in a process System E modelled with visible errors (perhaps limited
in a less severe way), then
NoFaults = System E  STOP
E

represents its behaviour under the assumption that no error ever occurs. Thereis no need to abstract error events in this process since they never occur. The
reﬁnement check
NoFaults

LE (System E )has a very interesting interpretation: it says that the system, with error events
permitted to the extent allowed by the deﬁnition of System E , behaves no worse
than the error-free version. In other words, it asserts that System E is fault tolerant
to the extent that it assumes faults can occur. The deﬁnition of lazy abstraction
implies that the reverse reﬁnement relation holds for any process System E at all,so proving the above relation actually implies equivalence.
This gives a very clean deﬁnition of what it means for a process to be fault
tolerant, and it is invaluable when faced with a system for which it is diﬃcult togive a complete functional speciﬁcation in a more abstract way. In using it you
should, however, realize that simply proving a system is fault tolerant does notmean it does what you intended. All it means is that any misbehaviour which ispresent in the version with faults is also there without. For example, the process
Chaos A∪E (which is, of course, reﬁned by any divergence-free process with thisalphabet) is fault tolerant because it behaves no worse when faults are allowed than
without. Thus it is not, in general, the case that if P is fault tolerant and P
Q
then Q is fault tolerant: fault tolerance is not a behavioural speciﬁcation. (Unlike
determinism it does satisfy a distributive law – see Exercise 12.3.5.)
Thus, if faced with the problem of developing a system which combines complex external behaviour with the need for fault tolerance, you should combine theabove reﬁnement check with tests of whatever basic functional speciﬁcations (suchas freedom from deadlock and safety checks) seem appropriate. Of course, it would
only be necessary to prove these of the NoFaults version.
In conclusion to this section, it is the author’s opinion that the approach
to modelling faults as controlled by visible actions, subsequently regulated and12.3

Abstracting errors: specifying fault tolerance319

error.0

error.1

error.2

Figure 12.1 Replicating data over multiple lanes (see Exercise 12.3.1).

abstracted, gives a more ﬂexible and usually superior method than simply using
nondeterministic choices. The exceptions to its superiority are cases, such as overcoming a speciﬁed level of message corruption by replicating messages on page 121,
where (i) there is no need to specify patterns of errors above a very low level, (ii) the
occurrence of errors is suﬃciently bounded to avoid problems with divergence and(iii) the overall system behaviour is suﬃciently simple so as to make the abstract
speciﬁcation of fault tolerance above unnecessary.
By their nature, interesting complete examples of fault tolerance are moderately complex. Thus it was not possible to give as many examples in this section
as we might have wished. The interested reader can, however, ﬁnd various analyses based on the methods described in this section at the associated web site (seePreface for details).
Deﬁne a buﬀer of bits ({0, 1}) which uses three error-prone channels
as shown in Figure 12.1. Channel i, after communicating the event error .i, may corrupt(but, for simplicity, does not lose) any bit it subsequently receives. Each bit is sent
separately through the channels and voted on at the other end.

Exercise 12.3.1

Describe such a system and formulate a reﬁnement check that asserts it is tolerantof one such error.

Exercise 12.3.2

Let P be any deterministic process with alphabet A. We can deﬁne

a processreboot(P ) = P error reboot(P )320

Abstraction

which reboots itself (back to initial state) each time the event error (∈ A) occurs. Deﬁnea context rebuild (·) which, though allowing all error events to occur, is such that
P = L{error } (rebuild(reboot(P )))Hint: rebuild(Q) should record the external trace. Whenever an error event occurs
it should communicate that trace to Q so as to bring it back from its rebooted state to theone it was in before the error. Be careful to take account of any errors that occur during
this rebuilding. It is helpful to use 1 → 2 renaming on the argument Q so that some of theevents it communicates are visible, but a second copy of them is available to be used while
resetting, and hidden. Speciﬁcally, you do not want to hide the ‘normal’ actions of Q, butneed to hide the rebuilding actions.
Why is it important that P is deterministic?
Deﬁne a process Alt which alternately outputs 0 and 1 on channel c,and another Switch which inputs values on channel d and communicates the event switch
each time it inputs a consecutive pair of values that are diﬀerent. Show that, as deﬁned
in this section, with CE as deﬁned on page 314, the process

Exercise 12.3.3

((Alt
{|c|}

CE (c, d)){|d|}Switch) \ {| c, d |}is fault tolerant.
Show that this behaviour is not preserved when CE (c, d) is replaced by the medium
process CN (c, d) deﬁned on page 132 used in the original version of the alternating bit
protocol which guarantees to transmit at least one of each N messages and to duplicate
each no more than N times. How does the misbehaviour manifest itself?
This is an illustration of the eﬀect mentioned in the text by which a system isconsidered fault tolerant, using the lazy abstraction deﬁnition, if it works provided there
are no more than ﬁnitely many faults between consecutive visible actions.

Exercise 12.3.4 Prove that the traces of Limit(E , A, N , M ) (page 317) are precisely
those members s of (A ∪ E )∗ satisfying

s = s1ˆs2ˆs3 ∧ #(s2 E ) > N ⇒ #(s2 A) ≥ M

Exercise 12.3.5 Suppose P and Q are both fault tolerant (in the sense deﬁned using
NoFaults) with respect to the same set E of error events. Show that P  Q is also fault
tolerant.

12.4

Independence and security

In the ﬁrst section of this chapter we imagined the existence of two users, and formed
views of how some process P looks to one of them with the other abstracted away.

12.4

Independence and security

321

Suppose they are working in a security conscious environment, and that Hugh hasa higher security classiﬁcation than Lois. It is a problem of considerable practicalimportance to understand when information about what Hugh is doing can get toLois via their joint use of P . You can imagine the following scenarios:(a) Lois, a spy, attempts to ﬁnd out about Hugh’s interactions with P , theassumption here being that Hugh is unaware of Lois’s presence.
(b) Hugh is a ‘mole’, namely an agent working in the high security levels of his
enemies. He is trying to set up a ‘covert channel’ with Lois, who is his friendon the outside, so that the information he has learned can be relayed back totheir spy-masters. Therefore they try to use P to get information from one
to the other, and may well have agreed some code in advance.
Though the second of these is, on the face of it, the more challenging problem
for the process designer from the point of view of counter-espionage, in an absolutesense they are the same. If no information about what Hugh does ever leaks throughto Lois (i.e., P is secure in the sense (a)) then automatically no covert channel
can exist since anything a malicious Hugh does under (b) to pass information, an
innocent one under (a) might have done ‘by accident’. It is only when considering
imperfect systems that the two modes should perhaps be diﬀerentiated.
Clearly what is important is Lois’s abstracted view of P . She can only see
what Hugh is doing if what he does aﬀects what she sees. What we are trying to
specify is what one can either view non-interference (i.e., what Hugh does does notinterfere with what Lois sees) or independence (i.e., what Lois sees is independentof Hugh). The latter of these two terms is more appropriate for the applications we
now have in mind. A very clear speciﬁcation of this is simply that Lois’s view isdeterministic: you can think of Hugh as a nondeterminism resolving dæmon within
an abstraction such as LH (P ), so if the abstraction is actually deterministic thennone of his choices is reﬂected in what she sees. You should use either lazy or mixed
abstraction depending on the nature of the interface between Hugh and P .
For a ﬁnitely nondeterministic, divergence and -free process P we can thusdeﬁne
• P is lazily independent from H (written LINDH (P )) if and only if LH (P ) is
deterministic, and• P is mixed, or transaction5 independent from H , with respect to the set ofsignals S (written MINDSH (P )) if and only if MSH (P ) is deterministic.
5 The term transaction independence (used by Wulf [138]) derives from the most common useof mixed abstraction: interpreting the output phases of transactions such as those seen in thememory example on page 307 correctly.

322

Abstraction

There is a clear connection between this deﬁnition and Corollary 12.1.3, since
it is evident that the condition of separability is closely related to security. Afterall, a process which is built as the parallel composition of two processes which do
not synchronize and respectively serve only Hugh and only Lois is self-evidently
secure. Indeed, some authors have used it as one deﬁnition of non-interference/
independence. It has two disadvantages: the easier to understand is that it isclearly symmetric whereas independence is not. We do not mind Hugh being able
to see what Lois can do, since we have not banned information ﬂowing that way.
We will discuss the second disadvantage later.
The best way to understand our deﬁnitions is to see some examples. Let
L = {l, l1, l2, ls1, ls2}, H = {h, h1, h2, hs1, hs2} and S = {ls1, ls2, hs1, hs2} (theset of signal events). The following simple processes show the main ways security
and insecurity manifest themselves.

1. Let P 1 = h → l → P 1. This is insecure because LH (P 1) = Chaos {l} , which
is nondeterministic. Intuitively, this process is insecure because Lois can see
exactly how many events Hugh has performed.
2. On the other hand, P 2 = (h → l → P 2) 2 (l → P 2) is secure, since
LH (P 2) = µ p.l → p. It is not, however, separable since the abstraction into
H is nondeterministic. The fact that l can always occur means that Lois canno longer count h’s by counting l’s.
3. Deﬁne
P 3 = l1 → P 32 h1 → P 3
P 3

= l2 → P 3
2 h2 → P 3P 3 is secure since LH (P 3) = µ p.l1 → l2 → p. It is not secure in the reverse
direction since
LL (P 3) = µ q.(h1 → q)

(h2 → q)The point is that only Lois controls which state (P 3 or P 3 ) it is in, but
Hugh can detect the state by looking which of h1 and h2 is permitted. Thus
information can pass from Lois to Hugh but not back.

12.4

Independence and security323

4. The following process, unlike those seen so far, uses signal events:
P4 =l1 → ls1 → P 4
2 l2 → ls2 → P 4
2 h1 → hs1 → P 4
2 h2 → hs2 → P 4

You can think of this process as one that both Hugh and Lois can ask questions of by inputting values, and it gives them the appropriate answer backas a signal. The lazy abstraction of this process is nondeterministic, since if
Hugh could delay the events hs1 and hs2 then Lois could tell he was doingso (and had input some value). The mixed abstraction MSH (P 4) is, however,deterministic and so this process satisﬁes MINDSL (·). This is appropriate,
since its behaviour towards Lois does not depend on what Hugh has done.
5. If Hugh is certain to receive a signal at some point then the fact that he does
does not convey information to Lois. Thus the following process satisﬁes
MINDSL (·), since to Lois it looks exactly like µ p.l → p.
P 5 = hs1 → l → P 5
6. On the other hand, if Lois can tell something about which signal Hugh received, then we get an insecure process, and indeed
P6 =hs1 → l1 → P 6
hs2 → l2 → P 6

fails the mixed condition. This only applies when, as in this example, thevalue Hugh gets is not predictable on the basis of what Lois legitimately
knows.
Now look back to the memory example on page 307. The work we did there
shows that this is secure, for | T |> 1, if and only if there is no location that Hughcan write to and Lois can read. This is, of course, exactly what one might expect.
This is perhaps the simplest of a wide range of situations where our two users areboth reading and writing to some system. Some extensions that can lead to further
security diﬃculties are listed below.
• They might be reading and writing to ﬁles, which have to be created using
some name. It is possible for information to ﬂow by Lois testing, by trying
to create a ﬁle with a given name, whether Hugh has one of the same nameopen. (This assumes that either user will have a request to create a ﬁlerefused if the other has one with the chosen name.)324

Abstraction• There might be contention for resources: if what Hugh does aﬀects whether
there is room (in memory, on disk etc.) for an action of Lois to be executed,
then information can ﬂow.
• Instead of the transactions on the data being only atomic reads and writes,
they may comprise series of actions which require locks to be placed on somedata items (usually non-exclusive read locks or exclusive write locks). If
Hugh were to place a read lock on a location Lois wants to write to, then it
is possible for information to ﬂow.

All of these situations have been dealt with successfully via the methods describedin this chapter. For more details, see [123, 138] and the worked examples on the
web site (see Preface).
Example 12.4.1 (sharing a communication medium) Interference, and hence
information ﬂow, can also appear in other applications where high-level and lowlevel processes share resources. One of these is shared communication media. Suppose Hugh and Lois respectively want to send messages to Henry and Leah, whoshare their security clearances. Consider the network
Comm 1 = ((SendH ||| SendL){|in|}

Medium){|out|}(RecH ||| RecL)

where
SendL

= send .lois?x → in.lois.leah!x → SendL

SendH= send .hugh?x → in.hugh.henry!x → SendH

RecL = out.leah?x → rec.leah!x → RecL
RecH
Medium= out.henry?x → rec.henry!x → RecH
= in?s?t?x → out!t!x → Medium

Even though the high-level processes cannot send messages to the low-levelones through this system, it does not satisfy the obvious lazy security property.
Despite the buﬀering provided at the two ends, it is possible for the high-levelprocesses to block up the network if Henry refuses to accept the messages that
arrive for him. This means that the low-level lazy abstraction is nondeterministic:
the low-level processes can detect certain high-level activity via their own messages
being blocked.
The following two solutions illustrate much more widely applicable methods
for overcoming security problems which arise, like this one, from contention forresources.

12.4

Independence and security

325

The ﬁrst solution is simply to give the low-level users priority in access toresources: we could replace the process Medium byMedium2 = in.lois?t?x → out!t!x → Medium2
2 in.hugh?t?x → Medium2 (t, x )Medium2 (t, x ) = in.lois?t  ?x  → out!t  !x  → Medium2
2 out!t!x → Medium2
This simply throws away any high-level communication that is sitting in the medium
when a low-level one comes along. In the revised system, Comm 2 , the low view
becomes deterministic (it is a 3-place buﬀer), but there is the great disadvantage
of losing some high level messages. That in turn can be got around by a further
revised medium informing a modiﬁed SendH whether each message got throughsuccessfully or not, with each thrown-away message being resent.
SendH 3
SendH 3 (x )= send .hugh?x → in.hugh.henry!x → SendH 3 (x )= ok .hugh → SendH 3
2 ref .hugh → in.hugh.henry!x → SendH 3 (x )Medium3 = in.lois?t?x → out!t!x → Medium3
2 in.hugh?t?x → Medium3 (t, x )Medium3 (t, x ) = in.lois?t  ?x  → ref .hugh → out!t  !x  → Medium3
2 out!t!x → ok .hugh → Medium3
This addition, producing Comm 3 , preserves security and re-establishes thelink between Hugh and Henry as a trace-correct buﬀer (with capacity reduced from
3 to 2). Except for this reduction in capacity, the system now gives essentially thesame behaviour towards Hugh and Henry as did the original system, but Lois andLeah cannot now detect what the high-level users are doing.
Attaining security by giving priority to low-level users will not be an ideal
solution in many cases. The system designer has to decide, on pragmatic grounds,
whether it is better or worse than the other solution, which is to limit individual
users’ access to the system suﬃciently that low-level users are never further restricted by high-level activities. In a ﬁle system one might, with an overall disk
capacity of N , allocate M units to high-level users and N − M to the low-level ones.
The analogy in our communication example is to use ﬂow-control to prevent either
user deadlocking the system. We reprogram the sender and receiver processes sothat the sender waits until it gets a message back from the receiver before it next
accepts an input on send , and the receiver does not send such a message until
it knows it will be able to accept another message. The following processes canbe combined with the original Medium (from Comm 1 ): the content of the reverse

326

Abstraction

messages is irrelevant.
SendL4= send .lois?x → in.lois.leah!x → out.lois?x → SendL4

SendH 4= send .hugh?x → in.hugh.henry!x → out.hugh?x → SendH 4

RecL4= out.leah?x → rec.leah!x → in.leah.lois.Zero → RecL4

RecH 4= out.henry?x → rec.henry!x → in.henry.hugh.Zero → RecH 4

The resulting Comm 4 is not only secure, it is separable and equivalent to thecomposition of a one-place buﬀer (i.e., COPY ) between each of the two pairs ofprocesses. Note that the medium is used more than previously, since two internal
messages are required for each external one, but it is used more carefully as eachtime one of the four processes around it sends a communication to it on in, it is
impossible for the resulting out to be refused. (End of example)
We have seen that the natural speciﬁcations of both security and fault tolerance involve similar ideas. They are, in fact, closely related speciﬁcations. Suppose
LINDH (P ) holds. The determinism of LH (P ) easily implies that it equals
LH (P  Q)
H

for any divergence-free process Q with alphabet H . This is reassuring, since itmeans that what Lois sees does not depend on what high-level process we put inparallel with P . It also means that
LH (P ) = P  STOP
H

and so P is ‘fault tolerant’ if you think of the high-level actions as the errors. This
is not surprising, since if there is no way of telling, by looking at the pattern of aprocess’s behaviour in its non-error alphabet, what, if any, errors have occurred,then it must be fault tolerant!
On the other hand, a process can be fault tolerant without the abstraction
LE (P )
being deterministic, so the reverse implication does not hold. The diﬀerence is that,when considering fault tolerance we have an inbuilt standard to judge the processagainst, namely the way it behaves without errors. If it should happen that someerror resolves a nondeterministic choice which would have had to be made anyway,
this does not matter in judging fault tolerance, but it might convey information to
the user about the pattern of errors. See Exercise 12.4.2 for a class of examples.

12.4

Independence and security

327

In real applications one will frequently have more than just the two security
levels we have modelled in this section. One could have any number with a partial
order security policy relating them: user Ui ’s behaviour can aﬀect Uj if and only ifclearance(i ) ≤ clearance(j ). There is, however, no need to extend our theory further
since all you have to do is to show that, for each security level λ, the collection of
all users with this level or below is independent of the collection of all the others.
Thus you simply look at a series of two-way partitions of the overall alphabet. For
example, if there is another user Mhairi with alphabet M whose clearance is midway between Hugh’s and Lois’s, then to establish security of a process P you should
prove
LINDH ∪M (P ) and

LINDH (P )i.e., neither Hugh nor Mhairi can inﬂuence what Lois sees, and Hugh cannot inﬂuence what Lois and Mhairi see.
The limitations of security modelling
Security modelling is a subject full of philosophical diﬃculties, and just about all
speciﬁcations of what it means for a process to be ‘secure’ can be criticized in one
way or another. A general text is not the place to go into this in detail, but it is as
well to understand just what our particular speciﬁcation can and cannot do.
First and foremost, a security speciﬁcation couched in a particular model canonly reﬂect information ﬂow via the sort of behaviour the model records. The mostobvious thing missing from the models we have used is timing information, and it
is certainly possible to construct examples which appear secure over N which one
would suspect might contain ‘timing channels’ if implemented in the obvious way.
The various secure communication examples above, such as Comm 4 , come into thiscategory as the low users will presumably get a variable bandwidth depending on
the level of activity of Hugh and Henry.
By and large, the more detailed a model one chooses, the more complex
both process modelling and security analysis become, and (presumably) the more
likely we are to ﬁnd small ﬂaws in security. All one can do is to pick one’s model
intelligently and be aware of the limitations built into the choice.
As we will see in Chapter 14, it is possible to take time into account in modelling CSP. There is no reason in principle why the determinism-based speciﬁcation
could not be used to specify security over that sort of model too.
There is a clear sense in which the determinism-based condition can be viewed
as too strong. It only deﬁnes as secure those processes whose low view-point is deterministic. However, it is undoubtedly possible to build a secure process whose328

Abstraction

low-level abstraction is nondeterministic, since the mechanism resolving the nondeterminism has nothing to do with how the high interface behaves. For example,
there are many separable processes whose low-level abstraction is nondeterministic,
and clearly any process implemented as an interleaving of entirely disjoint high andlow-level processes is secure. In this sense,
Chaos H ∪L = Chaos H ||| Chaos L
is secure.
The point you should try to understand, however, is that just because one
implementation of a given process is secure, this is no guarantee that all are. For
example, if LEAK is any divergence-free process whatsoever, for exampleµ p.hugh?x → lois!x → p
you would not naturally think of
Chaos H ∪LLEAK

as secure since it is free to behave like LEAK every single time it is used. The
above process is, however, equivalent to Chaos H ∪L , and we thus have two process
deﬁnitions that none of our semantic models can tell apart, one being plainly secureand one insecure. Perhaps the problem is that our models go to great lengths torepresent nondeterminism as abstractly as possible, and speciﬁcally do not give us
information about whether a given nondeterministic decision is resolved innocently
or in a way that allows information to ﬂow.
A number of authors have attempted to deﬁne conditions to decide whether
a general CSP process is secure in the sense we have being trying to capture. Invariably these conditions are satisﬁed by Chaos H ∪L , even though this process is
reﬁned by many others which do not satisfy them. We might call this the reﬁnement paradox. The idea that P can be secure and Q  P insecure is contrary to
all our understanding of what reﬁnement means. Reassuringly, it is true that if
LINDH (P ) and P Q then LINDH (Q), because by constructionP

Q ⇒ LH (P )LH (Q)and the only reﬁnement of a deterministic process is itself. In truth, it simply is notpossible to determine whether a general process is secure by looking at its value inthe standard denotational models of CSP.
A good analogy is provided by deadlock freedom: if P is deterministic you
can tell if it can deadlock by looking at its value in T , but for general processes youneed a richer model like N . Similarly, if P is low-deterministic6 in the sense that
6 Any deterministic process is low-deterministic, as is any process satisfying LIND (·).
H

12.4

Independence and security329

for all traces s and a ∈ Lsˆa ∈ traces ⊥ (P ) ⇒ (s, {a}) ∈ failures ⊥ (P )then you can accurately decide whether or not it is secure from its value in N . For
values outside this class, like Chaos H ∪L , they do not give enough information.
Just how much ﬁner a model is required to deal with the general case isdebatable: certainly you need something about as ﬁne as that provided by theoperational semantics in Chapter 7, and arguably you should incorporate probability
as well. In any case it is very unlikely that such an attractive, persuasive, or
practical (thanks to FDR’s ability to check determinism: see page 225) deﬁnition
can be found.
Recall from page 317 that a monitor for a set A of events is one that
Exercise 12.4.1
never refuses any member of A. Say that P is semi-separable with respect to (H , L) if there
is a monitor M for L and a process PL using only events from L such that P = M PL .
L(a) Show that if P is separable then it is semi-separable.
(b) Suppose P is semi-separable (into (M , PL ) as above) with respect to (H , L). Show
that LH (P ) = PL for such P . Deduce that if PL is deterministic then LINDH (P )holds.
(c) Now suppose that P is such that LINDH (P ). Let M be the process whose failuresare{(s, X ∩ H ) | (s, X ) ∈ failures(P )}∪ {(sˆlˆt, Y ) | Y ∩ L = {} ∧ s ∈ traces(P ) ∧ lˆt ∈ L∗ ∧ l ∈ initials(P /s)}
LH (P ) and hence that P is semi-Show that M is a monitor such that P = M
Lseparable.

Exercise 12.4.2
Let P be any divergence-free process with alphabet H ∪ L. Show
that P  = P  Chaos L satisﬁes the deﬁnition of fault tolerance
P

STOP  LH (P  )H

but need not be secure.7
7 There are a number of deﬁnitions of ‘security’ in the literature which would deﬁne such P  tobe secure for all P , even though if with P = LEAK from page 328, for example, you can guaranteethat if Hugh communicates anything with P  , then Lois gets to hear it.

330

12.5

Abstraction

Tools

With the exception of the ﬁne distinctions made at the start by the interpretationof abstraction over inﬁnite traces, just about everything in this chapter is relevant
to FDR. The ways of structuring the checking of speciﬁcations using abstraction
both helps in formulating the properties you want of processes and in using thetool’s compression functions (see Section C.2).
We have seen various applications of determinism checking in this chapter,in the sense that it has been used to characterize security and separability. FDR’s
ability to check determinism was included mainly because of these results. Notethat because of the way lazy and mixed abstraction are formulated it will often benecessary to use the stable failures model F for these determinism checks, just as it
is used for reﬁnement checks involving abstraction. For the only formulation of lazy
abstraction which can be rendered in ﬁnitely nondeterministic CSP is the one on
page 303 which, if interpreted over N , often introduces false divergences that would
confuse FDR. This means that you are, in fact, checking a process that might welldiverge for F-determinism as discussed on page 221. This is only a technicality,
however, since the F-determinism of LF
H (P ) is equivalent to the (true) determinismof the other two formulations of LH (P ).
All the signiﬁcant examples from this chapter, and several larger applicationsof the deﬁnitions of fault tolerance and security, can be found on the web site.

12.6

Notes

The work in this chapter has developed over the past three years, with many of theresults arising from Lars Wulf’s doctoral studies with the author: his thesis provides
by far the most extensive study of the compositional properties of abstraction andits application to security. Jim Woodcock was very inﬂuential on the early phasesof this work.
The precise formulations of lazy and mixed abstractions in this chapter arenew. They are direct descendants of the versions used in [109, 123, 124] which werebased on a deﬁnition of lazy abstraction using interleaving:|||

LH (P ) = P ||| RUN H
The intuitive justiﬁcation for that form of abstraction is that the process RUN H
camouﬂages events in H : you can never get any information about P from such an
event occurring since it could always have come from RUN H .
The one advantage of the earlier version is that it is easily deﬁnable using
standard operators over N , while we have had to compute ours over F (in the

12.6

Notes

331

knowledge that the N version is, in fact, the same). It has at least three disadvantages. The ﬁrst is that it is not natural to have an abstraction into L performing
lots of events in H , with the consequence that many of the results and deﬁnitions
we have formulated do not work as neatly since they have to take account of the
camouﬂage events. The second is that the corresponding way of lifting a speciﬁcation on L to one on the whole alphabet (implied by the second part of Exercise
12.2.2) does not lend itself nearly as well to facilitating compression.
|||

The third and main disadvantage is that LH (P ) is not quite abstract enough:it identiﬁes strictly less processes than LH (P ). If the event l ∈ L is only possible
after h ∈ H this is still true of the interleaving abstraction. Thus if
l → STOPP1= STOPP2= h → l → STOP

P3

= h → h → l → STOP|||

we have that LH (Pi ) are all the same, but LH (Pi ) are all diﬀerent. The interleavingbased abstraction of P1 has the trace l, whereas the shortest traces of the otherabstractions containing an l are respectively h, l and h, h, l. Intuitively, theinterleaving deﬁnition gets this wrong since surely all these three processes actually
do look the same in L.
Having seen this example you might wonder why the interleaving deﬁnition
was ever used, but in fact this diﬀerence does not show up in three of the mostimportant applications of lazy abstraction. Thanks to the result contained in thesecond part of Exercise 12.2.2, noting that
NoFaults = P  STOP
E

never communicates in E , we get that P is fault tolerant in the sense describedearlier if and only if|||

LE (NoFaults)|||

LE (P )

So it yields an identical deﬁnition of fault tolerance.
|||

It can be shown that LH (P ) is deterministic if and only if LH (P ) is. Thisis left as an (interesting) exercise. It follows that independence deﬁned in terms ofthe determinism of either abstraction is identical, and that a deterministic process||||||
is separable if and only if both LH (P ) and LL (P ) are deterministic.
An example of the use of abstraction in formulating fault tolerance properties
can be found in [141]. Earlier fault tolerance case studies such as [14] have used
speciﬁcations crafted to the examples under consideration.

332

Abstraction

There have been numerous deﬁnitions of security, in the sense of independence/non-interference, over CSP models. Several of these, namely those of [125, 2,
44, 38] turn out to be equivalent to ours for deterministic P , though they usually
make the decision to extend their deﬁnitions over all processes rather than restricting them to the low-deterministic processes or a subset. That usually leads to theirconditions passing processes that appear decidedly suspect.
An exception to this problem is the work of Forster [38], who develops conditions on labelled transition systems that are both equivalent to ours for lowdeterministic processes and which are extremely careful not to admit any insecure
processes – at least provided one interprets labelled transition systems in a particular way. That is, he insists that when a process’s operational semantics produce agiven labelled transition system, all the potential behaviours displayed in the LTS
must actually be possible in every implementation. In other words, there must be
no implementation decisions taken that reﬁne away some options. In this possiblistic view of processes, where the range of potential behaviours may not be reduced,
the concept of reﬁnement more-or-less has to be discarded. While this is hardly
welcome, the fact that we lose the reﬁnement paradox with it is some compensation.
His conditions themselves are very simple in concept. They essentially statethat the result of each high-level action in any state σ is equivalent, in the lowview produced by banning all subsequent high actions, to the same low view of σ.
Though generalisations of lazy independence, they are nevertheless still very strong
conditions, perhaps chieﬂy because they look at LTS’s as basically sequential things
where all actions subsequent to a given one are inﬂuenced by it. Perhaps for thatreason they seem to be good at handling examples in which nondeterminism is used
to mask8 potential insecurities arising in the low-level user’s interactions with thesame process in a network, but not at handling ones in which the nondeterminism
is introduced by a diﬀerent one.
Forster named his conditions (there are variations based on diﬀerent processequivalences and diﬀerent ways of handling the case where a given state has several
copies of the same high-level action) local non-interference. An implementation ofperhaps the main variant has since been included in some versions of FDR.
Both Forster’s thesis [38] in which the conditions are described in detail, andseveral example ﬁles, can be found via the web site of this book.
Though we have, of course, couched our determinism-based deﬁnition of security in the models of CSP, one can argue that it is largely independent of which
8 This typically means that an analysis is done to discover what range of behaviours might bevisible to low as a result of diﬀerent high-level choices, and we ensure that these choices are always
present whatever high has done.

12.6

Notes

333

process algebra equivalence is used. This is explained in [109] and illustrated in[37].
2005: The work on noninterference in this chapter has recently been extended
to timed processes of the form found in Chapter 14.

Part III

Practice

Chapter 13

Deadlock!

We have already met several examples of deadlock, which is certainly the bestknown pathology of concurrent systems. It is also – probably for this reason – themost feared. A system becomes deadlocked when no further progress can be made.
We distinguish it from livelock, where an inﬁnite amount of internal progress isbeing made without any interaction with the external environment, even thoughfrom the outside a deadlocked and a livelocked system look similar. Internally thetwo phenomena are quite unalike, meaning, for example, that diﬀerent techniques
are needed for analyzing when they can appear.
In the ﬁrst section we ﬁnd out how deadlock arises, how to eliminate deadlocks arising for local reasons, and hence how to eliminate deadlock in tree networks.
There are various useful ad hoc conditions on networks, many based on orderings,
which can be used to eliminate deadlock; these are surveyed in the second section. The third section looks at some more general global techniques for deadlock
avoidance. The fourth shows how the construction and topology of a network cansometimes allow us to factor its deadlock analysis into a number of smaller parts.
The ﬁfth section looks at the limitations of the style of local analysis we advocate.

13.1

Basic principles and tree networks

13.1.1

Assumptions about networks

We cannot detect or reason about deadlock using traces alone. After all, for any
process P ,traces(P ) = traces(PSTOP )

338

Deadlock!

and the right-hand side can deadlock immediately whether or not the left-hand sidecan. Deadlock is best described in the stable failures model of CSP, where it isrepresented by the failure (s, Σ ∪ {}) for s any trace in Σ∗ . (The fact that aprocess does nothing after it terminates should not be regarded as deadlock.) In
fact, systems in which both deadlock and termination are simultaneously an issue
are (at least in the author’s experience) very rare and it would be an unnecessary
complication to have to deal at every turn with the case of processes or networks
terminating. This leads us to make the ﬁrst of a number of assumptions about
the sorts of network we are dealing with. These are all things we will assume
throughout the ﬁrst four sections of this chapter, since they all help in pinning
down and reasoning about deadlock in realistic systems.
(A) Throughout this chapter we will assume that none of the component processes of our networks can terminate (though this does not preclude them
being constructed out of sub-processes that can).
Deadlock is a static condition: when it happens no process is making progress
and, in particular, both the shape of the network and the states of all the processes
in it are, from that moment, ﬁxed. This leads to our second assumption about the
networks we are considering:(B) We will consider only statically-deﬁned networks  (Pi , Ai ), where thei=1
communications of Pi are entirely within Ai .
nThis does not mean we are excluding dynamically-growing networks such as those
we can build with piping and enslavement, merely that one would have to take asnapshot of such a network at the moment of deadlock and think of it in our new
terms. The use of the alphabetized parallel operator means we have excluded uses
of ||| and  where there are some events that can be communicated independently
X(i.e., without synchronization) by more than one process. We want to know exactly
which process or processes participate in each event. The majority of practicaluses of  and ||| could be written in this way since they do not use the powerXof those operators to introduce ambiguity about which process performs an event.
In practice we will allow the use of these operators as long as the network could
have been built using the alphabetized parallel operator. What we have done isto concentrate on ‘realistic’ style compositions, at the expense of forms of parallel
composition which are mainly used for establishing speciﬁcation eﬀects. This isequally true of our next assumption:(C) We will consider only networks that are triple-disjoint, meaning that there
is no event that requires the synchronization of more than two processes. In

13.1

Basic principles and tree networks

339

other words, if Pi , Pj and Pk are three distinct nodes in the network, thenAi ∩ Aj ∩ Ak = {}.
Thus all events are either communications between a pair of processes, or are simple
interactions between a single process and the environment. All interaction within
the network must be point-to-point. The main thing that this excludes is the useof parallel composition as the many-way conjunction of trace speciﬁcations.1
Implicit in assumption (B), but suﬃciently important that it should be stateddirectly, is the following:(D) We consider only networks built using parallel composition from their component processes. In particular, they contain no renaming or hiding.
Since the majority of networks one meets in practice violate this, especially becauseof the hiding of internal communications, this looks like an over-strong assumption.
The reason why we make it is to allow us to concentrate on a single central case andto see the communications of all the component processes of a network directly. Twobasic facts and a series of laws mean that we can always transform any reasonablenetwork into one which is, from the point of view of deadlock, equivalent and whichmeets condition (D). The two facts are:• P is deadlock-free if, and only if, P \ X is for any X ⊆ Σ. (P \ X may beable to diverge when P cannot, but see Section 8.4.)• P is deadlock-free if, and only if, P [[R]] is for any alphabet transformation R
which contains all of P ’s events in its domain.
Intuitively these are both obvious: since deadlock means reaching a state where noaction of whatever name and whether visible or invisible is possible, it does notmatter if the actions are renamed or hidden.
The laws referred to are just hide-X Y -dist (3.7), f [·]-X Y -dist (3.10),
f [·]-hide-sym (3.11), and f [·]-hide-null (3.12).
These usually allow us to move all the hiding to the outside of a parallel
composition, and all the renaming onto the individual component processes. The
hiding is then irrelevant from the point of view of deadlock, and the renaming simply creates new (and necessarily busy if the originals were) component processes.
(Two of these laws are restricted to 1–1 renaming, but fortunately it is that sort ofrenaming which is generally used in the construction of realistic models of implementations – typically modularized into operators like >> and //.) An example isgiven at the end of this chapter in Section 13.7.
1 In that case, deadlock is likely to arise because of ‘inconsistency’ in the speciﬁcations: they
allow a trace s but no continuation of s.

340

Deadlock!
Our ﬁnal assumption is much easier to understand than the one above:(E) We assume the network is busy, deﬁned to mean that each component process
is deadlock-free.
While there are many deadlock-free networks that do not satisfy this, the deadlocks
occurring in their individual processes usually fall into one of the following two
categories:• states (often error states) which in fact – and often because of the correctfunctioning of the network – the component process never reaches; and• the component process that is deadlocking is one (most often the process
STOP itself) which is an ‘extra’ process designed to prevent some undesirable
event from happening in the main network.
In the second case one can usually (and always when the oﬀending process is STOP )just redesign the individual processes so that they simply avoid the oﬀending behaviour rather than require an externally imposed ban. To expect a deadlock analysis technique to be able to handle the ﬁrst case is like using a screwdriver to hammer
in a nail – one should not expect it to be able to analyze trace conditions of individual component processes. Thus this assumption of busy-ness is a reasonable
starting point for examining deadlock behaviour per se.
Finally we make an assumption about the way we describe processes rather
than about the processes themselves. The concept of a channel in CSP is rather
broad, and in general many processes may share events from the same channel (i.e.,
the events c.x for the name c) even when the network is triple-disjoint. This is
typically because the name c really represents an array of ‘real’ channels. Throughout our discussions of deadlock, the word channel will be restricted to this ‘real’
sense: a collection of events used either by a single process to communicate withthe environment, or by a pair of processes to talk to each other. In other words,
any channel that intersects the alphabet of a process is contained in it. There isalso the implication in the word ‘channel’ that communications over it are somehow
well-behaved and co-ordinated. This is an idea we will be able to make clearer atthe end of the next section.
This completes our base assumptions. Though they may seem severe, theintention is only to concentrate on the central cases of deadlock and to give ourselves
a common language to talk about the systems we are considering. In fact we willﬁnd that the methods used to combat deadlock are often phrased in a way that is
not speciﬁc to our tightly-deﬁned class of networks, merely to the class of networks
that could be transformed into it in the ways described above.

13.1

Basic principles and tree networks

13.1.2

341

Ungranted requests and conﬂicts

The assumption of triple-disjointness gives particular importance to the concept of
a communication graph, something we ﬁrst discussed in Section 2.2, for this graph(a node for each process and an edge between a pair if their alphabets intersect)now ‘shows’ all the interactions between processes. The essence of any deadlock
state will be the collection of requests for communication that processes are making
to each other along the edges of this graph.
We might as well assume that this graph is connected (i.e., that there is a paththrough the edges between any chosen pair of nodes). If it were not connected thevarious connected components into which it divides can be thought of as completely
independent processes from the point of view of deadlock analysis.
Since deadlock is a static phenomenon, we can examine the ﬁxed state inwhich it occurs. Each component process is in a state which we can add to thecommunication graph. Because of our assumption of busy-ness, each process must
be able to perform some action. In general this might be either one which does
not require the agreement of any other process or (because of triple-disjointness)
one which requires the agreement of exactly one other process. The ﬁrst of these(which breaks into two cases: internal (τ ) actions and ‘external’ communications)cannot be the case in a deadlock state since there would be nothing in the network
preventing the action – meaning that it was not deadlocked. Therefore every process
must have one or more requests to other processes – necessarily ones that do notagree to any of the requested actions.
Thus, all of the interest in a deadlock state is concentrated on the set ofcommunications that are shared by two processes: we will call this set{Ai ∩ Aj | i = j }the vocabulary of the network.
Suppose P and Q, with alphabets A and B , are processes in the network
which can communicate with each other (i.e., A ∩ B = {}). We deﬁne an ungranted
request to exist from P to Q in the state σ (the details of which we will discuss later),σwritten P =⇒•Q, if neither process can communicate outside the vocabulary of the
network; P can communicate in B but they cannot agree on any communication in
A ∩ B.
Ungranted requests are the building blocks of a deadlock. We can form asnapshot graph of a deadlock by superimposing the (directed) arcs representing them
onto the communication graph. A possible example is shown in Figure 13.1 (where
the dotted lines represent edges of the communication graph with no ungranted
request). We should notice that any ungranted request which appears between a342

Deadlock!

c

d

e

b

a
Figure 13.1 Typical snapshot graph of a deadlock state.
pair (Pi , Pj ) of processes in the entire network can also appear when Pi and Pj are
put in parallel (only) with each other.
There are very good reasons why as much as possible of the analysis (whether
for deadlock or anything else) of a large network should be done locally rather thanconsidering the whole system all the time. The patterns of behaviour that occur
between small and localized collections of processes are much easier to understandboth for humans and computer tools – the latter because of the state-space explosion
which occurs as networks grow. The various assumptions (A)–(E) above are allconditions that apply to an individual process (i.e., are local in the strongest sense),
and it is clear that enumerating the ungranted requests between pairs of processes
is also very local.
Start from any process P0 in a deadlocked network. It has an ungranted
request to another process P1 , which in turn has an ungranted request to some P2 ,and so on. Since the network we are looking at is ﬁnite this sequence must repeat,
giving a cycle of processesPr , Pr +1 , . . . , Pr +s−1 
where Pr = Pr +s . This simple argument, and the chains and cycles of processes it
creates, are central in deadlock analysis.
Look again at Figure 13.1. Wherever you start here, and whatever choices13.1

Basic principles and tree networks

343

Two nodes in conflict (both may have external requests)

Strong conflict (at most one may have external requests)

Figure 13.2 Illustrations of conﬂict and strong conﬂict.
are made about which requests to follow, the sequence leads to one of two cycles:
either a, b or c, d , e. The latter is very much what we might have expected, but
one might well regard the former as rather peculiar: an adjacent pair of processes
each waiting for the other. This can, of course, happen when the intersection of apair’s alphabets has size greater than 1 (consider the processes µ p.a → b → p andµ q.b → a → q placed in parallel). There are two variants of this situation thatneed to be studied separately.
• We say that a pair of processes are in conﬂict if each has an ungranted request
to the other, no matter what other requests they may have.
• They are in strong conﬂict if, additionally, one of the two processes in conﬂict
has its only ungranted request to the other. (Note that the pair a, b are instrong conﬂict.)
These two situations are illustrated in Figure 13.2.
One can search for potential conﬂicts and strong conﬂicts between a pair ofneighbours by looking at their binary parallel composition. They are said to be freeof conﬂict (respectively free of strong conﬂict) if the appropriate situation neveroccurs. (Note that the vocabulary of the entire network is necessary to judge thesethings since it aﬀects whether a given state is formally an ungranted request. In
practice the escape clause this can provide is rarely used, though it certainly can
prove invaluable.) A network is free of (strong) conﬂict if all its constituent pairs
are. Notice that this is another example of a locally-checkable property.

344

Deadlock!

As we will see in the rest of this chapter, these are extremely useful properties for a network to have. Most well-designed systems, except ones with rather
symmetric communication patterns, are (or can readily be made) conﬂict-free. For
example, any pair of processes connected by a single channel will be conﬂict-free (except in unusual circumstances where the inputter can select which inputs it wants),
as will any pair where both sides agree on the sequence of channels/events to becommunicated (with the same caveat).
Note that freedom from strong conﬂict is a weaker condition than conﬂict
freedom. (It is better to avoid the potentially ambiguous phrase ‘strong conﬂict
freedom’ so as not to get confused about this.) Since to fail it there must be
one process Q which is willing to communicate only with another one, P , which
strangely oﬀers some communication to Q but none that Q can accept, this is acondition which is met by the great majority of practical networks. And the few
correctly functioning networks that fail to satisfy it can invariably (at least in theauthor’s experience) be redesigned so that they do satisfy it without changing the
behaviour of the network at all. The author believes it should be adopted as adesign principle for parallel networks.
Example 13.1.1 (dining philosophers) One of the ﬁrst examples of deadlock
we saw (in Section 2.2.1), and certainly the best known generally, is the ﬁve dining
philosophers (the number of philosophers, as it turns out, being immaterial). We
look at it again here because it turns out to be an excellent example for illustrating
the design principle discussed above.
The basic example described earlier is easily shown to be conﬂict-free. The
only pairs of processes we have to examine are adjacent FORK j and PHILi processes(i ∈ {j , j ⊕ 1}), and both of these agree that the sequence of communications
between them will be a potentially unbounded alternating sequence of picksup.i .jand putsdown.i .j events. Since they always agree on what their next communication
will be, they can never be in conﬂict.
The situation becomes much more interesting if we adopt one of the standard
ways of avoiding the deadlock: the introduction of a BUTLER process whose duty
it is to prevent all the philosophers sitting down simultaneously. Perhaps the mostobvious deﬁnition of this process is BUTLER 0 , where
BUTLER n= (sits?i → BUTLER n+1 <I n < 4>I STOP )n
2 (getsup?i → BUTLER n−1 <I > 0>I STOP )This process just keeps a count of how many philosophers there are at the table,
allowing another as long as there are no more than three already there, and allowing
one to leave as long as there is any there. This process works: if it is put in parallel13.1

Basic principles and tree networks

345with the network described in Section 2.2.1, synchronizing on {| sits, getsup |}, theresult is deadlock-free.
This solution has much more the feeling of a patch put on to cure the observed
deadlock than of a network designed from ﬁrst principles to be deadlock-free. It isrelatively easy to ﬁnd the right patch for this example since there really is only one
deadlock possible in the original system (as well as there only being one cycle in thecommunication graph), but on more complex systems it would be relatively harder.
For that reason we will, in the rest of this chapter, concentrate on ways of building
systems that are intrinsically deadlock-free rather than on removing deadlocks after
they have been introduced.
The network augmented by this deﬁnition of BUTLER, perhaps surprisingly, contains strong conﬂicts between the new process and philosophers. These
arise when four philosophers are sitting down and the ﬁfth (PHIL0 say) wants tosits down. The BUTLER quite correctly refuses, but also (on close examination,
bizarrely) is quite happy to let PHIL0 get up from the table (the event getsup.0),
an event that this philosopher in turn refuses, not being at the table! Because thesetwo processes each have an ungranted request to the other, this is a conﬂict; because
PHIL0 has no other request it is a strong conﬂict.
We can remove this by a slightly more careful deﬁnition of BUTLER: it
becomes BUTLER  ({}), where
BUTLER  (X )=(sits?i : ({0, 1, 2, 3, 4}  X ) → BUTLER  (X ∪ {i })<I | X |< 4>
I STOP )2 getsup?i : X → BUTLER  (X {i })This is designed so that it does not make oﬀers to philosophers that it should know
they cannot accept. The behaviour of the network with BUTLER  is identicalto that with the other; the new network is, however, more amenable to deadlock
analysis. (End of example)
We can easily transfer the notion of conﬂict freedom to a single channel
connecting two processes. This will be when the two processes cannot both oﬀer
communication on the channel without agreeing on at least one event in the channel. This deﬁnition is more focused than simply saying that the two processes are
conﬂict-free since it ignores the other channels they may have and their external
communication. However, we can say that if two processes are only connected by asingle conﬂict-free channel then they are conﬂict-free.
Channels that are not conﬂict-free, while easy to give examples of, are asomewhat counter-intuitive concept. From the point of view of deadlock analysis it
will sometimes be helpful to assume all channels are conﬂict-free.

346

Deadlock!

Formal deﬁnitions
Many of the concepts in this section have been deﬁned more in words than in mathematical notation. Though hopefully these words have clearly expressed what we
wanted, it is important that we can formalize our reasoning within our mathematical models. While the concepts and deﬁnitions in this section may help clarify
things for the mathematically inclined reader, it is only necessary to understandthe concepts below if it is intended to pursue deadlock proofs at a very formal level.
The rest of this chapter does not depend signiﬁcantly on the precise deﬁnitions
below; other readers can safely proceed to the next section.
As discussed earlier, the model we are using here is the stable failures model
F where (except for the special case of  actions which is irrelevant to this chapter
because of assumption (A)) a process is identiﬁed with the sets(i) of pairs (s, X ) such that it can perform the trace s and then reach a stablestate where it cannot perform any action from X , and(ii) of its ﬁnite traces.
The network V =  (Pi , Ai ) is deadlocked when it has the failure (s, Σ)
i=1
for some s ∈ Σ∗ . (Our assumption that no Pi can terminate means that we canignore the refusal of , which must now be refused in every stable state.) We
nknow (from the failures deﬁnition of the parallel operator) that s ∈ ( i=1 Ai )∗ ,that si = s  Ai ∈ traces(Pi ) and that there are refusal sets Xi such that (si , Xi ) ∈failures(Pi ) andnni=1 Ai=n

i=1 Ai ∩ Xi

(In general there may be many diﬀerent combinations of Xi that work here.) A deadlock state is the pair (s, X1 , . . . , Xn ): it allows us to see how each Pi contributed
to the deadlock. Except in quite exceptional circumstances, where both Σ is inﬁnite
and the deﬁnitions involve unbounded nondeterminism, we can assume that all thecomponent failures (si , Xi ) are maximal in the sense that there is no Y ⊃ Xi with(s, Y ) ∈ failures(Pi ). We can and will always assume that Xi ⊇ Σ  initials(P /si ).
In the common case that a Pi is deterministic, the only option is to set
Xi = Σ  initials(Pi /s).
We can generalize the above notion of deadlock state to look at how any
failure of a parallel composition arises:
Definition A state of 
• s ∈(ni=1(Pi , Ai ) is a pair (s, X1 , . . . , Xn ) wheren∗i=1 Ai ) ,• (s  Ai , Xi ) ∈ failures(Pi ),13.1

Basic principles and tree networks

347• Xi ⊇ Σ  initials(Pi /s  Ai )A state is maximal if all the Xi are maximal refusals as described above. It is adeadlock state if
ni=1 Ai=n

i=1 Ai ∩ Xi

Note that from any state we can deduce a state for each subnetwork, in particular
all adjacent pairs of processes.
The notions of request, ungranted request, conﬂict, etc. are now straightforward to deﬁne formally.
Definition If (s, X ) ∈ failures(Pi ) and X ⊇ Σ  initials(Pi /s), then we say Pi ismaking a request to Pj (i = j ) if Aj ∩ (Σ  X ) = {}.
Definition There is an ungranted request from P to Q in the composition P A B
Q, with respect to vocabulary C ⊇ A ∩ B if it has a state (s, XP , XQ )• (Σ  XP ) ∪ (Σ  XQ ) ⊆ C• B ∩ (Σ  XP ) = {}• B ∩ (Σ  XP ) ⊆ XQ .
There is an ungranted request from Pi to Pj in the deadlock state σ (writtenσPi =⇒•Pj ) if the corresponding state of the parallel composition of Pi and Pj is anungranted request with respect to the vocabulary of the whole network V .
Definition A conﬂict (with respect to vocabulary C ⊇ A ∩ B ) in the parallel
composition P A B Q is a state (s, XP , XQ ) which is simultaneously an ungranted
request (with respect to C ) in both directions.
Definition A strong conﬂict of the pair P A B Q with respect to C is a conﬂict(s, XP , XQ ) with respect to C such that either Σ  XP ⊆ B or Σ  XQ ⊆ A.
Definition The network V is free of conﬂict (respectively strong conﬂict) if eachpair of adjacent processes in its communication graph are, in the sense that no stateof their pairwise composition is a conﬂict (respectively strong conﬂict) with respect
to the vocabulary of V .
13.1.3

The Fundamental Principle and tree networks

If a network is free of strong conﬂict, we can make an important assumption about
the sequence of nodes P0 , P1 , P2 . . . constructed when developing the Fundamental
Principle, namely that Pn = Pn+2 for any n. This is because, even though Pn+1

348

Deadlock!

may have an ungranted request to Pn , we can guarantee that it has one to at least
one other node, for otherwise Pn and Pn+1 would be in strong conﬂict. We canimmediately deduce that the cycle of ungranted requests produced by the sequencemust be a proper cycle, namely one which is a sequence of at least three distinct
nodes. This is the fundamental result which underpins all of our deadlock analysis
techniques.
Fundamental principle of deadlock If V is a network which satisfies ourbasic assumptions (A)–(E)2 and which is free of strong conflict, then any deadlock
state of V contains a proper cycle of ungranted requests.
It has one immediate consequence, since no tree network (i.e., one whose
communication graph is a tree) can contain a proper cycle of ungranted requests.
Deadlock rule 1
is deadlock-free.

If V is a tree network which is free of strong conflict, then V

This is likely to be the only rule you ever need for proving deadlock freedom intree networks. What it shows is that deadlock is not a real concern in well-designed
tree networks.
Since the dynamic networks produced by recursing though operators like >>and // (see Chapter 4) are almost invariably trees, it is worth noting here thateven though these do not ﬁt directly within assumptions (A)–(E) set out earlier,the remarks and transformations set out with those assumptions mean that to all
intents and purposes Rule 1 still applies. Thus, so long as basic principles (suchas busy-ness and freedom from strong conﬂict) are adhered to, deadlock is rarely aproblem in this type of network.
One could generalize Rule 1 a little to deal with the case where the communication graph is not a tree, but where there are enough (directed) edges between
nodes over which ungranted requests are impossible to exclude proper cycles ofthem. Obviously one should bear this in mind if there are such edges, but it does
not seem to be a very common situation.
Let us suppose we need to pass messages in either direction between
a pair of users separated by a chain of intermediate nodes. Someone proposes the following
design for a node:

Exercise 13.1.1

Node

=

leftin?m → rightout!m → Node
2 rightin?x → leftout!m → Nodewhere, in composing the network, these channels are renamed so that each adjacent pairis connected by a pair of channels, one in each direction. He argues that this must be
deadlock-free because the communication graph is a tree.
2 In subsequent results we will, for brevity, omit these assumptions, which will be implicit.

13.2

Speciﬁc ways to avoid deadlock

349

Show that he is wrong and that it can deadlock, and explain why in terms of theanalysis in this section.
What modiﬁcation would you suggest so that the system meets its intended purpose
but is deadlock-free?

Sketch a proof that the dynamic network described on page 110 for
implementing the quicksort algorithm is deadlock-free. To do this you should show thatany deadlock state is equivalent, from the point of view of deadlock, to one of a conﬂictfree tree network satisfying our assumptions. (Unless you are keen to do this, there is noneed to go into details of the transformations that manipulate the renaming and hiding
introduced by enslavement.)

Exercise 13.1.2

A token ring, as previously discussed on page 311, is a network inwhich a ﬁxed number of tokens are passed round the processes in a ring network. We
are not yet in a position to prove one these deadlock-free since it is evidently not a tree
network! One can, however, produce an interesting variant on this which is.

Exercise 13.1.3

Suppose we are presented with an arbitrary connected tree structure of processes,
and we want to ensure that exactly one of these has a token at any time. Design a node
process which achieves this, and additionally allows any node to issue a request for thetoken which will normally result in it being sent. (The resulting network should have thegiven tree as its communication graph.) It should be deadlock-free by Rule 1.
It is helpful to note that (with correct initialization) each node can always either
have the token or know which of its neighbouring processes is the right one to ask for thetoken. After our node has seen the token, this is simply the neighbour to whom it mostrecently passed the token.

13.2

Speciﬁc ways to avoid deadlock

If the communication graph of V is not a tree (i.e., it contains cycles) we need toﬁnd ways of showing that the sort of cycle produced by the Fundamental Principle
cannot appear, even though there is now ‘room’ for it to do so.3 In this section wemeet a number of design rules which, when they are followed, guarantee that nosuch cycle can appear. Each of these rules tends to apply to only a certain class of
system.
3 Though in fact there are cases of deadlock-free networks that can contain proper cycles ofungranted requests, all our rules are based on removing them. In fact the careful reader may
notice that a few of our later rules do not exclude the possibility of there being some, provided
that ones that ‘matter’ in some sense are not there.

350
13.2.1

Deadlock!
Node orderings

Our ﬁrst few rules and examples are based on the existence of some partial orderingon the nodes which represents something like the direction in which data, or perhaps
some decision process, ﬂows. A node ordering on a network is a partial order on its
nodes where every pair of processes whose alphabets intersect (i.e., have an edge
between them in the communication graph) are comparable. We will use theseorderings to break symmetry and eliminate the possibility of cycles.
Deadlock rule 2 Suppose V is conflict-free and has a node ordering < suchthat whenever node Pi has a request to any Pj with Pj < Pi then it has a request
to all its neighbours Pk such that Pk < Pi . Then V is deadlock-free.
The proof of this particular rule is very easy: if there were a cycle of ungranted requests P0 , P1 , . . . , Pn  then necessarily this contains at least one Pi which
is maximal (under <) among the members of the cycle. Necessarily Pi has an ungranted request to Pi+1 , a process less than itself; the assumptions of the rulemean that it therefore has a request (necessarily ungranted) to each Q such that
Q < Pi . But the predecessor Pi−1 of Pi in the cycle is necessarily one of these, andso (in contradiction to the assumption of conﬂict freedom) these two processes arein conﬂict. This completes the proof.
Notice that the assumptions of Rule 2 imply that when a node Pj has anungranted request to a Pi with Pj < Pi , then Pi must have a request to a Pk with
Pi < Pk (for, by busy-ness, Pi must have a request somewhere and it cannot havea request to any of its predecessors). This fact alone is enough to imply deadlock
freedom since it would imply that any deadlock state contains an ever-increasing
sequence of nodes, each with an ungranted request to the next. This is impossible
because the network is ﬁnite. This rule would be slightly more general than Rule 2
but also it would also be harder to verify its conditions, since one has to look at how
pairs of processes behave in parallel rather than at the construction of individual
processes.
Example 13.2.1 (layered routeing) An elegant example of the use of this Ruleis provided by a routeing algorithm invented by Yantchev [140], which he calls‘virtual networks’.4 Suppose we have a rectangular5 grid of nodes {Ni,j | 0 ≤ i ≤A, 0 ≤ j ≤ B } and might want to send a message packet from any one of thesenodes to any other. On the face of it, this system is too symmetric to apply theabove rule: messages can be sent in any direction so there is no obvious partial
4 He also invented a clever hardware-level packet propagation mechanism which minimizes propagation latency in this network. He called this the mad postman algorithm, but the details are
not relevant to the present discussion.
5 In fact the algorithm works equally well in any number of dimensions.

13.2

Speciﬁc ways to avoid deadlock

351

N 1,1

N 1,2

N 1,3

N 1,4

N 2,1

N 2,2

N2,3

N 2,4

N 3,1

N 3,2

N 3,3

N 3,4

in

I-up

O-up
I

I-leftI-rightoverOO-right

O-leftout
I-downO-downFigure 13.3 Virtual network routing and detail of a node.
ordering on the nodes that we could begin to use for Rule 2. The trick is to divide
each node Ni,j into the parallel composition of two processes Ii,j and Oi,j and to
put the following ordering on the resulting network:
Ii,j
Oi,j
Ii,j

≤
≤
≤

Ii  ,j 
Oi  ,j 
Oi  ,j iﬀ i ≤ i  ∧ j ≤ j iﬀ i ≥ i  ∧ j ≥ j 
for all i , j , i  , j This implies (following the intuition of the order) that data ﬂows into the Ii,j ;352

Deadlock!

through these in increasing index order; over to a Oi  ,j  , and then through these in
decreasing index order before leaving the network.
In fact it is possible to route from any Ni,j to any other Ni  ,j  in this way:data is input into Ii,j ; routed to Ii  ,j  where i  = max {i , i  } and j  = max {j , j  };passed over to Oi  ,j  and then routed to Oi  ,j  before being output. A picture of the
4 × 3 version of this network is shown in Figure 13.3, with the routeing technique
illustrated by the path a message takes from N1,3 to N2,1 .
One implementation of this is given by the following process descriptions:Ii,j= in?x ?y?m → Ii,j(x , y, m)(x , y, m)
2 I-up?x ?y?m → Ii,j(x , y, m)
2 I-left?x ?y?m → Ii,j(x , y, m) = I-right!x !y!m → Ii,jIi,j<I i < x>I
(I-down!x !y!m → Ii,j<I j < y>I over !x !y!m → Ii,j )Oi,j= over ?x ?y?m → Oi,j(x , y, m)(x , y, m)
2 O-down?x ?y?m → Oi,j
2 O-right?x ?y?m → Oi,j (x , y, m)(x , y, m) = O-left!x !y!m → Oi,jOi,j<I i > x>I
(O-up!x !y!m → Oi,j<
I j > y>I out!x !y!m → Oi,j )Here, X-up, X-down, X-left and X-right (with X ∈ {I , O}) are the channels connecting Ii,j or Oi,j to the process of the same sort in the chosen direction in the
X -plane, over is the channel connecting Ii,j and Oi,j , and in, out are the channels connecting Ni,j to the environment. (All of these need to be renamed when
composing the complete network so as to get the synchronizations right.) These
processes transparently satisfy the requirements of Rule 2 with respect to the given
order. (End of example)
Rule 2 applies to networks where, whatever nodes are doing with the data
they are taking in, they do not mind what order it arrives on the various input
channels (i.e., the neighbours that precede them). There is no restriction on which
output channels are used and when. The rule applies to systems where (like theexample above) each input is in some sense complete and atomic. It does not reallydeal with situations where a pair of neighbours have a related series of communications, since the greater one in the partial order is obliged to deal with all its other13.2

Speciﬁc ways to avoid deadlock

353

neighbours every time it oﬀers a communication to the lesser one of the pair: it cannot concentrate temporarily on one predecessor. Rule 3 below, a direct extensionof Rule 2, speciﬁcally allows for this in a way that is frequently useful.
Deadlock rule 3 Suppose V is conflict-free and has a node ordering <. Further,
suppose that the state space of each process Pi of V breaks into two parts A and
B in such a way that
• when Pi is in a state of type A it obeys the assumptions of Rule 2;• when Pi is in a state of type B it has a request to some Pj with Pj < Pi ;• the parallel composition of each pair of neighbours Pj and Pi with Pj < Pi
is such that whenever Pi , in a state of type B , has an ungranted request to
Pj , then Pj is also in a state of type B .
Then V is deadlock-free.
The proof of this is almost as easy as Rule 2: we can ensure that the cycleof ungranted requests picked by the Fundamental Principle has the property thatthe ungranted request from any node in a B -state is to another, lesser node in a
B -state. It follows that if one of the nodes in the cycle is in a B -state then they
all are, in a sense that is incompatible with the node ordering; so they are all in an
A-state and the Rule 2 argument applies.
In this rule, a node is in a B -state just when it is waiting for a communicationfrom the (usually) unique predecessor to whom it is temporarily engaged. The rulesays that we must only allow such a request to be ungranted when the predecessor issimultaneously engaged with one of its predecessors and waiting for communicationon that session. In this way, chains (or occasionally more complex patterns) of theseengagements can build up through the network. The wormhole routeing example
below shows how these arise.
Networks of the form amenable to this rule are often termed client/server
networks, the idea being that each process acts as a server for some activity for
those processes less than it in the order, which are its clients. The conditions of therule can then be paraphrased:• A server process is either engaged by one of its clients or is available to themall.
• A client and server never get into conﬂict, and the only way an ungranted
request can arise from a server to a client it is currently engaged by is whenthat client is itself a server to another process and has itself a request to thatprocess.

354

Deadlock!

S1

R2

R1

*
S2

Figure 13.4 Wormhole routeing in action.
Example 13.2.2 (wormhole routeing) A typical example of the type of network supported by Rule 3 is an extension of the class of network seen in our previous
example. Suppose a typical message is large: it may be that they can be too large to
ﬁt into a single node in our routeing system; even if not, the time taken to transmit
a message step-by-step across the network may be substantial if the whole message
has to enter a node before the node can begin to send it out.
What we do is to break up each message into a variable number of packets
where the ﬁrst one (the header) contains all of the routeing information and eachnode can tell when it has received the last packet (either by counting relative tosome earlier ﬁgure contained in the header or by a marker).
When a node is not currently engaged in transmitting a message it behavesvery much like one of the nodes in the earlier example. After receiving and passing
on a message header it will only accept input from the node which sent it theheader (passing on the packets one at a time) until the message is complete. Thus
a complete message, at any one time, occupies a connected chain of nodes which,when the message is completely within the network, is at least as long as the numberof packets it comprises. The way it works leads to this method being given the name

13.2

Speciﬁc ways to avoid deadlock355

wormhole routeing.
Figure 13.4. shows how this might look, with two messages currently intransit. The two messages are from S 1 to R1 and S 2 to R2 respectively. Noticethat the second message is temporarily blocked by the ﬁrst: it will only be able toprogress when the ﬁrst message clears the node labelled ∗.
The actual coding of wormhole routeing in CSP is left as an exercise. (Endof example)

13.2.2Cyclic communication networks

There is a large class of calculations that can be performed on (usually) regular
networks where data and partially-computed results ﬂow through, and where eachprocessor regularly inputs one collection of values before performing a calculationand then outputting another collection on another set of channels. These are often
referred to as systolic arrays, though that term more properly applies to the casewhere the calculations and communications in the network are regulated by a global
clock rather than being self-timed. These networks are perhaps the most common
example of a rather diﬀerent class of ordered networks to those treated by Rules
2 and 3: ones where each node communicates in a ﬁxed cyclic pattern with its
neighbours.
Definition A cyclic communication network is a network V in which• Every node is connected to each of its neighbours by one or more distinct,
conﬂict-free channels.
• The communications of each node Pi are divided into cycles.
• On each cycle Pi communicates exactly once on each of its channels in aﬁxed order.
The following two rules show how to design these networks to be deadlockfree.
Deadlock rule 4 A cyclic communication network is deadlock-free if and only
if there is a linear (total) ordering of all the channels linking the nodes such thateach Pi addresses its neighbours in order on each cycle.
Deadlock rule 5 If there is exactly one channel connecting each pair of neighbours in a cyclic communication network V (i.e., no pair of processes communicate
twice in any one cycle), and there is a linear node ordering on V such that eachnode addresses its neighbours in this order, then V is deadlock-free.

356

Deadlock!

Rule 5 is just a somewhat simpliﬁed version of Rule 4: it is easy to show that
it is a corollary of it since under the assumptions of Rule 5 one can ﬁnd an orderingon the channels satisfying Rule 4 – see the exercises.
The proof that Rule 4 works is rather like those of earlier rules. It depends
on the following two facts, both of which are easy to see when you consider how theparallel composition of a pair of neighbouring processes communicate in a cyclic
communication network:σ• If Pi =⇒•Pj then the number of cycles completed by Pi either equals thecorresponding number for Pj or exceeds it by exactly 1.
σ• If Pi =⇒•Pj and they have completed the same number of cycles, then thechannel currently oﬀered by Pj (there is always exactly one) precedes thatoﬀered by Pi (to Pj ) in the order on channels.
From the ﬁrst of these we get that all the nodes in a cycle of ungranted requests
have completed the same number of communication cycles. The second then shows
the cycle cannot exist because the order on channels decreases all the way round.
Showing that deadlock freedom actually implies the existence of such an order (theother half of this if-and-only-if result) is rather harder.
Often the way this type of network is built makes it natural for the nodes
to perform a group of communications within a cycle in parallel. In other words,
instead of enforcing a ﬁxed order between the communications a1 , . . . , ak , say, they
are all made available, and as each is performed it is removed from the set until
they have all happened. These communications are termed parallel because it isequivalent to writing(a1 → SKIP ||| . . . ||| ak → SKIP ); P 
where P  is the subsequent behaviour (though there are likely to be identiﬁer binding
problems if this style is used for parallel inputs).
We can liberalize the deﬁnition of cyclic communication networks to takethis into account.
Definition A generalized cyclic communication network is a network V in which• every node is connected to each of its neighbours by one or more distinct,
conﬂict-free channels;• the communications of each node Pi are divided into cycles;• each Pi partitions its channels into a number of subsets and oﬀers these eachof these sets in parallel in turn, the order of the sets being ﬁxed.

13.2

Speciﬁc ways to avoid deadlock357

It is a good idea to make the communications in one of these networks asparallel as possible. Putting communications in parallel can substantially reducethe computation time because nodes are not blocked from communicating for solong. It is important to know that this ‘parallelization’ does not interfere withdeadlock freedom: this is captured in the following rule.
Deadlock rule 6 If V is a deadlock-free generalized cyclic communication network, and V  is identical except that one or more groups of consecutive communications in nodes of V have been made parallel, then V  is still deadlock-free.
The proof of this result can be found in [118].
Example 13.2.3 (matrix multiplication) The rows and columns of two matrices we want to multiply together can ﬂow, respectively, along the rows and columnsof a rectangular grid. As pairs of values meet, their product is added to a valuethat is accumulating in the node where they meet. Recall that the product of thep × q and q × r matrices [ai,j ] and [bj ,k ] is the p × r matrix whose terms are
ci,k =

q

j =1 ai,j bj ,kThe top left-hand corner of the array is shown in Figure 13.5, including an
example conﬁguration of data.
We will ﬁrst code this without parallel communication. Since the nodes all
communicate once with each neighbour per cycle, we can do this by selecting alinear node ordering and using Rule 5. Since we expect our node to input (up andleft) on each cycle before outputting (right and down), the order must make thetwo nodes that a given one inputs from less than the two it outputs to. This still
gives a great deal of freedom in the choice of order, but there are only a few naturalones, one of which isNi,j ≤ Ni  ,j 

⇔ i + j < i  + j  ori + j = i  + j  ∧ i ≤ i .

The resulting code for a node (omitting whatever method is used to access the ﬁnal
value) is N (0), whereN (x ) = up?a → left?b → right!b → down!a → N (x + a × b)
since, for any ﬁxed node, the surrounding ones are ordered in the way implied bythese communications.
It is rather unnatural to impose an order on the two inputs and the two
outputs of a node in this example. Knowing that the above system is deadlock-free358

Deadlock!

b5,1

b4,2

b4,1

a1,5

b3,2
a1,3

a1,4

b3,1

a2,4
a2,3

a1,2

a2,2

a3,2

b2,4

b2,3

b2,2

b2,1

a3,3

b3,3

b1,4
a1,1

b1,3
a2,1

b1,2
a3,1

b1,1

a4,2
a4,1

Figure 13.5 Matrix multiplication on a rectangular array.
we can use Rule 6 to observe that the system where the inputs and outputs areboth put in parallel is still deadlock-free:N  (x )N  (x , a, b)= up?a → left?b → N  (x , a, b)
2 left?b → up?a → N  (x , a, b)=(down!a → SKIP ||| right!b → SKIP ); N  (x + a × b)

Notice that inputs have been ‘put in parallel’ by giving explicit alternatives to allow
the values of a and b to carry over. (End of example)
It is worth noting that the generalized cyclic communication network produced over any node-ordered network in which each node communicates with all thepreceding processes in parallel, and then with all the following processes in parallel,is bound to be deadlock-free.

13.2

Speciﬁc ways to avoid deadlock

359

Finally, if it is possible to put all the communications of each cycle in parallel
then the network is guaranteed to be deadlock-free without the need to consider
any orders at all. This could well be possible in a network iterating the solution
to an equation6 by a method in which the (n+1)th value at a given point is somefunction of the nth values at that point and the four surrounding ones.
13.2.3Resource sharing

Many classic deadlocks, not least the dining philosophers, occur because of contention for resources. The basic set-up is that the network consists of two separate
classes of process: users and resources. For simplicity we will assume that the only
communications are between a user and a resource7 (i.e., the alphabets of any two
users, or any two resources, are disjoint). Each resource can be acquired by a user
U , and then cannot be acquired by any other until it is released by U . Notice how
this describes the dining philosophers, where the resources are the fork processes
and each fork can only be acquired by the two neighbouring philosophers.
More formally, the user processes will be enumerated {Ux | x ∈ Υ} and theresource processes are {Rn | n ∈ {1, . . . , k }}. The resource processes each allow
themselves to be acquired by one user at a time (acq.x .n represents the acquisitionof Rn by Ux ), and have to be released (release.x .n) before being available to others:
Rn = acq?x :Xn !n → release.x .n → Rn
Here Xn ⊆ Υ is the non-empty set of users that Rn can be acquired by.
Notice that this deﬁnition of Rn completely abstracts away from whatever
the users do with the resources once they have them. In a real example it is likelythat there would be other communications, but eliminating them here allows us toconcentrate on the central issue of contention.8
Our objective is to understand how the users must behave to prevent deadlocks like that in the dining philosophers. We must obviously assume that the users
interact properly with the individual resources: any trace of a user alternates acquiring and releasing a speciﬁc Rn . For simplicity we will assume that, initially, nouser holds any resource so that the ﬁrst event of each of these alternating sequencesis the appropriate acq.x .n. Notice that this assumption means that our network iscertainly conﬂict-free.
6 Perhaps an elliptic partial diﬀerential equation like Poisson’s equation.
7 Technically, the communication graph is bipartite.
8 From the point of view of eliminating deadlock when communications between users andcurrently-held resources are allowed, it should be very helpful to observe that at all times theseclusters are all rather simple tree networks.

360

Deadlock!

If tr is any trace of a user process Ux , we can easily compute the set ofresources held after tr :resources x (tr ) = {n | tr ↓ acq.x .n > tr ↓ release.x .n}
Because there will never be an ungranted request from a user to an unused
resource, or from a user to a resource which it currently has possession of, it follows
that any cycle of ungranted requests in such a network is bound to look essentiallylike the one in the dining philosophers. It will alternately consist of users andresources; with a given user waiting for the next resource on the cycle while holding
the previous one with the resources waiting to be released.
The classic way to prevent this, which you will see is very like the methods
we have already developed for other types of network, is to follow the principle set
out in the following rule.
Deadlock rule 7 Suppose we have a network V of users and resources as set
out above, and each Ux follows the principle that it never tries to acquire a resourceof lower index than one it presently holds, i.e.,trˆacq.x .n ∈ traces(Ux ) ⇒ resources x (tr ) ∩ {m | m > n} = {}then V (under our usual assumptions such as busy-ness) is deadlock-free.
Of course this assumption about the users would imply that the indexes of
the resources increase as we move round the cycle of ungranted requests discussed
above, which is clearly impossible, hence the deadlock freedom.
Example 13.2.4 (asymmetric dining philosophers) Given the above rule itis simple to apply it to the dining philosophers example. We would not expect it tomatter to a philosopher in which order he or she picks up the forks, but the above
rule shows that this order is the key to eliminating deadlock. All we have to do
is pick any enumeration whatsoever of the forks and to program the philosophers
so that each of them picks up the one with lower index ﬁrst. Using the obvious
enumeration (the one used to deﬁne them) we get the following deﬁnition of aphilosopher: if i ∈ {0, 1, 2, 3} thenPHILi

= thinks.i → sits.i → picksup.i .i → picksup.i .i + 1 →eats.i → putsdown.i .i + 1 → putsdown.i .i → getsup.i → PHILi

PHIL4= thinks.4 → sits.4 → picksup.4.0 → picksup.4.4 →eats.4 → putsdown.4.4 → putsdown.4.0 → getsup.4 → PHIL4

while

13.2

Speciﬁc ways to avoid deadlock361

If the network is otherwise constructed as in Section 2.2.1, it satisﬁes all the conditions of Rule 7, and so this very slight adjustment has made it deadlock-free.
What we have in essence done is to break the symmetry of the original example byvarying the order (in the sense of the ring) in which the philosophers pick up theirforks. We end up with four left-handed ones and one right-handed (say). (End of
example)13.2.4

Communication order

The rules introduced so far have certainly not covered all the possible ways of
eliminating cycles of ungranted requests. Any reader who cannot make a networkﬁt any of the rules given here is encouraged to try to capture why it is deadlock-free
and to attempt to formulate it either in the same way or to translate it into themethods described in the rest of this chapter.
To illustrate this process we will give an example which does not ﬁt into anyof the categories shown so far, and then show how this motivates another class ofrule.
Example 13.2.5 (non-blocking message ring) The objective here is to createa ring network where messages may be input at any node, addressed to any othernode. They are to be transported in one direction (clockwise, say) round the ring
until they get to their destination, and are then output.
It is very easy to build such a system that deadlocks: this is the fate, forexample, of just about the simplest possibility, described below.
Di= in.i ?m → Di (m)2 ring.i ?m → Di (m)Di (m) = out.i !m → Di<
I destination(m) = i>Iring.(i ⊕ 1)!m → Di
Here every node has one ‘slot’ for a message: this can be occupied either by amessage input from the local user over in.i or by one from the ring. One way todeadlock the resulting ring is for all the users simultaneously to transmit a message
for another node. All the processes are then stuck waiting to output to the next
member of the ring.
One’s ﬁrst reaction to this might be to add more buﬀering capacity to thenodes. But this in itself does not help, since however large a ﬁnite capacity we give
each node we cannot stop them becoming full if the external users are very keen to
send messages.

362

Deadlock!

What we need is a mechanism to prevent the ring getting ﬁlled up. There areseveral ways to do this. The ﬁrst way, which is unacceptable9 for practical reasons,is to take the approach of the BUTLER process for the dining philosophers: a single
process, put in parallel, which counts how many messages are present (i.e., input
but not yet output) and prevents ones being inserted over a given limit.
A second approach (which is in some respects just a distributed implementation of the ﬁrst) is to implement a token ring alongside the communication ring.
This ring contains a number (again, less than the number that could deadlock thecommunication ring) of tokens. A message can only be input to the communication
ring by a node that has a free token, and the message then occupies the token for
as long as it is in the ring. There has to be some mechanism for nodes seeking to
input but without a token to obtain one (if available), in this sense one would haveto produce a more sophisticated ring than that seen in Section 12.2: see Exercise
13.3.3.
The third approach, which is much simpler to describe in CSP than thesecond, is to make each node responsible for making sure that it is not the one tocomplete the deadlock. This is done by increasing the buﬀering capacity of eachnode to at least two, picking a limit for each node that is at least one and strictly
less than its total capacity, and programming the nodes so that they only accept
new messages from their own user when this would not make the total content
exceed this limit. We can easily modify the earlier deﬁnition to get the required
node process (which is now parameterized by the sequence of message it currently
holds):Di (s) =(in.i ?m → Di (sˆm)<I #s < limit(i )>I STOP )2 (ring.i ?m → Di (sˆm)<I #s < capacity(i )>I STOP )2 (STOP <I s = >I
(out.i !head (s) → Di (tail(s))<
I destination(head (s)) = i>Iring.(i ⊕ 1)!head (s) → Di (tail(s))))(where 1 ≤ limit(i ) < capacity(i )).
We would intuitively expect a ring of these processes to be deadlock-freebecause• The ring can never become full, in the sense that every node is full to its
capacity. Therefore there is at least one node that is not full.
9 It is unacceptable because one would normally expect the ring to be moderately well distributed. Having a process which has to synchronize with every input and output is therefore notpractical.

13.2

Speciﬁc ways to avoid deadlock363• A node that is not full will accept input from its ring predecessor.
• The said predecessor can at all times either communicate with its own useror output to our node.
The crux of this argument is, of course, the ﬁrst line. To turn it into a formal
proof we would have to deﬁne and prove this statement, which itself requires understanding every state the ring can reach. (One would probably go about this byformulating and proving a suitable invariant – something we will discuss later.) We
will shortly ﬁnd that the proof of deadlock freedom can be cast in rather diﬀerent
terms, much more akin to the methods seen hitherto.
A substantial case study (most of which is cast in occam rather than CSP)
of how this ring mechanism can be extended to a deadlock-free routeing protocol
for use on an arbitrarily connected network can be found in [103]. (End of example)
The only cycle of ungranted requests that could arise in the ring above is ofeach node blocked from outputting to its clockwise neighbour. (The reverse cycle ofeach node waiting for input does not arise because then all the nodes are prepared
to input – i.e., communicate outside the vocabulary of the network, which means
this is not formally an ungranted request.) Consider the state of an individual nodein this cycle: it is certainly full, and the last communication it performed was theone that ﬁlled it. But that communication must have been from its anticlockwiseneighbour rather than from its external user, because of the way it is deﬁned. We
can deduce that our node has communicated more recently with its anticlockwiseneighbour than with its clockwise one.
This brings us right back into familiar territory: as we progress clockwiseround the cycle of ungranted requests we ﬁnd that the most recent communications
on the channels were earlier and earlier, creating the usual contradiction when
we have gone all the way round. Thus the cycle, and consequently deadlock, areimpossible. This is formalized in the following.
Deadlock rule 8 Suppose V is a network which is free of strong conflict andsuch that, for each pair P , Q of neighbouring processes, it can be shown that,whenever P =⇒•Q,(i) Q has previously communicated with P and(ii) Q has done so more recently than with at least one other process to which
Q has a request,
then V is deadlock-free.
This rule allows us to prove our ring deadlock-free by local analysis (since,
like all of our rules, the conditions underlying this one are checked by looking at

364

Deadlock!

the behaviour of individual processes or small collections of them). Another, larger
example that uses Rule 8 can be found in Section 15.3.1.
Of course, once we have discovered this rule, other related rules immediately
occur to us. We could, for example, turn the above rule around and specify that
Q must have communicated with another neighbour (to which it has a current
request) more recently than any communication with P . This looks less likely andthe author is not aware of any natural applications.
Recall the treatment of the alternating bit protocol in Section 5.3.
We argued on page 134 that it is deadlock-free. That argument can be re-cast in terms of
one of the rules in this section: do so.

Exercise 13.2.1

Suppose V is a cyclic communication network satisfying the assumptions of Rule 5. Show how to build an ordering on the edges that satisﬁes the conditionsof Rule 4, showing that Rule 5 is a consquence of its predecessor. Hint: identify each edge
with the two-element set of the nodes at each end.

Exercise 13.2.2

Exercise 13.2.3 Deﬁne a version of the ‘virtual network’ on page 350 that operates inthree dimensions rather than two. You still only require 2 layers. Deﬁne the node orderingwith respect to which Rule 2 applies to your network.
Create a ring network in which the communications of each node nconsist of external events in.n.m.x and out.n.m.x , respectively meaning that the message
x is being sent to or received from node m, plus communications with the adjoining nodesof the form ring.n.p meaning that packet p is being sent to node n by its predecessor (i.e.,
anti-clockwise neighbour), where p is either of the form Message.a.b.x (meaning that it
carries message x to b from a) or is Null , meaning that it carries no message. It shouldhave the eﬀect of reliably delivering messages as addressed. Each node should basicallyhave the capacity of one packet, and should only be able to input on in when this packet
is null.

Exercise 13.2.4

The result should be a cyclic communication network that is deadlock-free by Rule
4. (Note that it is only the communications with other nodes that have to follow a strict
cyclic pattern and that the external inputs and outputs therefore do not.) Why are thenull packets important? (In other words, why can we not simply get away with twoconsecutive ring nodes only communicating when they have something substantive to say
to each other.)Comment on what happens when there are no real messages passing round thesystem, so that all packets are null. What are the advantages and disadvantages of thisapproach as compared to the one in Example 13.2.5?
Provide deﬁnitions of the nodes in a wormhole routeing network
based (like that in Figure 13.4) on a two-dimensional virtual routeing network. Assume
that each message consists of a series of packets, with a special one representing the end

Exercise 13.2.5

13.3

Variants

365of the message. Identify which of the states of these processes are types A and B for Rule4, and check that they satisfy the necessary conditions to make this rule work.

13.3

Variants

13.3.1Introduction

The arguments underlying the various principles in the previous section seem to bevariations on a common theme: we follow a putative cycle of ungranted requests
and ﬁnd that some ordering property gives a contradiction once we have gone all
the way round.
We can unify the rules under a single theory, which gives perhaps the mostgeneral practical tool for proving deadlock freedom in networks with cycles. The
idea is related to a well-known method of proving loop termination in sequential
programming, namely variants. In sequential programming a variant function is ausually natural-number valued function of state, with the property that every time
the loop body is executed the value of the function decreases. The fact that such afunction cannot decrease for ever means that the loop must terminate after a ﬁnite
number of iterations.
The corresponding idea in deadlock analysis is to make sure a variant function
decreases round a cycle of ungranted requests. We associate a value – its variant –with the state of each process. Showing this decreases once round the cycle isenough since the variant of each process is then less than itself in the same state,
which gives exactly the sort of contradiction we were getting in the arguments inthe previous section. Because this type of argument is essentially ﬁnitary, there
is no need to restrict ourselves to orders which, like the natural numbers, have no
inﬁnite descending sequences.
The ﬁrst thing we have to do to use variants is to deﬁne the functions themselves. Usually these depend on two things: the node’s position in the network andits current trace. But there is no particular limitation on what is included – it may
be necessary, for example, to include internal process parameters or to take accountof the way an internal nondeterministic choice is resolved. All that matters is thatthe variant can be calculated in terms of the node’s own state and history.
The reason why this last condition is necessary is the requirement that thepreconditions to our proof rules are locally checkable. We need to be sure that thefact that variants decrease across ungranted requests between P and Q when we
examine their parallel composition implies that the same is true when they are partof a large network.
Given a network {(Pi , Ai ) | 1 ≤ i ≤ N } the associated variant functions
will usually be written {fi | 1 ≤ i ≤ N }. The fi are all functions into the same

366

Deadlock!

partial order Z , and as discussed above will usually be functions of the traces of
the corresponding Pi . For clarity, many of the rules and arguments below assume
that they are functions of traces but can be modiﬁed easily to take account ofother circumstances. The objective in deﬁning these functions is to make the value
decrease over any ungranted request. In many – perhaps a majority of – practicalcases it is possible to make the variant decrease strictly over every ungranted request,
which gives the easiest-to-understand case.
Deadlock rule 9 A network V is deadlock-free if it has a system of variant
functions such that, for every pair (Pi , Pj ) of neighbouring processes and every
state σ of their parallel compositionσ

Pi =⇒•Pj ⇒ fi (trσ  Ai ) > fj (trσ  Aj )Notice that we did not explicitly assume the network to be free of strong
conﬂict: in fact the assumptions of the rule imply conﬂict freedom since two processes with an ungranted request to each other would both need to have variants
less than the other.
Most of the rules in the previous section can be reduced to this one. Two
examples of this are given below, and others are included as exercises at the end of
this section.
Example 13.3.1 (rule 4 in terms of rule 9) We can more or less translate
the proof that Rule 4 (concerning cyclic communication networks) guarantees deadlock freedom into a system of variant functions. Notice that the proof uses two levelsof order: a cycle count and then events. This suggests that the partial order should
compound these two ideas together: N × L, where the ﬁrst component is the natural
number of cycles a node has completed and the second is the linear order from thestatement of the rule. The order on this structure is(n, a) ≤ (m, b) ⇔ n ≤ m ∨ (n = m ∧ a ≤ b)
The variant of process Pi after trace s is then just the pair (n, c) where n is
the number of cycles completed (i.e., the natural number #s div ki where ki is thenumber of events Pi communicates each cycle) and c is the channel on which it isdue to communicate on next. The statement that, for each state σ of the parallel
composition of Pi and Pj ,σPi =⇒•Pj ⇒ fi (trσ  Ai ) > fj (trσ  Aj )then follows by exactly the arguments we put forward earlier when justifying Rule

13.3

Variants367

4. We have simply translated the original proof to the framework of variants rather
than found a genuinely diﬀerent proof.
We can, of course, use orders (for the range of the variant functions) thatare less contrived. For example, if we enumerate the channels in the order of L:
c1 , c2 , . . . , cM then, for suﬃciently large K the variant functions
fi (s) = K × (s div ki ) + nextindex (s)work, where nextindex (s) is the index in this enumeration of the channel that Pi
is due to communicate on next. (K has to be suﬃciently large so that any pair ofneighbouring processes with one a cycle behind the other always give the smaller
variant to that one. M is certainly large enough.)
Slightly simpler variant functions than these can be found for many examplesof this type: see the exercises for ones that work on the matrix multiplication
examples. (End of example)
Example 13.3.2 (rule 2 in terms of rule 9) The two things we have to build
the variant from in Rule 2 are a node’s position in the node ordering, and what it
is doing. So far as the rule is concerned there are really only two possibilities forthe latter: either it is making a request to all processes less than itself (call this an
α state), or it is not making a request to any of them (a β state). There are four
sorts of ungranted requests we can get in one of these networks:
1. A process in an α state can have an ungranted request to a predecessor inan α state.
2. A process in an α state can have an ungranted request to a predecessor in a
β state (because the latter is waiting for a diﬀerent successor).
3. A process in an α state might (if able to output as well as input) have an
ungranted request to a successor in a β state.
4. A process in a β state can have an ungranted request to a successor in a βstate.
The other four cases are impossible because of the assumptions of the rule: aprocess in a β state has no requests to its predecessors, and no process can have an
ungranted request to a successor in an α state (here we are using the assumptionof conﬂict freedom from the rule).
The partial order we use is thus {α, β} × W , where W is the node ordering,and• (α, x ) > (β, y) for all x and y368

Deadlock!
• (α, x ) > (α, y) if, and only if, x > y• (β, x ) > (β, y) if, and only if, x < y (note that the sense of the node ordering
is reversed for this clause).

The variants are then obvious: a process maps to the pair of the type of its stateand its position in the node ordering. That these satisfy the requirements of Rule
9 follows directly from the analysis above.
It is worth remarking that these variant functions may have to be thoughtof as functions on (maximal) failures rather than traces: in the general case it may
not be possible to tell from the trace alone whether a process is in an α or β state.
(End of example)
13.3.2

Cycle-cutting sets

Having established the basic idea of a variant function, we can develop a few variations which give it a little more power. The ﬁrst of these is based on the realizationthat making the variant decrease strictly all the way round a cycle contains anelement of overkill. It would be just as eﬀective if we were to guarantee the variant
is non-strictly decreasing (i.e., ≥) over each ungranted request, in such a way that
there is always at least one strict decrease in every cycle.
The easiest-to-understand way to obtain this is to nominate a set C of directed edges such that every proper cycle in the communication graph contains oneof them. Then we simply have to insist that ungranted requests over an edge in C
always have a strictly decreasing variant. Such a set will be called a cycle-cutting
set for obvious reasons.
As an example, consider a rectangular grid network like that deﬁned for thematrix multiplier array earlier in this chapter. A possible C for this network is theset of all directed edges leading in any one of the four directions up, down, left or
right – since any cycle is bound to contain at least one of each.
Deadlock rule 10 If the network V is free of strong conflict and has a systemof variant functions fj and a cycle-cutting set C such that, for every pair (Pi , Pj )of neighbouring processes and every state σ of their parallel compositionσ

Pi =⇒•Pj ⇒ fi (trσ  Ai )fi (trσ  Ai )≥ fj (trσ  Aj )> fj (trσ  Aj )and
if (i , j ) ∈ Cthen V is deadlock-free.
We have had to bring in the explicit assumption of freedom from strong
conﬂict, since the non-strict variant decrease is not enough to exclude it.

13.3

Variants369

The more liberal requirements for variant functions can be used both tocreate simpler variants for networks that could have been dealt with by Rule 9, andto deal with some that could not. Below there is an example of each.
Example 13.3.3 (matrix multiplication again) We once again deal with theﬁrst – purely cyclic – array of processes deﬁned for matrix multiplication. Choose
as C the set of downward-pointing edges. It turns out that with this choice we cansimplify the variant functions to just the cycle-count: i.e.,fi,j (s) = #s div 4
Work previously done implies that this variant is non-increasing over all ungranted
requests in any cyclic communication network. The important thing to notice about
the cyclic order we chose (guided by a linear order) – up, left, right, down – is that
because the ﬁrst thing a node does on each cycle is look up, the existence of an
ungranted request on a downward-pointing edge (i.e., one in C ) implies that theupper node is one cycle ahead of the lower one. In other words the simpliﬁed
variants decrease and the conditions of Rule 10 are satisﬁed. (End of example)
Example 13.3.4 (binary switching network) Suppose there are a number ofpotential senders and receivers of messages, each of whom might wish to send amessage to any one of a class of receivers. With a carefully chosen network structure
one can connect 2n of each with the average path length only being as long (to withina small constant factor) as that of the n 2 nodes connected by a square version of
the virtual routeing network we saw earlier.10
The network, shown for n = 3 in Figure 13.6, has 2n columns of n ‘switch’processes, with a sender and a receiver connected at each end. Each is connected toexactly one process in a diﬀerent column: the one in column i and row j is connectedjto the one in row k and column i , the natural number with the same binary
representation as i except that the j th least signiﬁcant bit has been complemented.
The routeing algorithm is very simple: it is the duty of the processes in row j
to make sure that the j th least signiﬁcant bit in the address of the message matches
that of the place it is sent to. In other words, if the (i , j ) process receives a message
from above, the j th bit of i is compared with that of the address. If they are thesame the message is sent down, if not it is switched across to the node’s partner
j(i , j ). The path from 6 (110 in binary) to 5 (101) is illustrated in Figure 13.6.
In fact the precise nature of this routeing algorithm is irrelevant from thepoint of view of deadlock analysis, as are the contents of the messages communicated. Thus, we abstract away from these details. All we need concern ourselves
10 Though that network certainly has compensating advantages.

370

Deadlock!

S0,1

S1,1

S2,1

S3,1

S4,1

S5,1

S6,1

S7,1

S0,2

S1,2

S2,2

S3,2

S4,2

S5,2

S6,2

S7,2

S0,3

S1,3

S2,3

S3,3

S4,3

S5,3

S6,3

S7,3

Figure 13.6 Binary switching network.
with is the fact that a node might receive a message from above or its partner.
A message from the partner (on channel swin, say) is always sent down (channelout), while one from above (channel in) is either sent down or across to the partner(channel swout). From our point of view, under this abstraction, this latter choice
is nondeterministic.
The behaviour of a typical node is given below:
Sw= in → (Sw  out → Sw )2 swin → out → Sw

Sw 

= swout → Sw
2 swin → out → Sw 

Notice that, when this process contains a message which it has decided to send
over its link (i.e., is in state Sw  ), it retains the ability to accept a message fromthe linked process. This is to avoid the strong conﬂict which would otherwise havearisen if both of a pair of partners decided simultaneously to relay messages to eachother. The network is free of strong conﬂict, but not of conﬂict, since when each of13.3

Variants

371

a pair of partners is empty they have ungranted requests to each other. This lastfact implies that Rule 9 does not apply, but it is straightforward to apply Rule 10with C the set of all vertical edges (i.e., all except the ones linking partner nodes).
The variant function fi,j of node Swi,j is deﬁned:

fi,j (s) =j−jwhen the node contains no message
when it contains one or more messages

These work because, in our network, no node that contains a message can have an
ungranted request to one that is empty. Notice that when a pair of partners areeither both empty or both non-empty, their variants are equal.
The node process above is what you would get if you started with a deﬁnitionin which all the information necessary for routeing were included, and the decisions
made accordingly, and then applied a forgetful many-to-one renaming which omitted
the address and data components of communications. This abstraction mechanism
will be re-examined in Section 13.6.1 (End of example)

13.3.3

Selective requests

The rules seen so far insist that all ungranted requests a process makes have a
reducing variant across them. Looking back at how we derived the Fundamental
Principle, this is a little more than we really need. All we require is that theungranted requests which we happen to have chosen for the processes in the cycle
have this property. And of course we are free to select any ungranted request forthe process Pn in the sequence as long as it is not back to Pn−1 .
In just about all the examples we have seen to date (the nearest thing to an
exception among the concrete examples being the binary switching network), all therequests a process makes in any one state have been similar to each other. There wasno particular reason why the process should single one out. But in less symmetricexamples one can imagine a process might be making several very diﬀerent requests
at once, and of course it (and we) might have diﬀerent expectations about theprocesses at the other ends of these requests. Since we only need to follow a single
path to ﬁnd the cycle for the Fundamental Principle, it may be sensible in suchcircumstances to nominate which request to follow from a given one (selected fromthe set of requests it is making in its current state). Ordinarily one would expect
to select the one (or one of those) that we are relying on eventually being able tosatisfy the request.
So as well as having a variant function of each process’s state, we will also
have a request selector function. For each state σ of process Pi which is (i) stableand (ii) refuses all events not in the vocabulary of the network, ci (σ) must choose a372

Deadlock!

process to which Pi has a request in σ (the assumption of busy-ness implying there
is at least one to choose from). The advantage of this is that the variant only hasσto decrease across chosen ungranted requests: Pi =⇒•Pj where ci (σ) = j .
We state here the rule that corresponds to Rule 9 – i.e., the variant functions
always decrease strictly. One could similarly produce an analogue of Rule 10, but
in that case care has to be taken to ensure that a pair of nodes in conﬂict do notselect each other.
Deadlock rule 11 If the network V has a system of variant functions such that,for every pair (Pi , Pj ) of neighbouring processes and every state σ of their parallel
compositionσ

Pi =⇒•Pj ∧ j = ci (σ) ⇒ fi (trσ  Ai ) > fj (trσ  Aj )then V is deadlock-free.
It is possible to modify some of the rules of Section 13.2 in the same way toallow for explicit selection, notably Rule 8 (which already contains an element ofit).
One of the best uses of selection functions is to liberalize communications
in a network that has been carefully engineered to be deadlock-free, but where aseemingly heavy penalty has been paid for this. The approach is to extend therange of requests a process makes – adding some ‘optimistic’ ones – but in sucha way that the variant functions continue to be deﬁned and to work for the oldrequests. The selection functions then choose the old requests.
One example of this – relaxing the constraints imposed by Rule 7 on resource
acquisition – can be found in the exercises below.
13.3.4

Weak variants

A weak set of variants is one where there is never the requirement of a strict decreaseover an ungranted request. All we insist on is a non-strict reduction. (While there
may be some use for ones equipped with selection functions as discussed above, wewill assume that this decrease occurs over all ungranted requests.) Weak variants do
not in themselves prove absence of deadlocks – after all if we simply choose the same
constant function for each process in a network, the non-decreasing requirement issatisﬁed whether the network deadlocks or not.
What they can do is reﬁne our understanding of where a deadlock might
be in a network, allowing us to concentrate our search. In some cases it may bepossible to reﬁne the weak variants into a set that does prove deadlock freedom by
one of our earlier rules, or to establish deadlock freedom by some other method. In
other words, weak variants are an analytic tool.

13.3

Variants

373

The following rule captures the main analytic principle using weak variants.
Deadlock rule 12 If the network V is free of strong conflict, and has a systemof variant functions such that for every pair (Pi , Pj ) of neighbouring processes andevery state σ of their parallel compositionσ

Pi =⇒•Pj ⇒ fi (trσ  Ai ) ≥ fj (trσ  Aj )(a weak set of variant functions) then every deadlock state of V has a proper cycleof ungranted requests in which all the variant values are equal.
Example 13.3.5 (cyclic communication again) Good examples of the analytic power of weak variants can be found in the area of cyclic communication
networks and, more generally,11 conﬂict-free networks where each process communicates exactly once each cycle on each channel.
The natural weak variants for such systems are just cycle counts: in thenotation of earlier discussions of similar networks:
wi (s) = s div ki
No process can have an ungranted request to a neighbour that has completed
more cycles, because this would imply that the requesting process has communicated on the requested channel less times than the other process (contradicting thefact that the two processes synchronize on such events and so have at all times
communicated on the channel exactly the same number of times).
Thus, by Rule 12, any deadlock state must contain a cycle of ungranted
requests with every process having completed the same number of cycles. Thismeans, for example, that the fact that a process can vary its order from cycle tocycle is irrelevant: all that matters is the particular order they have chosen for thiscycle. One can, by examining how this cycle can arise, deduce that there is a cycle ofprocesses Q0 , . . . , Qr −1  and one (with the same length) of channels c0 , . . . , cr −1 
where ci and ci⊕1 are both in the alphabet of Pi which insists (in the oﬀending
cycle) on communicating ci⊕1 before ci .
If we had not already seen Rules 4, 5 and 6 we would have been in a muchbetter position to deduce them after the above analysis.
We now turn to a fascinating speciﬁc example, where we can reﬁne the weakvariants a little. Imagine a network which behaves like the rectangular matrix
multiplication array except that nodes are allowed to choose nondeterministicallyin which order to communicate the two inputs and in which order to communicate
11 The generalization comes from not assuming that the communications are in the same ordereach cycle.

374

Deadlock!

the two outputs. (We still insist that inputs precede outputs.) Ignoring the data
values and calculations, the resulting node then behaves like
NDN=((left → up → SKIP )(up → left → SKIP));((right → down → SKIP)(down → right → SKIP));NDN

Now consider the number of half-cycles a node has completed when it has an ungranted request to its neighbour.
• When it has an ungranted output (down or right) request it must have completed at least one more half-cycle than the process it is requesting to.
• When it has an ungranted input (left or in) request it must have completed
at least the number that is one less than the half-cycle count of the process
it is requesting.
If we therefore deﬁne a set of weak variants
wi,j (s) = i + j + (s div 2)
we ﬁnd that these satisfy the conditions of Rule 12. For a process such that i +j = K(level K ) outputs to ones at level K + 1 and inputs from ones at level K − 1.
We can thus infer that any deadlock state of the resulting network must havea cycle of nodes whose variants wi,j (s) are equal. Closer examination shows this tobe impossible, for• If a process (in level K , say) has an ungranted request to one in level K + 1
and their variants are equal (i.e., the ﬁrst process has completed exactly one
more half-cycle than the second) then the second process itself has all its
ungranted requests to other processes in level K . (In other words, it must
be waiting for its other input ﬁrst.)• If a process (in level K , say) has an ungranted request to one in level K −1 andtheir variants are equal, then the second process itself has all its ungranted
requests to other processes in level K .
• If follows that the cycle of ungranted requests lies in the nodes on two adjoining levels: K and K + 1, say. But there is no cycle amongst these nodes(which actually form a chain when thought of as a graph).

13.3

Variants

375

In other words, from the point of view of deadlock, it actually does not matter
what order the nodes choose to input and output in on each cycle (and they may
choose independently) so long as they make all their inputs before their outputs.
Exactly the same analysis applies when we move up to higher-dimensional
grids of processes (e.g., three-dimensional) and allow the processes to order their
inputs and outputs nondeterministically (there being as many of each as there aredimensions). Except, that is, the very last part, for in three or more dimensions theset of processes in two consecutive layers does contain cycles, and the system canactually deadlock (see exercises). This diﬀerence between two and three dimensions
is most surprising and the fact that we can discover it so easily illustrates the powerof weak variants in focusing in on the essentials of a deadlock analysis. (End of
example)Exercise 13.3.1

Show that the variantsfi,j (s) = 2 × (i + j ) + #s
work for Rule 9 for the matrix multiplier array.

Exercise 13.3.2 On page 367 we showed how Rule 2 could be shown to be a consequence of Rule 9 by constructing a set of variant functions. Do the same thing for Rule3.
Recall Exercise 13.1.3. Now design a token ring, in which a single token circulates in anti-clockwise direction, and in which nodes acquire the token bysending requests to their clockwise neighbours (either on their own behalf or in passing
on requests received when they do not hold the token). Find a set of variant functions forRule 9, and a simpliﬁed set (together with a set of cycle-cutting edges) for Rule 10.

Exercise 13.3.3

Exercise 13.3.4 (a) Show that Rule 7 (resource acquisition) can by proved via Rule9, again by deﬁning a suitable set of variants.
(b) Use the variant functions deﬁned in (a) and Rule 11 to liberalize Rule 7:users can be given the additional ability to acquire any resource they want at any time
provided they follow rules about there being at least one ‘legitimate’ request in each state.
Formulate these rules.

Exercise 13.3.5 Figure 13.7 shows a road layout allowing visitors to drive round amonument. Cars all enter the road at A and pass round the loop until they exit at B . As
you can see, a pair of rocks have meant that one stretch of road is too narrow for cars topass each other: it is single lane there and two-lane elsewhere.
Code CSP processes which implement this layout, with one process per lane segment with the assumption that no more than one car can occupy each with, for the
moment, no other restriction on who can move forward onto the next segment on their376

Deadlock!

D

C

B
A

Figure 13.7 Road with a narrow section: see Exercise 13.3.5.
route. (Except for segment C , each should have two states, Empty and Full ; C shouldhave three states, Empty, Leftwards and Rightwards.) Show that this can lead to deadlock.
It is then decided to give out-going (i.e., rightward in our picture) cars priority overin-coming ones, in the sense that an in-coming car is not allowed to enter the single-lanesegment (C ) until segment D is empty. Modify your coding to achieve this, it will require
extra communication between C and D. Your aim should be to produce a system that is
now deadlock-free via a rigorous argument. The following is a suggested argument.
Use a set of weak variants (taking values in {0, 1}) to show that, in any state with adeadlock, either all segments are empty or there is a cycle of ungranted requests involving
full segments only. Show that the ﬁrst of these is not deadlocked.
Now show that, when full, segment C can never have an ungranted request to D
nor vice-versa, and that therefore the cycle of full processes cannot arise.
How would your coding and argument be aﬀected if there were more than one
single lane segment (all separated by two-lane stretches)? Would it work to give in-coming
traﬃc priority rather than out-going?

Exercise 13.3.6 Find the deadlock discussed on page 375 that appears in a threedimensional version of a nondeterministic input/output systolic array.

13.4

Network decomposition

Remember Rule 1, which shows how simple deadlock analysis is for tree networks.
We might hope to inherit some of this simplicity in cases where the network, though
not a tree itself, can be decomposed into a number of components (probably nottrees themselves) which are connected to each other like a tree. Speciﬁcally, we
might hope that the proof of deadlock freedom can be broken down into a separate
proof for each component.

13.4

Network decomposition

377

First, we have to decide on exactly what it means for a graph to break
down into a number of components. There are really two sensible answers to thisquestion, both of which turn out to be relevant to decomposing deadlock analyses.
For simplicity we will concentrate on the coarser factorization (i.e., the one that
divides a network into fewer pieces), but will later indicate where the other one
could have been used.
Deﬁne a disconnecting edge to be one whose removal would disconnect thecommunication graph. Such an edge can never be part of any cycle since the restof the cycle provides an alternative path between its two ends. These edges canbe thought of as the edges of a tree whose nodes are the components they leavebehind when they are all removed. These components might be termed essential
components since we hope to concentrate our deadlock analysis on these.
This gives a very pleasing decomposition of our network: if C1 , C2 , . . . , Ck are
the partition of the nodes (or rather their indexes) into essential components, andA∗1 , A∗2 , . . . , A∗k are the unions of the alphabets of the members of these components,
we havei=1 (Pi , Ai ) = i=1 (Pi∗ , A∗k ) where Pj∗ = i∈C (Pi , Ai )nkjis the composition of the processes in the component Cj . The communication graphof this re-construction of the network is, of course, a tree and the intersection in thealphabets of two neighbouring components is just the intersection of the alphabetsof the unique pair of processes in them that are adjacent in the original graph(across a disconnecting edge).
Since we have a tree (the network V ∗ comprising the (Pj∗ , A∗j )), the obvious
hope is that we can apply Rule 1. There are two requirements of Rule 1 that weneed to be careful are satisﬁed:• The new network has to be busy. In other words, the subnetworks deﬁning
the Pj∗ must all be deadlock-free. This is hardly surprising: the individual
proofs of deadlock freedom for the Pj∗ are just the parts our overall analysis
gets factored into.
• The new network has to be free of strong conﬂict. This creates more of aproblem since it turns out that even if the original network V was free ofstrong conﬂict, V ∗ need not be. If, however, each of the (disconnecting)edges in V linking two of the Pj∗ is free of conﬂict, then it is easy to see thatV ∗ is also free of conﬂict, which is of course enough.
Deadlock rule 13 If each of the essential components of the network V is freeof deadlock, and each of the disconnecting edges in V is free of conflict, then V isdeadlock-free.

378

Deadlock!

This rule is pleasingly general except for the requirement that the disconnecting edges are conﬂict-free. This more or less excludes the nodes at either end
getting into a state where each is waiting for some stimulus (e.g., a message packet)
from the other. Its use is therefore largely restricted to cases where, either naturally
or by careful design (e.g., the introduction of to-and-fro polling across such edges),
the two processes at the ends of a disconnecting edge agree which channel their next
communication will be on.
Of course we are still left with the problem of proving the essential components deadlock-free. It is quite likely that we will use some of the methods seenin this chapter which work by proving the non-existence of cycles of ungranted
requests. If this is done, then the restriction that the disconnecting edges are
conﬂict-free can be dropped.
Deadlock rule 14 If the network V is free of strong conflict, and such thatnone of the essential components can contain a cycle of ungranted requests (judged
relative to the vocabulary of V , not those of the components) then V is deadlockfree.
This is, of course, a trivial consequence of the Fundamental Principle since
the cycle of ungranted requests this generates must lie entirely within one of theessential components. Of our rules so far, Rules 2, 3, 4, 5, 7, 9 and 10 all exclude
cycles entirely.
For example, we can choose the variant functions (if Rule 9 or 10 is to be
our chosen method) for the diﬀerent essential components independently: there isno need for variants to decrease across disconnecting edges.
We mentioned above that there are two natural ways to decompose a network.
The diﬀerence between these comes from so-called articulation points: nodes rather
than edges whose removal would disconnect the graph. The biconnected components
of a graph are the largest subsets of a graph such that any two diﬀerent points belong
to a proper cycle. In general one essential component12 may divide into several
biconnected components: the divisions coming at articulation points like the one
shown in Figure 13.8 which belongs to three diﬀerent biconnected components. To
ﬁnd out more about this, consult a book on graph theory such as [46].
Rule 14 applies if essential components are replaced by biconnected components, since any proper cycle always lies completely inside one of these (which
are the smallest regions of which this can be said). This can lead to the curious
situation where we have to deﬁne two (or even more) diﬀerent variant functions fora single node: one for each biconnected component it belongs to!
Exercise 13.4.1

Suppose there are two adjacent tables of dining philosophers, each

12 In graph theoretic terms essential components are termed edge biconnected components.

13.5

The limitations of local analysis

379
Articulation point
Essential component
Smaller biconnected component
Disconnecting edge

Figure 13.8 Two ways of decomposing graphs.
individually made deadlock-free as in Example 13.2.4. A pair of them (one from each table)
make a pact that they will always eat at the same time: how is this situation described in
CSP? Show that it does not harm deadlock freedom. What can happen if there are two,
disjoint, pairs of philosophers like this?

13.5

The limitations of local analysis

Deadlock is a global phenomenon over a network and sometimes arises – or fails toarise – for extremely subtle reasons. There is probably no complete method for deciding whether or not a network deadlocks other than brute-force state exploration.
And yet all the methods described in this chapter so far have relied entirely on
local analysis: establishing properties of the behaviour of small collections – usually
no more than 2 – of processes. Such methods can never hope to decide all cases,
though they do seem to work in a large proportion of the examples that we humans
are cunning enough to devise.
If faced with the problem of designing a network that had to be deadlock-free,
you should look ﬁrst to the principles already established in this chapter, including
concepts not emphasized much such as building some of the pairs of processes sothat an ungranted request can never arise in one or both directions.
There is a rather precise sense in which all of our existing methods produce
networks that are robustly deadlock-free. It is this: all of the existing rules whichthemselves guarantee deadlock freedom (Rules 1–11) actually guarantee the stronger
condition of hereditary deadlock freedom, meaning that the network and all its
subnetworks are deadlock-free.

380

Deadlock!

Full track segment
Empty track segment

Figure 13.9 A simple railway layout with two trains.

What this does mean is that there can be no hope of using them to provethe deadlock freedom of networks where one subnetwork relies on the behaviour ofother processes to prevent it reaching a deadlock state it might otherwise ﬁnd itself
in. The archetypal example of this is the dining philosophers with butler we saw
earlier: this is not hereditarily deadlock-free since the network can deadlock if the
BUTLER process is removed.
That was a case where it was very easy to do things properly, but there areother examples where this is much harder and/or unreasonable. An example of thisis shown in Figure 13.9 which shows a picture of a small railway layout, in which
each of the pieces of track is one-way and there are two sets of points. The rules arethat a train can only move onto an empty section of track (where, if relevant, thepoints are not against it) and that each set of points can only be switched when thesegment of track containing it is empty. Unlike some other codings of railways inthis book, the only processes in this network are the track segments, with adjoining
ones communicating with each other to represent the movement of a train, rather
than there being separate train processes.
If we happen to know that there are only two trains running round thispicture we will probably quickly come to believe it is deadlock-free. On the other
hand, it is not hereditarily deadlock-free: as soon as we look at a proper subnetwork
such as that shown in Figure 13.10 there is nothing to prevent what is left becoming
ﬁlled up with trains. We have to rely on the fact that the overall network is closed
to prevent any more getting in. And this can lead to deadlocks: the conﬁguration in13.6

Deadlock and tools

381

Figure 13.10 A subnetwork that deadlocks.
Figure 13.10 (in which one track-segment process has been removed) is deadlocked
because the lower ‘exit’ set of points on the small loop cannot move to let out anyof the trains that are clogging this loop.
In this particular case a substantial re-coding to make trains explicit processes
would help, but the more natural way to go is probably to prove an invariant of the
network (namely that the total number of trains is 2) and then use this to contradict
the existence of cycles of ungranted requests. This speciﬁc sort of invariant, which
can be written
ni=1 fi (σi )= Kwhere fi (σi ) is a function of the state σi of the i th process, can itself be establishedby local analysis: what we have to show is that each action of a single process Pi
leaves its contribution unchanged, and that each communication between a pair ofprocesses leaves their joint contribution fi (σi ) + fj (σj ) invariant.

13.6

Deadlock and tools

We already know how to test a process for deadlock via reﬁnement checking13 : test
it against one of the speciﬁcations
DF

=

DF 

= (

a∈Σ

a → DFa∈Σa → DF  )SKIP

13 FDR has a speciﬁc deadlock-checking function. At the time of writing all this does is toperform this reﬁnement check; everything discussed in this section about improving the eﬃciencyof the said check therefore applies to the FDR deadlock check.

382

Deadlock!

depending whether or not it has the potential to terminate. When a system iswithin the scope of this type of check, this is usually the easiest way to analyze fordeadlock. It has the added advantage that none of the basic assumptions such as
busy-ness and triple-disjointness made at the start of this chapter is required. In
the ﬁrst part of this section we look at ways of bringing relatively complex networks
within the scope of this form of checking; in the second we discuss tools which
implement techniques more like those seen hitherto in this chapter.
13.6.1

Direct mechanical checking of deadlock freedom

The direct approach to analyzing systems for deadlock: simply testing for reﬁnementof DF has two main drawbacks. The ﬁrst, which we can do little about, is thatany check of a system on FDR requires us to deﬁne a speciﬁc network. There isno sense in which we can directly prove that a particular structure of network is
deadlock-free whatever its size. We can only attack N dining philosophers for aparticular N , not for all N at once.
The second problem is one of state-space size. Many problems of interest
have (at least in non-trivial instances) very large state-spaces and quickly get outof the range that FDR can deal with by enumerating one state at a time. There
are two main tricks that can be used to bring a problem down to the size where its
deadlock behaviour can be analyzed on FDR.
The ﬁrst is abstraction. Usually our intended use of a network will involve
it in handling data values; for example, passing messages around or processing
numbers. Certainly we would expect the values passed along channels to dependon this data. It may or may not be the case that which channels the process
communicates on also depends on data. Good examples to consider here are thematrix multiplication nodes, where the values passed along channels depend on
data, but the choices of which channels do not, and our various routeing networks,
where both the contents of messages and where they are sent depend on data (i.e.,address ﬁelds).
Assume that communication on a given channel is straightforward (speciﬁcally, conﬂict-free). In the ﬁrst case above – where the only thing that depends on
input data is output data – it is clear that the data being passed is quite irrelevantfrom the point of view of deadlock analysis. Thus, for deadlock analysis, the matrix
multiplication node process
N (x ) = up?a → left?b → right!b → down!a → N (x + a × b)
is equivalent to one with all the data values removed:N † = up → left → right → down → N †13.6

Deadlock and tools

383

This process of abstraction has reduced a process with an inﬁnite state space (assuming the values are real numbers) to one with four states.14
Now consider a node from the virtual routeing network (Section 13.2.1). The
data it transmits is in two parts: address and message contents. We would expect
to be able to abstract away from the contents ﬁeld in exactly the same way, since
the only thing that depends on what is input is the value later output in the sameﬁeld. The address ﬁeld is, however, used in a crucial way to decide where (in eachcase of three options) to send the data, so we cannot eliminate that so easily.
Whether we can eliminate it at all depends on whether we believe (and this isa belief we can test using the following) that the precise choice between the available
options is important from the point of view of deadlock. Unless you are sure it isimportant, you should turn all the choices, made on the basis of the data you aretrying to abstract, into nondeterministic ones. Thus, the two types of node in thevirtual network will becomeI†=in → I †
2 I-up → I †
2 I-left → I †

I †

=

I-right → I †I-down → I †over → I †O†=over → O †
2 O-down → O †
2 O-right → O †

O †

=

O-left → O †O-up → O †out → O †This abstraction procedure is one you can check: if forget is the renaming functionthat forgets whatever data values we are abstracting from channel communication(e.g., forget(in.i .j .m) = in), you should ﬁnd thatI†

forget(I )In other words, every behaviour that I might make is reﬂected in the abstracted
process.
14 This form of abstraction – removing detail which is irrelevant to the internal operation ofcomponent processes – is very closely linked to the topic of data-independence which we will study
in Section 15.3.2.

384

Deadlock!

You should then use the processes I † and O † in place of the originals whenchecking for deadlock freedom. In this case it would work: in fact the proof of
deadlock freedom in terms of Rule 2 works just as well for the abstracted network
as it did for the original. If it does work this guarantees deadlock freedom forthe unabstracted network. If it does not, and a deadlock is found, you have todecide whether the oﬀending behaviour was one that the unabstracted network
could have produced or not. Bear in mind that just because a single deadlock of
the abstracted network could not appear in the original, this does not imply theoriginal is deadlock-free.
The formal basis of this abstraction procedure is captured in the following
rule.
Deadlock rule 15 (abstraction rule) Suppose ‘forget’ is the function that
abstracts away the data contents of one or more conflict-free channels (each of whichis contained in each process alphabet it intersects) in the network V = {(Pi , Ai ) |1 ≤ i ≤ n}. Then

i=1 (Pi†, A†i )nforget(ni=1(Pi , Ai ))where (Pi† , A†i ) = (forget(Pi ), forget(Ai )). Hence if the left-hand side of the aboverefinement is deadlock-free, so is V .
Notice that we already performed the same sort of abstraction in the binary switching network (page 369). It can, of course, also be applied to wormhole
routeing.
The second method of making the state spaces of explicit checks manageable
is the combination of hiding and compression. In the stable failures model a CSP
process P can deadlock if and only if P \ Σ can (see Section 8.4 for technical details).
This is of interest because it is generally the case that the more hiding is present
in a process deﬁnition, the more susceptible it is to hierarchical compression. The
objective of hierarchical compression (which is discussed in more detail in SectionC.2) is to build up processes in stages, at each one trying to minimize the number ofstates in their representations. The eﬀectiveness of this technique is demonstrated
by several of the example ﬁles on the web site (see Preface).

13.6.2

Automated checking of rule-based proofs

While the methods described above frequently allow one to investigate automaticallywhether a network is deadlock-free, it will certainly sometimes occur that, evenusing compressions, addressing the state space of the entire network is too great aproblem.

13.6

Deadlock and tools

385

It is then natural to ask whether automation can help in the sort of deadlock
analysis addressed in the rest of this chapter. All of the basic conditions on networks
we have used, such as busy-ness and freedom from (strong) conﬂict, as well as thepreconditions to Rules 1–8, can quickly be checked for any network of ﬁnite-stateprocesses, though it sometimes requires a good deal of ingenuity to do so witha reﬁnement checker like FDR. The reason for this problem is that in conditions
relating to how a pair of processes evolve (such as strong conﬂict) it is necessary
to examine the inner workings of the pair (such as whether they have requests toeach other) as well as their outward appearance as a process. It is really better,particularly because of this need to examine how pairs evolve, to build a specialized
tool for checking the preconditions for deadlock rules. This has been done by Jeremy
Martin, whose tool is called the Deadlock Checker.15
The later, variant-based, rules are a little more problematic to automate
because we need some way to represent the variant function. It must be recognizedthat sometimes adding a variant function can turn a ﬁnite-state process into an
inﬁnite-state one: this obviously happens when, as in the variants used for cyclic
communication networks, the variant has an inﬁnite range.
Martin’s tool incorporates an additional method of analyzing for deadlock
which is arguably very close to the concept of variant, but has the advantage ofbeing completely automatic. This is based on the State Dependency Digraph (SDD),
something which is usually too unwieldy to work out by hand but which is wellwithin the scope of an automated tool even for very large networks. The SDD ofa network has one node for each state of an individual process in the network V –thus its size is the sum of the state space sizes of the component processes. It has anedge from (i , σ) (Pi in state σ) to (j , ρ) if, and only if, Pi and Pj can simultaneously
reach σ and ρ when put in parallel and then Pi has an ungranted request to Pj .
It is possible to show that the SDD is acyclic if, and only if, there is a setof variant functions for V satisfying the preconditions of Rule 9 and such that thefunctions are all based purely on the position the processes are in their ﬁnite statemachine representations. (It should be noted that not all the variant functions
used earlier have this latter property. The exceptions are those relating to cyclic
communication networks and similar.) Thus an acyclic SDD implies deadlock freedom. Martin’s thesis [78] and tool both contain extensions of this technique to allow
SDDs to be used for proving deadlock freedom in wider classes of network such as
networks with conﬂict.
Clearly any cycle of ungranted requests in the network implies the existenceof a cycle in the SDD. It is tempting to believe the reverse, but there are two reasons
why the existence of a cycle in the SDD does not necessarily imply the possibility
15 See the Bibliography for the availability of this tool.

386

Deadlock!

of a cycle of ungranted requests in V .
Firstly, just because the processes round some cycle in V can reach someassignment of states when we consider their parallel compositions pairwise does notmean that the same combination can be reached in the parallel composition of theentire network.
Secondly, and more interestingly, it is entirely possible for diﬀerent states ofthe same process to appear in the same cycle in the SDD. Obviously no such cycle
can correspond to a cycle of ungranted requests. It is this possibility that generates
the restriction above that the variant functions have to be based on the speciﬁcstates used in constructing the SDD. Clearly one can look only for those cycles thatinvolve all diﬀerent processes, but this appears to be much more time consuming.
Despite these drawbacks, methods based on analyzing SDD graphs appear
to be perhaps the most interesting and powerful class for building deadlock analysis
tools.

13.7

Notes

The deﬁnitions and results in this chapter are largely taken from the author’s papers
with Dathi and Brookes [118] and [21] together with the theses of Dathi [28] andMartin [78], as are many of the examples. These are probably the best sources topursue for further details. Earlier work on the analysis of deadlock in CSP networks
can be found in [101] and [20]. There have been various applications of this type ofanalysis, especially in the occam community, see [103, 136], for example.
The fact that tree networks are a special and easy case in deadlock analysis
has been long known and it is hard to pin down where it originates. The conditions
and deﬁnitions in Section 13.1 can be thought of as an attempt to capture formallythe circumstances under which the result ‘trees are deadlock-free’ is true.
The concept of a cyclic communication network was described by Dijkstra
and Scholten in [33], and Deadlock Rule 4 is essentially derived from that source.
It should be appreciated that none of the combinatorial techniques describedin this chapter is complete, in the sense of guaranteeing to establish deadlock freedom whenever it is true. It seems almost certain that no tractable locally-based
technique could do this, since in general the problem of deciding whether a CSP
network can deadlock is NP complete. All one can hope for is that the methods wehave described, and other similar ones, are suﬃcient to deal with the majority ofpractical deadlock analyses. Provided one is prepared to espouse the principle discussed on page 345 that we should build our systems to be inherently deadlock-freerather than adding patches later, this seems a much more reasonable desire.

13.7

Notes

387

The author hopes that the wide range of deadlock analysis techniques in thischapter will deal with many of the examples readers want to handle, and also givethem ideas about how to formulate and prove their own rules to deal with otherexamples.
2005: It has recently come to the author’s attention that the concept of conﬂuent processes (namely ones where if two events are possible then performing one
will not preclude the other), which can be found in Milner’s work [82], is closely
connected with the CCNs presented in this chapter. Furthermore, it can be shownthat both these classes of network (and any others for which a set of non-decreasing
variant functions can be found, that never decrease as a process evolves) are buﬀertolerant with respect to deadlock freedom. Namely, adding arbitrary buﬀering neverintroduces deadlock into them.
Example transformation
A typical transformation using algebraic laws to manipulate hiding and renaming
as discussed when introducing assumption D in Section 13.1.1 is given below. The
example considered is the parallel/hiding/renaming combination(P >> Q) >> R
We wish to move all hiding to the outside, and all renaming on to the component
processes.
First we observe that the name of the channel mid used in deﬁning >> isirrelevant, because, for any other name n (apart from left and right),
P >> Q= (P [[right, mid /mid , right ]] {|left,mid|} {|mid,right |}Q[[mid , left /left, mid ]]) \ {| mid |}= ((P [[right, mid /mid , right ]] {|left,mid |} {|mid ,right|}
Q[[mid , left /left, mid ]]) \ {| mid |})[[n /mid ]]= (P [[right, n /n, right ]] {|left,n|} {|n,right |} P [[left, n /n, left ]]) \ {| n |}(Here the second line follows by f [·]-hide-null, and the ﬁnal one by a combinationof f [·]-hide-sym, f [·]-X Y -dist and [[R]]-combine (3.16).) Note that the last line
above is identical to the deﬁnition of P >> Q except that the name n replaces mid .
This shows that (P >> Q) >> R can be written:(((P [[right, n /n, right ]] {|left,n|} {|n,right |}Q[[left, n /n, left ]]) \ {| n |})[[right, mid /mid , right ]]{|left,mid |} {|mid ,right |} R) \ {| mid |}388

Deadlock!

This is important because it allows us to push the renaming of the inner combination
down to P and Q (using f [·]-hide-sym and f [·]-X Y -dist) without changing thename of the channel hidden at the intermediate level:(((P [[right, n /n, right ]][[mid , right /right, mid ]] {|left,n|} {|n,mid |}Q[[left, n /n, left ]][[mid , right /right, mid ]]) \ {| n |}){|left,mid |} {|mid ,right |} R) \ {| mid |}And equally importantly it then lets us move this intermediate-level hiding, usinghide-X Y -dist, to the outside since the events hidden do not intersect the alphabetof the right-hand process.
((P [[right, n /n, right ]][[mid , right /right, mid ]] {|left,n|} {|n,mid|}
Q[[left, n /n, left ]][[mid , right /right, mid ]]){|left,mid ,n|} {|mid,right |} R) \ {| n |} \ {| mid |}Finally, we can collect all the renamings of each component, and all the hiding at
the outside, together.
((P [[right, n /n, right ]][[mid , right /right, mid ]] {|left,n|} {|n,mid|}
Q[[left, n /n, left ]][[mid , right /right, mid ]]){|left,mid ,n|} {|mid,right |} R) \ {| n |} \ {| mid |}Chapter 14

Modelling discrete time

14.1

Introduction

All of the modelling we have done so far has been done without measuring thepassage of time. We have cared about what order events happen in, but not how
long there is between them or at what time any speciﬁc one happens. When ourcorrectness criteria are independent of time (as have been all we have seen to date, ofcourse) and our implementations do not rely on internal timing details to meet their
speciﬁcations, this abstraction is very useful since it simpliﬁes both the descriptionof, and reasoning about, processes. Nevertheless, it is in the nature of the sort ofinteractive systems we describe using CSP that sometimes it is desirable to be able
to reason about their timed behaviour.
There are two distinct approaches to this. The more elegant is to re-interpret
the CSP language over time, and record the exact time at which each event occurs.
A trace thus consists of a series of time/event pairs rather than just events. This
leads to a range of semantic models incorporating time, just as we have seen avariety of models for the untimed version. This theory of Timed CSP, though its
models are sometimes surprisingly diﬀerent to those we have seen (and generally
more complex), has elegant links into the untimed theory allowing development andveriﬁcation to be carried out in both. This will typically allow the developer to use
the more complex timed models only for those parts of his or her work which requireit.
There is a substantial literature on Timed CSP (see Section 14.8) and, inparticular, a textbook (by S.A. Schneider) covers it in detail. We will not, therefore,
go into the details of it here.
In Timed CSP, the times associated with events are non-negative real numbers. In other words, it adopts a dense, continuous model of time. This has an390

Modelling discrete time

intuitive appeal, since it corresponds with the standard way in which we think
about measuring time. It is unfortunately true that using continuous time substantially complicates the problem of automating veriﬁcation and, except in very
restricted circumstances, makes decision procedures based on state enumeration infeasible or impossible. For continuous time adds an extra inﬁnite dimension both to
the recording of events and to the evolving process state, and it is only by imposing
severe restrictions and using clever equivalences that this inﬁnity can be avoided.
The most obvious alternative model of time is of an inﬁnite series of discrete
instants, equally separated. This results in a time domain which looks like thenatural numbers, though the interval between successive beats of the drum might
be any size, from nanoseconds (as would typically be the case for a clocked circuit)upwards. In most computer applications where all of the component processes areultimately controlled by a single clock, such as clocked VLSI or scheduler-based
systems, a discrete clock is closer to the spirit of the system than a continuous timemodel. In any case it is often possible to give a good enough approximation to othersystems using suﬃciently ﬁne discrete models.
There is a considerable variety of ways in which we could include a discrete
time model into CSP. Many of these would involve incorporating time explicitly intosemantic models, as described above for Timed CSP. The subject of this chapter,
however, is how to model timed systems in ordinary, ‘untimed’ CSP by including thedrum-beat of the passage of time as an explicit event. This event is conventionallycalled tock (rather than tick since that is easily – especially on tools – confused with
). All of the processes with timing constraints must synchronize on the event tock :this allows us to regulate and reason about the amount each process and the overallsystem does in given time intervals.
Advantages of this approach are:• As we will see, it gives considerable ﬂexibility about how to model and reason
about timed systems.
• The human user can understand timed systems without having to learn another model.
• Existing tools can be applied to timed systems.

14.2

Meeting timing constraints

Having taken the decision to include the tock event in a process’s alphabet, one isforced to make detailed decisions about what its actions mean and how they occur
in time. This is illustrated by a timed version of COPY . Suppose it takes one unit

14.2

Meeting timing constraints

391

of time for a data value to pass through this one-place buﬀer, and that a further unitof time is required between the output and the next input. The obvious deﬁnition,
given this, is
TCOPY 1 = left?x → tock → right!x → tock → TCOPY 1
But there is a big diﬀerence between this process and the original COPY , because
this one insists on performing an action each unit of time: it does not allow time
to pass until it has done something on each and every cycle. The original COPY
will wait as long as you like either to input or output. It is reasonable to saythat TCOPY 1 becomes urgent one time unit after performing any action: it insists
on doing some visible action before time can progress. The correct translation of
COPY (with the same assumptions about how long it takes for one communication
to enable another) is actually
TCOPY 2 = left?x → tock → TCOPY 2 (x )2 tock → TCOPY 2
TCOPY 2 (x ) = right!x → tock → TCOPY 2
2 tock → TCOPY 2 (x )since this process says that there has to be at least one time unit between input
and output events, without expressing an upper bound. The states TCOPY andTCOPY 2(x ) might be said to be idling, in that the passage of time has no eﬀect
on them.
An interesting hybrid between these processes is one which will wait to input,
but not to output – it idles on input but is urgent about outputting:
TCOPY 3 = left?x → tock → right!x → tock → TCOPY 3
2 tock → TCOPY 3
By slight modiﬁcations one can come up with versions which expect one orother of their communications to occur within any ﬁxed N time units, or which cannondeterministically select when (and for how long) a communication is available.
Clearly, then, we can be much more expressive about how a process behavesin this timed world than previously. This makes it possible to describe paradoxical
networks which must meet inconsistent timing constraints. Imagine, for example,
placing TCOPY 1 in parallel with a process expressing the constraint that there
cannot be more than M communications in the ﬁrst N time units: TLimiter (N , M ),where
TLimiter (n, m) = RUN <I n = 0>I((STOP <I m = 0>I ?x : Σ {tock } → TLimiter (n, m − 1))
2 tock → TLimiter (n − 1, m))392

Modelling discrete time

If M < N then our two sets of timing requirements are inconsistent, which
manifests itself in the combination deadlocking. This is what happens when one
puts together a combination whose timing requirements do not match, which gives
us an easy way of testing for this. This situation is called a time-stop. If we can placea process like TCOPY 1 or TCOPY 3 into a system without creating a time-stop, it
essentially means that the timing assumptions on the availability of communicationthat are built into these processes are consistent with the system.
As a further example to illustrate this idea, we can modify TCOPY 3 so that
it is parameterized by the channels it uses and, more importantly, by the delay
between the input and output of a datum:
TCOPY 4(left, right, D) = left?x → TCOPY 4 (left, right, D, D, x )2 tock → TCOPY 4(left, right, D)
TCOPY 4 (left, right, D, N , x ) = tock → TCOPY 4 (left, right, D, N − 1, x )<I N > 0>I
right !x → tock → TCOPY 4(left, right, D)
Let us think about what happens if we ‘pipe’ two of these together:
TCOPY 4(a, b, D1 ){|b,tock |}TCOPY 4(b, c, D2 )If D2 ≤ D1 , all is ﬁne: we can guarantee that the right-hand process will not be
expected to make its (n+1)th input until at least D1 + 1 time units after its nth,and it is therefore ready. On the other hand, if D2 > D1 , then if (though it neednot) the left-hand process makes its second input as soon as it can, this will leadto a ‘time-stop’ when it needs to output D1 units later and the right-hand process
is not ready. If, on the other hand, the environment is suﬃciently slow in putting
inputs into the combination, the problem will not arise.
Notice that processes like TCOPY 4 and TLimiter (n, m) have many statesthat are neither urgent nor idling: in other words they allow tock but are notunchanged by it. It is as well to have a name for this type of state too, so wewill call them evolving. Every state of a timed system falls into one of the three
categories of urgent, idling and evolving, and it is a most helpful distinction to bearin mind when designing programs for this style of CSP system.
In most examples it would be ridiculous to have inﬁnitely many ordinary
actions between two tock s, since this would mean that inﬁnitely many actions occur
in a ﬁnite time interval. This is equally easy to check for, all we have to do is lookfor divergence in
P \ (Σ {tock })14.2

Meeting timing constraints

393

Indeed, the most basic ‘sanity check’ on this sort of model of a timed system isto verify that the above process equals (which is equivalent, because the following
process is deterministic, to saying that it reﬁnes)
TOCKS = tock → TOCKS
in the failures/divergences model. This shows that inﬁnitely many actions cannot
occur in any ﬁnite time interval, and that no matter what happens it is possible(provided the environment communicates appropriately) for time to progress – inother words, there are no reachable inconsistencies in the timing constraints. If there
were any possibility of our process terminating () we would have generalized thisto proving reﬁnement of
TOCKS  = (tock → TOCKS  )SKIPthough this will never be necessary for any of the examples we deal with in thischapter.
As said above, a process can satisfy this check when, in order to let time pass,
it is necessary for the environment to engage in suitable communications with theprocess. Both TCOPY 1 and TCOPY 3 satisfy it, for example. It may well be that
we need the process to be tolerant of not receiving some or all communications instantly – the most obvious distinction here being between input and output events.1(It may well be reasonable to assume that the environment is always willing toaccept an output, but it may be unreasonable to assume that the environment isalways waiting to send an input.)
If there is a set of events D which the environment is assumed to be allowed todelay indeﬁnitely, but may still allow, the above test should be modiﬁed to showingthat(P  Chaos D ) \ (Σ {tock })D

reﬁnes TOCKS . If D = {| left |}, we will have that TCOPY 3 satisﬁes this but that
TCOPY 1 does not. The point is that Chaos D may either allow or prevent actions
from D, so the process can neither discount the occurrence of these events nor relyon them happening. Setting D equal to Σ {tock } would correspond to all normal
events being arbitrarily delayable by the environment – the conventional CSP viewof communication.
1 There are similarities between this distinction and the one between ordinary and signal events

discussed in Section 12.1.2. Indeed, the process deﬁned here for testing timing constraints isexactly the mixed abstraction deﬁned in that section. Setting D = Σ {tock} reduces it to lazy
abstraction.



394

Modelling discrete time

In the above checks, using failures-divergences reﬁnement will ensure that
only ﬁnitely many events happen between tock s, whereas using failures reﬁnement
would check only for time-stops. It might well be the case that you want to relax
the condition that only ﬁnitely many events can happen between tock s, but only
as regards delayable events. In some circumstances it may be more appropriate torely on the external process instigating these events not to send inﬁnitely many in aﬁnite time, and so putting in restrictions into our process P might seem unnecessary
and overcomplex. A good example of this will be found in the case study of thebully algorithm (Section 15.2). One appropriate check to use in this case is thatP \ (Σ (D ∪ {tock }))failures/divergences reﬁnes
TOCKS ||| Chaos D
This says that events in D are never required to enable tock to happen, and that
only ﬁnitely many other events happen between each pair of events that are either
tock or in D. If you intend to join a pair of processes together, with each process’s
signal events being the delayable ones of the other, then this weaker check ought
only to be used at one end of the interface.
It would also be possible to allow for an environment that will guarantee
intermediate levels of acceptance of communication, such as guaranteeing to accept
any communication in a set B if oﬀered for at least N units. There might well be arole for such tests when we know that the component in hand will ultimately be put
in a system that makes such guarantees (because, for example, of scheduling). But
in specifying a ‘complete’ system, events will tend to come into the category thatare simply observed by the environment, which it cannot delay, and those which
the environment can delay indeﬁnitely.
Exercise 14.2.1 Deﬁne a version of TCOPY which outputs at a time it nondeterministically chooses between A and B time units from the corresponding input. It is thenready to input again C units later. What might happen when two of these are connected
together?
Exercise 14.2.2
Give trace speciﬁcations for the following: (i) no more than N
ordinary events occur between any two tock s, (ii) no more than M tock s occur between
consecutive occurrences of the event a. Give deﬁnitions for the characteristic processes ofthese speciﬁcations.
Recall the cash-point machine examples in Part I. Deﬁne a version
in which the machine will wait only M time units for the correct insertion of the PIN, andotherwise will retain the card. It should wait indeﬁnitely for all its other communications.
Identify which states of the system are urgent, which are idling, and which are evolving.

Exercise 14.2.3

14.3

Case study 1: level crossing gate

14.3

395

Case study 1: level crossing gate

A level crossing is where a road crosses a railway track (without a bridge or tunnel).
The road direction is usually controlled by a gate that is meant to stop cars getting
onto the railway line when a train is passing. In this example we consider a simple
model of this, in which timing is used to establish basically untimed safety properties(e.g., when a train is near or on the gate, the gate is down) and to specify timing
properties of the system (e.g., the gate goes up within K units when there is no
train near or approaching).
We describe this system as a parallel combination consisting of a number ofparts:• processes representing track segments;• processes representing trains;• processes describing timing constraints on these things;• a process representing the gate;• a controller process which monitors sensors, etc., and sends control signals
to the gate.
For simplicity we will model the case of a single line along which trains only
move in one direction. The track is broken into segments (which are at least as longas any train). They are numbered, with this sensor in segment 1 and the crossing
and output sensor in segment GateSeg .
We are not going to rely on timing for anything other than the properties of
the gate. Other safety requirements obviously apply to our little system, such asthat there are never two trains on the same track segment, but these will not be ourprimary concern here. Our method of system development will be to describe thetrack segments and trains as untimed processes, and later put processes in parallelwith them to describe their timed behaviour.
The following gives an untimed description of train t on track segment j .
Note that a train enters the next segment (j + 1) before it leaves segment j , andthat there is a ‘track segment’ 0 which represents the outside world. SC denotes
the number of segments including this segment 0. We will assume that the levelcrossing itself is in segment GateSeg, which lies between 1 and SC − 1. For timing
reasons it should never, in fact, be either the ﬁrst or last segment.2 Here, t ranges
2 If it were the ﬁrst then it would not be possible to get the gate down in time and if it were thelast then the way we later arrange our timing constraints means there would be no guarantee a
train would ever leave GateSeg, thus preventing the gate from rising. The best value for GateSeg
is probably SC − 2.

396

Modelling discrete timeover a set TRAINS of train names and ⊕ represents addition modulo SC .
Train(t, j ) = enter .t.j ⊕1 → leave.t.j → Train(t, j ⊕1)
The track segments can be occupied by one train at a time, and each time a
train enters segment 1 or leaves GateSeg the appropriate sensor ﬁres.
Track (j ) = (enter ?t!j → sensor .in → Trackf (t, j ))<I j = 1>I
(enter ?t!j → Trackf (t, j ))Trackf (t, j ) = leave.t.j → sensor .out → Track (j )<I
I j = GateSeg>
leave.t.j → Track (j )It makes sense to consider the combination of the SC − 1 track segmentprocesses with as many trains as we wish to consider. The processes within each ofthese classes do not communicate with each other, but the collection of all trains
synchronizes with the tracks on all enter and leave events apart from those relating
to the notional ‘outside’ segment 0.
Tracks= Track (1) ||| . . . ||| Track (SC − 1)

Trains= Train(Duncan, 0) ||| . . . ||| Train(Thomas, 0)

Network= TrainsTracks

IFace

where

IFace

= {enter .t.j , leave.t.j | t ∈ TRAINS ∧ j ∈ {1 . . . SC −1}}

It would, of course, be possible to prove various safety properties of this system,
such as the fact that there are never two trains on the same track segment.
None of these processes uses the time event tock , but since our eventual goal
is to ensure via timing that the gate is up and down at appropriate moments, wehave to make some assumptions about the relative timing of the events in the above
system. What we do in this case is to introduce one or more timing processes toregulate the behaviour of each of the component processes that needs it.
We can make assumptions about the speed of the trains as they pass throughour system by regulating how many units of time are taken over a track segment.
Let us suppose there are identiﬁers MinTocksPerSeg and MaxTocksPerSeg which
represent our assumptions about the minimum and maximum number of time units
a train can spend per track segment. This could be expressed either as a constraint
on trains or on track segments. In the former case one might set out the range oftimes a train can spend between successive enter events (in which case it is necessary
to special-case the behaviour when outside the system). In the latter case one might

14.3

Case study 1: level crossing gate397

express a bound on the time between any train entering and leaving a segment, or
between them entering a segment and entering the next. While the enter/leaveapproach has obvious attractions, it has the disadvantage that the length of a trainaﬀects how fast it can travel – presumably the enter event is triggered by the frontof the train and the leave event by the back. This would also mean that the same
tock s can apply to the train’s passage through two diﬀerent segments: the time
taken to pass through several would not be the sum of the times apparently taken
for the individual ones. The approach we take is therefore the ﬁrst alluded toabove: expressing upper and lower speed limits on all the real track segments via
consecutive enter events.
SpeedReg(j )= enter ?t!j → SpeedReg  (j , 0)tock → SpeedReg(j )SpeedReg  (j , n) = (tock → SpeedReg  (j , n+1)<
I n < MaxTocksPerSeg>
I STOP )2 (enter ?t!j ⊕1 → SpeedReg(j )<I n ≥ MinTocksPerSeg>
I STOP )Slight modiﬁcations would allow the speed limits to vary from segment to segment,or to change from this ‘track-centred’ constraint to a ‘train-centred’ one (with one
process per train).
The only other timing constraints we need are on the ﬁring of the sensors:
we specify that these must ﬁre within one unit of a train entering the ﬁrst segment
or leaving the last, as appropriate.
InSensorTiming= enter ?t!1 → sensor .in → InSensorTiming
2 tock → InSensorTiming

OutSensorTiming= leave?t!GateSeg → sensor .out → OutSensorTiming
2 tock → OutSensorTiming

Thus we end up with timing regulators only on the track segments. Thanks
to the associative properties of parallel operators, there are two equivalent ways ofadding in these constraints:• We could rebuild the process Network by adding the timing constraints individually onto the component processes before combining them together(bearing in mind that all the ones this is done to – in this case the track
segments – need to be synchronized on tock ). This approach is complicatedin our example by the fact that most SpeedReg(j )’s overlap the alphabets of
two Track (j )’s.
• We could combine all the timing constraints together as a single process

398

Modelling discrete timeand put it in parallel (synchronizing on all relevant events) with the existing
Network .
Using the second of these approaches, we get the additional process structure

SpeedRegs

=

SC −1

j =1 (SpeedReg(j ), αSR(j ))where αSR(j ) ={tock , enter .t.j , enter .t.j ⊕1 | t ∈ TRAINS }SensorTiming=

InSensorTiming

NetworkTiming=

SpeedRegs  SensorTiming

where S=

{tock } ∪ {enter .t.1 | t ∈ TRAINS }TimedNetwork=

Network  NetworkTiming

where T={leave.t.GateSeg | t ∈ TRAINS } ∪ {| enter , sensor |}{tock }OutSensorTiming

S

T

The gate is operated by a controller process. In terms of CSP modelling, we
could either build our assumptions about the timing behaviour of the gate into thecontroller process itself, or have a separate gate process. It is probably better todo the latter, particularly if there is any nondeterminism about the gate timing.
Therefore we will deﬁne separate controller and gate processes. There are then fourbasic states of the controller, some of them parameterized by a count of trains (thenumber currently in the domain).
To illustrate a diﬀerent way of constructing timed processes, we include therather simple timing constraints on the operation of the controller into its basic
deﬁnition rather than add them in later.
When the gate is up we allow time to pass or the inward sensor to ﬁre, which
immediately (i.e., before the next tock ) causes the godown command to be sent to
the gate. The ﬁrst of the four states is thus:
ControllerUp= sensor .in → gate!godown → ControllerGoingDown(1)2 tock → ControllerUp

This raises an interesting question about our model: what happens if the sensor .out
event occurs in state ControllerUp? Now of course we do not want this to happen,
since it would mean that a train was on the segment including the crossing while thegate is up. The process above, as written, would simply refuse the sensor event –a refusal that does not really correspond to reality since simply refusing to look at
a problem does not mean it is not there! There are at least three ways one could
resolve this:14.3

Case study 1: level crossing gate399

1. Remember that our description is not accurate in this eventuality but provelater that it never happens. (One of our aims will be to show that the gateis always down when there is a train nearby.)
2. Note that the process OutSensorTiming implies that the event in question
must happen within one unit of time from the one that causes it, and thatthe refusal of it when possible would cause a time-stop, since the basic timing
consistency check would have failed.
3. Add a clause to the above deﬁnition of ControllerUp which accepts the event.
It might then either cause an error/alarm condition or simply ignore it.
Of these, the author prefers the last since it avoids using either assumptions or
the subtleties of timing to ensure our deﬁnitions make sense. And while we canlater verify quite independently that the basic safety condition holds, it is useful for
debugging purposes explicitly to catch obvious error conditions, so we modify theabove deﬁnition toControllerUp= sensor .in → gate!godown → ControllerGoingDown(1)2 sensor .out → ERROR
2 tock → ControllerUp

On the whole, if a process is one that simply observes an event (as the controller
observes various sensors) rather than being able to refuse it, it is good practice
to write the deﬁnition of the process in such a way that this pattern is obviously
adhered to.3
The two states ControllerGoingDown and ControllerDown both keep a recordof how many trains have to pass before the gate may go up. Each time the sensor
event occurs this count is increased. In order to keep the controller ﬁnite state,
we put in a clause to ensure that the count should not get greater than the number of trains that can legally be in the domain (which equals the number of track
segments). The ControllerGoingDown state comes to an end when the gate.down
event occurs. It is no more legitimate for the sensor .out event to occur in this statethan the previous one, so the same solution is adopted.
ControllerGoingDown(n) = (ERROR<
I n > GateSeg>
I
sensor .in → ControllerGoingDown(n+1))
2 tock → ControllerGoingDown(n)2 gate.down → ControllerDown(n)2 sensor .out → ERROR
3 This is related to the concept of a monitor that was deﬁned on page 317.

400

Modelling discrete time

When the gate is down, either sensor event may occur, incrementing or decrementing the train count as appropriate (subject to the same ﬁnite state limitation).
When there are no trains left in the system the gate is signalled to go up.
ControllerDown(n) = (ERROR<
I n > GateSeg>
I
sensor .in → ControllerDown(n+1))
2 tock → ControllerDown(n)2 sensor .out →((gate!goup → ControllerGoingUp)<
I n = 1>
I ControllerDown(n−1))
When the gate is going up, the inward sensor may still ﬁre, which means thatthe gate must be signalled to go down again. Any occurrence of the other sensor
event is an error, as previously. Of course this state may get the signal conﬁrming
the gate is up, and will then return to its initial state.
ControllerGoingUp= sensor .in → gate!godown → ControllerGoingDown(1)2 sensor .out → ERROR
2 tock → ControllerGoingUp
2 gate.up → ControllerUp

In the above deﬁnitions, you can take ERROR to be any process whose
activation would make itself felt in the complete network, in the sense that it istrivial to check that it never occurs. The two obvious possibilities for ERROR
are the divergent process div (which requires the full failures/divergences model
to detect it), and a process that raises an alarm via an error event (which should
not, of course, be synchronized with any other error events there may be in otherprocesses).
ERROR = error → STOP
If the latter approach is taken, one should assert that the error event neverappears by proving that the ultimate system reﬁnes Chaos Σ {error } .
Neither ERROR nor div makes any allowance for how the system behavesafter an error occurs. This is ﬁne when, as in this case, our objective is to provethat errors never occur; but when errors can occur and have to be handled, a more
careful treatment would be required.
The gate process can always be commanded to go up or down, and will obey
the command in some nondeterministically chosen time within assumed bounds.

14.3

Case study 1: level crossing gate

401

When it reaches either the up or down state it sends a signal indicating this.
GateUp

GateGoingDown(n)GateDown

GateGoingUp(n)= gate.goup → GateUp
2 gate.godown → GateGoingDown(0)2 tock → GateUp= gate.goup → GateGoingUp(0)2 gate.godown → GateGoingDown(n)2 (((gate.down → GateDown)
tock → GateGoingDown(n+1))<
I n < DownTime>I (gate.down → GateDown))= gate.goup → GateGoingUp(0)2 gate.godown → GateDown
2 tock → GateDown= gate.goup → GateGoingUp(n)2 gate.godown → GateGoingDown(0)2 (((gate.up → GateUp)
tock → GateGoingUp(n+1))<
I n < UpTime>I (gate.up → GateUp))

This completes the deﬁnition of the component processes, and we can now
add the last two processes to the network:
GateAndController=

ControllerUp

SYSTEM=

TimedNetwork{|tock ,gate|}

GateUp{|sensor ,tock |}GateAndController

It is worth noting that all the components of the system have been initialized
to indicate that there are no trains in the domain and the gate is up. This is muchthe simplest (both to deﬁne and to understand) initialization, but it would bepossible to deal with other situations as long as care were taken to make sure that
all of the components were initialized consistently.
The reason why timing analysis is necessary in this system is that there isno interlock that prevents a train getting onto the level crossing when the gate is
not down: note that TimedNetwork and GateAndController only synchronize on
tock and the sensor events. We are relying simply on the relative times that thetrain takes to get from being sensed, to reaching the gate, and from the ﬁring of
the sensor to the gate being fully down. Whether the basic safety requirement is402

Modelling discrete timesatisﬁed will depend on just what parameters (number of track segments, speed
limits and gate timings) are used.
Before looking at this issue in detail we need to establish, on the patterndiscussed earlier, that the timing descriptions in our code are consistent. Most of
the events in our system are ones which are observed by, rather than controlled
by, the external environment. The only events that the system does not rely on
happening within some bound are those representing trains’ entries into segment 1.
Beyond that it does make various progress assumptions. So the only events that areconsidered to be delayable by the environment are D = {enter .t.1 | t ∈ TRAIN }in the check that
(SYSTEM  Chaos D ) \ (Σ {tock })Dfailures/divergences-reﬁnes TOCKS .
Given the chosen initialization, the assertion that the gate is always downwhen there is a train on the same segment as the crossing comes down to two things:• When a train enters GateSeg, the gate is down, in that the most recent (nontock ) event communicated by the gate process is gate.down. (Note that thegate is initially up.)
• The gate never goes up when there is a train on GateSeg, in that no gate
event occurs between a train entering GateSeg and leaving it.

These are both elementary safety speciﬁcations which can be expressed as follows.
Let A, B and C be disjoint sets of events. We can deﬁne a general trace speciﬁcation BetweenSets(A, B , C ) stating that events in C only happen between being enabled by any element of A and the next element of B (which disables C ).
OutsideSets(A, B , C ) is the same except that elements of C are initially enabled(becoming disabled by the ﬁrst member of B ). We deﬁne two processes representing
trace speciﬁcations of these things over the events A ∪ B ∪ C , and then lift4 these4 This is a case where we are specifying the behaviour of a process in what is potentially aproper subset of its alphabet. See Section 12.2 for alternative ways to formulate such checks.

14.3

Case study 1: level crossing gate403

to speciﬁcations that allow other events as well.
BetweenSets  (A, B , C ) =?x : A → OutsideSets  (A, B , C )2?x : B → BetweenSets  (A, B , C )OutsideSets  (A, B , C ) =?x : C → OutsideSets  (A, B , C )2?x : A → OutsideSets  (A, B , C )2?x : B → BetweenSets  (A, B , C )BetweenSets(A, B , C ) =BetweenSets  (A, B , C )OutsideSets(A, B , C ) =OutsideSets  (A, B , C )


A∪B∪C



A∪B∪C

Chaos ΣChaos ΣThe two requirements described above can thus be formalized as speciﬁcations to test for the reﬁnement of:EnterWhenDown

GateStillWhenTrain= BetweenSets({gate.down},{gate.up, gate.goup, gate.godown},{enter .t.GateSeg | t ∈ TRAINS })= OutsideSets({leave.t.GateSeg | t ∈ TRAINS },{enter .t.GateSeg | t ∈ TRAINS }, {| gate |})Since these are trace speciﬁcations we can take their conjunction by placing
them in parallel:
Safety = EnterWhenDown  GateStillWhenTrain
Whether or not this is satisﬁed will depend on the timing details, as discussed
above, even though the speciﬁcation itself does not mention time.
This is a safety speciﬁcation in more than one sense of the word! Anothersafety, in the technical sense only, speciﬁcation we might want is that the gate
does not go down unless there is a train in the domain. The most natural way of
expressing this one is as a pure trace property:
tr = tr ˆgate.godown ⇒ #(tr  INS ) > #(tr  OUTS )
where
INS
OUTS

= {enter .t.1 | t ∈ TRAINS }= {leave.t.GateSeg | t ∈ TRAINS }This can be expressed as a process to reﬁne, but since that process involves a countof the number of trains presently in the domain, in order to make it ﬁnite-state one
has to assume a limit (just as in the controller process).

404

Modelling discrete time

It is also possible to express safety conditions involving time, typically expressing some limitation on the times certain events can happen. In the present
case one could, for example, assert that the event gate.up only happens within acertain interval of an event of the form leave.t.GateSeg .
There are two distinct varieties of liveness conditions that appear in thissort of timed reasoning: those which assert that some set of events is oﬀered by theprocess in appropriate circumstances (very possibly involving time in the conditions)and those that assert that things deﬁnitely occur within some time. The ﬁrst sortcorresponds best to untimed liveness conditions, and we will shortly look at an
important class of these in detail. The second sort is made possible by our ability
to deﬁne urgent processes that insist on certain communications before allowing theevent tock . They are, in fact, trace conditions, since they make statements such as‘no more than three tock s occur before an output’ and depend on our model of time:
we know that tock s appear regularly, so if the only way for four tock s to happen isfor an output to appear, then it does. Thus any trace condition which expresses alimit on when the event tock can occur is, in fact, a liveness condition of this second
variety.
The following expresses a condition of this sort, namely that the gate rises
within K units of the last train leaving unless some other train appears before thattime limit expires. Once again we express it as a pure trace condition, the sameconsiderations applying to the construction of a process-style speciﬁcation as in theearlier case.
⎛
⎝ ∧
∧

⎞
((tr = tr ˆleave.t.GateSeg ˆtr  )(#(tr   INS ) = #(tr   OUTS ) + 1) ⎠ =⇒ tr  ↓ gate.up > 0#(tr   INS ) = 0 ∧ tr  ↓ tock > K )Again, whether or not this is satisﬁed will depend on the parameters. An example
ﬁle to allow you to experiment with them for this and all the other speciﬁcations
relating to this example can be found on the web site (see Preface).

Exercise 14.3.1 How should the system be adapted to handle two or more railway
tracks running over our crossing gate? Hint: diﬀerent tracks are independent of each other,and the total number of trains present is the total of those on the individual tracks.

Exercise 14.3.2 Give the controller the responsibility of turning on and oﬀ a red
traﬃc light that must always be on when the gate is down and for some deﬁned time
beforehand. You should both modify the ControllerUp process to do this, and formulate
appropriate speciﬁcations for the new events used by the light.

14.4

14.4

Checking untimed properties of timed processes

405

Checking untimed properties of timed processes

It will often be the case that we want to compare a process in our timed styleagainst an untimed speciﬁcation (which could be simply an untimed version of thesame process). Where the speciﬁcation is of traces only, there is no real problem incomparing a timed process against it: all one has to do is modify the speciﬁcation
so it ignores tock events – something we did without thinking about it several times
in the level crossing gate example and which could be done simply by hiding tock .
Divergence (except for cases where an inﬁnite number of events appear ina ﬁnite time) is a rather diﬀerent phenomenon in the timed world than in theuntimed one. In many ways it is less dangerous because of the fact that timed
ways of looking at processes tell you what they are doing at each moment, rather
than only giving an accurate picture when internal activity has stopped (which
never happens in a diverging process). It is suﬃciently diﬀerent that, except for thecase of inﬁnitely many actions in a ﬁnite time, it is diﬃcult to formulate a general
method for approaching the question in our timed formulation. Indeed, in manycases timed analysis can make sense of, and prove well-behaved, systems that theuntimed models would regard as divergent.
What we will concentrate on in this section is how to prove untimed failures
speciﬁcations of timed systems. In other words, we want to place limits on what
traces a process can perform, and specify things about what the process oﬀers
after each trace. (This is distinct from the extremely strong liveness properties
illustrated in Section 14.3 which asserted that events were not only oﬀered, but
deﬁnitely happened.) The crucial issue with this type of property is deciding what
we mean by the word ‘oﬀer’. An untimed failure (s, X ) means that the process can
get into a state after the trace s where it can refuse X and will refuse it for everafter because it has become stable. The best timed analogue of what is intended
by an untimed failures speciﬁcation that precludes a particular refusal X is that,after some time beyond the end of the trace, the process will get into a state where
it must accept an element of X , and will do so for ever after until some (non-tock )visible event occurs.
What we will in fact attempt to do in this section is to prove this statement,
but with the additional demand that the (permanent) oﬀer occurs within some ﬁxed
time bound. For the timed model gives us ability to see how long it takes for an
oﬀer to be made and makes it impossible to say that an oﬀer will eventually bemade without a limit of this sort.
The speciﬁcation methods we use will be developed using an example. Thisparticular example is one where the internal timing behaviour is needed to establishthat the speciﬁcation is met: the corresponding untimed process would not meetthe speciﬁcation.

406

Modelling discrete time

It simply consists of a pipeline of two processes, feeding data items from left
to right.
The sender process waits for an input, and then outputs it on the next timeinterval (i.e., after exactly one tock ). It then waits three tock s before being able toinput again.
TS= tock → TS
2 left?x → tock → mid !x → tock → tock → tock → TS

The receiver waits for an input, then outputs and returns to its initial stateon the next two time intervals.
TR=

tock → TR
2 mid?x → tock → right!x → tock → TR

The system is put together by synchronizing and hiding the shared datachannel and synchronizing on tock .
TIMP = (TS{|tock ,mid|}

TR) \ {| mid |}Thinking about this system, it is clear that the output must have occurred
before three tock s have happened since the corresponding input. This is before thenext input is possible and therefore this process behaves, in an untimed sense, likethe one-place buﬀer COPY
COPY = left?x → right!x → COPY
even though the untimed analogues of S and R would behave like a two-place buﬀer
if piped together. Note we are assuming that the external output is not refusableby the environment.
Since COPY is an untimed speciﬁcation that does not mention tock , and our
proposed implementation is a system that certainly does communicate this event,
it is clear that we cannot simply ask the question
COPY

TIMP ?

and expect a sensible answer. We will have to do one of two things:• Build an understanding of time, and of our requirements for when oﬀers need
to be made, into the speciﬁcation.
• Abstract away the time event tock from the implementation in an appropriate
way.

14.4

Checking untimed properties of timed processes

407

In fact, either of these is possible. The obvious argument against the ﬁrst isthat we have negated the objective of this section: if internal manipulation to bringtime into the speciﬁcation is needed, it is no longer an untimed speciﬁcation! In
fact we can do better than that and one can devise rather precise recipes for doing
the check in ways that do not require internal manipulation of either the untimed
speciﬁcation or the timed implementation. Since they are both quite interesting intheir own right and give insight into the problem and each other, we will describe
them in the following subsections.
14.4.1

Abstracting time

We know two basic ways to abstract away from a set of events: lazy and eager
abstraction (see Chapter 12). Since the tock event is interpreted rather diﬀerently
from other events, it is worth while investigating what it would mean to abstract itin these two ways.
In lazy abstraction we are placing no reliance on the abstracted events ever
happening. Thus the reﬁnement test appropriate for the use of lazy abstraction:
COPY

F

(TIMP



{tock }

Chaos {tock } ) \ {tock }asserts that the process TIMP does what is required of it by COPY no matter how
many tock s it has done. In particular, it can never refuse whatever event COPY
says it must accept next, no matter how short a time has passed since the lastaction. Clearly, then, this reﬁnement does not hold because our system takes sometime before it is able to move from one communication to the next.
In eager abstraction, where the corresponding check would be
COPY

FD

TIMP \ {tock }we are assuming that the abstracted events are never resisted by the environment.
While this is true (hopefully) of the tock event, the diﬀerent interpretation we makeof this event means that eager abstraction’s consequences for failures reﬁnement
testing are wrong. For any process which can let time pass indeﬁnitely (i.e., communicate inﬁnitely many tock s without other intervening communication) will giverise to divergence under this form of abstraction (which is just hiding) so that noassertion can be made about what the process accepts or refuses between these
tock s. In other words, eager abstraction will only pick up refusal information whenand if the process has run out of tock s to perform.
What we want to achieve is a mixture of the two. We want to allow a ﬁxed
interval to pass during which the process can oﬀer what it likes, but after that we408

Modelling discrete time

want to specify what it must oﬀer irrespective of whether it can perform anothertock . We need to apply eager abstraction to the ﬁrst few tock s after an event, andlazy abstraction to the rest.
A certain amount of subterfuge is required to achieve this hybrid abstraction(which is not the same as the mixed abstraction used in Chapter 12). We employ
the ideas introduced on page 3.2.3 to diﬀerentiate between identically-names events
via one-to-many renaming and parallel composition. We transform the timed implementation process by allowing either of two sorts of tock events when the originalcommunicates the original one:
RTIMP = TIMP[[tock 1, tock 2/tock , tock ]]Having got two sorts of tock , we then constrain the process so that exactly one ofthem is possible whenever the original process can perform a tock . Speciﬁcally, theﬁrst N after the start of time or a non-tock event become tock 1’s while the rest
become tock 2’s.
REG(n) = nontock → REG(N )2 (tock 2 → REG(n)<I n = 0>I tock 1 → REG(n−1))= REG(N )[[x /nontock | x ∈ Σ {tock , tock 1, tock 2}]]Reg

= RTIMP  Reg

RegTIMPΣThe eﬀect of this complex procedure is to give the classes of tock ’s that wewant to treat diﬀerently diﬀerent names. We can therefore apply eager abstraction
to the tock 1’s and lazy to the tock 2’s to get the eﬀect we want. The appropriate
test is then
COPY

F

(RegTIMP{tock 2}

Chaos {tock 2} ) \ {tock 1, tock 2}This establishes that the refusal of the implementation process is correctwhen either (i) at least N time units have passed either from the beginning or thelast non-tock event or (ii) the process insists on a communication before allowing
time to pass. In general, increasing N weakens this test, and decreasing it until it
fails will reveal the longest time one might have to wait before the underlying timed
process is ready to accept whatever is required by the speciﬁcation.
A larger example of this technique can be found in Section 14.5. Note the useof one-to-many (actually one-to-two) renaming here; as ever a very powerful tool
for achieving interesting eﬀects when combined with a parallel regulator process.

14.4

Checking untimed properties of timed processes

14.4.2409

Untimed speciﬁcations in a timed harness

In the ﬁrst method we essentially put a harness around the implementation which
understood the timing requirements we were putting on the process, and did appropriate things to tock events to allow for these. We will now deal with thedual approach: putting a similar harness round the untimed speciﬁcation so as totransform it into one which allows for the occurrence of tock and makes the samestatement about the relationship between the untimed speciﬁcation and the timed
implementation as was made by the ﬁrst method.
The check set out above in terms of the ﬁrst method seeks to establish thefollowing:• The untimed traces of the implementation are correct.
• If it is within N time units of the last non-time event or the start, theneither time can pass or the set of events oﬀered by the speciﬁcation meetsthe current requirements of the untimed speciﬁcation.
• If at least N time units have passed then the set of events oﬀered meets theserequirements whether time can pass further or not.
This careful statement takes account of the fact that our processes sometimes insist
on communicating before tock occurs. What we will do is construct a process
SpecReg which, put in parallel with any untimed speciﬁcation (synchronizing on all
non-tock events), transforms it so that it says the above:
SpecReg=

RSpec(M , r ) =RSpec(N , N )[[x /anyother | x ∈ (Σ {tock })]],

where(tock → RSpec(M , r − 1)
anyother → RSpec(M , M ))<I r > 0>I
(anyother → RSpec(M , M ))2 (STOP tock → RSpec(M , 0))We can now ‘lift’ our untimed speciﬁcation to a timed one by putting this process
in parallel with it:
TSpec = SpecRegΣ {tock }Spec(where Spec = COPY in the example we are considering). This achieves the goals
set out above since SpecReg allows any trace of Spec with arbitrary insertions of tock ,and when RSpec oﬀers anyother the renamed version SpecReg oﬀers all non-tock
events and hence TSpec oﬀers whatever of these events that Spec does.

410

Modelling discrete time

The reﬁnement check TSpec F System makes exactly the same statement
about System as the check developed using abstraction in the previous section. Thissecond version is easier to implement, since the amount of process transformationis less, but arguably required a closer understanding of exactly what we wanted to
say about such things as the passage of time.
One possible reason for proving an untimed speciﬁcation UTS of a timed
process TC is because you want to include it as a component in an otherwise
untimed system. It would then be natural to develop the untimed system with thespeciﬁcation in the place of TC , before developing TC to meet UTS in the sense
discussed in this section. One important thing that should be borne in mind if you
do this is that we have here considered processes to meet untimed speciﬁcations eventhough they may place upper time bounds on when some visible communications
occur: for example the outputs of the buﬀers above must happen within one time
unit even though the untimed COPY process would wait. It is therefore necessary
to perform a second check on the process TC which is developed to ﬁll the slot left
by UTS : any event of its interface with the rest of the system, which you are nottotally conﬁdent will never be delayed, must be included in the Delayable set for atiming consistency check on TC .
Exercise 14.4.1 Modify SpecReg so that it never refuses tock , but otherwise behaves
as before. Comment on how the revised timed speciﬁcation it produces (when combinedwith an untimed one) is relevant to the discussion above about TC and UTS . How would
the TIMP process above fare when checked against it?
Exercise 14.4.2 The example in this section shows how what is apparently a twoplace buﬀer might become a one-place one thanks to timing. Find an example of anapparently deadlocking system which is deadlock-free because of timing.

14.5

Case study 2: the alternating bit protocol

In this section we give a slightly larger example of the sort of reasoning introducedin the previous section, namely proving what are largely untimed speciﬁcations ofa system which depends on timing for its correct functioning. This is a versionof the alternating bit protocol which relies on time-outs to decide when it resends
messages and acknowledgements, rather than the mechanisms described in Section
5.3.
The overall speciﬁcation we want it to satisfy will still be the same, namelythat it is a one-place buﬀer.
Unlike the untimed example, this version does not rely on the eventual correcttransmission of data to avoid CSP divergence, but we do need some bound on the14.5

Case study 2: the alternating bit protocol

411

loss if we are to prove that data does eventually get through, and how long this takes.
Rather than make the occurrence of error ’s explicitly nondeterministic as in theearlier treatments of communications protocols, here we use the more sophisticatedcoding where error ’s are prompted by external actions as discussed in Chapter 12.
This has the advantage that the limits on errors do not have to be coded into thebasic system deﬁnition, and we can thus construct a single system and analyze it
under a variety of assumptions rather than having to reconstruct the system eachtime. The only error modelled here is message loss; duplication could easily be
added.
TE=

a?tag?data → tock → (b!tag!data → TE 2 error → TE )2 tock → TE

TF=

c?tag → tock → (d !tag → TF 2 error → TF )2 tock → TF

Note that we have speciﬁed that all messages take precisely one unit of timeto get through and that an arbitrary time then passes before the next input. Clearly
one could make this more nondeterministic. Also, the fact that the outputs havebeen made urgent imposes the obligation on us to ensure that the processes receiving
these outputs never refuse them when oﬀered.
The implementation of the protocol consists of a sender process and receiverprocess, linked by E and F above.
14.5.1

Describing time-outs

The crucial feature of the sender and receiver processes in this presentation is theiruse of time-outs. A time-out is a sort of choice operator between two processes(like 2 and ), that only fully makes sense in a timed model. A time-out gives one
process the chance to communicate for some length of time (which is a parameterto the time-out operator) and then, if no such communication has occurred, gives
up and behaves like the other process. In Timed CSP it is written
P {t} Q
meaning the process which times-out to Q if P has not communicated within t timeunits. It looks very like the untimed operator P  Q that we have seen from time
to time, since in its most natural implementation the latter essentially behaves likea time-out though without the control over exactly when the decision to time-out
is made.
In the style of CSP discussed in this chapter we will obviously have to tie theoccurrence of time-outs to the tock event. Unless we are thinking that tock has some

412

Modelling discrete timereal existence, like a broadcast clock signal, it is better not to make the time-out(i.e., the transition from P to Q) occur precisely at some tock (counted, presumably,from when the time-out combination was started). This would create a potential
synchronization between time-outs in diﬀerent parallel processes when there is no
mechanism to achieve it. As a simple example, consider P {t} Q  Q {t} P ,where P = a → P and Q = b → Q. If the time-outs are triggered by the same
tock , this combination is certain to deadlock while, assuming that in reality they
are managed by unsynchronized clocks, we would have the possibility (though not
the certainty) of being able to communicate one of a or b for a short interval.
It is usually preferable, therefore, to specify an interval (amongst the tock s)during which a time-out will occur, without forcing it to occur at a tock. Thus atime-out will be an event whose occurrence is tied to a speciﬁc interval, very likemany of the other events we have seen in this chapter.
Perhaps the most elegant way of achieving this is to delegate the ﬁring of thetime-out to a separate parallel process which, rather like a kitchen timer, can be set
up to ‘ring’ at a given time in the future. In general the time-out controller process
might, like the more sophisticated kitchen timers,5 be programmable with a variety
of intervals. It should therefore have an input channel setup over which this datais communicated, an event it communicates back when it ﬁres, plus the tock event.
Because any time-out is abandoned if the left-hand process communicates before
the set time, the time-out controller has to be programmed so that it can be reset.

TOC= setup?n → Armed (n)2 tock → TOC
2 reset → TOC

Armed (n) = ((timesout → TOC )<I n = 0>I (tock → Armed (n − 1)))
2 reset → TOC

The main process then sends TOC the setup signal to arm the time-out function,and includes the event timesout amongst the choices it oﬀers during the period while
the time-out might ﬁre. It is combined with the TOC process (of which there is one
for every separate component that needs one, since it is possible for the network tohave more than one time-out running at once) with the setup and timesout events
hidden.

5 Ones that are not egg timers!

14.5

Case study 2: the alternating bit protocol

413

The structure of the complete process is then either(Main  TOC [[a/reset | a ∈ R]]) \ {| setup, timesout |}
Σ

(Main



Σ {tock }or

TOC [[a/reset | a ∈ R]]) \ {| setup, timesout |}where R = Σ {tock , setup, timesout}depending on whether or not (respectively) the process Main is timed.
For example, if P and Q are the processes described earlier when discussing
the consequences of synchronized time-outs, we can describe P {t} Q by deﬁning
Main (in the ﬁrst line above) to be setup.t → (S ||| RUN {tock } ), whereS= timesout → Q
2P(This is a timed process because it insists on sending the setup.t signal immediately –before any tock s. The subsequent interleaving with RUN {tock } means there are nofurther timing constraints apart from the ones introduced by TOC .)If Q {t} P is deﬁned similarly, it is now possible forP {t} Q  Q {t} P
to synchronize on either a or b between tock s number t and t + 1.

14.5.2The sender and receiverIn this treatment of the alternating bit protocol we have factored the sender process
into three parallel components: one for transmitting data, one for managing thetime-outs for retransmissions, and one for receiving acknowledgement signals andﬁltering out repeats. By doing this it is easier to ensure that signals are sent andreceived at appropriate times. It is, of course, possible to do the same thing with asequential process: see Exercise 14.5.1.
Send (bit)= left?x → tock → Snd 1(bit, x )2 tock → Send (bit)Snd 1(bit, x )= a!bit!x → setup!sto → Snd 2(bit, x )Snd 2(bit, x )= timesout → Snd 1(bit, x )2 tock → Snd 2(bit, x )2 ack → Send (1−bit)414

Modelling discrete time

sto is a constant deﬁning how long the process waits between successive
outputs of the same piece of data. The following process sends the ack signal justwhen it gets each new, rather than repeated, acknowledgement on channel d .
SAck (bit) = d .bit → ack → SAck (1−bit)
2 d .(1−bit) → SAck (bit)2 tock → SAck (bit)Note below that this ack event is used to reset the time-out timer.
SEND=((Send (0){tock ,ack }SAck (0))

 TOC [[ack /reset ]]) \ {| ack , setup, timesout |}A

where A = {| tock , setup, ack , timesout |}The receiver has one main component plus a timer, which is only reset (nowexplicitly) when a new (rather than repeat) input is received. In this sense its
behaviour is not a classic time-out, since there are events the main process doesthat do not reset the timer. (This illustrates the ﬂexibility of this approach ofusing parallel timers.) rto is the interval between successive sendings of the sameacknowledgement. Note that, in both the sender and receiver processes, it is only
elapsed time which determines how many times each message and acknowledgement
are sent.
Rec(bit)REC= b?tag?data →(reset → tock → right!data → c!bit →setup!rto → Rec(1−bit)<
I tag = bit>I
Rec(bit))
2 timesout → c!(1−bit) → setup!rto → Rec(bit)2 tock → Rec(bit)= (Rec(0){|tock }∪αTOC

TOC ) \ αTOC

where αTOC = {| setup, timesout, reset}
TABP= SEND((TE{|a,d,tock |}{tock }TF )

{|b,c,tock |}REC ) \ {| a, b, c, d |}Aside from tock , the external alphabet of this system is {| left, right, error |}.
Of these events we are relying on the environment accepting the system’s outputs(on right) promptly. Therefore the timing consistency check deems the delayable14.5

Case study 2: the alternating bit protocol

415

events to be the complement of this set. It is appropriate to include the event error
in this set since not to do so would mean that we could not exclude the possibility
that the process is relying on some error ’s happening to ensure correct behaviour!
(Essentially we are lazily abstracting the error events, as recommended in Section
12.3.)
D={| left, error |}TimingConsistency=(TABP  Chaos D ) \ (Σ {tock })DAs ever, this check simply shows there are no contradictory timing requirements in our system. The main check, that our system behaves like a one-place
buﬀer, follows the pattern set out in the previous section. The checks set out below
attempt to show that the system meets the untimed speciﬁcation COPY with all
required communications being oﬀered within a speciﬁed number of time units since
the last external communication.
With Reg deﬁned as on page 408:
RTIMP
RegTIMP= TABP [[tock 1, tock 2/tock , tock ]]= RTIMP  Reg

This can now be checked against COPY by eagerly abstracting tock 1 andlazily abstracting tock 2 and error :RHS = (RegTIMP{tock 2,error }Chaos {tock 2,error } ) \ {tock 1, tock 2, error }This check, if successful (which depends on the timing parameters used), shows
something quite interesting because of the way it deals with errors. Since theprocess Reg (which chooses between tock 1’s and tock 2’s) allows an error event toreset its clock, what we are showing is that the oﬀers required by COPY are madeby the time that a ﬁxed interval has passed since the last input or output, and thelast error. This is the advantage of keeping the errors visible: we allow any numberof errors but only insist that the system makes progress when there have not been
any errors recently. If the thing which decides whether or not errors occur was aninvisible nondeterministic choice operator, there is no way such a statement could
be made.
Having put the system together in such a way as to leave errors (or, at least,
events that give us control over when these happen) visible, one can, if one chooses,
make assumptions about the error rate and see what eﬀect this has on system
performance. The typical assumption it might be appropriate to make would be416

Modelling discrete time‘there are no more than L errors in any T time units’: something it is easy to specify
using the tock style of CSP. If L = 1 we can deﬁne
ER1 (T ) = ER1 (T , 0),
ER1 (T , j )

=

where

tock → ER1 (T , j −1)<
I j > 0>I
(tock → ER1 (T , 0) 2 (STOP

and ERL+1 (T ) = ERL (T ){tock }

error → ER1 (T , T )))ER1 (T ). (This deﬁnition has a lot in common withthat of Limit on page 317.) The last line in the deﬁnition of ER1 (T , j ) includes thenondeterministic choice between error and STOP because we do not want processes
to be able to rely on errors happening.
The appropriate thing to do with one of these assumptions is to use it toconstrain TABP and then to hide the error event.
CSYSTEM = (TABP{tock ,error }ERL (T )) \ {error }One would then seek to prove that CSYSTEM meets the untimed speciﬁcation
COPY using the same methods as above, though this time there is no need to put
in the abstraction of error and the fact that error has already been hidden meansthat it does not reset the speciﬁcation clock. One would expect to ﬁnd that thetime one needs to wait before this version of the system makes the oﬀers requiredof it will be longer than in the version where error is allowed to reset the waiting
period for this, and also that there would be critical error rates beyond which no‘settle time’ is long enough because there are enough errors to prevent real progress.
When this check succeeds it establishes that, provided the error pattern is
within the limits speciﬁed, the system meets the speciﬁcation in a way independentof exactly when the errors happen. This shows how one can elegantly extend to
timed systems the concepts of fault tolerance described in Chapter 12. Thus, one
might prove that, provided there are no more than L errors every T time units, thesystem meets the COPY speciﬁcation with settle-time (since the last proper input
or output) of N units.
Exercise 14.5.1 Write an alternative version of Send (bit) that does not require thespecial acknowledgement handler SAck (bit) in parallel with it (though it should still use
TOC to handle its time-outs). Be careful that, whenever TOC wants to perform the event
timesout, your Send does not deadlock it.
Use the time-out mechanism provided by TOC to re-work youranswer to Exercise 14.2.3. Then produce a further version where the TOC is also used toplace limits on the time the user has to perform each of his or her other actions.

Exercise 14.5.2

14.6

14.6

Urgency and priority

417

Urgency and priority

Recall the process TCOPY 2, the timed version of COPY from the start of thischapter that behaves most like the original. It will wait indeﬁnitely for either an
input or an output. Now, preferably without looking ahead in this text, think how
you would expect the result of piping two copies of this together to behave:(TCOPY 2[[mid /right ]]{|mid,tock |}TCOPY 2[[mid /left ]]) \ {| mid |}The issue you have to decide is: when does the hidden communication on mid
happen? One time unit after the corresponding input by the left-hand process,both processes (assuming the right-hand one is not full) are willing and able to do
this action, but are also able to wait. A hidden action is one that the environment
has no control over, so the implementation (and our modelling) has to decide whichroute to follow.
In all the timed examples seen so far we have carefully avoided this ambiguity.
Whenever a hidden communication occurred between two parallel processes, one ofthem (invariably the one doing the ‘outputting’) speciﬁed exactly when it happened.
This puts us under the obligation to ensure that these communications are accepted
at precisely the speciﬁed moments, for otherwise the TimingConsistency checks fail.
In reasoning about untimed CSP we made the assumption that when a process had a hidden action (a τ ) available then the τ always happens unless someother action occurs quickly. Certainly the process could not wait for ever in a statewith a τ available. The problem we have to face in modelling the passage of timeby tock events is that the untimed models of CSP do not understand the special
nature of this event. They would model the system of two TCOPY 2’s shown abovein such a way that the hidden mid event can nondeterministically happen after any
number of tock s or never, in the sense that the inﬁnite traceleft.0, tock , tock , tock , . . .is possible without the transfer on mid occurring. Thus, this attempt at modellinga timed system in untimed CSP fails in an important way to model accurately ourunderstanding of how this system ought to behave.
Imagine the state this system is in one time unit after the input event left.0(which we can assume is the ﬁrst event the combination does). The internal communication (mid .0) is available; if it does not happen before the next tock then, unless
we are to keep some timer running, the state the system is in after the tock is identical to that before it. This means that if one tock is possible then, without special
treatment, it must be possible for there to be any ﬁnite number before the hidden
action occurs, and even for the hidden action never to happen at all. This would

418

Modelling discrete timemean that the interpretation we were putting on this internal event in this worldof tock s would be diﬀerent to the usual untimed models, where we have assumed
that a process cannot sit waiting for ever when there is an internal action possible.
The cleanest solution to this problem is to assert that a tock never happens when
there is an internal event available. In other words, internal events are urgent in
the sense that time does not pass when they are enabled. (Note that this mirrors
precisely the concept of an urgent state that we have already discussed.) This isoften called the assumption of maximal progress and is common across a variety ofmodels of timed concurrency, including conventional Timed CSP.
Looking at a timed system in this way gives a (possibly strict) reﬁnement of
the way we would interpret it over the usual models of CSP, thinking of tock as anyother event. This is because these models (in particular the failures/divergences one)allow the implementation to choose internal events that are available in preference
to any or all others (including tock ), while our new view simply asserts that in somecircumstances it is obliged to do this.
It is perfectly clear how to simulate a system running under these new rules:
we have to give internal events priority over tock . (Other events are not aﬀectedby this.) In terms of operational semantics, what we are doing is describing a newxxtransition rule −→T in terms of the old one −→: here T is a set of time-like actions(usually {tock }). Unless x ∈ T we havexx

P −→T Q ⇔ P −→ Q
If x ∈ T , then
x

x

τ



P −→T Q ⇔ P −→ Q ∧ ¬ ∃ Q  .P −→ Q  ∨ P −→ Q 
Here, τ is the usual internal action we are familiar with.
The consequences of this re-interpretation for our system of two TCOPY 2’s
is that the data moves across as soon as both sides are willing, namely, one time
unit after the later of the corresponding input and the output of the previous datum(if any) by the right-hand process.
In almost all circumstances this new, prioritized, view is the right way oflooking at timed systems and the cases where the conventional semantics provides
the right answer (like all those in previous sections of this chapter) are written
so that the above rules are, to all intents and purposes, followed by the standardxtransition rule −→ without the need to impose them. In other words, in those cases
the semantic values of the standard and prioritized views coincide.
As discussed above, this will be true whenever one of the participants in eachinternal action is unwilling to let time pass until it has occurred. Fortunately, since14.6

Urgency and priority419

the new prioritized view always gives a reﬁnement of the old one, checking a timed
system against a speciﬁcation6 will never give a false positive.
14.6.1Consequences for semantic models

While the prioritized view of time is easy to understand in terms of operationalsemantics, it presents rather more diﬃculties if you want to get a denotational theory
for predicting process behaviour (like the traces model, or the failures/divergencesmodel). The problem is that our usual models conceal all details of internal τactions, so there is no way of imposing the new interpretation on a process once wehave reduced it to its description in one of them. Whole new models, giving much
more detail about what was refused by a process during a trace as well as after it,
are required. While these are interesting, they are also complex and this is not theplace to describe them. The issues which arise are essentially the same as those as
in modelling (continuously) Timed CSP, and there is extensive discussion of thesein the literature.
It is possible, under the prioritized view, to have two processes that areequivalent in all the denotational models of untimed CSP which are inequivalent
when put in a simple CSP context. What this means from a practical point of viewis that the compression functions described in Section C.2 are unsafe for prioritized
analysis, and that techniques for proving properties of processes by putting themin contexts should be considered carefully before use. Basically, you should regard
the primary means of understanding a prioritized program as being its operationalsemantics, rather than the denotational models which dominate for the standard
interpretation.
We need to understand how this new prioritized view interacts with themethods described in Section 14.4 for proving a timed process meets an untimed
speciﬁcation. The answer is very simple: the ﬁrst method creates problems becauseof the way time is abstracted by hiding. The problem is that once one hides a tock
event, it becomes a τ and so is put into precisely the category of events we are giving
priority to over tock s. Thus, once this hiding is done, we have lost the mechanism
to impose priority of more normal τ ’s over the passage of time. Thus this methodshould not be used for systems with priority.
On the other hand, the second method, where the speciﬁcation was transformed and the implementation left unaltered, creates no problems and should be
used in preference.
The lazy abstraction of error events in this type of analysis does not appear
6 Necessarily a speciﬁcation that does not depend on the prioritized interpretation of time to
deduce its own behaviour.

420

Modelling discrete time

to cause any problems since, by construction, it allows the abstracted events to berefused at any time.

14.7

Tools

The style of CSP presented in this chapter was developed speciﬁcally to meet thedemand for a mechanism for analyzing timed systems with FDR. Probably becauseof the practical importance of timing analysis it has become widely used for that
purpose. A larger case study of the automated analysis of a timed system can befound in Section 15.2.
Except where priority is required, no special considerations apply to using
tools. The main thing anyone intending to use CSP tools for timing analysis should
do is get a good grasp of the principles of modelling time set out in this chapter.
It is possible7 to add an operator prioritize(P) to FDR as a function
applied to processes: the process the function is applied to is given a revised operational semantics of the sort described above.
Potential users of the prioritized implementation of timing are warned toensure they understand just what this construction achieves and the limitations onwhen it is safe to use it.
All the examples in this chapter, plus further examples of the style of CSP
it describes, can be found on the associated web site.

14.8

Notes

As we have said previously, the techniques presented in this chapter are not Timed
CSP in the sense described in the work of the author, Reed, Schneider, Davies andothers [29, 30, 31, 97, 98, 99, 127] because we do not use the continuous time model
used there. It has more in common, in terms of timing, with work on other ﬂavoursof timed copncurrency. A good survey can be found in [3], and the rest of the papers
in that conference proceedings are also useful. The primary reason for advocating
the discrete approach here is pragmatic: while it is not as mathematically elegant,
it is easier to automate its analysis and, in many respects, easier to program in.
David Jackson has played an important role in the development of the style and inpromoting it.
There have been several papers published applying the tock-timed style of
CSP [14, 49], but no widely available general introductions to this style before. The
7 This operator was present in later versions of FDR1. At the time of writing it has not yet
been included in FDR2.

14.8

Notes

421

level crossing example was originally proposed in [69] and was the example used in[49].
2005: The style of CSP presented in this chapter remains widely used. Joel
Ouaknine [88] proved the existence of unexpectedly close links between a variant on
it and (continuous) Timed CSP in his thesis. Recently the theory of information
ﬂow presented in Chapter 12 has been extended to tock-CSP and there has beeninteresting work on semantic models for the priority model by Ouaknine and Lowe.
The priority model is now supported by FDR.

Chapter 15

Case studies

We have already seen some moderately large examples of systems described andspeciﬁed in CSP in relation to protocols (Chapter 5), information ﬂow (Chapter
12), deadlock (Chapter 13) and timing (Chapter 14). In this chapter we look atsome more which illustrate some diﬀerent ideas and methods, and the notation’s
power in a wide variety of applications, some of which are by no means obvious atﬁrst sight.
All of the examples in this chapter are drawn from case studies developed
as applications of FDR by the author and his colleagues. The deﬁnitions of more
realistically-sized processes such as those we use here are often easier to read in
the ASCII-based syntax used by FDR with its slightly lower emphasis on ‘algebraic’ constructs. This syntax also helps in presenting the functional programs1
for manipulating data which form a vital part of most realistic FDR examples and,hopefully, will assist the reader to get used to the machine-readable version of thelanguage (details of which can be found in Appendix B).
In each case all the process deﬁnitions are included in the text, as are sufﬁcient subsidiary deﬁnitions to make these clear and to show what is involved insetting up a realistic system description in CSP. Copies of the complete ﬁles fromwhich they are drawn are obtainable on the Internet (see Preface). Where possible,
readers are encouraged to run these ﬁles in conjunction with studying this chapter.
The author hopes that readers will gain both ideas and conﬁdence in theexpressive power of CSP from looking at these examples.

1 These programs are frequently simple and self-explanatory, as the ones in this chapter hopefully
are. However, an understanding of functional programming such as can be obtained from [11] isundoubtedly useful for dealing with some types of example using FDR.

424

Case studies

Figure 15.1 Peg solitaire.

15.1

Combinatorial systems: rules and tactics

CSP can be used to describe systems quite unlike the obvious applications to networks of communicating parallel processes. There are a great many types of system
which evolve according to rules based on their states’ structures and where there isa designated set of states which either one wishes to prove unreachable, or perhaps
one is simply interested in ﬁnding out whether the set is reachable and if so how.
An example of the former might be a railway signalling system, where we would
hope to prove that, provided some set of rules were applied, no two trains end up
on the same segment of track (amongst other properties of a similar ﬂavour).
Examples of the latter are provided by the class of puzzles where the objective
is to reach one of a set of target states (frequently this set has only one member)from a ﬁxed starting state. The example we use in this section is one of the bestknown puzzles of this sort: peg solitaire. The starting position of the usual versionof this puzzle is shown in Figure 15.1. Thus initially there are 32 slots with a peg
in, plus an empty slot in the middle.
The rules are very simple: in any one of the four horizontal and verticaldirections (up, down, left, right) you can hop any peg over another peg into an
empty slot, after which you remove the hopped-over peg. The objective is to remove

15.1

Combinatorial systems: rules and tactics

425

all but one of the pegs and leave the remaining one in the slot that was initiallyempty. Most human beings ﬁnd this a very diﬃcult puzzle.
Evidently the initial conﬁguration can be varied, thus creating an inﬁnity ofdiﬀerent puzzles, some of which are soluble and some of which are not.2 The CSP
script on which this section is based supports a simple notation which allows theuser to design his or her own puzzles and try them out.
This is done by writing each puzzle as a rectangular list of lists (i.e., a list ofrows) in which the standard version is shown
Board = <<X,X,P,P,P,X,X>,<X,X,P,P,P,X,X>,<P,P,P,P,P,P,P>,<P,P,P,E,P,P,P>,<P,P,P,P,P,P,P>,<X,X,P,P,P,X,X>,<X,X,P,P,P,X,X>>
Here, X is a non-slot (there just to ﬁll up the rectangle), P is a slot with a
peg and E is an empty slot. (These are members of a data type which is declaredin the script.)
The rest of the script just compiles a parallel network out of the above
notation. To do this we need the dimensions of the board:
Height = #Board
Width = #(head(Board))
and a function which extracts the value of the (i , j )th member of the array. The
following deﬁnition allows for the fact that the above picture is inverted because
the 0th row is at the top, whereas it is easier to think of the origin (point (0, 0)) as
being at the bottom left-hand corner.
init(i,j) = nth(j,nth(Height-1-i,Board))
The following set then consists of all the co-ordinates of slots on the board.
BoardCoords = {(i,j) | i <- {0..Height-1},
j <- {0..Width-1}, init(i,j)!=X}
2 The puzzle can be analyzed mathematically and a theory developed which helps predict whichboards can be solved, and in some cases how to solve them. See [8] for an extensive treatment of
this. We will, however, treat the puzzle ‘blind’ to its theory.

426

Case studies

When using FDR you have to declare the types of all channels used. The main
events we will use are ones representing moves, with the indexing of the events
corresponding to the co-ordinates of the slot the move is to (rather than from orover). For reasons that will become apparent later we declare the possible indexesof these events to range over an area a little bigger than the actual board:
Ycoords = {(-2)..Height+1}
Xcoords = {(-2)..Width+1}
channel up,down,left,right:Ycoords.Xcoords
channel done
We next deﬁne a process for each slot with just two states: full and empty.
These record the eﬀects of the various moves and also permit the special event done
just when the state is correct for a solution (as recorded in the parameter target
using one of the values P and E used in the list-picture).
When a slot is full it can become empty in two basic ways: either the peg
that is in it hops out, or another hops over it. Since either of these can happen infour directions, there are eight move events it can participate in.
Full(i,j,target) = (target==P) & done -> Full(i,j,target)[] up.i+2.j -> Empty(i,j,target)[] down.i-2.j -> Empty(i,j,target)[] right.i.j+2 -> Empty(i,j,target)[] left.i.j-2 -> Empty(i,j,target)[] up.i+1.j -> Empty(i,j,target)[] down.i-1.j -> Empty(i,j,target)[] right.i.j+1 -> Empty(i,j,target)[] left.i.j-1 -> Empty(i,j,target)
When it is empty, the slot cannot allow any of the above moves, but does allow four
new ones, namely the four directions of a peg hopping in.
Empty(i,j,target) = (target==E) & done -> Empty(i,j,target)[] up.i.j -> Full(i,j,target)[] down.i.j -> Full(i,j,target)[] right.i.j -> Full(i,j,target)[] left.i.j -> Full(i,j,target)
The initial value of the process at co-ordinates (i , j ) is determined by the
picture: note the target is always the opposite.

15.1

Combinatorial systems: rules and tactics427

Slot(i,j) = if init(i,j) == E then Empty(i,j,P)else Full(i,j,E)
We are going to put all the various slot processes in parallel. To do so weneed an expression for the alphabet of each: it is just done plus all the moves theslot is involved in.
Alpha(i,j) = Union({{done},{up.i+k.j| k <-{0,1,2}},{down.i-k.j | k <-{0,1,2}},{left.i.j-k | k <-{0,1,2}},{right.i.j+k | k <-{0,1,2}}})
Placing done in all the alphabets like this will mean that it can only occur when
every process is in its target state.
In a sense the deﬁnitions of the Full and Empty states, and also the alphabets,
are too general. They assume that all slots have a full complement of moves, ignoring
the fact that ones within two units of an edge of the board (in any direction) havefewer. For example, a slot on the left-hand edge has no moves hopping over it toleft or right, none hopping in from the left and none hopping out to the left. Fora move to be a ‘real’ move, all of the from-, over- and to-slots need to be on theboard. This calculation is performed by the following:
JumpTos = {up.i.j, down.i.j, left.i.j,right.i.j | (i,j) <- BoardCoords}
JumpOvers = {up.i+1.j, down.i-1.j, left.i.j-1,
right.i.j+1 | (i,j) <- BoardCoords}
JumpFroms = {up.i+2.j, down.i-2.j, left.i.j-2,
right.i.j+2 | (i,j) <- BoardCoords}
RealMoves = inter(JumpTos,inter(JumpOvers,JumpFroms))
OffBoardMoves = diff({|up,down,left,right|},RealMoves)
The following deﬁnition of the complete puzzle comprises the parallel compositionof one process for each slot, which is put in parallel with STOP to prevent the
moves OffBoardMoves from occurring:
Puzzle = (|| (i,j):BoardCoords @ [Alpha(i,j)] Slot(i,j))[|OffBoardMoves|] STOP

428

Case studies

Notice that each move in RealMoves appears in the alphabets of exactly three slots,
and that done is, as discussed above, in the alphabets of them all.
We now have a perfect model of the puzzle in CSP: the traces are precisely
the legal sequences of moves, with the additional possibility of done when and if asolution is reached. There is a solution, indeed, if and only if this event can occur,and this fact leads to an obvious reﬁnement check which we can give to FDR tolook for one: it is failed if Puzzle can perform done. The following is the syntax
used to pre-load a (traces) reﬁnement check into FDR.
assert STOP [T= Puzzle \ {|up,down,left,right|}
This is all very well, but for the standard board the check is very large(187,636,268 states) and takes a long time to run. When the ﬁrst edition of thisbook appeared it was still out of range, but hardware and software advances meanthat it now (October 2000) takes 12-24 hours on reasonably powerful PC’s or 2 hours
20 minutes on a parallel implementation using 8 533MHz Celeron processors (seeAppendix C). However this is still too large a check to run unless really necessary.
An interesting way round this is to impose further rules on the puzzle in sucha way as to restrict the number of states, and then see if this constrained version
has a solution. This can be done by placing another process in parallel which limits
the patterns of up, down, left and right events. In this case it is best to regard
these as tactics for solving the puzzle, but in other games you could use exactly
the same programming structure to add in standard rules, and when analyzing amore real-life combinatorial system it could be used both for rules and to makeassumptions about the system’s environment.
Two examples are given below. The ﬁrst simply says that moves in the four
directions rotate:
Tactic1 = left?x -> Tactic1’
Tactic1’ = up?x -> Tactic1’’
Tactic1’’ = right?x -> Tactic1’’’
Tactic1’’’ = down?x -> Tactic1
Puzzle1 = Puzzle [union(RealMoves,{done})||RealMoves] Tactic1
This fails to ﬁnd a solution (i.e., the reﬁnement check succeeds), establishingthat the puzzle has no solutions of the form implied by the tactic. If this tactic
is weakened so that the rotation only applies for the ﬁrst 24 moves, a solution isfound: the coding of this is left as an exercise!
A second tactic is to make some of the pegs ‘sticky’ and forbid them being
moved until most of the others have gone. The best way to do this is to extend the15.1

Combinatorial systems: rules and tactics

429

notation used to deﬁne the puzzle to include a sticky peg S as well as an ordinary
one P. An arrangement that works well for the standard puzzle isBoard1 = <<X,X,P,P,P,X,X>,<X,X,P,P,P,X,X>,<S,S,P,P,P,P,P>,<P,P,P,E,P,P,P>,<S,S,P,P,P,P,P>,<X,X,S,P,S,X,X>,<X,X,S,P,S,X,X>>
Adopting this extended notation does not change the network produced by theearlier deﬁnition of Puzzle, because of the way the process Slot(i,j) was deﬁned
above. It does, however, allow us to deﬁne a tactic process to implement our
restricted search for a solution. The following constants (derived from this newboard) represent the number of pegs that are not to be delayed, and the moves
which are respectively in the alphabets of any sticky peg and those which are not.
NoDelays = card({(i,j) | (i,j) <- BoardCoords, init(i,j) == P})
DelayMoves = diff( Union({Alpha(i,j) | (i,j) <- BoardCoords,
init(i,j)==S}),{done})
NoDelayMoves = diff(RealMoves,DelayMoves)
To deﬁne the tactic fully we need to know how many moves need to happen
before a sticky peg can move. Perhaps the cleanest way to do this is to deﬁne aconstant NonStickiesLeft which deﬁnes how many other pegs are left when theﬁrst peg marked S can move. This can be used, in conjunction with NoDelays, tocompute the initial parameter for a process that runs in parallel with the system to
implement the tactic.
Tactic2(n) = if n==0 then []x:RealMoves @ x -> Tactic2(0)else []x:NoDelayMoves @ x -> Tactic2(n-1)
Puzzle2 = Puzzle [|RealMoves|]
Tactic2(NoDelays-NonStickiesLeft)
Provided this allowance is set to be at least 4, the conﬁguration given above(the ﬁrst one the author tried, and the one described in [108], where the implied
NonStickiesLeft is 5) ﬁnds a solution.

430

Case studies

Solving puzzles like this is great fun, and several times we have found solutions to other ones which are shorter than the best previously known. (Evidently
all solutions to solitaire have the same length!) The serious points of this example
are ﬁrstly to show how the constructs of CSP (especially its ability to synchronize
an arbitrary number of processes on a given event) allow us to model combinatorial
systems which evolve according to rules, secondly how to add further rules, tactics
or assumptions via parallel composition, and ﬁnally to show that model-checking
tools such as FDR really can discover things that are at or beyond the limit of what
the unassisted human can do.
Most of the exercises in this chapter require FDR or some similar tool.
Exercise 15.1.1 Modify Tactic1 so that it allows any move after 24 rotating ones
and ﬁnd a solution to the puzzle that follows this pattern.
Exercise 15.1.2 A farmer has to ferry a wolf, a goat and a cabbage across a riverusing a boat that is only big enough for him and one of his charges. Unfortunately, without
the farmer to control then, the goat would eat the cabbage and the wolf would eat thegoat. Devise a CSP program to ﬁnd the way the farmer can get all across safely.
Use your program to demonstrate that his task would become impossible if he had
even one more of any of the cargo items. Would it help him, in that case, to have an islandin the middle of the river?

Exercise 15.1.3 Produce a version of the solitaire script which uses a hexagonal grid
like the two example puzzles shown in the upper part of Figure 15.2, with the pieces now
able to hop in any one of six directions along the lines. Are the puzzles shown soluble, inthe sense that you can end up with a single peg left, in the initially empty slot?
Hint: you might ﬁnd adapting the script easier if you transform the hexagonal grid
to a rectangular one with moves allowed on one set of diagonals, as shown in the bottomof the ﬁgure.

15.2

Analysis of a distributed algorithm

In books such as [25] you will ﬁnd clear but relatively informal presentations of awide variety of distributed algorithms for things like clock synchronisation, transaction processing, database management and communication. These algorithms
are sometimes presented as a sequence of messages each node has to send andtheir reactions to each, and sometimes as an overall description of the pattern ofcommunication that arise in the system. The purpose of this section is to take aspeciﬁc example and to show how, unless one is exceptionally careful, this styleof description can lead to possibly dangerous imprecision. The example we use isof a leadership election algorithm – distributed algorithms frequently depend on

15.2

Analysis of a distributed algorithm

431

Figure 15.2 Hexagonal solitaire (see Exercise 15.1.3).
there being an agreed node who can play some co-ordinating role – called the bully
algorithm (for reasons that will become apparent).
The following description is paraphrased from p. 306 of [25].
The bully algorithm This is used to allow a group of processors to have anagreed co-ordinator from amongst them, despite the fact that processors may at
various times fail and revive, The aim is always to have them agree that the coordinator is the highest indexed processor that is working. We assume that communication is reliable, but processes can fail at any time (including during the election
procedure that the algorithm represents).
As with many distributed algorithms, time plays an important role in thisone. Therefore we use the tock-timed dialect of CSP introduced in Chapter 14 tomodel it.
There are three types of message that the algorithm description refers to
explicitly:
channel election:Proc.Proc
channel answer:Proc.Proc

432

Case studies

channel coordinator:Proc.Proc
where Proc={0..N-1}, say, and all these represent synchronisations between asender process (the ﬁrst index) and a receiver.
An election.n.m message is used to announce an election (from n to m);an answer message is sent in response to an election message; and a coordinator
is sent to announce the identity of the new co-ordinator. A process begins anelection “when it notices that the co-ordinator has failed”. This last statement
lacks detail about the mechanism by which this noticing of failure is done. We use
the two channels test and ok that are declared here: any process can decide tosend a test message to its co-ordinator, who only sends ok back if it is a properly
working co-ordinator. This raises the question of what happens if a process tests its
co-ordinator but the latter, though working, does not think is is the co-ordinator!
channel fail, revive:Proc
channel test,ok:Proc.Proc
The ﬁrst two are communicated when a process fails or revives (allowing us to see
what the current status of each process is). The last two are used by one process
to test another, and to give a positive response to such a test.
To begin an election, a process sends an election message to all those witha higher index. It then awaits an answer message in response. If none arrives
within time T1, the processor considers itself the co-ordinator (as it thinks all thehigher ones must be dead), and sends a coordinator message to all processes withlower identiﬁers announcing this fact. Otherwise, the process waits a further limited
period (T2), expecting to receive a co-ordinator message as described in the next
paragraph, before beginning another election (if no such message is received).
If a process receives a co-ordinator message, it records the identiﬁer of theco-ordinator contained within it (i.e., the sender of that message) and treats thatprocess as the co-ordinator.
If a process receives an election message, it sends back an answer message
and begins another election, unless it has begun one already.
When a failed process is revived, it begins an election. If it is has the highest
live process identiﬁer, then it will eventually decide that it is the co-ordinator, andannounce this to the other processes. Thus it will become the co-ordinator, eventhough the current co-ordinator is functioning. It is for this reason that the thealgorithm is called the bully algorithm.
For example, consider the case where there are four nodes 1–4, all initiallyworking so that the initial coordinator is node 4.

15.2

Analysis of a distributed algorithm433

If this node fails, and node 2 tests it, then an election will be started by node
2. It sends election messages to 3 (who answers and starts its own election) andto 4, who does not answer. Node 3 will get no answer to its election message to4, and will therefore send everyone a coordinator message. When 4 eventually
revives it will realise that it ought to be coordinator (since there is no process withhigher index) and bully all the others into accepting it.
The intention, it would seem, is that except when the co-ordinator has failed
and has not been tested since, the nodes either all agree on the correct coordinator(i.e., the live one with highest index) or are in the process of an election which will,in the absence of any further process failures or revivals, produce this result in abounded time. It is that which we will test in this section.
Part 1: Speciﬁcation
It is, of course, good practice to design your speciﬁcation before your system. In
the present case the speciﬁcation is also rather easier.
Assume all the actions described above, except for fail, revive and test
have been hidden as internal, and do not therefore play a part in our speciﬁcations.
Assume, furthermore, that there are additional channels
channel tockchannel leader:Proc.Proc
the ﬁrst showing the passage of time (as in Chapter 14), the second an external
channel of each process showing who it believes is the current co-ordinator, which
it is prepared to communicate on whenever it is neither failed nor in mid-election.
Basically, what we have to do is to translate the English speciﬁcation above
into CSP. This will require us to interpret some of its parts such as the concept of‘agree’ in CSP terms, and to give concrete interpretation to things like time bounds.
We can capture the intended speciﬁcation in terms of traces or (more strongly)
in terms of failures.
(a) Whenever no process has revived for TS time units, and each fail has been
followed by some revive or test event (the two sorts that could set an
election going) at least TS timed units ago, then if any node believes there isa co-ordinator (i.e., communicates leader.m.n) then n is the highest “living”
node.
There are three basic states to this speciﬁcation: one in which the conditionis enforced, and two where it is not because either the system is being allowed434

Case studies
time to settle, or an untested coordinator failure has occurred. All three areparameterised by the set of live processes (ones that have revived since last
failing).
The ﬁrst case is when the condition is being enforced.
AGREEBY(0,alive) =alive != {} & leader?m:alive!max(alive) ->AGREEBY(0,alive)[] tock -> AGREEBY(0,alive)[] fail?k -> (if k==max(alive) then
AGREEBY’(diff(alive,{k}))else
AGREEBY(0,alive))[] revive?k -> AGREEBY(TS,union(alive,{k}))[] test?n?k -> AGREEBY(0,alive)
In the second we are waiting n > 0 tocks before enforcing it. Note that
we allow failures other than the natural leader to reset the timer since theymight well disrupt an in-progress election.
AGREEBY(n,alive) = leader?m:alive?k -> AGREEBY(n,alive)[] tock -> AGREEBY(n-1,alive)[] fail?k -> (if k==max(alive) then
AGREEBY’(diff(alive,{k}))else
AGREEBY(TS,alive))[] revive?k -> AGREEBY(TS,union(alive,{k}))[] test?m?k -> AGREEBY(n,alive)
Finally, we have the state in which the leader has failed but has not yet beentested. Since either a test or a process revival ought to start an election,either breaks this state.
AGREEBY’(alive) = leader?m:alive?k -> AGREEBY’(alive)[] tock -> AGREEBY’(alive)[] fail?k -> AGREEBY’(diff(alive,{k}))[] revive?k -> AGREEBY(TS,union(alive,{k}))[] test?n?k -> AGREEBY(TS,alive)
The above is, of course, a trace speciﬁcation. On the assumption that allprocesses start oﬀ working properly the natural starting state of this speciﬁcation is AGREEBY(alive,0).

15.2

Analysis of a distributed algorithm

435(b) It is, however, easily turned into a failures(/divergences) speciﬁcation thatsays that under the same conditions all live processes deﬁnitely do believe inthe correct leader process. Simply replace the ﬁrst lines of the second twocases above by themselves nondeterministically composed with STOP, and put
the entire speciﬁcation in parallel withCHAOS({|tock,fail,revive,test|})synchronising on this set of all events that the speciﬁcation uses other than{|leader|}.
In addition to these functional speciﬁcations, we would obviously like our implementation to be deadlock-free and to satisfy the appropriate timing consistency
check (see page 393).
Part 2: Implementation
Given the freedom with which the nodes potentially run, it seems to be necessary,for the avoidance of deadlock, to make the nodes continually receptive of almost all
the messages that might be directed at them by another node. This even applies
when the node has failed, since we would expect a dead node to ignore things thatare directed at it rather than prevent them from happening. In other words thisis a case where the handshaken communication of CSP is being used to model asomewhat freer form of interaction.
In programming the nodes you soon realise that, because of the necessity set
out in the above paragraph, you have to deal with cases not directly catered forin the English description of the protocol. This is a very common experience intranslating from English to formal speciﬁcations. The situations we have in mind
here are ones in which a node is doing what it has to to perform its role in one runof the protocol when it gets interrupted by a message from another run.
For example, if node n receives an election message in the middle of distributing its own coordinator signal, then we might think we ought to abandon
the distribution and get on with the election, after answering the election message.
That, however would be a mistake, especially because the coordinator message
may well have arrived after (and therefore overridden) the election message elsewhere, including at its origin. If, on the other hand, it ignored an election message
from node m in a situation where this was sent subsequent to m having received
its own coordinator.n (e.g., because m has revived) this could also lead to problems. The right solution to this particular conundrum appears to be that sincenothing has happened to shake n from its belief that it is the rightful co-ordinator,

436

Case studies

the appropriate thing is for it to re-start its coordinator distribution so that theelection sender will deﬁnitely receive it again.
We take a minimalist approach to introducing timing into our system. In
particular we always assume that any response that the protocol calls for from node
n without it having to wait for anything else, happens immediately (i.e., before thenext tock). One could perhaps get a slightly more accurate model by introducing
small delays here, but we would get a more complex model with more states. And
in the end it does not appear to inﬂuence the outcome greatly. What the author
did have to do to avoid some oddities and failures of timing consistency was toassume that no process generates more than one test of the co-ordinator in any
time interval, and that at least one tock occurs between any process failing andreviving.
The following deﬁnitions set up the number of nodes, and some time delays.
We will ﬁnd later that this particular number of nodes is important.
N=4
Proc = {0..N-1}
T1 = 1T2 = 2TS = 5All communications in this algorithm go from high to low or low to high so
it is useful to have the following sets deﬁned:
above(n) = {k | k <- Proc, k>n}below(n) = {k | k <- Proc, k<n}Each process can be in one of a number of states. Let us begin with the one
in which it is just starting an election:
BeginElection(n) = SendElections(N-1,n)which results in it sending successive election messages to the appropriate nodes.
Note how it can handle the receipt of any message it might receive, with varying
results...
SendElections(k,n) = (if k<=n then AwaitAnswers(T1,n)else election.n.k -> SendElections(k-1,n))[] election?k’:below(n)!n ->answer.n.k’ ->15.2

Analysis of a distributed algorithm

437

SendElections(k,n)[] answer?k:above(n)!n -> AwaitCoordinator(T2,n)[] ok?k’:above(n)!n -> SendElections(k,n)[] coordinator?c:above(n)!n -> Running’(n,c)[] fail.n -> Failed(n)[] test?m:below(n)!n -> SendElections(k,n)
Below, it is waiting for answers from its election messages, with the timeout making it the coordinator if it has not had one within T1:
AwaitAnswers(t,n) = if t==0 then BecomeCoordinator(n)elsetock -> AwaitAnswers(t-1,n)[] answer?k:above(n)!n -> AwaitCoordinator(T2,n)[] ok?k:above(n)!n -> AwaitAnswers(t,n)[] election?k:below(n)!n -> answer.n.k ->AwaitAnswers(t,n)[] coordinator?c:above(n)!n -> Running’(n,c)[] fail.n -> Failed(n)[] test?k:below(n)!n -> AwaitAnswers(t,n)
After it has had an answer message, it sits and waits to be sent a coordinatormessage (or any of a number of others), before starting another election if nothing
signiﬁcant has happened.
AwaitCoordinator(t,n) = if t==0 then BeginElection(n)elsetock ->AwaitCoordinator(t-1,n)[] coordinator?c:above(n)!n -> Running’(n,c)[] answer?k:above(n)!n -> AwaitCoordinator(t,n)[] ok?k:above(n)!n -> AwaitCoordinator(t,n)[] election?k:below(n)!n -> answer.n.k ->AwaitCoordinator(t,n)[] fail.n -> Failed(n)[] test?k:below(n)!n -> AwaitCoordinator(t,n)
The following state represents when it has decided, for want of life above it,that it is the current co-ordinator
BecomeCoordinator(n) = SendCoords(n-1,n)It distributes a coordinator.n message to all below it. Note that since it is thecoordinator, it sends a positive response to the test message, unlike earlier states

438

Case studies

SendCoords(j,n) = if j<0 then RunAsCoord(n)else coordinator.n.j -> SendCoords(j-1,n)[] election?k:below(n)!n -> BecomeCoordinator(n)[] coordinator?c:above(n)!n -> Running’(n,c)[] fail.n -> Failed(n)[] test?k:below(n)!n -> ok.n.k -> SendCoords(j,n)
All the above states represent stages in the election protocol. Obviously
we also need states in which a process is running, or has failed. When a node isco-ordinator it takes the following state:
RunAsCoord(n) =tock -> RunAsCoord(n)[] test?k:below(n)!n -> ok.n.k -> RunAsCoord(n)[] coordinator?k:above(n)!n -> Running’(n,k)[] election?k:below(n)!n -> answer.n.k ->BeginElection(n)[] fail.n -> Failed(n)[] leader.n.n -> RunAsCoord(n)and one in which thinks some other node k is coordinator
Running(n,k) =test.n.k -> Testing(n,k)[] tock -> Running(n,k)[] coordinator?k:above(n)!n -> Running’(n,k)[] answer?j:above(n)!n -> Running(n,k)[] leader.n.k -> Running(n,k)[] election?k:below(n)!n -> answer.n.k ->BeginElection(n)[] test?j:below(n)!n -> Running(n,k)[] fail.n -> Failed(n)When it has sent a test message to the node it believes is co-ordinator, it waits
until one time unit has passed before deeming the co-ordinator to have failed andbeginning an election. Yet again, it is necessary to allow for anything else thatmight arrive in the meantime.
Testing(n,k) =ok.k.n -> Running’(n,k)[] tock -> BeginElection(n)[] answer?j:above(n)!n -> Testing(n,k)[] coordinator?k:above(n)!n -> Running’(n,k)[] election?k:below(n)!n -> answer.n.k ->BeginElection(n)15.2

Analysis of a distributed algorithm

439[] fail.n -> Failed(n)[] test?j:below(n)!n -> Testing(n,k)[] leader.n.k -> Testing(n,k)
After performing one test successfully, it goes into the following state in which it
has to wait a time unit before performing another one (thereby avoiding a potential
divergence):
Running’(n,k)=

tock -> Running(n,k)[] coordinator?k:above(n)!n -> Running’(n,k)[] answer?j:above(n)!n -> Running’(n,k)[] election?j:below(n)!n -> answer.n.j ->BeginElection(n)[] fail.n -> Failed(n)[] leader.n.k -> Running’(n,k)[] test?j:below(n)!n -> Running’(n,k)[] ok?j:above(n)!n -> Running’(n,k)

A failed process just absorbs messages sent to it until
Failed(n) = tock -> Failed’(n)[] coordinator?k:above(n)!n -> Failed(n)[] election?k:below(n)!n -> Failed(n)[] test?k:below(n)!n -> Failed(n)[] ok?k:above(n)!n -> Failed(n)[] answer?k:above(n)!n -> Failed(n)it is revived, which is not until at least one time unit has passed
Failed’(n) = tock -> Failed’(n)[] coordinator?k:above(n)!n -> Failed’(n)[] election?k:below(n)!n -> Failed’(n)[] test?k:below(n)!n -> Failed’(n)[] ok?k:above(n)!n -> Failed’(n)[] answer?k:above(n)!n -> Failed’(n)[] fail.n -> Failed(n)[] revive.n -> (if n==N-1 then BecomeCoordinator(n)else BeginElection(n))
Note that if the highest-index process revives it has no need to carry out an election
to know it should be co-ordinator.

440

Case studies

We can then give each process its obvious alphabet and run them in parallel
as a network.
Alpha(n) = union({|tock, fail.n, revive.n, election.n,coordinator.n, test.n,answer.n, leader.n, ok.n|} ,{election.k.n, coordinator.k.n,
test.k.n, answer.k.n, ok.k.n| k <- Proc})
Node(n) = if n==N-1 then RunAsCoord(n) else Running(n,N-1)
Network = || n:Proc @ [Alpha(n)] Node(n)The ﬁrst thing to try with any timed example is a timing consistency check along thelines set out on page 393. The following events are all deemed ‘delayable’ because
we do not want to have to rely on them happening urgently for time to pass (theinclusion of test here serves the purpose of showing that the individual nodes canbe ‘lazy’ about instigating tests of they want to be, though we will later be forced
to re-think this in some circumstances).
Delayable = {|fail, revive, leader, test|}
Urgent = diff(Events,union({tock},Delayable))
The following give us two nearly equivalent ways of testing it, the second being
stronger because it proves that hiding the urgent events can’t introduce divergence,
which would break various assumptions of the abstraction method.
assert TOCKS [F= (Network [|Delayable|]
CHAOS(Delayable))\diff(Events,{tock})assert TOCKS ||| CHAOS(Delayable) [FD=Network \ Urgent

TOCKS = tock -> TOCKS
15.2.1AnalysisWith the values of the parameters given, the timing consistency checks succeed,
meaning that our model makes sense as a timed system. Fascinatingly, however,
the others fail, even though we have done our best to implement the algorithm fromthe literature. A typical error trace follows (though it is far from unique):fail.2, fail.3, test.1.3, tock,15.2

Analysis of a distributed algorithm

441

election.1.3, election.1.2,
revive.2, revive.3, coordinator.3.2,
fail.3, test.0.3, tock,coordinator.1.0, tock,
tock, tock, tock, leader.2.3
This can be interpreted as follows:
1. Nodes 2 and 3 fail.
2. Node 1 tests node 3; when it gets no response an election is started.
3. Both 2 and 3 revive shortly after they miss (through being failed) the election
messages they get from 1.
4. 3 manages to tell 2 it is the coordinator before failing again.
5. 0 begins a test of 3.
6. By this time, 1 decides that since it has not had any response to the election
it started, that it is the rightful co-ordinator. It therefore tells 0, which
pre-empts the test the latter is doing.
7. The speciﬁcation then gives the system time to settle (the tock events towards the end of the trace), though nothing of signiﬁcance actually happensin this time.
8. We are left in a state where 0 and 1 believe 1 is the co-ordinator, and 2
believes that 3 is (though 3 has failed). Actually, of course, 2 ought to be.
It is the way various elections get mixed up, and the way in which processes canfail in the middle of broadcasting a message to the others, that causes the problem.
These two themes are common to about every error the author has examined tocome out of FDR. Indeed, if process failure is prevented during the SendCoords
phase of broadcasting coordinator messages, all the speciﬁcations succeed.
The impossibility of this sort of failure might or might not be regarded asa reasonable assumption, though it would appear a dangerous one if the messages
really do get sent out one after another. If not, the fact that the protocol appears
to work if we do assume it provides a clue as to how we might correct the program.
We need to guard against only some of the nodes that ought to be informed about
n’s co-ordinator status getting this message. The dangerous scenario following thisappears to be that one of the nodes who has not heard the coordinator.n message
tests who it thinks is the coordinator, which is suﬃcient for the speciﬁcation to thinkthat the network ought to settle to a correct state. One way to avoid this is to ensurethat each node m that gets a coordinator.n tests n long enough after so that if442Case studies

this succeeds then it knows the broadcast has not been interrupted, for if the test
fails then a new election will be started, and the inconsistent state will be cleared
up. It is sensible to extend the minimum possible time between node failure andrevival, to make sure that n as discussed above has not done these things between
m getting coordinator.n and completing the test of n. (If such an assumption is
not realistic, nodes could simply be programmed to wait an appropriate time after
revival before doing anything.)
It is straightforward to adapt our program to encompass these extra tests
and delay assumption. One slight complication arises from the timing model: in theﬁrst model it was helpful to think of the test events as delayable, since we did notwant to rely on them happening simply to allow time to progress. We would still
like to take this view of the tests that arise ‘optionally’, but it does not ﬁt with thecompulsory tests that happen after being sent a coordinator event. To solve thiswe make test.n events urgent, and guard each optional test with a new delayable
event dotest.n.
Thus the following state can perform dotest, which takes it
Running(n,k) =dotest.n -> Testing1(n,k)[] tock -> Running(n,k)[] coordinator?k:above(n)!n -> Running’’(n,k)[] answer?j:above(n)!n -> Running(n,k)[] leader.n.k -> Running(n,k)[] election?k:below(n)!n -> answer.n.k ->BeginElection(n)[] test?j:below(n)!n -> Running(n,k)[] fail.n -> Failed(n,TR)

to the Testing1 state, which actually starts the test proper.
Testing1(n,k) =test.n.k -> Testing2(n,k)[] answer?j:above(n)!n -> Testing1(n,k)[] coordinator?k:above(n)!n -> Running’’(n,k)[] election?k:below(n)!n -> answer.n.k ->BeginElection(n)[] fail.n -> Failed(n,TR)[] test?j:below(n)!n -> Testing1(n,k)[] leader.n.k -> Testing1(n,k)

Testing2(n,k) =ok.k.n -> Running’(n,k)[] tock -> BeginElection(n)[] answer?j:above(n)!n -> Testing2(n,k)

15.2

Analysis of a distributed algorithm443[] coordinator?k:above(n)!n -> Running’’(n,k)[] election?k:below(n)!n -> answer.n.k ->BeginElection(n)[] fail.n -> Failed(n,TR)[] test?j:below(n)!n -> Testing2(n,k)[] leader.n.k -> Testing2(n,k)
Here, Running’(n,k) a state like Running(n,k) except that it will not instigate
a further test until after a tock. Running’’(n,k) is a state that moves to state
Testing1(n,k) after one tock, thereby testing the co-ordinator one time unit after
coordinator.k is received.
With this amendment, the protocol meets its speciﬁcation for all the cases(with reasonable timing parameters) that we have tried.
15.2.2Conclusions

There are a number of observations we might make about this case study. During
the process of creating the program for the bully algorithm set out above, there
were far more problems encountered than is obvious from how we have described
it. Speciﬁcally, a number of iterations of the program failed deadlock or timing
consistency checks, usually because the author had not allowed for various sorts ofmessages arriving at nodes who (one might have thought) were not really expecting
them. The fact that these messages had to be handled, and the decisions about
how to handle them, impressed on him that the English description of the protocol
left more unanswered than one might think on ﬁrst reading it.
Having ironed out these problems, we were left with an apparently working
model (the uncorrected one presented above). Indeed, for three nodes all the speciﬁcations of it succeed, though as we have seen four is suﬃcient to ﬁnd problems.
It doesn’t seem likely that many humans would ﬁnd the ways in four nodes have tointeract in order to ﬁnd the subtle problems FDR discovered. Indeed, the author
had taught the bully algorithm in tutorials for several years without spotting them.
It was only the feeling that there were stones left unturned in the arguments weconstructed annually as to why the algorithm worked that led to this FDR analysis.
It is hard to say that the problem we encountered with inconsistent states
for four or more nodes represents a deﬁnite error in the algorithm itself. What
it does show is that a highly plausible implementation of the algorithm can failwhat looks like an equally plausible formalisation of its speciﬁcation. The author
once used this example as an end-of-course assessment for Masters students, giving
them the English description and a few hints on how to create the necessary CSP
speciﬁcations and implementations. A majority of the students found essentially444

Case studies

the same problem, and in at least one case a diﬀerent problem that occurs when
the order in which broadcast messages are sent out is changed. This might be taken
as evidence that, at least for this algorithm, simply implementing what you ﬁnd
described in English in a book is far from being a guarantee of correctness.
The fact that the original implementation worked for three but not four
nodes is both interesting and worrying. The only Masters student who made aserious attempt at correcting the problem uncovered at four nodes came up with aversion that worked for four but not ﬁve nodes – amazingly enough repeating what
had happened to the author on an earlier attempt at correcting the system. Theseexperiences are likely to leave anyone worried that the corrected version might work
up to some limit (say 10) and after that fails in a system of such size that FDR
cannot handle it.
One method for addressing this scaling problem, but unfortunately not one
that can be used (at least, straightforwardly) to address the current example, canbe found in the next section. The best option for a general proof would appear
to be mathematical induction. This would probably take the form of showing thatthe uppermost k nodes of our implementation meet some condition that implies the
speciﬁcations when all n nodes are present, and which is closed under the inductive
step of attaching a further node at the bottom. The basic properties one would
require are fairly obvious, namely that within appropriate time limits of either anelection message being sent from below (when one of the k is alive) or a processfrom the k reviving, an appropriate coordinator broadcast occurs. As with theoriginal protocol description, this broad brush speciﬁcation ignores lots of nuances,and it seems certain that any working inductive hypothesis would have to deal withmany of these. This is not something we have yet done.
This example thus displays both the strengths of the automated approach –since it found errors a human was unlikely to discover and allowed us to correctthese at least to the bounds of FDR’s capabilities to handle the resulting system –and one of its main weaknesses.
Observing that it is node n-1 who is the ﬁrst recipient of any batchof coordinator messages from node n, it is plausible to suggest that only this node needs
to instigate the test of node n that was introduced in the correction. Is this correct? (Youshould ﬁrst attempt to solve this problem without using FDR on a modiﬁed ﬁle, but canof course use this method should you not be sure of the answer you then get.)Exercise 15.2.1

Exercise 15.2.2 Are the answer.n.m messages a necessary part of the protocol? If so,why, and if not can you suggest any pragmatic arguments as to why they are neverthelessthere?
Consider the following modiﬁcation to the algorithm. There are
now two sorts of election message. Elections caused by someone noticing co-ordinator

Exercise 15.2.3

15.3

Distributed data and data-independence

445

failure use one sort, and follow exactly the same path as before. Elections caused bya node reviving use an election’ channel, with the property that when a node who isrunning normally receives it, it simply tells the sender who the coordinator is via a channel
coordinator’.n.m.c (n telling m that the co-ordinator is c). If a reviving node has notbeen sent such a message or an answer (sent by nodes receiving election’ when they arein the process of an election themselves) within a reasonable time, it deems itself to be theco-ordinator and broadcasts this fact as before.
Does this work (a) when the uncorrected program is modiﬁed accordingly, and if
not, (b) the corrected one is modiﬁed so that only coordinator as opposed to coordinator’messages force a test, and if not (c) the corrected one is modiﬁed so that both sorts force
a test? What advantages and disadvantages do you see for this new approach?

15.3

Distributed data and data-independence

Many of the applications CSP is best suited to are systems that handle data items
without altering them. Rather they manage data values, and input and output
them – hopefully at appropriate times on the desired channels. We have seen many
examples in buﬀers and communication protocols, stacks and bags. Some of themost striking examples are systems that store multiple copies of data (either for
security against failure or speed of access) but seek to maintain the appearance ofa single copy which can be accessed for reading and writing.
In this section we see two of these: one where copies of a store are heldat every node on a ring, and a model of a cache not unlike those used on mostmicroprocessors. One of our main objectives is to explain and illustrate the theoryof data-independence, whereby it is often possible to prove facts about processes of
the type described in the previous paragraph for any data type by showing theyhold for a particular ﬁnite data type.
15.3.1

A ring database

Imagine that you have a ring of processes, each holding a copy of a selection ofregisters, and that you want each node to be able to update any of these. An
update is ﬁrst executed locally, and then transmitted around the other nodes inturn until it arrives back home. See Figure 15.3. If two nodes at opposite sides(A and D, say) of the ring choose to update the same register at very nearly thesame time, it is evident that the resulting updates will be seen in diﬀerent orders
if they both simply pass all the way round the ring. This, in turn, might lead to asituation where even after all updates have completed their journeys, nodes B andF disagree on the value of the register.
Unless some sort of locking mechanism is employed – inevitably expensivein time and eﬀort – it is certain that we must put up with there being instants

446

Case studies
W
X
Y
Z

F

W
X
Y
Z

E

W
X
Y
Z

W
X
Y
Z

A
W
X
Y
Z

B

W
X
Y
Z

C

D

Figure 15.3 The ring database.

where simultaneous reads to the same register will yield diﬀerent results. What wecannot tolerate is any inconsistency which persists, like the one described above,even when the system is quiescent. The author proposed several related algorithms
in [106]3 which guarantee at least this degree of consistency under various scenarios:
the simplest one is described below.
Let the nodes on the ring be Ni for 0 ≤ i < M , with indexes increasing in
the direction messages pass round. The user of any node may read or write anyof a set of registers locally. When a local write has occurred, Ni will generate an
update that is entered into the ring to carry the new value round the other nodes.
3 In that paper they are proved mathematically. The mathematical arguments have the advantage that they apply to any size of ring, and yield rather more detail about the pattern of values
visible than we do here: provided the priorities are restructured to follow a logical time regime, aform of sequential consistency can be proved. They have the disadvantage of being very far fromtrivial, and also do not address questions such as deadlock and livelock freedom as we will here.

15.3

Distributed data and data-independence

447

If otherwise uninterrupted, an update passes round until it arrives back at the nodethat generated it; updates thus carry the identity of their origins with them, andeach node keeps a list Ei of the updates it has generated that are expected back.
In order to resolve the inconsistencies that can arise due to simultaneously
existing updates to the same register, the nodes are all assigned unique priorities:
let pi be the priority of Ni . These aﬀect what happens when an update u originatedby Ni arrives at Nj :• If i = j then u is removed from the head of Ej provided it is there. Its absence
is an error: we can deal with it any way we please. In the implementation
below we do not notice it belongs to the node if Ej is empty, and so it justgets executed and passed round. Other options would be to STOP locally ortransmit some error event.
• If i = j and there is no clashing update (i.e., an update of the same location)in Ej , u is executed locally and passed on round the ring.
• If pi < pj , and Ej contains any updates that clash with it, then u is stopped:
it is neither passed on round the ring nor executed locally.
• If pi > pj , and Ej contains any updates that clash with it, then u is executed
locally and passed on round the ring, and the clashing updates are cancelled(removed from Ej ).
In studying this algorithm it is plainly suﬃcient to consider only a single
register (i.e., each node has a copy of this register), since, while updates to thesame location interfere with each other in a complex way, ones to diﬀerent locations
do not. Thus, in building our implementation we will restrict ourselves to thatcase. This has the twin advantages of somewhat simplifying the programming andreducing the size of the state space, though it would not be diﬃcult to adapt thedeﬁnitions to deal with any number of registers.
It is clearly desirable that the system we build is free of deadlock and livelock
as well as satisfying consistency results. There would be no hope of achieving
this if the underlying mechanism that transports updates round the ring could
deadlock or livelock. We therefore base this aspect of our system on sound principles,
namely Deadlock Rule 8 (see page 363) in a way similar to the message-passing ring
described with the rule. Speciﬁcally we give each node the capacity to hold two(travelling, as opposed to expected-back) updates, but only allow it to become full
due to an input from the ring.
Our later speciﬁcations will be predicated on what the system looks like when
it is quiescent (no updates circulating and none expected). This is the role of theevent quiet: each node can communicate it when it is locally quiescent; we force

448

Case studies

them all to synchronize on it so that the event can happen when, and only when, thewhole system truly is quiescent. This event is not one that would be part of a real
implementation; it is simply something we will need for the purpose of speciﬁcationand veriﬁcation. It actually has a lot in common with the event done from theprevious section, since they are both synchronized over all processes to identify aparticular global state.
The processes deﬁned below do not actually hold the local copy of the register:we will later combine each of them in parallel with a process that does. What they
do is handle updates according to the above algorithm, assuming that any that are
input have already been executed on local data and that any output are immediately
applied (at the point of output).
Below, N0(i,E,T) represents the node Ni which presently holds no travelling
updates, and which is expecting the list E of updates back from the ring. The
parameter T is the type which is being stored in the register: the reasons for making
this explicit will become apparent later. We impose a limit on the length of E since
this is necessary to keep the process ﬁnite state.
N0(i,E,T) = (#E<limit) & in.i?x:T -> N1(i,E^<x>,i,x,T)[] #E==0 & quiet -> N0(i,E,T)[] ring.i?j?x:T -> (if #E==0
then (out.i.j!x -> N1(i,E,j,x,T))
else (if i==jthen N0(i,tail(E),T)
else (if priority(i)<priority(j)then (out.i.j!x -> N1(i,<>,j,x,T))
else N0(i,E,T) )))The connections of the channels when these are put in parallel are shown in Figure15.4. Since there is only one register, there is no need to name it when passing
updates round the ring. The communication ring.i.j.x means the passing to Ni
round the ring of an update to the register originated by Nj of value x . In theabove state our node can (subject to the limit on E) accept inputs either from its
environment or the ring. When it already holds an update j.x which it is readyto output on the ring, then because of the requirements of Deadlock Rule 8, it will
only accept a ring input, but otherwise it behaves similarly.

15.3

Distributed data and data-independence

in.0

N0

out.0

rin

.0

out.5

449

g.1

g
rin

in.1

N5

N1
out.1

ring.5ring.2

in.5

in.2

out.4
N4
in.4

N2

rin

g.3

g.4

rin
N3

out.3

out.2

in.3

Figure 15.4 Communications in the implementation.

N1(i,E,j,x,T) = ring.((i+1)%M)!j!x -> N0(i,E,T)[] ring.i?k?y:T ->(if #E==0
then (out.i.k!y -> ring.((i+1)%M)!j!x -> N1(i,E,k,y,T))
else (if k==ithen N1(i,tail(E),j,x,T)
else (if priority(i)<priority(k)then (out.i.k!y -> ring.((i+1)%M)!j!x ->N1(i,<>,k,y,T) )else N1(i,E,j,x,T) )))Since the capacity of these nodes is 2, whenever they are full they insist on outputting on the ring before accepting any more inputs. The ring can then be assembled as follows.
Alpha(i) = {|in.i, out.i, ring.i, ring.(i+1)%M, quiet|}
RING(T) = (|| i:NodeNames @ [Alpha(i)] N0(i,<>,T))\{|ring|}

450

Case studies

It is natural to split the desired properties of this system into safety (traces)
and liveness (failures/divergences) speciﬁcations. For this basic ring without registers, one can identify three diﬀerent liveness checks.
The ﬁrst and most obvious is deadlock freedom, established, for example, via
the check4
DF [F= RING(T)(1)

It is not too hard to see that the ring as constituted is divergence-free, because
each time a hidden action occurs (i.e., a communication on ring), this is precededby either the input (in) or an output (out) of the relevant update. It is, however,interesting to ask whether the process RING(T)\{|out|} can diverge.
CHAOS(Events) [FD= RING(T)\{|out|}(2)

Such a divergence would correspond to one or more updates circulating endlessly
without the need for further input; this is plainly not meant to happen but could
if an update ever arrived back home to ﬁnd the relevant Ej empty (i.e., it was notexpected).
Assuming that both deadlock freedom and this extended form of livelock
freedom have been proved as they can be (for given implementations) with FDR,
the ﬁnal liveness check we use is to establish that, on the assumption that nodes
are never prevented by the environment from outputting updates, they inevitably
stabilize in the quiescent state. In other words, left to its own devices, the ring
will eventually come back to the state where no updates are active and none is
expected back. We need to show that, eagerly abstracting the output events andlazily abstracting the input events, the ring failures reﬁnes the process
QS = quiet -> QS
The abstracted process can be represented and checked as follows:
QS [F= MixedAbstraction({|in|},{|out|},RING(T))(3)

where the mixed abstraction operator is deﬁned
MixedAbstraction(D,E,P) = (P[|D|]CHAOS(D)) \(union(D,E))
See Section 12.2 for more details of this style of speciﬁcation using abstraction. Thisparticular check has much in common with the style of timing consistency checkdescribed on page 415. A more direct and equivalent check is to show that
4 The checks in this section are numbered so we can refer to them later.

15.3

Distributed data and data-independence

451

CHAOS({|in|}) ||| QS
is failures or, equivalently, failures/divergences, reﬁned by RING(T)\{|out|}.
Now that we know that our system always returns to the quiescent state, anatural way of formulating the basic safety speciﬁcation (namely, consistency) is toassert that whenever it is quiescent all the copies of the register are equal. One cando this directly on the process RING(T) described above by carefully monitoring
the pattern of updates that occur in each node within the speciﬁcation. This isdone as an alternative in the example ﬁle which illustrates this section, but here
we concentrate on the more obvious method, which is to add the actual registers
into the network. The following deﬁnition adds a new channel read, but identiﬁes
writes to the register at node i with the communications in.i.x. There is nothingessential about this approach and writes could also take place on a separate channel
provided the register process carried a ﬂag which indicates whether an update needs
to be sent to the ring. (It would be set just when a local write had occurred more
recently than the last communication on in.i or out.i.)
VAR(i,x,T) = (out.i?j?v:T -> VAR(i,v,T))[] (in.i?v:T -> VAR(i,v,T))[] read.i!x -> VAR(i,x,T)
VARS(x0,T) = ||| i:NodeNames @ VAR(i,x0,T)
DDB(x0,T) = (RING(T) [|{|in,out|}|] VARS(x0,T))\{|out|}
Here x0 (ranging over the type T) represents the initial value of the register.
The appropriate trace speciﬁcation is then simply that whenever a quiet has
occurred more recently than a write (i.e., in this case an in event), two reads will
give the same answer. This can be established by showing that
SS [T= |˜| x0:T @ DDB(x0,T)
where the speciﬁcation process SS is deﬁned
SS= quiet -> Q0[] read?j?x -> SS[] in?j?u -> SS

Q0 = read?j?x -> Q1(x)[] quiet -> Q0[] in?j?u -> SS

(4)

452

Case studies

Q1(x) = read?k!x -> Q1(x)[] quiet -> Q1(x)[] in?j?u -> SS
Note that Q1(x) only permits one value to be read (any other leading to a failureof reﬁnement) whereas the other two states permit any. This is because Q1(x)represents the case where at least one read (giving value x) has occurred since aquiet event and before any further input on in.
15.3.2

Data-independence

Processes often have one or more parameters, namely quantities or objects that canvary giving diﬀerent instances of the system. Only the very simplest CSP processes
are usually deﬁned without using parameterization at all. Parameters are typicallyused to help capture the states of individual processes or to create a number ofsimilar components to include in a network (e.g., PHILi ), but often a complete
network will still depend on one or more parameters (such as the total number ofphilosophers). The parameters of the distributed database in the previous sectionare:
1. The data type T of stored values.
2. The number of nodes.
3. The limit on the sizes of expected-back queues.
4. The ordering on nodes used to determine priority.
In addition, one could address the question of whether it was buﬀer tolerant (asdiscussed in Section 5.2) and regard the sizes of the buﬀers as parameters.
What we would really like to do is prove all the results about liveness andconsistency of the database independently of these parameters. However, tools like
FDR generally only address one speciﬁc instance at a time and are usually only capable of handling ones with relatively small values for variable-sized parameters suchas the ﬁrst three above. The general Parameterized Veriﬁcation Problem (PVP), ofwhether a system satisﬁes a correctness condition for all parameter values, is certainly formally undecidable [4] (it being easy to reduce other undecidable problems
such as the halting problem to it), but the subject of looking for speciﬁc classes
of problems where it might be made tractable is an active area of research (over amuch wider range of theories than simply CSP) and will probably remain one formany years to come.

15.3

Distributed data and data-independence

453

At the time of writing the most progress, by far, has been made with parameters of the ﬁrst sort described above, namely data types, and this section isdevoted to presenting the most accessible and useful results about these.
A data type T used in a program P can fairly be said to be a parameter if
P treats it data-independently: it can input and output values of type T along its
channels, store them for later use, but never perform any ‘interesting’ computations
on them that constrain what T might be. (For example, if members of T were added
to each other, they would have to be numbers, . . . ) With one or two exceptions,the criteria for deciding whether a type is data-independent are identical to thosefor deciding whether it is a free polymorphic type variable in the sense of languages
such as ML. Precise criteria for this, which are readily automatable, can be foundin [65], but the following are the main principles:(i) Concrete values from T (such as 0, true, etc.) may not appear in the program
text of P , though abstract constant symbols can appear.
(ii) You may use basic polymorphic operations on T such as tupling, list formation and suitable operations for extracting members of structures built out of
T in these ways. Intuitively these can be thought of as operations which passmembers of T around without looking inside them at all. No other functions
which involve T either in the types of their arguments or result may be used.
(iii) No predicate (in a conditional) used in the program can depend on values
from T . The only exception to this rule is that we allow equality (andinequality) tests between members of T . We do not, however, allow ordercomparisons such as ≤ and >.
(iv) Operations such as card(S) (the size of a set) may not be applied to any set
involving set T . (This would give a way of extracting information from Tthat could be used to inﬂuence how P behaved.)(v) No replicated constructs except nondeterministic choice (|~| x:S @ Q(x))
can appear in the process if their indexing set depends in any way on T .
Thus, parallel and external choice constructs indexed over T are banned,
though the eﬀect of the latter can, in practical circumstances, almost always
be recovered using input (c...?x:S...), which is allowed.
Typical data-independent processes are COPY (in the type communicated)
and all the processes in the section on the distributed database (in the parameter
type T).
A data-independent program over type T makes sense whatever non-empty
set is substituted for T . If Spec and Impl are two of them, then it makes sense to
ask questions such as454

Case studies• SpecT Impl?

• SpecF Impl?

• SpecFD Impl?

• is Impl deterministic?
for any speciﬁc T . Anybody performing many checks of this sort quickly comes tothe conclusion that there must be a strong relationship between the answers to thesequestions for diﬀerent sizes of T (it being relatively easy to see that the answer for
any pair of T ’s of the same size must be the same). Fortunately this intuition istrue and in almost all cases there is a threshold: an integer N such that the answer
to one of the above questions for a type of size M ≥ N is independent of M . In
other words, one can prove or refute a result for all suﬃciently large5 T via one
check on FDR.
It is obviously of great practical importance to determine when these thresholds exist, and to ﬁnd as small a threshold value as possible for each question we arepresented with. There is a recently developed theory, too complex to present here,
which allows the computation of thresholds by an extension of the theory of logicalrelations (or parametricity) to processes, by augmenting the operational semantics
and CSP normalization to encompass terms with free variables as symbols for members of the independent type, and by using techniques for exploiting symmetry instate spaces. For details of this theory, see Section 15.5 and [68, 64]. References
to related work can be found in these papers and in Section 15.5. What we canpresent here are the main conclusions.
There are four main factors which inﬂuence the size (and in some cases theexistence) of a threshold for a given reﬁnement check. These are• the extent to which the speciﬁcation constrains which members of T arecommunicated,• the kinds of equality checks between members of T that are present in thespeciﬁcation and implementation,• the subtlety of any nondeterminism in the speciﬁcation, and• the extent to which any values of type T which the speciﬁcation uses arerecorded in its traces (rather than only having some ‘behind the scenes’
eﬀect)
5 Where there is such a threshold N the answer for suﬃciently large ﬁnite T also applies to all
inﬁnite T .

15.3

Distributed data and data-independence

455

Lazić has proved a wide variety of results for calculating thresholds for reﬁnement and determinism checks, falling into four main categories. The following
sections present the central ideas and results from each. Often the result presented
can be improved (e.g., by weakening its assumptions or strengthening its conclusions) if, for example, we are interested only in traces reﬁnement: the interested
reader should consult [65, 68, 64].
When | T |= 1 is enough
One frequently wants to prove speciﬁcations of data-independent processes that do
not say anything of signiﬁcance about how they are permitted to handle membersof T . Examples are deadlock and divergence freedom and any trace speciﬁcationthat is always happy to allow any member of T in an event when it allows one.
It turns out that in many cases it is suﬃcient to prove such speciﬁcations for thesimplest possible T : a one-element type. In other words, the threshold is just 1.
Equality tests over T are banned altogether from both the speciﬁcation andimplementation6 :NoEqT A data-independent process P satisﬁes this when it contains no test ofequality between members of T .
All the processes of the distributed database example satisfy NoEqT, as do COPY
and all the other buﬀer and similar examples we have seen.
NoEqT eﬀectively rejects the liberal side of condition (iii) in the deﬁnitionof data-independence. To ensure that the speciﬁcation basically ignores T we assertthat the only way a member of T can occur in a communication of the speciﬁcation
process Spec is via a nondeterministic selection of the form a$x:T -> P which is
introduced as an abbreviation for|~| x:T @ a.x -> P
(For the purpose of trace speciﬁcation, this is equivalent to a?x:T -> P.) In otherwords, Spec can never specify which member of T is communicated or that any
6 It should be pointed out that there are ways of introducing ‘hidden equality tests’ into CSP

programs via some operations and predicates on sets and sequences, and via communication. The
communication eﬀect appears when we synchronize on two output events: c!x -> P [|{|c|}|]c!y -> Q contains an implicit equality check between x and y and therefore violates NoEqT.
These problems do not appear in the great majority of practical programs and can be avoided
provided the only set constructs used involving T are unioning of straightforward channel alphabets(for synchronization and hiding), and each synchronization over channels of type T only has one
output. If you are in doubt about the legitimacy of some construct you should consult one of[65, 64].

456

Case studies

more than one arbitrary member of T is oﬀered. We will only use the $ form on
the speciﬁcation side of reﬁnement, since it will always be permissible to re-write
ones in the implementation using the more general |~| as above.
The characteristic processes DF of deadlock freedom and Chaos Σ of divergence freedom satisfy these criteria, as do processes like
ALT = a$x:T -> b$x:T -> ALTThis particular example just says that communications over a and b alternate without placing any constraint on which members of T appear.
We can now state the ﬁrst of a number of results establishing exact criteria
for data-independent reasoning.
Theorem 15.3.1 Suppose we have processes Spec(T ) and Impl(T ), each dataindependent with respect to the type parameter T and additionally satisfying condition NoEqT. Suppose further that Spec is restricted to nondeterministic selections over T as described above. Then, with representing any of { T , F , FD }the result of the refinement check
Spec(T )Impl(T )is independent of which non-empty T is used. In particular, the answer for all T is
answered by the check when T = {0} is a one-element type.
What this result says, in essence, is that if we have a program whose controlﬂow does not depend on which members of T it holds, and a speciﬁcation which
ignores how it handles members of T relative to each other, then we can collapse
T to a single value without aﬀecting the result of a reﬁnement check. Obviously
this will usually give a signiﬁcant advantage in state space size. It applies to checks(1–3) from the distributed database example.
In fact, essentially the same result holds when Impl is, in addition, allowed
to use arbitrary functions whose result is of type T . These processes, which we canterm weakly data-independent, can thus calculate values in T in non-trivial ways,
but still cannot let T aﬀect their control-ﬂow. See [67, 68, 65, 64] for details.
When | T |= 2 is enoughIf we build a system which is data-independent in some type T then it is likelythat we will want to prove things about how it handles members of T as well as
speciﬁcations that ignore T like those dealt with above. It turns out that, provided
we make the same assumptions about the implementation as in the previous section(i.e., it is data-independent and satisﬁes NoEqT), and follow a set of conditions

15.3

Distributed data and data-independence457

on the speciﬁcation designed to remove ambiguity about what state it is in after agiven trace, then we can assume that T has just two elements. In other words, thethreshold is then 2.
The following condition states, in essence, that the speciﬁcation is alreadynearly in the normal form for CSP used in the algebraic semantics (Section 11.4)
and in reﬁnement checking (Appendix C).
Norm A process Spec meets this condition if(i) its deﬁnition contains no hiding or renaming;(ii) the only parallel operators allowed are alphabetized parallel P[X||Y]Q and
its replicated version;(iii) other than the nondeterministic selection construct7 a$x:S -> P describedabove, no indexed nondeterministic choice is used whose indexing set depends on T ;(iv) all internal and external choice constructs (Q |~| R, Q [] R, indexed versions of these, and [> (the ‘time-out’ operator)) have the initial events ofeach argument disjoint (i.e., once one event has occurred we must know
which branch was chosen) and(v) any uses of the operators ; and /\ ( , the interrupt operator) conform tosome technical conditions given in [65] which essentially ensure that (iv) is
not broken implicitly.
The main role of this condition is to avoid the introduction of any nondeterminism
except when its eﬀects are immediately apparent. Almost all natural speciﬁcation
processes one ever builds satisfy this condition, or could easily be transformed toones that do, since in order for us to know what a speciﬁcation says it should beclear what state it is in after a given trace. In other words, Norm can be regarded
almost as a well-formedness condition on speciﬁcations in a wider sense.8
Theorem 15.3.2 Suppose Spec and Impl are data-independent processes, bothsatisfy NoEqT and Spec satisfies Norm. Let be any of { T , F , FD }.
7 It is legitimate to use complex preﬁxes such as c$x$y?z, but for technical reasons (see [68, 64])

you may not mix (either here or anywhere else the nondeterministic selection construct is used in
the study of data-independence) nondeterministic selections over T with inputs over types otherthan T .
8 The only major class of speciﬁcations we have seen that do not fall within this category
are the fault-tolerance speciﬁcations such as NoFaults on page 318. These, being derived from
implementations, may very well contain hiding, etc.

458

Case studies• If Spec(2) Impl(2) holds (i.e., for T of size 2) then Spec(m)holds for all finite and infinite m ≥ 1.
• If the refinement Spec(2) Impl(2) fails then Spec(m)all finite and infinite m ≥ 2.

Impl(m)Impl(m) fails for

The diﬀerence between this result and the previous one is that here there isnothing to prevent the speciﬁcation restricting which of the values of T it knows
about is communicated after a given trace. Also, in the case of failures and failures/divergences speciﬁcations, it can specify much more about which refusal sets
involving members of T are acceptable. Thus, for example, any of the processes
N
BUFF N and WBUFF  from Section 5.1 would be acceptable for Spec in this result
but not for Theorem 15.3.1.
Intuitively, this result says that if we have both an implementation and a
speciﬁcation which pass members of T around without letting them determine thecontrol-ﬂow, then in order to check whether a reﬁnement holds it is suﬃcient tolook at T of size 2. What you have to check in these cases is that each value input
into an implementation is output in just the right places. In [67, 68, 65, 64] itis shown that in many cases you can restrict the state space of the check further:although it still requires a data type of size 2, one can assume that all but one of thevalues input into the implementation are equal. These references also contain (i)signiﬁcant strengthenings of Theorem 15.3.2 which depend on deﬁnitions we have
not had space for here, and (ii) discussion of the extent to which speciﬁcations that
do not satisfy the condition Norm can be transformed into ones that do via anequivalent of the normalization procedures described in Section 11.4 and Appendix
C.
The consistency check (4) of the distributed database, as well as most of theearlier correctness conditions of communications protocols and similar processes,
come directly within the scope of the above theorem, however. Thus all the checks
in the previous section have, as far as the type parameter T is concerned, a thresholdof 1 or 2.
There is an important generalisation to this case that we ought to mention
here, since it will be important in the section on cryptographic protocols. This isthat many of the results in this subsection continue to hold if we relax our insistencethat there are no equality tests and replace it with conditions that permit equality
tests but only allow progress when equality is true. In other words, we allow thetests in contexts likeif e1 == e2 then P else STOP
where e1 and e2 are expressions of the data-independent type. The precise form of15.3

Distributed data and data-independence459

both the booleans in these conditional and the process P depends on which form of
the condition we are using.
A process description is said to satisfy PosConjEqT when it contains noequality tests (explicit or implicit) which can result in some behaviour on inequalitythat is not possible on equality (other than on tests for equality with constantsymbols). For a formal deﬁnition see [64].
The general case
The deﬁnition of data-independence quoted at the start of this section allowed forequality tests between members of T . Thus the process
RemDups = left?x -> right!x -> RemDups’(x)RemDups’(x) = left?y -> if x==y then RemDups’(x)else right!y -> RemDups’(y)which removes adjacent duplicates from a stream of values is data-independent eventhough its control-ﬂow depends on the values of T it uses. Evidently, however, thisdoes not satisfy the condition NoEqT, and so neither of the earlier results applies toit. In cases like this it is still, under appropriate conditions, usually possible to ﬁnd
thresholds, but they vary with the complexity of the processes under consideration.
For example, a process which inputs N values and then communicates a only ifthey are all diﬀerent plainly needs a threshold of at least N in order to show thatit can sometimes communicate a.
Lazić has shown how to compute thresholds in terms of the following quantities. Bear in mind that we are going to assume that the speciﬁcation Spec satisﬁes
Norm whereas no such assumption will be made of Impl.
W Impl is the maximum number of values of type T that the implementation Impl
ever has to store for future use. This number can be computed by going through the operational semantics of the process in such a way thatmembers of T are treated as ‘symbolic’ identiﬁers and counting how manyof them are required in any state. For the RemDups example above, thisnumber is 1 because in any state it only has to store ‘x’ or ‘y’. (It might
appear that the point in RemDups’(x) just before the equality test has tostore two values, but in fact the operational semantics merges the eﬀect
of any conditional with the preceding action. The fork produced by theconditional thus occurs as part of the left?y action, with some values ofy leading one way and some the other.)W Spec is the corresponding number for the speciﬁcation.

460

Case studies

is the largest number of values of type T that can be input in any single
LImpl?
visible event of Impl. This can be greater than one when dealing withchannels with multiple components and/or components that are tuples,
lists and similar.
LSpec is the corresponding number for the speciﬁcation, except that it additionally takes into account nondeterministic selections (using $) which may bepresent in Spec.
is the largest number of values from T that can be nondeterministicallyLImpl
chosen in any single nondeterministic choice made over sets involving T in
Impl. Thus the choice |~| p:(T,T) @ Q(p) requires this quantity to be(at least) 2.
All of these quantities can be inﬁnite in some circumstances, for example, throughthe use of unrestricted-length sequences of type T . When a constant necessary forcomputing a given threshold is inﬁnite, it essentially means that no useful one canbe obtained in this way.
The following results show the thresholds. We get a lower one for traces
reﬁnement because it is not necessary to worry about how the members of T get
involved in the creation of refusal sets. There are examples (see [68, 65, 64]) whichshow that neither of the thresholds given in the following pair of results can be
improved under the stated assumptions.
Theorem 15.3.3 Suppose Spec and Impl are data-independent processes, Specsatisfies Norm, andImpl

B ≥ W Spec + W Impl + max (L?

, LImpl )Then for all N ≥ B , the following traces refinements are equivalent:Spec(B )T Impl(B )Spec(N )T Impl(N )Theorem 15.3.4 Suppose Spec and Impl are data-independent processes, Specsatisfies Norm, and, LImplB ≥ W Spec + W Impl + max (LSpec , LImpl
 )?
Then for all N ≥ B andeither ofSpec(B )Impl(B )Spec(N )Impl(N )F or

FD , the refinements

15.3

Distributed data and data-independence461

are equivalent.
For example, we might deﬁne a dual process to RemDups which, instead of removing duplicates, only keeps the members of a sequence of values that do duplicate
their immediate predecessors.
OnlyDups = left?x -> OnlyDups’(x)OnlyDups’(x) = left?y -> if x==y then right!y -> OnlyDups’(y)else OnlyDups’(y)Obviously we would expect the process
FilterAll = RemDups [right <-> left] OnlyDups(the machine-readable version of RemDups >> OnlyDups) not to transmit any value
at all. In other words, it should reﬁne
Sink = left?x -> Sink
The various parameters for the reﬁnement check Sink FilterAll are W Sink = 0,
= LSink = 1 and LFilterAll= 0. Thus the threshold value
W FilterAll = 2, LFilterAll?
for both Theorem 15.3.3 and Theorem 15.3.4 is 3. Similarly, the process
Partition = RemDups [|{|left|}|] OnlyDups
can be shown to reﬁne COPY with a threshold of 4 (since W COPY is 1 rather than 0).
In fact, the threshold for this last check can be lowered to 3 by observing
that, in Partition, the two component processes always hold the same member ofT so that, in fact, W Partition is 1 rather than 2.
A bigger application of these results can be found in the next section.
Though this has not been done at the time of writing, there is an obvious potential for the creation of tools that check the various conditions of dataindependence and calculate thresholds. It should also be possible to do two further
things:• Transformation of more arbitrary speciﬁcations into ones satisfying Norm.
• The theory that Lazić developed to prove the theorems in this section also
anticipates the possibility of proving a reﬁnement parameterized by a data
type by carrying out the check symbolically, in the sense that members of thetype are kept as symbols during the check which is otherwise performed not462

Case studies
unlike the method described in Appendix C. This should be automatable
and, in many cases, should be signiﬁcantly more eﬃcient than checks derived
from thresholds calculated using general formulae. (One can argue that inmany cases the ‘real’ threshold of a given check is often lower than the values
predicted by Theorems 15.3.3 and 15.3.4.)

Determinism checks
It is natural to ask whether versions of the results we have seen for reﬁnement checks
also exist for determinism checking, as this is a condition of processes that is notreadily characterized as a reﬁnement check. In other words, can we compute thresholds which are suﬃcient to prove that a given data-independent process Impl(N )is deterministic for all larger N ? We have already seen the practical importance of
this question, particularly in Chapter 12 where determinism was the key to deciding
issues of security.
As with reﬁnement checking, there are a number of results depending on
the complexity of the use of T within Impl. We quote two here, respectively forprocesses that do, and do not, satisfy NoEqT. In the ﬁrst case, perhaps surprisingly
given Theorem 15.3.2, we get a variable threshold rather than the ﬁxed value of 2.
It is, however, equal to 2 in most simple cases since the following constant is usuallythen 1:
Impl
LOccur is the largest number of distinct values of type T that can appear in any
single visible event of Impl.

Theorem 15.3.5 Suppose Impl is data-independent and satisfies NoEqT. Then(a) If Impl(LImpl
Occur + 1) is deterministic, then Impl(N ) is deterministic for all
N ≥ 1.
(b) If Impl(LImpl
Occur + 1) is nondeterministic, then Impl(N ) is nondeterministic
for all N ≥ LImpl
Occur + 1.
This result applies to all the versions of Example 12.4.1 (page 324 et seq), ineach case giving threshold 2 (in the type of messages).
The second result covers the same class of Impl as Theorem 15.3.3, namely
general data-independent processes, and uses the same quantities to compute thresholds. The assumption about renamings should hold in the great majority of cases:a threshold can still be computed when it does not hold, see [64].
Theorem 15.3.6 Suppose Impl is data-independent and contains no renaming
which conceals the value of any member of T input in a communication, then

15.3

Distributed data and data-independence463

the threshold for determinism is given by, LImpl
2 × W Impl + max(LImpl
 )?
in the sense that Impl(N ) is deterministic if and only if Impl(M ) is, for M , N atleast this value.
Both these results apply equally9 to true determinism (decided in N ) and to
the weaker notion of F-determinism discussed on page 221. The latter is relevant
since the recommended way of of deciding the determinism of lazy abstractions
LH (P ) (as discussed in Chapter 12) is via the F-determinism of the potentiallydivergent process (P  Chaos H ) \ H .
H

15.3.3

Cache coherency

Imagine your computer has a large memory which is relatively slow to access compared to the clock-speed of the process that is accessing it. The standard solution
to this is to use a cache: a relatively small piece of fast memory through which theprocessor makes all accesses and which always keeps part of the main memory in
it, in the hope that the addresses which are required will be already there. Modern
computers may have several levels of cacheing, for example:• ‘Real’ (i.e., RAM) memory versus virtual memory (on disk)..
• An oﬀ-processor (often SRAM) cache versus slow (often DRAM) memory.
• Cache which is an integral part of the processor chip versus oﬀ-processor
memory.
Though the technology of these diﬀerent levels may be diﬀerent, the logicalproblems are the same, namely ensuring that, though there are in fact several copies
of some memory locations around, this does not aﬀect the values the processor reads
relative to any writes that may have occurred. Logically, the combination of thecache and the memory which it uses must be equivalent to the memory itself. You
can think of the memory as being enslaved to the cache:
Memory= Cache//m : Memory

Since enslavement is not supported directly in machine-readable CSP (seeSection 4.3) we will re-write this as
9 In fact, at the time of writing, the quoted threshold in Theorem 15.3.6 is known to be tightfor F -determinism but not for true determinism. It is conjectured that, for the latter, the factorof 2 on W Impl can be removed.

464

Case studies

Memory = Cache [m_ra <-> ra, m_rv <-> rv, m_w <-> w] Memory
where the memory has three channels respectively for read requests, read values
and writes, and the cache has the same three channels (for its processor interface)and separate versions (m_ra etc.) for communicating with the memory.
channel ra, m_ra:address
channel rv, m_rv:value
channel w, m_w:address.value
In order to prove this equivalence it will be suﬃcient to prove that the righthand side reﬁnes Memory, since the latter will be deterministic. (There should be
no need to apply the data-independence results above to establish this determinism: Lemma 9.1.4 on page 224 should apply.) We will therefore concentrate on
establishing this reﬁnement.
At any time the cache keeps a list of triples (a,(v,b)) where a is an address10
presently resident in the cache, v is the value stored in that address and b is a bitwhich records whether or not the address has been written to since it was brought
into the cache. b is necessary because it lets us tell, when the address is eventually
removed from the cache, whether or not the stored value has to be written-back to
the main memory. The four parameters of the process Cache are this list, the typesof addresses and storable values in use, and the maximum number of addresses thatcan be stored in the cache at once.
The cache starts oﬀ empty and ﬁlls itself up as the processor asks to read andwrite to addresses. Such reads evidently require a fetch from memory. Any reador write to a location already in the cache is done without any interaction with themain memory. When the cache is full and a miss occurs (i.e., an attempt to accessa location not presently held) it is necessary to ﬂush one thing out of the cache inorder to make room for the new member. There are a number of cache replacement
policies used to do this, such as FIFO (ﬁrst in, ﬁrst out), random, and least recently
used. It is the last of these which is implemented below since each time an address
is used it moves up to the front of the queue.
The following deﬁnition captures all the behaviour of such a cache except
what happens when a ﬂush is required. Note how the boolean ﬂags that control
write-backs are set to true whenever a write to the given location occurs.
Cache(ps,A,V,N) = ra?a:A ->(if elem(a,<a’ | (a’,_) <- ps>) then
10 In practice, data tends to be stored in blocks of more than one address. This would have aminor impact on what follows.

15.3

Distributed data and data-independence

465(rv!val(a,ps) -> Cache(tofront(a,ps),A,V,N))else if #ps < N thenm_ra!a -> m_rv?v:V -> rv!v ->Cache(<(a,(v,false))>^ps,A,V,N)
else FlushAndRead(ps,a,A,V,N))[] w?a:A?v:V ->if elem(a,<a’ | (a’,_) <- ps>) thenCache(update(a,v,ps),A,V,N)
else if #ps < N thenCache(<(a,(v,true))>^ps,A,V,N)
else FlushAndWrite(ps,a,v,A,V,N)
The following three functions used above respectively fetch a value from the cache,move a just-read address to the front of ps and perform a write to an address alreadyin the cache.
val(a,ps) = head(<v | (a’,(v,_)) <- ps, a’==a>)tofront(a,ps) = <(a’,x) | (a’,x) <- ps, a’==a>^<(a’,x) | (a’,x) <- ps, a’!=a>update(a,v,ps) = <(a,(v,true))>^<(a’,x) | (a’,x) <- ps, a’!=a>
The following two processes ﬂush the last member of the queue (i.e., the least
recently used member) out, performing a write-back to memory if necessary. They
then ﬁll up the vacant space with a new location either read-from or written-to.
FlushAndRead(ps^<(a’,(v’,wr_bk))>,a,A,V,N) =if wr_bk then
m_w!a’!v’ -> m_ra!a -> m_rv?v:V -> rv!v ->Cache(<(a,(v,false))>^ps,A,V,N)
else
m_ra!a -> m_rv?v:V -> rv!v ->Cache(<(a,(v,false))>^ps,A,V,N)
FlushAndWrite(ps^<(a’,(v’,wr_bk))>,a,v,A,V,N) =if wr_bk then
m_w!a’!v’ -> Cache(<(a,(v,true))>^ps,A,V,N)
else
Cache(<(a,(v,true))>^ps,A,V,N)

466

Case studies

There are various ways in which one can provide a model of the memory thatthe cache is intended to interact with. Perhaps the obvious one is to model it as asimple shell around a function from addresses to values.
Memory(A,V,f) = ra?a:A -> rv!f(a) -> Memory(A,V,f)[] w?a:A?v:V -> let f’(a’) = if a==a’ then v else f(a’)
within Memory(A,V,f’)This does not work with FDR at the time of writing since the tool, for very goodreasons, does not detect the equalities between the functions that arise as it explores
the states of this process. The above deﬁnition can easily be modiﬁed so that it
does work by replacing the function with, for example, a set of address/value pairs.
The check that the Memory/Cache combination reﬁnes the Memory alone hasinteresting data-independence properties in the types V of storable values and A of
addresses. The processes concerned are data-independent in both types, and satisfy
NoEqT in V. The process Memory satisﬁes Norm with respect to both. They donot, however, satisfy NoEqT with respect to A since the behaviour of Cache depends
quite explicitly on comparisons between addresses, and Memory needs, whatever thedetails of its deﬁnition, to be able to compare addresses to know which internal
value to read or modify.
Theorem 15.3.2 tells us that, whatever A is, it is suﬃcient to prove reﬁnementwith V of size 2. If we can ﬁnd a threshold for A with such V, we can then guaranteethat reﬁnement holds for all larger instances of both types.
Unfortunately there is no useful threshold deducible from Theorems 15.3.3
and 15.3.4 in the type A for the reﬁnement check involving the cache coupled withthe whole memory, since the process Memory has every member of A in its state:
there is no bound on either W Impl or W Spec .
This can be remedied in an interesting way: we can concentrate on a single
but arbitrary address. Instead of proving that all interactions with the cache are as
expected for a well-behaved memory, we show that for any particular location eachread from the cache gives the right answer purely on the assumption that the reads
that the cache itself makes for the chosen location are well-behaved. The following
process behaves like a reliable memory for whatever address is chosen (together
with initial value) in the ﬁrst communication. On the other locations it selects thevalue of a read nondeterministically rather than by reference to previous writes:
this means that it only has to remember a single address rather than them all.
OneLoc(A,V) = loc?a:A?v:V -> OneLoc’(a,v,A,V)
OneLoc’(a,v,A,V) = w?a’:A?v’:V -> (if a==a’ then OneLoc’(a,v’,A,V)

15.3

Distributed data and data-independence

467
else OneLoc’(a,v,A,V))[] ra?a’:A ->(if a==a’ then rv!v -> OneLoc’(a,v,A,V)
else |~| v’:V @ rv!v’ -> OneLoc’(a,v,A,V))
We can then check to see if this process is reﬁned by a combination of the cacheand itself, which takes the form below to prevent any communications between theenvironment and the cache before the special location is chosen:
Test(A,V,N) = loc?a:A?v:V ->(Cache(<>,A,V,N)[m_ra <-> ra, m_rv <-> rv, m_w <-> w]
OneLoc’(a,v,A,V))
In a sense, the fact that OneLoc(A,V) is reﬁned by Test(A,V,N) proves astronger correctness condition than the more obvious one involving Memory, since
it shows that the reads made from the cache of address a only depend on the reads
the cache makes of the memory at a being correct.
Theorems 15.3.3 and 15.3.4 can be applied to this check since all the quantities they use are ﬁnite with respect to the type A: W Test = 2 + N , W OneLoc =LOneLoc = LTest= 1 and LTest= 0. Thus, for a cache of size N it is suﬃcient to?
prove the reﬁnement for N + 4 addresses (and 2 storable values).
It should not come as a surprise that the required size of A increases with
N , since the control-ﬂow of the cache depends crucially on whether it is full or not,and obviously it could not get full if it had more slots than there were addresses!
The size of the cache is, of course, another parameter that we would like to dispensewith within the scope of the PVP. It is not, however, one that can be dealt with
via data-independence. At the time of writing there is no technique of comparable
generality to handle variation in N . We have to resort to ad hoc (i.e., application
speciﬁc) arguments. It can be shown without too much diﬃculty that the possible
behaviours relating to any given address are independent of cache size since any
behaviour of a small cache corresponds to a behaviour of a large one with moreaccesses to other addresses between accesses to the chosen one.
Three diﬀerent arguments have thus shown that our cache works for any11
V, A and N provided it does for them respectively being of sizes 2, 5 and equalling 1.
Exercise 15.3.1
Recall the buﬀer deﬁned on page 121 which worked by majority
voting over groups of three bits, and was tolerant of no more than one corrupted bit in
11 In fact, the data-independence theorems do not always allow us to conclude reﬁnement below
the threshold from reﬁnement at it, and so it is actually necessary to deal separately with smaller
values of A.

468

Case studies

any three. Deﬁne a version of this in which bits are replaced by an arbitrary type. We thenhave to deal, when programming the receiver, with a group of three all being diﬀerent:
you should make it deadlock in that case.
Your complete program, including a revised version of the corrupting channel,
should be data-independent and a buﬀer reﬁning BUFF 3 . What threshold for the dataindependent type do the results predict for this (failures/divergences) reﬁnement check?

In the previous section we brieﬂy discussed cache replacement policies. One such policy is FIFO, where the value in the cache to be replaced is always theone that has been there longest (irrespective of how recently it has been used). It canhappen with this policy that adding to the size of the cache increases the number of cache
misses in a given series of reads and writes.

Exercise 15.3.2

Build a CSP model that allows you to ﬁnd an example of this behaviour with
FDR: it will probably consist of two diﬀerent-sized caches to allow you to compare how
they behave on each possible run.
Although it is about caches, this fairly diﬃcult question has much more in common
with the puzzles of Section 15.1 than with the cache model seen in this section. In particular,
the values stored in the memory and caches are irrelevant. All that matters is how theaddresses in the two FIFO queues of the large and small caches correspond.

Exercise 15.3.3 In books such as [25] you will ﬁnd many intriguing distributed algorithms for a wide variety of tasks, generally expressed at a lower level of formality thanthose we have seen in this section. It is a fascinating practical exercise to take one of these,
re-work it in CSP and analyze versions with FDR, as we did for the database and cachealgorithms. Clearly these vary signiﬁcantly in diﬃculty: suggestions taken from [25] are
Two-phase commit and concurrency control techniques. Many will require timing to bebuilt into the model in the style of Chapter 14.

15.4

Analyzing crypto-protocols

One sometimes needs to achieve secure interactions between individuals over a
medium which is untrustworthy and subject to tampering by potential intruders.
These interactions, and the consequent need for security, vary widely from application to application, and several possibilities are given below.
1. The most obvious is to make communications between parties secret. No
information which Alice sends conﬁdentially to Bob should become known
to an intruder.
2. Parties should be able to authenticate others: if Bob thinks he has beentalking to Alice, then he should have been (and Alice should think she has
been talking to Bob).

15.4

Analyzing crypto-protocols

469

3. We might want to authenticate that a message is precisely the one issued by
Alice, even when we are not concerned about conﬁdentiality.
4. In contexts where ﬁnancial transactions are being implemented, we clearlyneed to protect their integrity from interference and fraud.
To do these things in a context where an intruder can overhear messages,
stop messages from reaching their intended destinations, and even potentially fakemessages, for example, to Bob purporting to be from Alice, you need to make useof encryption and related methods which limit:(a) an intruder’s ability to understand the messages he or she hears, and equallyimportantly,(b) the potential for the intruder to create fake messages which can convince
someone else that they are genuine.
CSP is not an appropriate vehicle either for describing encryption algorithms
or for devising methods of deciphering coded messages. That involves a lot of
sophisticated mathematics in number theory, algebra, etc. However, it is often thecase that a use of encryption fails not because of vulnerability of the cipher in use,
but because of the way it is used. Frequently it is possible to defeat protocols using
and supporting encryption even under the assumption that the encryption method
used is unbreakable.
A cryptographic protocol is a series of carefully deﬁned messages, often encrypted, between two or more participants designed so that when it is complete,they can be sure that a speciﬁed goal has been achieved, even in the presence of an
intruder who can perform the malicious acts described above. The only restriction
we place on the intruder is that it is unable to decrypt coded messages without theappropriate key or to generate faked messages when it does not possess the necessary information. Many cryptographic protocols are concerned with establishing aconnection between two nodes, often involving the trading or generation of a key foruse during the resultant session. CSP and FDR have proved to be excellent tools formodelling and analyzing cryptographic protocols, using symbolic representations ofencryption.
The following is an authentication protocol known as the Needham–Schroeder
Public-Key protocol. It is intended to authenticate a pair of nodes to each other (sothat each is aware that the other is willing to talk to it), and to ensure that eachpossesses the other’s public key.12 We assume that there are potentially many nodes
that might want to talk to each other, and that they do not necessarily remember
12 Public-key encryption is based on the idea that it is possible to ﬁnd algorithms where (i)the key required to decrypt a message is diﬀerent from the one used for encryption, and (ii) it is470

Case studies

all other’s public keys, but do remember that of a server S from which they canrequest other users’ keys. (Servers are a common, though by no means universal,
feature of cryptographic protocols, and play a wide range of roles in them.) The
protocol proceeds as follows when node A wants to establish communication withB:
1. A → S : B
2. S → A : {pk (B ), B }sk (S )3. A → B : {NA , A}pk (B)
4. B → S : A
5. S → B : {pk (A), A}sk (S )6. B → A : {NA , NB }pk (A)7. A → B : {NB }pk (B)Here {X }Y means the public-key encryption of the message X under the key Y .
A commentary on this protocol follows:
1. A asks the server for B ’s public key.
2. S sends it, signed. There is no need for this information to be encrypted, but
it has to be signed (as a combination with B ’s name) to prevent, for example,
a malicious node substituting its own public key so it can impersonate B tocomputationally infeasible to construct one of this pair of keys from the other. Any node may
thus publish one of a pair of keys like this as its public key, retaining the other for itself as its
secret key. Then anyone holding the public key can send it a private message that only our node
can understand.
A more subtle use is for the node to send a message encrypted with its secret key: anyone candecrypt this on the assumption that (as is true with some algorithms such as RSA), the decryption
key for the secret key is the public key. But when they do they will realize that the only person
who could have sent it is the node holding the secret key. This is an example of a cryptographic
signature. In fact it is generally considered good practice to use separate pairs of keys for signingmessages and conﬁdentiality, but the same ideas still apply.
There are several problems in the use of public-key encryption in transmitting information
between nodes. An important one on practical grounds is that the algorithms used tend to becomputationally signiﬁcantly more complex than symmetric algorithms (ones where the encryption
and decryption keys are the same). A second, and more directly security-related problem, is that
one has to guard against the situation where it is possible for an intruder to guess that a message
is going to be a member of a small set such as {yes, no}, since all the intruder has to do is toencrypt each member of the set using the public key and compare them against the one actuallysent. Therefore public-key encryption is often used only during the establishment of a session, andis replaced by a symmetric algorithm once it is possible to give the participants a key known only
to them (the session key).

15.4

Analyzing crypto-protocols

471

A. The body of this message can be regarded as a certiﬁcate that B ’s public
key is pk (B ).
3. A can then send a message to B , which has the purpose of requesting a session
set-up. NA represents a nonce, which is a piece of random information which
has just been made up by A so that when it gets a response containing NA
it knows it must have been generated for this message 3.
4. B then requests A’s public key from the server,
5. and is sent it exactly as with message 2.
6. B can then reply to message 3, acknowledging it with the nonce NA and a
new nonce of its own, which
7. A then sends back to B so that B knows that the message 3 it has been acting
on was genuine (bearing in mind that, from B ’s point of view until it receives
message 7, anyone could have made message 3 up, and the conﬁrmation to
B that it is real is when A understands and acts on message 6).
Apparently, when the run is complete, both A and B are reassured that the otherexists and is willing to talk to it, and the nonces NA and NB that have been createdare secrets known only to these two.
Note that messages 1 and 4 of this protocol are completely unsecured, merely
being indications to the server that a particular sort of information would be appreciated. There is nothing to stop an intruder preventing one or both of these getting
through and then replaying old messages 2 and 5 it may have recorded much earlier,but the signature mechanism means that they would be identical to the ones theserver actually would have sent, and no fundamental security problem is created.
(However, if a node’s public key ever changes, this would create a problem and theprotocol would have to be improved.)
In fact, the mechanism for distributing public keys in messages 1, 2, 4 and
5 is largely independent of the authentication mechanism contained in messages 3,
6 and 7, which still makes sense as a protocol if we assume that nodes do not needto communicate with a server to discover each others’ public keys. For simplicity we will concentrate henceforth on the three-message version, re-numbering themessages accordingly.
To test a protocol like this one with CSP we have to build models of wellbehaved nodes and an intruder and see how the latter can interfere with the former.
There is usually no need to create more than two well-behaved nodes (plus a wellbehaved server, if one is used in the protocol, which it is not in the abbreviatedNeedham–Schroeder protocol). Rather, we give the intruder the ability to behave
like other nodes and to interact properly as well as improperly with the good ones.

472

Case studies

The basic facts we then aim to prove are that the security of a session between thewell-behaved nodes is intact whatever else happens, and that neither of them canbe fooled into thinking it has a session with the other when it does not. Both ofthese things should hold even though one or both nodes may previously have hadsessions with other, possibly corrupt, users.
An attack on a protocol is a series of messages that the intruder can bringabout in which each trustworthy node carries out its role properly but which brings
the network into an insecure state. Essentially our job in analyzing a protocol is tocapture this concept precisely and ﬁnd out if attacks are possible.
15.4.1

Data types for symbolic encryption

What follows is a coding of this network. As we have already said, the encryptions
and similar will be modelled as symbolic objects: we create an appropriate data
type to contain them which consists of various constants we will need, public-key(PK) and symmetric-key encryption constructions and a sequencing construct.
datatype fact = Sq. Seq(fact) |PK. (fact , fact) |Encrypt. (fact, fact) |Alice | Bob | Cameron |Na | Nb | Nc |pkA | pkB | pkC |skA | skB | skC |AtoB | BtoA | Cmessage
The type fact contains various collections of constants, which can be collected together into sets for later use. The three identities used are those of two
nodes we will later treat as reliable, plus one (Cameron) for the intruder to assume
when it acts as another party.13
agents = {Alice, Bob, Cameron}publickey = {pkA, pkB, pkC}
secretkey = {skA, skB, skC}
nonces = {Na, Nb, Nc}
13 With the great majority of protocols it would not improve the intruder’s prospects to haveany more identities (Donald, Eve, etc.) to play with. This is because any attack which involved
more than one of these identities acting would also work with them all being Cameron.

15.4

Analyzing crypto-protocols

473

sessmess = {AtoB, BtoA, Cmessage}
The roles of these sets will become apparent later.
We can tie the keys to these identities as follows, thereby deﬁning functions
for determining the public and secret keys of each node and for mapping a key to
its inverse or dual.
keybindings = {(Alice,pkA,skA), (Bob,pkB,skB),(Cameron, pkC, skC)}
pk(a) = pick({k | (a’,k,_) <- keybindings, a==a’})sk(a) = pick({k | (a’,_,k) <- keybindings, a==a’})dual(k) = pick(Union({{k’’ | (_,k’,k’’) <- keybindings, k==k’},{k’ | (_,k’,k’’) <- keybindings, k==k’’}}))
Here pick is a function that maps a singleton set {x} to its member x (see also page528). The following deﬁnitions allow us to make the symbolic encryption operations
into functions.
pke(k,m) = PK . (k , m)encrypt(k,m) = Encrypt . (k , m)
15.4.2Deﬁning reliable nodes

We are now in a position to deﬁne processes representing the behaviour of a reliablenode implementing the protocol. The following deﬁnes the node with identity idwhich has the supply of nonces ns to use in sessions: we have to keep these lists ﬁnite
and fairly small if the size of checks generated on FDR is to be reasonable. Evidently
the deﬁnition below, which gives up when the list is empty, is not adequate if we
expect the resulting system to satisfy liveness14 but in this treatment we will only
worry about safety (traces) properties and so the only real concern is whether thesize of system used is suﬃcient to reveal any pathologies in the protocol. A nodecan either act as an initiator of the protocol (Send) or as the responder (Resp).
14 The coding that follows is, for quite separate reasons, insuﬃcient to achieve liveness. In orderto stop the intruder deadlocking well-behaved nodes in a protocol like this, very careful use of
constructs like time-outs is required, which produces a system too complex to include here. In
any case, the presentations of crypto-protocols in the literature generally ignore issues of livenessand so, to analyze them in their own terms, it is probably better to restrict the implementations
to simple ones that allow only safety properties to be addressed.

474

Case studies

User(id,ns) = if ns == <> then STOP elseSend(id,ns) [] Resp(id,ns)
When acting as an initiator, the node chooses a target to start up a session
with, and then communicates the three messages of the protocol in turn with it.
Note that any nonce is accepted as NB in the second message. When the threemessages are complete, it enters a state (which is discussed below) in which it ishappily in a session with its partner.
Send(id,ns) = |~| b:diff(agents,{id}) @comm.id.b.pke(pk(b),Sq.<head(ns),id>) ->([] nb:nonces @comm.b.id.pke(pk(id),Sq.<head(ns),nb>) ->comm.id.b.pke(pk(b),nb) ->Session(id,b,nb,tail(ns)))
The responder process performs the same three messages, only from the opposite
perspective regarding who chooses nonces, etc. Note that each side, by accepting
only those events in an appropriate set, performs a check on the message it getsfrom its partner containing its own nonce. Because we are only studying the threemessage version of the protocol, we assume each node has a (true) knowledge of the
public key it must use to communicate with the other.
Resp(id,ns) = [] a:diff(agents,{id}) @[] na:nonces @comm.a.id.pke(pk(id),Sq.<na,a>) ->comm.id.a.pke(pk(a),Sq.<na,head(ns)>) ->comm.a.id.pke(pk(id),head(ns)) ->Session(id,a,head(ns),tail(ns))
There is nothing in the protocol description which says what the nodes doonce their sessions are set up. They may very well send each other messages either
under their public keys or under a symmetric session key constructed out of thesecrets established in the protocol run. Clearly the design of the code that does thishas to be as careful as that of the protocol itself, since for example:• there is no way of knowing who has sent a public-key encrypted message
unless it is either signed or contains a secret known only to the sender andrecipient;• a symmetrically encrypted message can potentially be replayed at the node
who sent it, who will (unless is contains something to securely authenticate
its origin) believe it has come from its partner; and15.4

Analyzing crypto-protocols

475• in either case the intruder can trap, duplicate or reorder messages.
The Session state below uses the second nonce as a key for symmetric encryption, but you should bear in mind that our purpose in designing this process is
not really to pass messages, but to test the correct behaviour of the main protocol.
Namely, we wish to show that when a node behaving like either the initiator or responder has completed the protocol and entered the Session state then its partner
has also engaged in the protocol in the opposite mode and the secrets of the run(namely the two nonces) really are secret.
When connected to another node, a process in state Session uses the (arbitrarily chosen) second nonce as the key and sends appropriately chosen messages
to its partner. Alice and Bob send messages that are symbols introduced to represent secrets, when they believe they are connected to each other (namely AtoB and
BtoA) but do not use these when connected to Cameron.15 We add a clause (onemade possible by the special choice of messages) which checks to see whether, if
one trustworthy node (Alice, say) receives a message which is apparently part of asession with the other one (Bob), it really is. If, in this case, Alice receives anythingother than BtoA then something must have gone wrong.
Session(id,a,n,ns) =comm.id.a.encrypt(n,mess(id,a)) ->Session(id,a,n,ns)[] ([] m:sessmess @comm.a.id.encrypt(n,Sq.<id,m>) ->(if ok(id,a,Sq.<id,m>) then Session(id,a,n,ns)
else error -> STOP))[] close.id -> User(id,ns)ok(a,b,m) = (mess(b,a)==m) or (b==Cameron)
Equally, we would expect the intruder to be unable to learn the secrets AtoB and
BtoA, since these are never revealed to Cameron deliberately.
We are going to plumb the system together as shown in Figure 15.5. The
spy or intruder can hear whatever passes between Alice and Bob, can interact withthem as Cameron, and can intercept and fake messages.
• An intercepted message must look to its sender no diﬀerent to one that got
through successfully, but obviously it should not be received by its intended
recipient.
15 There is no sense in which Cmessage, AtoB and BtoA are real messages that Alice, Bob, andCameron might wish to send to each other. Rather, they are tangible ways of demonstrating andtesting their beliefs about who they are connected to.

476

Case studies

A

B

Spy
Connections with "imaginary" nodes
Spy overhearing normal communications
comm
take

fake

Channel where communications can beintercepted or faked by the spy

Figure 15.5 Network to test a simple crypto-protocol.
• A faked message should be indistinguishable at its destination from an identical message that was sent from its supposed sender (who, of course, should
never have seen it).
We have programmed our nodes so all communications use a channel called comm(labelled with sender and address ﬁelds). An elegant way of implementing interception (abbreviated take) and faking is to introduce two ‘shadow’ channels with thesame type, and then put a shell around each node that doubles each communication
by renaming:channel comm,take,fake:agents.agents.messages
RenUser(id,ns)= User(id,ns)[[comm.id <- comm.id,
comm.id <- take.id]][[comm.a.id <- comm.a.id,
comm.a.id <- fake.a.id |15.4

Analyzing crypto-protocols

477
a <- agents]]

Each output comm can now either happen (so far as the outside world is concerned)
either as itself or as the corresponding take, and similarly each input comm can now
happen as the result of an external comm or fake. It is important to realize that theUser process inside has no way of knowing which way any of its communications
appears to the outside. The following parallel connection thus synchronizes Aliceand Bob on their mutual comm channels, but leaves the corresponding take and fakechannels to be manipulated by the spy. The resulting system actually gives the spy
two routes to and from each node when it acts as the third identity Cameron:the divisions of the channels are unnecessary there. The ﬁnal line below simply
removes this ambiguity: all communications with Cameron are (from the external
perspective) along take and fake rather than comm.
Network = (RenUser(Alice,<Na>)[|{|comm.Alice.Bob,comm.Bob.Alice|}|]RenUser(Bob,<Nb>))[|union({|comm.Cameron|},{|comm.a.Cameron | a <- agents|})|] STOP
15.4.3Creating a set of deductions

All that remains is to build the spy process. At ﬁrst thought, you might expect
this to be a process endowed with great ingenuity and cunning to allow it to breakprotocols. The great disadvantage of following this approach is that if, eventually, it
proves that your spy cannot break the protocol, all you have established is that theparticular tactics employed by the spy you happen to have created do not succeed.
There is no real evidence about the possible eﬀects of other tactics, some ofwhich you might not even have imagined. As we saw in Section 15.1, the eﬀect ofadding a tactic is to narrow a search making the ﬁnding of a solution (in the case ofa protocol, an attack) less likely. It is far better, unless prevented by a combinatorial
explosion as we were in Section 15.1, to create a deﬁnition which models all possible
tactics: we simply build a process that can perform any trace that a spy reasonably
ever could, and incorporate that into our network. If, after doing this, the result isa system where the protocol remains intact in the sense that it satisﬁes appropriate
safety speciﬁcations, then you can be sure that no spy, however cunning, could havebroken it.
The most general spy can always overhear (comm) and intercept (take) any
message available to it. The limitation comes in what it can fake, since we aremaking basic assumptions about the cryptographic devices used, such as the undecipherability of encryptions without appropriate keys and the non-guessability

478

Case studies

of nonces. The entire coding that follows is devoted to the problem of creating aprocess whose message generation ability is determined by what it initially knew,
what it has overheard or intercepted since, and a set of rules governing deducibilityof messages through encryption.
The rules of deducibility have to be programmed into our spy. We can workout what deductions are relevant to a given ﬁnite subset X of the data type factusing the following clauses. In them, a deduction is a pair (Y , a) where Y is a
ﬁnite set of facts and a is a fact which anyone in possession of the whole of Y canconstruct. Below, we set up three types of deduction, each of which operates in two
directions, one ‘constructing’ and the other ‘destructing’. The ﬁrst type says that
if one knows a sequence one can extract any of its members, and if one knows all
its members one can build the sequence:
deductions1(X) = {({Sq . m}, nth(j,m)) ,({nth(i,m) | i <-{0..#m-1}}, Sq . m) |Sq.m <- X, j<-{0..#m-1}}
The other two types of deduction are based on encryption, one on symmetrickey encryption and the other on public-key encryption. In each case they say thatanyone in possession of a message and the appropriate key can build an encryption,and that someone holding an encryption and the key necessary to decrypt it (thedetail of which diﬀers between the two cases) can know the contents. Finally, we
can put together all three sorts of deductions into a single set.
deductions2(X) = {({m, k}, encrypt(k,m) ) ,({encrypt(k,m), k}, m) |Encrypt.(k,m) <- X}
deductions3(X) = {({m, k}, pke(k,m) ) ,({pke(k,m), dual(k)}, m) |PK.(k,m) <- X}
deductions(X) = Union({deductions1(X),deductions2(X),deductions3(X)})
We omit here the deﬁnition of the ﬁnite set messages: it is the subset of fact
consisting of all message bodies which could form part of any protocol run or session
between two of our three nodes. It is ﬁnite because the sets of agents, nonces, etc.
are ﬁnite. messages obviously forms the basis of what the spy might ever learn or
want to construct for faking. However, since the spy might build or learn messages
in parts it helps to have a way of taking a subset X of fact, and creating from it15.4

Analyzing crypto-protocols

479

a larger set consisting of all objects which are of direct relevance to members of X.
Applied to messages, this gives the set of facts which it might be sensible for the
spy to construct en route to building a message. The ﬁnal clause of the following,
which is present to deal with all the constants (such as Alice and pkC) from fact,
exploits the convention that where a function is ‘over-deﬁned’ on a particular value,
the textually ﬁrst deﬁnition applies.
explode(Sq.xs) = union({Sq.xs},
Union({explode(x) | x <- set(xs)}))explode(PK.(k,m)) = union({PK.(k,m),k,dual(k)},explode(m))
explode(Encrypt.(k,m)) = Union({{Encrypt.(k,m)},explode(k),explode(m)})
explode(x) = {x}AllFacts = Union({explode(m) | m <- messages})
AllDeductions = deductions(AllFacts)
AllFacts is a ﬁnite set, unlike the full data type fact, which is inﬁnite.
The spy will have an initial basic knowledge: public facts such as agent
names and public keys, and the private facts necessary to enable it to act as theagent Cameron.
Known’ = Union({agents, publickey,{sk(Cameron)}, {Nc,Cmessage}})Our spy can initially construct a number of legitimate messages (such as initialmessages asking for sessions with either Alice or Bob, acting as Cameron) fromthis set. The full initial knowledge can be found by closing up Known’ under the
deductions.
Close(S) = let
S’ = {f | (X,f) <- AllDeductions, diff(X,S)=={}}
withinif diff(S’,S)=={} then S else Close(union(S,S’))
Known = Close(Known’)
There remain many messages that the spy does not initially know, so we need todescribe how its state of knowledge evolves as it overhears more things. An obvious
coding of the spy which says exactly what we want is Spy1(Known) where

480

Case studies

Spy1(X) = learn?x -> Spy1(Close(union(X,{x})))[] say?x:X -> Spy1(X)In other words, it can always create any message it knows, and each time it learns
a new one it adds in all the resultant deductions. Here, learn and say are twochannels of type messages which would subsequently be plumbed by renaming sothat they respectively took the roles of overhearing and intercepting, and of faking(see below).
This would be a perfect deﬁnition, as well as being delightfully simple, if itwere not for one practical problem. This is that there are, for a typical protocol
model, between 50 and 1000 messages and perhaps 50% more other facts of relevanceto the spy (in the example presented here, there are respectively 90 and 42). The
state space of the spy when deﬁned as above becomes impossibly large, given FDR’s
desire to pre-compute the state spaces of all ‘low-level’ processes such as this thatit encounters. In fact Spy1’s state space, when measured like this, is generally
exponential in the number of interesting facts. Most of these states are neveractually reached when the spy is eventually explored as part of the complete system,
but this only adds to the frustration of having computed them in the ﬁrst place.
15.4.4The lazy spy

We need to ﬁnd an equivalent process deﬁnition that avoids this impossible amountof pre-computation. We will do this by creating a parallel network which has one
process for every fact that the spy (i) does not initially know and (ii) could conceivably learn during a run. These are the facts contained in the set LearnableFactsdeﬁned below, since the spy can never know anything outside what can be deduced
from its initial knowledge and all the messages it could ever hear. (In the present
example this set has 96 members.)
PossibleBasicKnowledge = union(Known,messages)
KnowableFacts = Close(PossibleBasicKnowledge)
LearnableFacts = diff(KnowableFacts,Known)
We can discard all those deductions whose conclusion is something the spy
knows already, or where either the conclusion or one of the assumptions is neverknowable by him. For diﬀerent reasons we know that these will never be relevantto the spy in any run.
Deductions = {(X,f) | (X,f) <- AllDeductions,15.4

Analyzing crypto-protocols

481

member(f,LearnableFacts),
not member(f,X),
diff(X,KnowableFacts)=={}}For each fact in LearnableFacts we can then create a component of our spy: it
only has two states, respectively representing ignorance and knowledge of the fact.
It can always learn its fact, but can say it only when the fact is known. Since
these actions are only relevant when the fact is a complete message these actions
are limited to this case. Inferences are carried out by a channel infer of type
Deductions: each one can only occur when all its assumptions are known (either
because they are in the set Known or because the relevant process is in state knows)
and the conclusion is not known. Thus each infer.(X,f) action may have many
diﬀerent components synchronize on it.
ignorantof(f) = member(f,messages) & learn.f -> knows(f)[] infer?t:{(X,f’) | (X,f’) <- Deductions, f’==f}-> knows(f)knows(f) = member(f,messages) & say.f -> knows(f)[] member(f,messages) & learn.f -> knows(f)[] infer?t:{(X,f’) | (X,f’) <- Deductions, member(f,X)}-> knows(f)[] member(f,Banned) & spyknows.f -> knows(f)The last line above assumes we have deﬁned a set Banned of events which the spy is
not allowed to know. For our example we deﬁne this to be {AtoB, BtoA} since weknow that these two facts will never properly be sent to Cameron. The respectivealphabets AlphaL(f) of these processes are the sets of events they can perform.
The spy is then constructed by putting all the component processes in paralleland hiding the infer events, since these are internal actions of this parallel inference
system. It is important to note that, by deﬁnition of Deductions, any assumptionof an infer.(X,f) which is not in LearnableFacts is initially Known to the spy.
Thus, whenever this event occurs in the following process, all the assumptions are
known.
Spy = (|| f:LearnableFacts @ [AlphaL(f)] ignorantof(f))\{|infer|}||| SayKnown
SayKnown = say?f:inter(Known,messages) -> SayKnown[] learn?f:inter(Known,messages) -> SayKnown482

Case studies

Note that Spy incorporates a process which can always communicate any message inKnown, since evidently the spy can generate these messages and we did not include
them in the set LearnableFacts.
This version of the spy process is equivalent to Spy1(Known), but does not
suﬀer the same problems. As it runs the infer.(X,f) actions which occur (hidden)
within it have the same eﬀect as the Close function used in Spy1. Whenever it learns
a new fact it can carry out just those inferences which extend its present state ofknowledge (deﬁned to be Known plus the set of facts f whose component process is instate knows(f)) appropriately. We have christened this model the lazy spy because
it avoids the eager pre-computation of inferences, most of which are unnecessary,present in Spy1.
To use the spy in the network proper, we rename it so that the messages itlearns come from communications it has overheard or intercepted, and what it says
becomes a fake. Obviously the messages it overhears and fakes in actual runs havesender and address ﬁelds, but since these are irrelevant to the issue of knowing what
the spy can generate16 we left these oﬀ when building the spy processes for reasonsof eﬃciency.
RenSpy = Spy[[learn.f <- comm.a.a’.f,learn.f <- take.a.a’.f |a <- agents, a’<- agents]][[say.f <- fake.a.a’.f |a <- agents, a’<- agents]]
System = Network [|{|comm,take,fake|}|] RenSpy
We can then test for attacks on the protocol by checking for occurrence of theevents error and spyknows.f, since none of them should be possible. Essentially,
the ﬁrst represents a failure of authentication and the second a failure of conﬁdentiality. In the particular case we are looking at, either of these checks reveals astriking attack (discovered by Gavin Lowe17 [71] many years after the protocol was
published and despite the fact that it had been analyzed with various logics without revealing problems). The bottom line of this attack is that if one trustworthy
node (Alice, say) chooses to communicate with a node (Cameron) who proves to be
16 The address ﬁelds never contain information unknown to the spy, and whenever the spy cangenerate a message it can send it to whomever, and ‘from’ whomever, it pleases.
17 Lowe was the ﬁrst person to apply the combination of FDR and CSP to crypto-protocols. The
CSP model Lowe developed for the Needham–Schroeder Public-Key protocol in [71] diﬀers fromthe one presented here mainly in its relatively ad hoc spy model. The lazy spy model presented
here, with its power and easy adaptation to new protocols, has since become the standard method
and has been integrated into Lowe’s protocol compiler Casper: see below.

15.4

Analyzing crypto-protocols

483

corrupted, then the intruder can impersonate Alice in opening a session (learning
all the secrets therein) with any other trustworthy node (Bob). Thus Bob thinks
he has a session with Alice, even when she may never have heard of him. We might
doubt Alice’s judgement in talking to Cameron, but she always behaves honestly.
It is clearly unacceptable for the security of sessions between a pair of honest nodes
to depend on the set of nodes with whom they have previously interacted.
The attack proceeds as follows: it contains two interleaved runs of the protocol, labelled α and β. Where you see C (A) below it means a situation where Cintercepts a message for A or fakes one apparently from A, as appropriate. Eachmessage is shown in two ways, with the right-hand one being the literal output from
FDR.18
α.1 A → C : {NA , A}pk (C )take.Alice.Cameron.(pkC.Sq.<Na,Alice>)

β.1 C (A) → B : {NA , A}pk (B)fake.Alice.Bob.(pkB.Sq.<Na,Alice>)

β.2 B → C (A) : {NA , NB }pk (A)take.Bob.Alice.(pkA.Sq.<Na,Nb>)

α.2 C → A : {NA , NB }pk (A)fake.Cameron.Alice.(pkA.Sq.<Na,Nb>)

α.3 A → C : {NB }pk (C )take.Alice.Cameron.(pkC.Nb)

β.3 C (A) → B : {NB }pk (B)fake.Alice.Bob.(pkB.Nb)

The spy uses node A in run α to decode the message it receives (but cannot at thatstage understand) in message β.2, since because of the way the protocol works A
assumes the nonce NB was generated by C in run α and so sends it back to C inmessage α.3. Upon receipt of message β.3 node B has completed a run apparently
with A, as claimed.
The methods described in this section have been employed to analyze a wide
variety of protocols, dealing with a range of protocol features and speciﬁcation
techniques we have not had time to cover here. Many of the analyses have involved
timing analysis along the lines set out in Chapter 14. Frequently they have discovered attacks which were in no way imagined at the time of creating the CSP
model.
In the three years since the ﬁrst edition of this book appeared the techniques
for analysing crypto protocols have developed enormously. There have been threeespecially signiﬁcant developments. The ﬁrst is the ability to handle the far more
complex protocols that are common in growing applications like electronic cash
and electronic commerce: the basic idea here is that the security of such protocols
usually depends only on a few of their many details, and Lowe has developed a set
18 The trace continues take.Bob.Alice.Encrypt.(Nb,Sq.<Alice,BtoA>) which enables the event
spyknows.BtoA.

484

Case studies

of safe, simplifying transformations which allow one to reduce them to a size FDR
can handle without losing any attacks. Namely, if there is an attack on the original
protocol, there will be one on the simpliﬁed one.
The second and third both address the problem of proving protocols secure:the methods described so far allow us to discover if a very small implementationof a protocol (with very few users and runs) can be attacked. There is no obvious
way of inferring, from an FDR run that ﬁnds no attack on a small system, that
there is no attack on larger ones: at the time of the ﬁrst edition it could reasonably
have been said that our methods were excellent at ﬁnding attacks, but were foundwanting when it came to proof. One approach [74] to this problem has been throughcareful analysis of how a potential attack might proceed, and Lowe produced a set of
essentially syntactic conditions (such as that both participants identities are boundup in each encrypted component of the protocol) which, if true, enable one to inferthat an implementation of any size of a protocol will satisfy certain natural secrecy(as opposed to authentication) properties if a minimal one does (consisting of just
Alice and Bob, able to run the protocol once each, plus a server if necessary andan intruder like the one set out above except that it does not need an identity like
Cameron to play with).
The other approach to proof is via data-independence [113, 117, 13], as described in the previous section of this chapter. It seems a reasonable goal that wemight use data-independence to derive thresholds for the sizes of types like node
identities, nonces and keys that are used in protocol models. This is so because theway our programs treat these objects is data-independently (they are just passed
around and compared for equality, possibly bound up in the complicated tupling
constructs that our symbolic models of protocol messages really are). Indeed, it
was recognition of this possibility that led the author to get seriously interested indata-independence in 1995. There are, however, signiﬁcant hurdles to overcome,
especially regarding the intruder process, which meant that this ambition was notrealised untilrelatively recently. The problem is that the most general intruder(i.e., the one we are trying to model) clearly has an unbounded memory for datathat it sees and deduces. So the contribution this process makes to the thresholdcomponent WImpl is, regrettably, inﬁnite. Except in the case of the type of node
identities (perhaps) there seems no option but to use the data-independence theorems that make use of the theorems involving this parameter. The solution is to use
a transformation that is safe (in the sense that it never loses an attack) but mighttheoretically introduce false attacks (ones that are not really possible). What we
do is to introduce a Manager process for each type like nonces and keys, which has
the duty of monitoring what each foreground value in the type is being used for,issuing them to processes who request them, and, when such a value is forgotten
by all nodes other than intruder, maps it to a background value by causing trans-

15.4

Analyzing crypto-protocols

485

fers within the intruder’s memory. Thus all memories of runs that are no longer
active in either Alice or Bob will be clustered around these background values. The
potential for false attacks comes if the intruder can exploit the fact that values inseveral old runs have been artiﬁcially identiﬁed to bring about an attack, for example by making deductions which are possible only because of the identiﬁcation. A
crucial component in this work is the condition PosConjEqT, described on page459, and small variations upon it, which cryptographic protocols usually satisfy for
two reasons:• Nodes often test for equality between values (e.g., for equality between aname in a received message and the node that the session is supposedly
with, or between a nonce received and one generated earlier) but rarely forinequality. Thus the result of an inequality is likely to be the run aborting,which can easily be made consistent with PosConjEqT.
• The deductions that the intruder performs often rely on the equality of two
or more values (such as the key used to encrypt a message and the one we
happen to know) but rarely inequality. We say that a deductive system thatnever relies on inequality is positive.
The proofs that the transformations we do are safe rely crucially upon these things,
so the methods only apply to protocols and deductive systems that satisfy them.
The result is that we can now often prove that protocols meet their speciﬁcations for any number of node identities with agents who can perform any numberof protocol runs sequentially (i.e., they must ﬁnish or abort one run before starting another). At the time of writing, research to extend this to the case where asingle agent can perform any number of runs in parallel is underway, but is not yet
concluded.
Gavin Lowe has produced a compiler (Casper, [73]), which inputs protocols
described in a notation close to the one used to describe the Needham–Schroeder
protocol on page 470, and outputs a CSP ﬁle which can be used to check various
forms of correctness. See the Bibliography for how to obtain this tool. All of thishas made FDR into arguably the most powerful tool available at the time of writing
for checking properties of crypto-protocols.
There are two main lessons to get out of this example aside from the intrinsic
interest of security protocols. The ﬁrst of these is the way renaming has been used
at various points to achieve subtle eﬀects in plumbing the network together. In
fact this idea can be taken a stage further to allow crypto-protocol analyses to takeaccount of any algebraic equivalences that may relate encrypted terms, such as{{M }a }b = {{M }b }a486

Case studies(the statement that if a message is encrypted twice, the order of the encryptions
does not matter). The second is how we managed to code what is eﬀectively an
inference system as a parallel process,19 exploiting the multi-way synchronizations
allowed in CSP.
This example is also illuminating because it shows how very large networksof CSP processes (almost exactly 100 processes in the present example, and quite a
lot larger in the case of other protocols we have worked with) can have a practicaluse on FDR. The way it stores states means that it gets 32 one-bit spy components
into each word of memory.
15.4.5

Cutting corners

Initially the spy process used above does not know the nonce Na. It can easily learn
this nonce by being sent the messagecomm.Alice.Cameron.pke(pk(Cameron),Sq.<Na,Alice>)This immediately allows it to generate many more messages than it could before:
9 new message 1’s (of the abbreviated protocol), 9 new message 2’s and 3 moremessage 3’s. In all, there are 31 facts which can be inferred from this new one. They
cannot be deduced in any order. For example, the deduction of Sq.<Na,Alice>from the body of the above message (and the spy’s knowledge of sk(Cameron)) via
a Deduction3 must be done ﬁrst, and the subsequent deduction of Na from thisis necessary for almost all the others. However, there is an enormous number ofalternatives for the order in which these inferences are performed (certainly greaterthan 2412 ), and similarly a huge number of states that the spy process can passthrough en route to the state where it knows all 31 new things (more than 224 ).
This combinatorial explosion is unfortunate since it considerably slows up
checks of protocols on FDR, and severely limits the sizes of protocols and depthsof checks it can manage. Fortunately, however, there is a way round the problem.
When our spy performs an inference it never loses the ability to perform any otheraction (either visible or inference) it could already do. If we simply force all available
inferences to be performed in the spy, in an arbitrarily chosen order, before any otheraction is allowed, then the observable behaviour of the spy is unchanged but thestate explosion is completely avoided. In the example above, it will simply be forced
through 30 inferences (‘appearing’ externally as τ actions) before coming to rest in
the state corresponding toSpy1(Close(union(Known,pke(pk(Cameron),Sq.<Na,Alice>))))
19 It would be interesting to try the techniques of the lazy spy on other applications where one
wants an inference system as part of a network.

15.4

Analyzing crypto-protocols

487

A function has been incorporated into FDR for this purpose: chase(P) behaves like P except that whenever P reaches a state where it can perform a τ action,
this operator executes τ ’s until no more are possible. The other behaviour paths
are not explored. Thus this operator has, in general, the right to select from a rangeof states since it may have many paths of τ ’s to follow. In the case of the spy (orany similar inference system) there is a unique ﬁnal state which any path reaches,
but this is certainly not true for general processes.
Unlike the other compression operators (see Section C.2) deﬁned in FDR,
chase sometimes changes the value of the process it is applied to and should only
be used when, as with the Spy example, we are conﬁdent it does not. It is always
true thatP

FD chase(P)since the chase operator only takes decisions which an implementation is free tomake. Thus chase(P) is equivalent to P whenever P is deterministic (as our spy is,since it is equivalent to the process Spy1(Known)), but in most cases the above reﬁnement is proper when P is nondeterministic. (It need not be since chase does notremove nondeterminism other than that introduced by τ actions. It will not remove
the nondeterminism created by the initial ambiguity in (a → P ) 2 (a → Q).) You
should note that chase is an operator which is properly thought of as being applied
to a transition system, not to an abstract process, and that, for nondeterministic P ,diﬀerent transition system implementations of P may well produce diﬀerent results
when the operator is applied.
In principle you can, of course, use the determinism checking capability ofFDR (see Section 9.1) to test if a process is one suitable to chase. Indeed, thedeterminism checking algorithm has a lot in common with chase. But since a
determinism check involves visiting each state of the process under examination,
this is rarely a sensible option with processes we want to chase, since the whole
point of the exercise is to avoid visiting them all! Thus most applications willprobably involve a more mathematical proof of determinism.
The use of the chase operator has an enormously beneﬁcial eﬀect on protocol
checks in FDR. For the one described above, running on the version of FDR2 current
at the time of writing, it cut the number of states visited in ﬁnding the attack fromseveral million to 325. The reduction is even greater in cases where no attack isfound, since ﬁnding the above attack takes fewer actions than would allow an unchased version to go through the complete combinatorial explosion detailed above,
while a complete reﬁnement check inevitably explores it all. For example, if thesecond message of the abbreviated protocol is changed from
B → A : {NA , NB }pk (A)to

B → A : {NA , NB , B }pk (A)488

Case studies

Lowe’s attack is avoided and (subject to various assumptions we do not have time todetail here) the protocol appears to be secure. Certainly the corresponding checks
now succeed, using about 300 states with the use of chase and being well out ofreach on the present tool without it. Thus, the lazy spy model only really makes
sense as a practical proposition on FDR with the chase operator, and fortunately,with it, one is able to model protocols signiﬁcantly more complex than the one wehave seen here.
The chase operator is an extreme – and by far the clearest applying to CSP
at the time of writing – example of a model-checking technique known as partial
order methods.
These can be deﬁned as methods for avoiding complete state
explorations in model-checking runs by the knowledge that certain actions can be
performed in any order (when available) without aﬀecting the check, so that not allorders need be explored. More examples of these as applied to other notations canbe found in [131, 96], amongst many others. (This is a regular topic for papers in
the annual proceedings of CAV, for example.)

15.5

Notes

The solitaire example presented here is a slightly updated version of the one described in [108]. A number of similar puzzles can be found on the web site describedin the Preface.
The topics of Sections 15.2, 15.3.1 and 15.4 all come under the general heading of distributed algorithms. There are, of course, many more, and an extensive
survey can be found in [25]. Certainly many of the others would make interestingcase studies for CSP and FDR, and, indeed, some of them already have been.
The bully algorithm was invented by H Garcia-Molina [41]. It is much usedin distributed systems. Since the curious behaviour we discovered depends both on
implementation details and the precise speciﬁcation chosen, it is really for anyone
who has implemented it to decide whether it applies to them. Even if it is not,they might decide that it is a good idea to run a check that does correspond totheir implementations and expectations. As far as the author knows, the behaviour
discovered here and the consequential correction are original.
The algorithm for managing a distributed database presented in Section 15.3
is taken, as stated there, from one of the author’s earlier papers [106] where it isproved mathematically. The main reason for including it in this chapter is that it
shares one important quality with the examples from Sections 15.1 and 15.4, namelythat it is far from obvious on ﬁrst encountering it whether it works or not.
The concept of data-independence, or something like it, has occurred independently to many people. This is probably because of the amount of time they

15.5

Notes

489

have wasted watching their respective tools analyzing successively larger versions ofsome system in which, in some sense, all the ‘interesting’ behaviours really ought tohave been caught using relatively small examples. The ﬁrst person to have studied
it formally is Wolper [137], other references being [50, 58, 61].
Some of the data-independence rules for CSP set out in this chapter wereconjectured by the author in [122] (an earlier version of the distributed database casestudy). These conjectures were proved, and many further results found, by Ranko
Lazić [65, 64, 67, 68], who established, amongst other things, a formal connection
with the theory of parametricity, or logical relations from functional programming[17, 62, 85, 93, 100, 134] and developed versions of the operational semantics andnormal forms that diﬀer from those seen in Chapters 7 and 11 in that they use
symbolic representations of data values (parts of this work are similar to workon other process algebras, for example [52]). This work also exploits techniques,
related to those in [24, 34, 35, 58, 59] for exploiting symmetry in state spaces.
The data-independence results in this chapter were produced by Lazić speciﬁcallyfor this book, and are mainly consequences of more complex results that you canﬁnd in [65, 64, 67, 68]. The cache example in this chapter is adapted from theone presented in [67]. See [42, 95] for other examples of how techniques related
to data-independence can be applied to caches. Many more references to work on
data-independence and related topics can be found in [64, 67, 68].
2005: Work on data independence has proceeded rapidly since this book cameout. Work to note includes the extension of data independence to include such things
as arrays (indexed by data independent types and possibly containing a diﬀerent
data independent type) and partial orderings (e.g. [66]), and the combination ofdata independence and induction to create a new proof method for arbitrary-sizednetworks called “data independent induction” [26, 27].
There is a large literature on the subject of crypto-protocols, fascinating
because of the remarkable proportion of protocols which are proposed with highlyplausible rationale for, or formal proofs in some logic of, their security, only to havean attack found on them in a subsequent paper. There can be no other area ofcomputer science where such short programs are so frequently wrong. It is alsointeresting how little consensus there is on how this security should be speciﬁed in
the abstract. Usually, though not invariably, researchers will agree on whether a
speciﬁc ‘attack’ is real; it is much harder to get them to agree on what constitutes
an attack in general. Some references to applications of CSP to these protocols
are [71, 72, 73, 75, 110, 111]; for more general references the reader should follow
up some of the citations in these papers or look through publications such as the
Journal of Computer Security and the annual proceedings of the IEEE Computer
Security Foundations workshop.
A natural question that may well have arisen in the minds of readers who

490

Case studies

have studied both Section 12.4 and Section 15.4 is how the rather diﬀerent viewsof computer security seen in them are related. The non-interference/independence
discussed in the ﬁrst of these is an absolute notion and is best applied to analyze thesecurity of systems whose internal details are assumed to be inaccessible to potential
intruders. We look for ways in which one user can aﬀect another, when bothare using ‘natural’ (generally unencrypted) interfaces to the system. Encryption
is necessary, in essence, when it is assumed that an intruder might well have anentrée to some information being stored or passed around the interior of a system.
(You should think of networks over which encrypted messages pass as being highly
distributed systems in which the intruder can see and manipulate much of theinternal state, namely the messages.) It does not seem, at the time of writing, tobe possible to make the independence conditions properly understand the fact thatencrypted traﬃc is incomprehensible without the relevant key. The problem is thatthe deﬁnition of independence does not understand that the distinctions between
the intruder seeing the encrypted messages {X }K and {Y }K are of less signiﬁcancethan those between it seeing X and Y . Therefore the notions of independence andnon-interference are of limited used when dealing with the security of any encryptedview of a system. So even though at an intuitive level one might characterize
our requirements of crypto-protocols as achieving two-way non-interference between
legitimate users and the intruder (i.e., the intruder cannot disrupt the users andcannot detect what they are doing), the two approaches are not as closely related
as one might immediately expect. In fact, the level at which it is traditional toanalyze crypto-protocols (and is the level in Section 15.4) rarely achieves absolutenon-interference in either direction.
2005: There has been an explosion of work on crypto protocols since 1997,
both using CSP/FDR and other methods. It is now possible to check and (if possible)
prove such protocols reasonably routinely over quite a wide range. However the coreof the CSP approach remains exactly as set out here, though the need to create suchmodels by hand is generally eliminated by Casper.

Appendix A

Mathematical background

Much of our work on semantics requires knowledge of the mathematics that underlies the models we build. This appendix is designed to provide a tutorial introduction to two theories which go beyond the basic mathematics of sets, relations
and functions we have used throughout this book and which are essential to a fullunderstanding of Chapters 8, 9 and 10. These are partial orders and metric spaces.
Naturally, we concentrate on those aspects of these things which are most needed
elsewhere in this book, in particular the ﬁxed-point theories derivable in each. The
intention is that each of the two sections is, however, freestanding (in particular,
being independent of the other). Examples are drawn both from conventional mathematics and from the world of CSP.

A.1

Partial orders

A.1.1

BasicsA partial order is a relation that describes when one member of a set is less thananother in some sense. It is generally written either something like x < y, indicatinga strict order where an element is not less than itself, or like x ≤ y, indicating a‘less-than-or-equal-to’ style order where each element is comparable to itself. The
following are some examples.
• The usual order on numbers.
• The ‘divides’ relation on natural numbers: n | m ≡ ∃ r .n × r = m.
• The subset relation ⊆ on any set of sets.
• The preﬁx order ≤ on Σ∗ (s ≤ t ≡ ∃ u.sˆu = t).

492

Mathematical background

There are two properties a relation must have to be a partial order. It must betransitive:x ≤y ∧y ≤z ⇒ x ≤z
(Here, x , y, z are arbitrary members of the underlying set X .) This simply says that
if x is less than y and y is less than z then x is less than z . The statement of theother property, that no pair of distinct objects are less than each other, is diﬀerent
depending on whether we are looking at a strict or non-strict order, namelyx ≤y ∧y ≤x ⇔ x =y
x < y ⇒ ¬(y < x )These are called anti-symmetry properties, with the former encompassing reﬂexivity(meaning that everything is related to itself) and the second anti-reﬂexivity.
There is no requirement that any two objects are comparable, and indeed
only the ﬁrst of the four examples above satisﬁes the following property which, when
it is true in addition to the other properties, deﬁnes a total order:
x <y ∨ y <x ∨ x =yAs a relation, ≤ is always the (disjoint) union of the corresponding < andthe identity relation {(a, a) | a ∈ X }. When discussing an order we will feel free
to move between <, ≤ and the reverse versions > and ≥ when discussing a given
order, even though they are all diﬀerent relations in a formal mathematical sense.
It is often convenient to represent partial orders (especially ﬁnite ones) as
pictures: Figure A.1 is an example of a Hasse diagram which shows the subset orderon P({a, b, c}).
Two partial orders with the same Hasse diagram are said to be order isomorphic. This generalizes to inﬁnite orders: (X , ≤1 ) is order isomorphic to (Y , ≤2 )if and only if there is a bijection f from X to Y such that x ≤1 x  ⇔ f (x ) ≤2 f (x  )for all x , x  ∈ X .
A number of branches of mathematics and theoretical computer science havebeen built on top of partial orders, each of them generating its own set of special
conditions on orders to generate appropriate results about them. Two well-known
examples are lattice theory and domain theory. In the rest of this section we will
introduce just the relatively small portions of these theories that are important tothe study of CSP.
If a partial order has a least element (one that is less than all others), it isconventionally written ⊥ (pronounced ‘bottom’). Similarly, a greatest element isA.1

Partial orders

493{a, b, c}
•
@
@
@
@
@
@
@
{a,
c}
@• {b, c}•{a, b} •
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@•
@•{c}
{a} •
{b}
@
@
@
@
@
@
@
@• {}

Figure A.1 Hasse diagram of a simple partial order.
written  (‘top’). Clearly, an order can have at most one ⊥ or , though, if it
does not have one or other of these, it can have many minimal or maximal elements(ones that have no other element less than, or respectively greater than, them). For
example, the set N (natural numbers) with its usual order has a bottom (0) but notop. P(X ), under the subset order, has both a bottom ({}) and a top (X ). The set
N {1} = {0, 2, 3, . . .} under the divisibility order described above has a top element(0, since n | 0 for all n) and all prime numbers as its minimal elements.
Suppose P is a partial order. If X ⊆ P and a ∈ P then a is an upper boundfor X if x ≤ a for all x ∈ X . Similarly it is a lower bound if a ≤ x for all x ∈ X . It
is the least upper bound of X (written X ) if it is an upper bound and a ≤ b for
all upper bounds b of X , and is the greatest lower bound (written X ) if a lower
bound and greater than all others. The following remarks should help to explainthese concepts:• Since a (least) upper bound is just a (greatest) lower bound in the reverse
order, everything that is said about one can, with suitable modiﬁcations totake account of the switch, be said about the other.

494

Mathematical background• A set X can have many upper (lower) bounds or none at all. For example, if
the set Σ∗ is given the preﬁx order and s, t ∈ Σ∗ , then the set {s, t} always
has at least one lower bound () and perhaps many, but only has upperbounds if s is a preﬁx of t or vice-versa. Note that if P has a ⊥ (), thenevery set has a lower (upper) bound.
• If

X.

X exists it is unique, and similarly for• Even when a set has upper bounds, there may be no least one. The simplest
example to show this is a four-point order {a, b, c, d } where a < c, a < d ,b < c, b < d and the pairs a, b and c, d are incomparable. Here, {a, b} has
two upper bounds (c and d ) but no least one.

• Note the similarity between the pairs of symbols , and , . Over the
powerset P(A) (with subset order) they correspond exactly:

X = X for all X ⊆ P(A).

X =

X and

• Since every x ∈ P is both an upper and a lower bound for the empty set {},⊥ = {} and  = {} (these two bounds existing just when ⊥ and  do).
If they both exist and P has at least two points we have the odd situationthat {} < {}: something that can be true for no other set since x ∈ Ximplies thatX ≤ x ≤• Similarly, ⊥ =X

P and  =P whenever these objects exist.

It will often be important to us to understand which sets X have X and
X existing, and how these operators behave. Just about the strongest possible
assumption that could be made in this department is that every set has both. An
order with this property is called a complete lattice.1 Good examples of complete
lattices are the powerset P(A) and the traces model T of CSP (the non-empty,
preﬁx-closed subsets of Σ∗ ), both ordered by ⊆. That the latter is a complete
lattice is seen from the following observations.
• If X is any non-empty subset of T then
preﬁx closed. It follows that X = X .

X is necessarily non-empty and• If X ⊆ T is non-empty then X is non-empty (it contains ) and preﬁx
closed (if s < t and t ∈ X then necessarily s belongs to all x ∈ X ).
•{} = {} (the bottom element) and{} = Σ∗ (the top).

1 A lattice is a partial order in which all ﬁnite sets X have

X and

X existing.

A.1

Partial orders

495

In fact, there is an interesting proof that if every set has a greatest lower
bound, then every set also has a least upper bound. Of course, the reverse is also
true by symmetry. Thus an order is a complete lattice if each set has a least upperbound or if each set has a greatest lower bound.

Lemma A.1.1 If

X exists for every set X , then so does

X.

Proof Let X ⊆ P , and deﬁne Y = {y | y is an upper bound for X }. Clearlyx ≤ y whenever x ∈ X and y ∈ Y , so we can deduce that each x ∈ X is a lower
bound for Y . It follows that x ≤ Y , since the latter is the greatest lower bound.
Thus Y ∈ Y , by deﬁnition of Y , and it is clear thatmember of Y , i.e., the least upper bound of X .

Y is necessarily the least

Note that any complete lattice L necessarily has both a  ( {} andL)and a ⊥ ( {} and L). It tends to be the case in computer science that we use
orders where x < y means that y is in some way better than, or more deﬁned than,x . It is usually possible and realistic to arrange that there is a worst process, or ⊥,but it is often inconceivable that any process could exist that was better than allothers. For this and other reasons we frequently have to deal with orders that haveandas complete lattices.
⊥’s but do not have such rich structures of
There are two main reasons why we will frequently need CSP models tohave interesting structures of least upper bounds and greatest lower bounds. These
are the ﬁnding of ﬁxed points to yield the semantics of recursive terms, and thesemantics of nondeterministic choice. The latter requirement comes from the factthat very often the order on the models corresponds to reﬁnement: P Q if, andonly if, Q reﬁnes P . In that case it is natural to expect that the nondeterministic
choice S of the set of processes S is the most reﬁned process that is reﬁned by all
the members of S , i.e., the greatest lower bound of S . This explains the coincidence
in symbols between greatest lower bound and nondeterministic choice. In a model
like this, greatest lower bounds have to exist for all sets of processes over which we
expect to be able to take nondeterministic choices. Depending on whether or not
you expect to be able to handle unbounded nondeterminism, these will either be all
the non-empty sets, or all the non-empty ﬁnite sets.

There are two essentially diﬀerent partial orders with two elements:
one where they are comparable and one where they are not. How many are there with 3 and
4 elements respectively? Draw Hasse diagrams of all the possibilities. For higher numbers
than 4 elements it is better to use a computer to enumerate the number of diﬀerent orders.

Exercise A.1.1

496
A.1.2

Mathematical background
Functions and ﬁxed points

If P and Q are partial orders with least elements ⊥P and ⊥Q , then the function
f : P → Q is said to be strict if f (⊥P ) = ⊥Q .
A function from one partial order to another is called monotonic (or monotone) if
x ≤ y ⇒ f (x ) ≤ f (y)In other words, the larger the input to the function, the larger the output. It turns
out that, provided a partial order with a ⊥ has a reasonably rich structure of least
upper bounds, any monotone function from a partial order to itself has a ﬁxed point.
Indeed, it has a least ﬁxed point, and this is in most cases the correct one to assign
as the value of a recursively deﬁned program. Note that the least ﬁxed point of any
strict function from a partial order to itself has least ﬁxed point ⊥.
There are numerous versions of this theorem proved by many people, butthey are all traditionally collected together under the name ‘Tarski’s theorem’,or sometimes ‘Knaster-Tarski’. The strongest possible assumption we could makeabout an order is that it is a complete lattice; in this case the theorem has a simple
if clever proof.
Theorem A.1.2 (tarski’s theorem for complete lattices) If P is a complete lattice and f : P → P is monotonic, then f has a least fixed point.
Proof The least ﬁxed point is given by the following formulax ={y ∈ P | f (y) ≤ y}Call the set on the right-hand side above Y : the set of all points that are mapped
down by f . (Though this is not important for the proof, this set is clearly non-empty
since it contains .) If y ∈ Y then x ≤ y, sof (x ) ≤ f (y) as f is monotonic≤ y
by deﬁnition of Y
It follows that f (x ) is a lower bound of Y , and hencef (x ) ≤ x
as x is the greatest lower bound⇒ f (f (x )) ≤ f (x ) as f is monotonic⇒
f (x ) ∈ Y
We can thus conclude that f (x ) ≥ x and, putting this together with the above, thatx = f (x ). The least-ness of x is an easy consequence of the fact that Y contains
every ﬁxed point.

A.1

Partial orders

497

We need to weaken the assumption that the underlying order is a complete
lattice, since we will often need to ﬁnd ﬁxed points in orders that do not satisfy it.
It turns out that we can still prove Tarski’s theorem provided that certain subsetsthat look as though they ought to have least upper bounds actually do.
Definition A subset D of P is said to be directed if each ﬁnite subset F of D has
an upper bound in D; in other words, there is y ∈ D such that x ≤ y for all x ∈ F .
The concept of a directed set generalizes that of a chain, a subset in which
every pair of elements is ordered, i.e., a totally ordered subset. Every chain C is
directed, since a ﬁnite subset F of C necessarily has a greatest element. There aremany directed sets that are not chains, for example• in P(N) with the subset order, the set of all ﬁnite subsets is directed;• any set with a greatest element is directed (whether a chain or not).
You should think of a directed set D as an abstract picture of how a systemof elements of P ‘converges’ from below to a limit (that may or may not actuallyexist in P ). The higher an element is in D, the closer it is to the place we areconverging to. This is easiest to understand for an increasing sequencex0 ≤ x1 ≤ x2 ≤ . . .
which simply converges upwards towards a supposed limit. A directed set with agreatest element is just like a converging sequence that is eventually constant.
The limit of a directed set is thus its least upper bound, where this exists.
Not all directed subsets of partial orders have limits, since for example the natural
numbers N have no least upper bound in R. Putting the condition on a partial orderthat all directed sets do have limits is therefore a deﬁnite restriction. It characterizes
an extremely important class of partial orders.
Definition A complete partial order (often abbreviated cpo) is one in which every
directed set2 has a least upper bound, and which has a ⊥.
Clearly every complete lattice is a cpo, but the reverse does not hold. The
most obvious distinction is that cpo’s need not have ’s. For example, since everyﬁnite directed set D has a greatest element (the one in D that bounds the whole ofD), which is necessarily D, any ﬁnite partial order with a ⊥ is complete.
2 Directed sets are sometimes replaced by chains in this deﬁnition. It is possible, but far fromeasy, to show that this substitution does not matter, in the sense that an order is directed-set closed
if and only if it is chain closed. These equivalent concepts are both strictly stronger than anotherdeﬁnition one frequently encounters, namely ω-completeness, in which only countable increasing
sequences x0 ≤ x1 ≤ . . . are obliged to have limits. For example, the set of all countable subsets
of an uncountable set such as Ê is (under the subset order) ω-complete but not complete.

498

Mathematical backgroundΣ∗ is not complete under the preﬁx order, since directed sets such as{, a, a, a, a, a, a, . . .}have no upper bound. It becomes complete, however, if we add in the inﬁnite traces:
Seq = Σ∗ ∪ Σω . Each inﬁnite trace u is then maximal in the order, in the sense that
there is no v such that v > u.
Two interesting examples of cpo’s are (i) the set FXY of all partial and total
functions from X to Y (arbitrary sets) and (ii) the set OX of all strict (i.e., < rather
than ≤) partial orders on any set X . In each case the order is subset (⊆) on therespective representation as a set of pairs. Both of these have least elements (theempty set, representing respectively the partial function with no mappings and theorder in which no distinct objects are comparable). The arguments why these twoorders are closed under the limits of directed sets depend crucially on directedness.
If ∆ ⊆ FXY is directed, then ∆ is its least upper bound, because it is a function.
This is because the only way it could fail to be a function would be if there were
x and y, y  with y = y  such that (x , y), (x , y ) ∈ ∆; but then there would be
f , g ∈ ∆ such that (x , y) ∈ f and (x , y  ) ∈ g. Directedness of ∆ then tells us that
there is h ∈ ∆ such that f , g ⊆ h, contradicting the fact that h, as a function,cannot contain both (x , y) and (x , y  ). The very similar argument for OX is left as
an exercise.
Both FXY and OX have interesting classes of maximal elements. The maximal elements of FXY are precisely the total functions (as any non-total function
can clearly be extended, and a total function cannot be extended without losing
the property of being a function) and those of OX are the total orders (see Exercise
A.1.5).
Not all partial orders have maximal elements: this happens when, as in N
and R, we can ﬁnd a way of moving upwards through the order so that there is noelement greater than all the ones we pass through. This means we are ‘converging’out of the top of the order with some chain or perhaps other directed set. Thiscannot happen in a cpo since every directed set has an upper bound in the order,
meaning that however far we move up through it we can never ﬁnd this sort ofbehaviour. Thus, we would expect every cpo to have maximal elements. This
principle, which is known as Zorn’s lemma, is a subtle and important result ofadvanced mathematics.3 Clearly it is extremely important in understanding thestructures of cpo’s. For proofs of Zorn’s lemma and discussion of its position in
3 It is one of the standard equivalents of the Axiom of Choice. Zorn’s lemma is usually quoted

as the statement that any partial order in which every chain has a (not necessarily least) upperbound has maximal elements. The version given here (that every cpo has maximal elements) canreadily be shown equivalent.

A.1

Partial orders

499

mathematics, the interested reader should consult a book on set theory such as[36].
We are now in a position where we can state and prove perhaps the mostgeneral version of Tarski’s theorem.
Theorem A.1.3 (tarski’s theorem for complete partial orders)
Suppose P is a cpo and f : P → P is monotonic. Then f has a least fixed point.
Proof We begin this proof with two observations that are frequently useful whenreasoning about monotonic functions between cpo’s:• If D is a directed set, then f (D) = {f (x ) | x ∈ D} is also directed, since any
ﬁnite subset of f (D) is f (F ) for some ﬁnite subset of D, and monotonicity
implies that f (y) is an upper bound for f (F ) where y ∈ D is chosen to be
an upper bound for F .
• If X is any set for which both X and f (X ) are deﬁned (something thatis true for any directed X by the above), then f (X ) ≤ f ( X ). This is because x ≤ X for all x ∈ X , which implies f (x ) ≤ f ( X ) by monotonicity.
Now, let Fix be the set of f ’s ﬁxed points in P . For all we know so far, thismight be empty. This is used to deﬁne a subset Q of P :Q = {x ∈ P | x ≤ f (x ) ∧ ∀ y ∈ Fix . x ≤ y}
Q is the set of all points that are mapped up by f and are less than or equal to every
ﬁxed point of f . Q is non-empty, since it contains ⊥. If we look at the partial order
structure Q inherits from P , it is actually complete. To show this, it is enough toestablish that whenever D ⊆ Q is directed then D ∈ Q (where the upper boundis taken in P ). Since each y ∈ Fix is an upper bound for D, it follows that D ≤ yalso. And f (D) is a directed set such thatD≤f (D) as x ≤ f (x ) for x ∈ D≤ f ( D) by the second observation above

These two things show

D ∈ Q.

If x ∈ Q then f (x ) ∈ Q since (i) x ≤ f (x ) ⇒ f (x ) ≤ f (f (x )) by monotonicity
and (ii) if y ∈ Fix then x ≤ y ⇒ f (x ) ≤ f (y) = y. So if we choose x to be one of the
maximal elements of Q that Zorn’s lemma tells us exist, then necessarily x = f (x )since x < f (x ) would contradict x ’s maximality. Thus x is a ﬁxed point and, by
deﬁnition of Q, is plainly the least one. (Incidentally, this proves that Q actually
only has one maximal element.)

500

Mathematical background
The least ﬁxed point of a function f is frequently written µ f .

The two proofs of versions of Tarski’s theorem we have seen to date arestylistically rather similar, though understandably the second required a little moremachinery. In essence they are clever manipulations of the ordering that give little
or no idea why it might be reasonable to use the least ﬁxed point as the naturaldenotation of recursively deﬁned programs. This can be remedied for an important
subclass of the monotonic functions, to which we can frequently restrict our attention. The concept of a function whose value at a limit point can be determinedfrom its values on a sequence converging to that point is familiar to students of real
analysis and topology: it is said to be continuous. Recalling that we are thinking ofa directed set in a cpo as being a generalized convergent sequence, we can extend
the idea of continuity to partial orders.
Definition If P and Q are two cpo’s and f : P → Q, then f is said to becontinuous if, whenever ∆ ⊆ P is directed, {f (x ) | x ∈ ∆} exists and equalsf ( ∆).
Notice that this deﬁnition does not assume f is monotonic. It does, however,
imply this, for if x ≤ y then {x , y} = y, so if f is continuous {f (x ), f (y)} exists
and equals f (y), which of course implies that f (x ) ≤ f (y). (If this had not been
provable, we would certainly just have added a condition that f was monotone into
the deﬁnition of continuity. Almost invariably the ﬁrst thing one does when trying
to prove that a function is continuous is to prove it is monotone.)
Because we already know that monotone functions preserve directedness,this shows that continuous functions map ‘convergent sequences’ to ‘convergent
sequences’, and by deﬁnition map the limit of one to the limit of the other.4 Not
all monotonic functions are continuous: consider P = P(N) under the subset order,
and the function f : P → P deﬁned{} if x is ﬁnite
f (x ) =N if x is inﬁnite.
Continuity fails for this function whenever ∆ is an inﬁnite directed set of ﬁnite sets,for example ∆ = {X ∈ P | X is ﬁnite}.
Figure A.2 illustrates the deﬁnitions of monotonicity and continuity by three
simple examples. The partial orders with ‘and so on’ dots (ellipsis) all consist of an
inﬁnite increasing sequence below a single limit point.
Both monotonicity and continuity are preserved under function composition,in the sense that if f : Q → R and g : P → Q both have one of these properties,
then the composition f ◦ g : P → R has the same one.
4 These properties deﬁne what it means for a function to be continuous in real analysis or overmetric spaces.

A.1

Partial orders

501
Q

f

P

. •
•. . . . . . . .f

P

Q

. •
•. . . . . . . .•.

.
.
•.

•.

Q

f

P
.

.

•
.

.

.
.

. .
.
. .

.
.7
.

.
w

•

not monotone

.
•.

.
.

.

.

. .
. .
.
•. .
.. ..
.. ..
. . .Uw.
s. ••. . . . . . . .monotone but
not continuous

•.

.

.

.
.

..
•.

.
.

.
.

..

.
.

.
.

.
.7 •
.
.7

.
.3
..

•
•
•

. •
•. . . . . . . .continuous

Figure A.2 Monotonicity and continuity.

Since continuous functions are all monotone, the theorem proved above establishes that they have least ﬁxed points. There is, however, a very diﬀerent proof
that is highly suggestive of how to build the ﬁxed point, as might be done by arecursive deﬁnition.
Proof of Tarski’s theorem for continuous functions on a cpo P Since⊥ is the least element, we have ⊥ ≤ f (⊥). Now suppose f n (⊥) ≤ f n+1 (⊥). It follows
immediately from the fact that f is monotone that f n+1 (⊥) ≤ f n+2 (⊥). We havethus proved by induction that f n (⊥) | n ∈ N is an increasing sequence in P .
But f is continuous, sof ( {f n (⊥) | n ∈ N}) ={f n+1 (⊥) | n ∈ N} .

It is obvious that if ∆ is any directed set then ∆ = (∆ ∪ {⊥}). (Clearly any
upper bound of one set is an upper bound of the other!) Therefore {f n+1 (⊥) |n ∈ N} = {f n (⊥) | n ∈ N}, and it follows that x = {f n (⊥) | n ∈ N} is a ﬁxed
point of f .
Now, if y is any other ﬁxed point then clearly ⊥ ≤ y. Suppose f n (⊥) ≤ y.

502

Mathematical backgroundThen
f n+1 (⊥) ≤ f (y) = y
as f is monotone and y is a ﬁxed point. It follows that f n (⊥) ≤ y for all n andhence that y is an upper bound for {f n (⊥) | n ∈ N}. But x is the least upperbound, so x ≤ y.
The least ﬁxed point of a continuous function is thus the limit of the increasing sequence we get by applying f over and over to ⊥. This is a much moreconstructive picture of µ f than that produced by the earlier proofs, but unfortunately it only applies to continuous functions.5
There are a great many ways in which we can establish properties of the least
ﬁxed point. Some of the simplest are described below and more can be found in
Section 9.2.
If x is any point in a cpo P then it is easy to see that the sets
Ux
Lx

= {y ∈ P | x ≤ y}
= {y ∈ P | y ≤ x }are themselves both cpo’s (under P ’s order) with least elements x and ⊥ respectively. Thus, if the monotone function f : P → P maps either of these sets toitself (i.e., f (Ux ) ⊆ Ux or f (Lx ) ⊆ Lx ) then f has a ﬁxed point in the given set.
If f (x ) ≤ x then f (Lx ) ⊆ Lx (by monotonicity), so f has a ﬁxed point less than x(meaning, of course, that the least ﬁxed point is less than x ). Such an x is called
a post-ﬁxed point. Similarly if f (x ) ≥ x then f (Ux ) ⊆ Ux so f has a ﬁxed point
greater than x , and x is termed a pre-ﬁxed point.
If it is known, for whatever reason, that f has a unique ﬁxed point, andx ≤ f (x ), the above of course implies that x ≤ µ f . The main way of showing theuniqueness of ﬁxed points is discussed in Section A.2 below, but there are others,
such as the simple observation that if the least ﬁxed point is maximal in P then it
is necessarily unique.
Exercise A.1.2

Suppose f : A × B → P , where A and B are sets and P is a partial

order, such that•{f (a, b) | a ∈ A ∧ b ∈ B } exists, and• F (b) ={f (a, b) | a ∈ A} exists for all b ∈ B .

5 In fact, the more usual proof of the monotone function on cpo version works on the same

principle with potentially much longer sequences than these merely inﬁnite ones! It requires
some advanced mathematical concepts such as ordinal numbers, which is why we gave the lessconstructive but easier to understand Zorn’s lemma proof.

A.1

Partial orders

503

Show that {F (b) | b ∈ B } exists and equals {f (a, b) | a ∈ A ∧ b ∈ B }. (This showsthat it does not matter whether one takes a complex upper bound ‘all at once’ or takes
the upper bounds of suitable cross-sections ﬁrst and then bounds these. Of course, if the
opposite cross-sectional upper bounds F  (a) = {f (a, b) | b ∈ B } also exist, the above
result establishes{ {f (a, b) | b ∈ B } | a ∈ A} ={ {f (a, b) | a ∈ A} | b ∈ B }or, in other words, we can take upper bounds with respect to a and b in either order.)Exercise A.1.3

Which of the following partial orders are complete lattices or cpo’s?

(a) The natural numbersm.

= {0, 1, 2, 3, . . .} under the divisibility order n ≤ m ≡ n |(b) The closed interval [0, 1] = {x ∈  | 0 ≤ x ≤ 1}.

(c) [0, 1] { 12 }(d) C = {X ⊆ | a, b ∈ X ∧ a = b ⇒ gcd(a, b) = 1} under the subset order, where
gcd(a, b) is the greatest common divisor of a and b. C ⊂ ( ) is the set of coprime
subsets of .
Find a complete partial order that has a  but is not a complete
lattice. Hint: ﬁnd a ﬁnite partial order with  and ⊥ where not all subsets have least
upper bounds.

Exercise A.1.4

Exercise A.1.5

Recall that OX is the set of all strict partial orders of a set X .

(a) Show that OX is a cpo under the subset order.
(b) Show that the maximal elements of OX are precisely the total orders on X . Hint:
show that if < is a partial order and x , y are incomparable under < (x = y, x < yand y < x ) then there is an order < which extends < and in which x < y. Be
careful to ensure that the < you build is transitive.
Consider the complete partial order Σ∗ ∪ Σω . Let a and b be distinct
members of Σ. Show carefully that the functions

Exercise A.1.6

f (s)
g(s)

=
=

aˆs
aˆ(s[a, b/b, a])are continuous, where s[a, b/b, a] means the trace s with all a’s replaced by b’s and viceversa.
What are µ f and µ g?

504
A.1.3

Mathematical background
Product spaces

A product space is one where objects have a number of components, each from somesmaller space. The simplest product space is the Cartesian product P × Q of thesets P and Q – consisting of all pairs (x , y) where x ∈ P and y ∈ Q.
If P and Q are both partially ordered then P × Q can be given an orderin several diﬀerent ways. The standard order (which we will always use except,
perhaps, in a few exercises) is deﬁned(x , y) ≤ (x  , y  ) ⇔ x ≤ x  ∧ y ≤ y  .
It is sometimes called the component-wise order because one pair is less than another
if and only if each of its components is less than the corresponding component of
the other pair.
We will sometimes need to use product spaces where there are many or eveninﬁnitely many components. The elements of such a space can be thought of as
vectors or tuples with the appropriate number of components, or alternatively as
functions from an indexing set to the union of the sets from which the components
are taken. Thus, for ordered pairs in P × Q, we would choose an indexing set withtwo elements (say {1, 2}) and think of pairs as being functions from {1, 2} to P ∪ Q,
where the image of 1 is in P , and the image of 2 is in Q.
The most obvious case where this need arises is in deﬁning the semantics ofa mutual or parameterized recursion, since instead of deﬁning a single process as aﬁxed point, we have to compute a whole system of processes.
A typical example of an inﬁnite product space is P ω , the inﬁnite sequencesof elements of P ; this is identiﬁed with the functions from N to P . Another is the{0, 1}X for any set X – this is naturally isomorphic to the powerset P(X ) since we
can identify a tuple with the set of all components with value 1, and the productorder becomes the usual subset order ⊆.
Note that we have used the ‘to-the-power-of’ notation X Y to denote thefunction space Y → X where this means the product of Y copies of X . This isjustiﬁed by the observation that if X has n elements and Y has m elements, thenthe product space X Y has n m elements. A more general notation isλ∈Λ Pλwhich denotes the product space with indexing set Λ in which λth components oftuples are picked from Pλ .
It is often convenient to use vector notation for product spaces (especiallylarge ones): a typical element of P Λ will be underlined, x and its λ component is
xλ . In ‘tuple’ notation we then have x = xλ | λ ∈ Λ.

A.1

Partial orders505

The partial order on an arbitrary product space is a straightforward extensionof the one above:xλ | λ ∈ Λ ≤ yλ | λ ∈ Λ ⇔ ∀ λ .xλ ≤ yλ .
With the exception of total ordering, which is not preserved (for example,
the product of a two-point total order with itself has two incomparable points),
almost all of the properties identiﬁed in earlier sections are preserved by product.
This is shown by the following result.
Theorem A.1.4 If each of Pλ has (the same) one of the following properties, thenλ∈Λ Pλ also has that property.
(a) complete(b) lattice(c) complete latticeProof Suppose that X ⊆ λ∈Λ Pλ and that, for each λ ∈ Λ, the set Xλ = {xλ |x ∈ X } has a least upper bound yλ . Then y = yλ | λ ∈ Λ is an upper bound for
X – since if x ∈ X we know xλ ≤ yλ for all λ – and if z is any other upper boundthen zλ is an upper bound for Xλ for all λ, and so y ≤ z . In other words, y is theleast upper bound of X .
The same component-wise construction also works for greatest lower bounds.
These observations essentially prove each of (a), (b) and (c) since if X ⊆Pλ∈Λ λ is (a) directed or (b) ﬁnite then it is clear that all Xλ also have thecorresponding property. The only thing left to show is that the product of cpo’s
has a bottom element: this is obviously ⊥λ | λ ∈ Λ where ⊥λ is the bottom ofPλ .
Clearly a function such as f (x , y) that has more than one argument drawn
from partial orders can be thought of as a function with a single argument drawn
from some product space. This identiﬁcation deﬁnes what it means for such afunction to be monotone or continuous. The following result shows that where
there are two (and hence, inductively, any ﬁnite number of) arguments, there is astraightforward test for these properties.
Lemma A.1.5 Suppose P , Q, R are partial orders and f : P × Q → R. Then we
may define two functions fx : Q → R and fy : P → R for any x ∈ P and y ∈ Q byfx (y) = fy (x ) = f (x , y) .
The continuity and monotonicity of f is related to that of fx and fy as follows.

506

Mathematical background(a) f is monotone if and only if all fx and fy are (i.e., if f is monotone in eachargument separately).
(b) f is continuous6 if and only if all fx and fy are (i.e., if f is continuous in eachargument separately).
Proof The fact that f being monotone implies all fx and fy are is trivial, so
suppose that all fx and fy are monotone and that (x , y) ≤ (x  , y  ). Then x ≤ x and y ≤ y  , sof (x , y) =≤=≤=fx (y)as fx monotonefx (y  )fy  (x )fy (x  )as fy monotonef (x , y )This proves part (a).
If ∆1 , ∆2 are directed subsets of P and Q respectively then {(x , y) | x ∈ ∆1 }and {(x , y) | y ∈ ∆2 } are directed in P × Q with respective limits ( ∆1 , y) and(x , ∆2 ). It follows immediately that if f is continuous then all fx and fy are. So
suppose all fx and fy are continuous and that ∆ ⊆ P × Q is directed. Deﬁne∆1 = {x | (x , y) ∈ ∆} and∆2 = {y | (x , y) ∈ ∆} .

We know already from the proof of Theorem A.1.4 that ∆ = ( ∆1 , ∆2 ). It isclear that ∆∗ = ∆1 × ∆2 is directed with the same limit as ∆, and that ∆ ⊆ ∆∗ . If
(x , y) ∈ ∆∗ then there are x  , y  such that (x , y  ) and (x  , y) are in ∆ and hence, bydirectedness, there is (x  , y  ) ∈ ∆ with (x , y) ≤ (x  , y  ) and so by monotonicity off:{f (x , y) | (x , y) ∈ ∆∗ } ≤{f (x , y) | (x , y) ∈ ∆}and the reverse inequality holds because ∆ ⊆ ∆∗ , so that in fact the terms areequal. But we then have{f (x , y) | (x , y) ∈ ∆}={f (x , y) | (x , y) ∈ ∆∗ }={f (x , y) | y ∈ ∆2 ∧ x ∈ ∆1 }={ {f (x , y) | y ∈ ∆2 } | x ∈ ∆1 } (1)(2)={f (x , ∆2 )} | x ∈ ∆1 }(3)
= f ( ∆1 , ∆2 )= f ( ∆∗ )6 Continuity only makes sense if P , Q and R are cpo’s.

A.1

Partial orders

507

Line (1) is an application of the result established in Exercise A.1.2. Lines (2) and
. This completes the proof.
(3) follow respectively from the continuity of fx and f∆2This result does not generalize to the case of inﬁnite product spaces: if
f : {0, 1}ω → {0, 1} is deﬁned
f (x ) =0 if inﬁnitely many xn equal 1
1 otherwisethen f is not monotone but all the fn are (being constant functions, since the valueof f (x ) is unaﬀected by a change to a single component of x ). A trivial modiﬁcation
to this example (deﬁning g(x ) = 1 − f (x )) produces a monotone but discontinuousfunction all of whose ‘sections’ gn are continuous.
However, the corresponding result for functions to product spaces is not
restricted in this way. All parts of the following result are easy to prove.
Lemma A.1.6 The function f : P → λ∈Λ Qλ is (a) monotone or (b) continuous
if and only if all of the component functions fλ : P → Qλ are (a) monotone or (b)continuous, where fλ (x ) = f (x )λ .
Function spaces as product spaces
We have already seen how product spaces can be thought of as the sets of functions
from some indexing set to a partial order (or several partial orders). These spaces
pay no attention to any partial order structure that may be present in the indexing
set, but we have already met two classes of functions that do, namely the monotonic
ones and the continuous ones. In this subsection we will examine the partial orders
these restricted function spaces inherit from the full product space. Notice that thepartial order can be writtenf ≤ g ⇔ ∀ x .f (x ) ≤ g(x ) .
mcDefinitions If P and Q are two cpo’s, deﬁne P → Q and P → Q respectively
to be the sets of all monotone and continuous functions from P to Q.
Both of these constructions preserve the two main categories of cpo’s we havedeﬁned:mcLemma A.1.7 Both of the spaces P → Q and P → Q are cpo’s if P and Q are. If
Q is, in addition, a complete lattice, then both function spaces are, too.

508

Mathematical background

Proof The least upper bound of a set Φ of functions (directed in the case where
Q is a cpo rather than a complete lattice) is, in all cases we have to consider, thesame as that in the full product space, namely(

Φ)(x ) ={f (x ) | f ∈ Φ} .

To prove the result we must simply prove that if all elements of Φ are respectively
monotone or continuous then so is Φ.
The monotone case is very straightforward since, if x ≤ y, then f (x ) ≤ f (y)for all f ∈ Φ, so certainly{f (x ) | f ∈ Φ} ≤{f (y) | f ∈ Φ} .

For the continuous case, suppose ∆ ⊆ P is directed. Then we have(Φ)( ∆)===={f ( ∆) | f ∈ Φ}
{ {f (x ) | x ∈ ∆} | f ∈ Φ}
{ {f (x ) | f ∈ Φ} | x ∈ ∆}{( Φ)(x ) | x ∈ ∆}

(1)
(2)
(3)

where line (1) is by continuity of the f ’s, line (2) is a general property of partial
orders (see Exercise A.1.2) and line (3) is by deﬁnition of Φ.
The ﬁnal result of this section is important because it is needed to justify
the application of versions of Tarski’s theorem to functions which have themselves
been deﬁned using least ﬁxed points (i.e., ﬁnding the value of a recursive constructwhich has another recursion nested within it). For example, in order to show that
F (p) = µ q.(a → (p  q)){a}

is a continuous function, you need to have not only that the operations of preﬁxing
and parallel composition are continuous over the chosen semantic model, but alsothat the very process of extracting ﬁxed points is continuous.
m

Lemma A.1.8 Let P be a cpo. Then (a) the least fixed point operator µ : (P →P ) → P on the space of monotonic functions is itself monotonic, and (b) restrictedcto the space of continuous functions µ : (P → P ) → P it is continuous.
Proof For part (a), we note that if f is any monotone function thenµf ={x | f (x ) ≤ x }A.1

Partial orders509

since we know that µ f belongs to the set on the right-hand side and have alreadyobserved that if y belongs to this set then µ f ≤ y. But now if f ≤ f  in thefunction-space order, then trivially{x | f (x ) ≤ x } ⊇ {x | f  (x ) ≤ x }so the greatest lower bound of the left-hand side is necessarily less than or equal to
the greatest lower bound of the right-hand side, which is what we require.
c

For part (b), suppose Φ ⊆ P → P is directed. We know from the proof of
Tarski’s theorem on page 501 that, for any continuous f ,µf ={f n (⊥) | n ∈ N} .

Claim that for all n we have{f n (⊥) | f ∈ Φ} .

Φ)n (⊥) =(This is certainly true when n = 0 (both sides are ⊥), so suppose it holds for n.
Then by induction, the deﬁnition of Φ and the continuity of all g ∈ Φ we have{g(f n (⊥)) | g, f ∈ Φ} .

Φ)n+1 (⊥) =(But since all f , g ∈ Φ have k ∈ Φ with k ≥ f , g this is in turn equal to{k n+1 (⊥) | k ∈ Φ}
as claimed.
Given this, we have
µ(

Φ) =
=
=
=

{( Φ)n (⊥) | n ∈ N}
{ {f n (⊥) | f ∈ Φ} | n ∈ N}
{ {f n (⊥) | n ∈ N} | f ∈ Φ}{µ f | f ∈ Φ}

which proves the lemma.
Exercise A.1.7
Suppose P , Q and R are cpo’s. Prove that the following pair ofpartial orders are order isomorphic when → is interpreted as (i) the full function spacemc(equivalently product space) operator, (ii) → and (iii) →.
(P × Q) → R

andP → (Q → R)

510

Mathematical background

This is the identity underlying the functional programming construct of Currying;7 toprove these isomorphisms you should show that the maps
curry :
uncurry :((P × Q) → R) → (P → (Q → R))(P → (Q → R)) → ((P × Q) → R)

andare (well-deﬁned) order isomorphisms in each of the three cases.

Exercise A.1.8

If X is any partial order, show that X ω and (X ω )ω are order isomor-

phic.

Exercise A.1.9 Let P = ∪ {a, b} be ordered with the usual order on and suchmthat n < a < b for all n ∈ . Construct a directed set ∆ of functions in P → P such that{µ f | f ∈ ∆} = µ( ∆). What does this demonstrate?
Exercise A.1.10
p0
q0

=
=

Suppose P and Q are cpo’s. The mutual recursion

F (p0 , q0 )G(p0 , q0 )mm

for monotonic functions f : P × Q → P and g : P × Q → Q is naturally identiﬁed
with the least ﬁxed point of the composite function H (p, q) = (F (p, q), G(p, q)). We canalternatively interpret the recursion as an iterated ﬁxed point: let
p1
q1

=
=

µ p.F (p, µ q.G(p, q))µ q.G(p1 , q)Show that (p1 , q1 ) is a ﬁxed point of H and hence that (p0 , q0 ) ≤ (p1 , q1 ). Next, show thatq0 ≥ µ q.G(p0 , q) and hence that
F (p0 , µ q.G(p0 , q)) ≤ q0
Deduce that p1 = p0 and q1 = q0 ,A.2

Metric spaces

The concept of distance should be familiar to readers, both through everyday experience and through the mathematical study of ordinary Euclidean space. For
example, if a = (x , y, z ) and a = (x  , y  , z  ) are two members of R3 (Euclidean
3-space), the distance between them would ordinarily be deﬁned to bede (a, a ) =√((x − x  )2 + (y − y  )2 + (z − z  )2 )7 Currying (named after H.B. Curry) involves taking a function f (x , y) of two arguments andturning it into a function which takes them separately: curry(f )(x ) is the function which takes any
y and returns the value f (x , y). Thus, if plus is the function that adds two numbers, curry(plus)(1)is the function that adds one to any number.

A.2

Metric spaces

511

As with many other phenomena, mathematicians have sought to identify
and axiomatize the essential properties which make a distance function like thisone work. A metric is a function from any two points in a space X to R+ (thenon-negative real numbers) which satisﬁes the following three laws:d (x , y) = 0 ⇔d (x , y) =d (x , z ) ≤x =ydiagonald (y, x )symmetryd (x , y) + d (y, z ) triangle inequality

These just say that the distance from any point to itself is 0 but the distance between
any two distinct points is strictly positive; that the distance from y back to x is thesame as that from x to y; and that the distance from x to z via y must be at leastthat of the direct route.
All of these are either obvious or well known for de .
It is possible to have many diﬀerent metrics on the same space. For example,
if d is any metric then so is any multiple of d , and if X is any set then the following
discrete metric always satisﬁes the axioms:d (x , y) =0 if x = y
1 otherwise

A metric space is just the pair (X , d ) for a space X and metric d on X . Just
as with partial orders, we will usually be happy to refer to X alone as a metricspace as long as the metric d can be understood from the context.
Example A.2.1 The metric spaces used in CSP (and other process algebras) bear
remarkably little resemblance to ordinary Euclidean space. In many ways they aresimpler to reason about. Consider the example of ﬁnite and inﬁnite traces over aset Σ:
Seq = Σ∗ ∪ Σω
We can deﬁne a distance function on this set by examining how far down thesequences we have to look to tell two of them apart. This can conveniently be doneby deﬁning restriction functions ↓ n that give a standardized view of any sequence
to a chosen depth n ∈ N:s ↓nsˆt ↓ n= s
= s

if s ∈ Σ∗ and #s ≤ n
if s ∈ Σn and t ∈ Seq

The important features of these functions are(a) s ↓ 0 = t ↓ 0 for all s, t;512

Mathematical background(b) s ↓ n ↓ m = s ↓ min(n, m) for all s, n, m;(c) if s = t, then there is n such that s ↓ n = t ↓ n
Together, these imply that whenever s = t there is n ∈ N such that s ↓ m = t ↓ m
if and only if m ≤ n. A set together with a family of restriction operators satisfying(a), (b) and (c) will be called a restriction space.
The distance between two points of a restriction space can be deﬁned to be
inf {2−n | s ↓ n = t ↓ n}(the choice of 2 being arbitrary). This is just 2−n where n is the length of theirlongest common preﬁx when s = t, and 0 when s = t. This is a strange measureof distance, not least since the range of possible distances is restricted to powers of
1
2 . It obviously satisﬁes the ﬁrst two conditions for a metric, so the only remaining
thing we have to check is the triangle inequality. This is trivial to check in the casethat any two of the points x , y and z are equal, so we can assumed (x , y) = 2−nand d (y, z ) = 2−m

If k = min(n, m), it follows that x ↓ k = y ↓ k and y ↓ k = z ↓ k , and hence thatx ↓ k = z ↓ k . Thusd (x , z ) ≤ 2−k = max (d (x , y), d (y, z )) (≤ d (x , y) + d (y, z ))which is actually a much stronger inequality than the triangle law.8 This inequality
is very hard to visualize since it says that the distance from x to z is no longer than
the greater of the two legs of this journey via y, for arbitrary y!
The metrics used for CSP models are almost invariably derived from restriction spaces in this way.
Metric spaces allow us to transfer understanding about things like convergence – derived from distance over Euclidean space – to a more general setting
where we have any well-behaved distance function. Firstly, it is simple to deﬁnewhat it means for a sequence of points xi | i ∈ N to converge to a point y: for any
positive distance > 0, if we go far enough down the sequence the entire remainderof the sequence must lie within of y:> 0 ⇒ ∃ N . ∀ n ≥ N .d (y, xn ) <The limit point y is unique, because if there were another, say y  , then you could
set = d (y, y  )/2 which would lead quickly to a contradiction.
8 Metrics satisfying it are sometimes called either ultra-metrics or non-Archimedean metrics.

A.2

Metric spaces

513

Notice that the only convergent sequences under the discrete metric are thosethat are eventually constant, since otherwise there would be no way of getting
below 1. This is also true of sequences with a ﬁnite trace as limit in Seq, since if#s = n then the only point within 2−(n+1) of s is s itself. However, all membersof Σω have many ‘interesting’ sequences converging to them. For example, thesequences, a, a, a, a, a, a, . . . andb, b, . . ., a, b, b, . . ., a, a, b, b, . . ., a, a, a, b, . . .both converge to a, a, a, . . ..
The subset C of a metric space X is said to be closed if, whenever xi | i ∈ N
is a sequence of points in C that converges to a point y of X , then y ∈ C . In otherwords, the process of convergence cannot take us outside C . Closed sets have thefollowing crucial properties:• The empty set {} is closed (having no convergent sequences); the whole space
X is closed, and any one-point set {x } is closed as the sequence x , x , x , . . .converges to x .
• If C and D are closed, then so is C ∪ D since if xi | i ∈ N is a convergent
sequence of points in it then an inﬁnite subsequence must belong either to C
or D. It is easy to see that any inﬁnite subsequence of a convergent sequenceis convergent with the same limit; and since C and D are closed it follows
that the limit of our sequence is contained in one of them.
• If C is any non-empty set of closed sets, then C is closed, because the limitof each inﬁnite sequence in this set clearly belongs to each C ∈ C.
An open set U is one whose complement is closed. This is equivalent to saying thatwhenever x ∈ U there is no convergent sequence in X  U with limit x . An elegant
way of re-phrasing this is to say that for each x ∈ U there is a ball (of suﬃciently
small positive radius ) about x contained in U :B (x ) = {y ∈ X | d (x , y) < } ⊆ U
Just as the set of closed sets is closed under ﬁnite union and arbitrary intersection, the open sets are closed under ﬁnite intersection and arbitrary union.9(This follows, amongst other things, from de Morgan’s laws.)
9 Mathematicians’ love of

abstraction is shown by the fact that, just as metric spaces put
distance into a general setting, a whole subject has been built up from these properties of open
and closed sets. A topology on a set X is any collection of subsets containing {} and X , and closed
under ﬁnite intersection and arbitrary union. This is just a yet-more-abstract way of looking at

514

Mathematical background

Every subset of the discrete metric space is closed (and open). A preﬁxclosed subset C of Seq is closed if, and only if, each s ∈ Σω is in C whenever all its
ﬁnite preﬁxes are.
A sequence of points xi | i ∈ N is said to be a Cauchy sequence if it looks
as though it ought to be converging in the following tightly deﬁned sense: for every
positive distance δ > 0, if we go far enough down the sequence the points are
all within δ of each other. And this means all points beyond some N , not justconsecutive ones:
δ > 0 ⇒ ∃ N . ∀ n, m ≥ N .d (xn , xm ) < δ
Every converging sequence is a Cauchy sequence: this follows by taking the
N obtained for = δ/2 in the deﬁnition of convergence, and using the symmetry
and triangle properties of a metric.
Cauchy sequences play exactly the same role in metric spaces as directed sets
do in partial orders: they are the ‘formally convergent’ structures, and we judge
completeness by seeing if they really all do converge.
Definition A metric space is said to be complete if, and only if, all Cauchy
sequences converge to some point.
Not all metric spaces are complete: a good example is the set of all rationalnwhere n ∈ N and m ∈ Z {0}) with its usual distance function (| x −y |).
numbers ( mIf you take the decimal expansion of any irrational number such as π (a number being
irrational when it is not rational, of course), then the sequence of ﬁnite truncationsof this, for example
3,

3.1,

3.14,

3.141,

3.1415,3.14159,

3.141592,...

is a Cauchy sequence of rationals that fails to converge to a rational.
Seq is complete: if xi | i ∈ N is a Cauchy sequence then for any r we canﬁnd Nr such that n, m ≥ Nr implies xn ↓ r = xm ↓ r . The limit of the sequence isconstructed as the unique sequence which agrees with xNr up to depth r for all r .
In general we say a restriction space is complete if its associated metric is also
complete, which turns out to be equivalent to the property that for every sequenceof points x0 , x1 , x2 , . . . such that xn+1 ↓ n = xn , there is a (necessarily unique)point x such that x ↓ n = xn for all n.
the idea of convergence and, in fact, it is suﬃciently general to encompass the partial order notionsof convergence we have previously seen. We do not pursue this subject here, since it is not needed
for a basic treatment of the theory of CSP.

A.2

Metric spaces

515

The most important property of complete metric spaces, at least for us,
bears a striking similarity to the corresponding property of complete partial orders:
a useful class of functions can be shown always to have ﬁxed points.
Suppose f : X → Y is a function between two metric spaces. f is said to be• non-expanding if d (f (x ), f (y)) ≤ d (x , y) for all x , y ∈ X , and• a contraction map if there is a positive constant α < 1 such thatd (f (x ), f (y)) ≤ αd (x , y)for all x , y ∈ X . (α must be independent of x and y.)Thus a non-expanding function is one that guarantees not to increase the distance
between points, and a contraction is one that decreases the distance in a uniform
way. Obviously• each contraction map is non-expanding;• the composition f ◦ g of two non-expanding functions is non-expanding, and• if f and g are both non-expanding and one is a contraction, then f ◦ g is acontraction.
The following result is certainly the most widely-used ﬁxed point theorem in mathematics, even though it is not quite as frequently used as Tarski’s theorem in computer science. The proof has much in common with that for the continuous function
version of Tarski’s theorem, since both involve constructing the ﬁxed point as thelimit of a sequence formed by iterating the function we are extracting the ﬁxed
point from.
Theorem A.2.1 (contraction mapping theorem or banach’s theorem)
Suppose X is a complete metric space and f : X → X is a contraction map. Thenf has a unique fixed point (i.e., exactly one y ∈ X such that f (y) = y).
Proof It turns out that sequence obtained by applying f over and over to any
point converges to a ﬁxed point: if we choose any x0 ∈ X and deﬁne xn+1 = f (xn ),then if α is the contraction factor of f , we haved (xn+2 , xn+1 ) = d (f (xn+1 ), f (xn )) ≤ αd (xn+1 , xn )and hence d (xn+1 , xn ) ≤ αn d (x1 , x0 ) for all n. Thus the distance between consecutive points in this series decreases (at least) like powers of α starting from
whatever happens to be the distance K = d (x1 , x0 ) between the ﬁrst two. The

516

Mathematical background

series K , K α, K α2 , . . . is known as a geometric progression and has a ﬁnite sum:K /(1−α). This easily leads to the conclusion that xi | i ∈ N is a Cauchy sequence:d (xr , xr +n )≤ d (xr , xr +1 ) + . . . + d (xr +n−1 , xr +n )≤r +n−1


K αj

j =r

≤

∞


K αj

j =r

=

K αr
1−α

The ﬁrst line of the above follows from the triangle inequality, and the last line
can be made as small as we please by choosing large enough r . Thus this sequence
converges on a point y. This is certain to be a ﬁxed point: to show this we suppose
the contrary, i.e., d (y, f (y)) > 0. The fact that xi | i ∈ N converges to y implies we
can ﬁnd r such that d (xr , y) and d (xr , xr +1 ) are both strictly less than d (y, f (y))/3.
Thend (y, f (y)) ≤ d (y, xr ) + d (xr , xr +1 ) + d (xr +1 , f (y))≤ d (y, xr ) + d (xr , xr +1 ) + αd (xr , y)
< (2 + α)d (y, f (y))/3
which is a contradiction. Here, the ﬁrst line is just the triangle inequality and thesecond follows as xr +1 = f (xr ).
We can thus conclude y = f (y). If z is any ﬁxed point, thend (y, z ) = d (f (y), f (z ))≤ αd (y, z )as y and z are ﬁxed points
as f is a contraction

which implies d (y, z ) = 0, proving that y = z . Thus y is the unique ﬁxed point.
A particularly simple example is given over the complete metric space R by
the contraction map x → x /2. Wherever we start iterating this function from weend up with a sequence converging to 0, for example 1, 1/2, 1/4, 1/8, . . ..
Notice that it was much easier to show in the proof that the ﬁxed point is
unique than to show it exists in the ﬁrst place. All we really need, to show that there
is no more than one ﬁxed point, is that d (f (x ), f (y)) < d (x , y) whenever x = y:neither the uniformity of α nor the completeness of X is required. Both of these arenecessary to get us a ﬁxed point: in the incomplete space {x ∈ R | x > 0} (with theusual metric | x − y |), the contraction map f : x → x /2 has no ﬁxed point. And
similarly, in the complete space {x ∈ R | x ≥ 1}, again with the usual metric, theA.2

Metric spaces

517

function g : x → x + 1/x has no ﬁxed point even though | g(x ) − g(y) |<| x − y |when x = y.
The structure of the metric on Seq means that d (f (x ), f (y)) < d (x , y) implies
that d (f (x ), f (y)) ≤ d (x , y)/2, so that any function that brings distinct points closer
together is bound to be a contraction. Remembering that the distance between two
points is determined by the depth up to which they look the same, for a function
f to be a contraction over Seq it must be that, to whatever depth x and y lookidentical, f (x ) and f (y) must look the same to a strictly greater depth. If x ↓ n =y ↓ n, then f (x ) ↓ n+1 = f (y) ↓ n+1. This is the formal deﬁnition of f being a
constructive function over any restriction space. Similarly, non-expanding functions
correspond to non-destructive functions: ones such that if x ↓ n = y ↓ n, thenf (x ) ↓ n = f (y) ↓ n.
A simple example of a constructive function over Seq is the one deﬁned
f (s) = aˆs
We can infer from the proof of the ﬁxed point theorem that from wherever you begin
to construct the sequence xi | i ∈ N, a sequence will be found that converges tothe same ﬁxed point. If we iterate this from the starting points  and b, b, b, . . .
we get precisely the two sequences seen earlier that converge to a, a, a, . . ., which
is obviously this function’s ﬁxed point.
The structure of the metric means that any constructive function whose ﬁxed
point is a ﬁnite sequence with length n must reach this ﬁxed point after no morethan n + 1 iterations.
Non-destructive functions might have many ﬁxed points (for example, theidentity function ﬁxes all points) or none at all. An example of the latter for Seq
when Σ = {a, b} is given byf () = af (aˆs) = bˆsf (bˆs) = aˆs
Thus constructiveness is clearly required to get us the unique ﬁxed point result.
The great advantage of the contraction mapping theorem over Tarski’s theorem, where both can be applied, is the uniqueness of the ﬁxed point it generates.
It is, of course, the justiﬁcation of the UFP rule that we have used to good eﬀectover several CSP models.
A good general introduction to the simpler topics in metric spaces and topology can be found in [128].
Exercise A.2.1 Show that a closed, non-empty subset Y of a complete metric space
X is itself a complete metric space under the restriction of X ’s metric to Y .

518

Mathematical backgroundNow suppose that f is a contraction mapping on X such that f (Y ) ⊆ Y . Show
that the unique ﬁxed point of f lies in Y .
Show that the inﬁnite traces Σω are a closed subset of Seq. Use theresult of the previous question to show that if f : Seq → Seq is a constructive functionthat maps inﬁnite traces to inﬁnite traces (i.e., f (s) ∈ Σω when s ∈ Σω ) then its ﬁxed
point is inﬁnite.

Exercise A.2.2

Can Σω be replaced by Σ∗ in this result. If not, why not?
Find a constructive function from Seq to itself which is not monotonic
in the sense described in Section A.1.2.

Exercise A.2.3

Appendix B

A guide to machine-readable CSP

B.1

Introduction

The machine-readable dialect of CSP (CSPM ) is one result of a research eﬀort1
with the primary aim of encouraging the creation of tools for CSP. FDR was theﬁrst tool to utilize the dialect, and to some extent FDR and CSPM continue to
evolve in parallel, but the basic research results are publicly available (see later for
more details). The language described here is that implemented by the 2.1 releaseof FDR and has many features not present in FDR1.
CSPM combines the CSP process algebra with an expression language which,while inspired by languages like Miranda/Orwell and Haskell/Gofer, has been modiﬁed to support the idioms of CSP. The fundamental features of those languages are,however, retained: the lack of any notion of assignment, the ability to treat functions
as ﬁrst-class objects, and a lazy reduction strategy.
Scripts
Programming languages are used to describe algorithms in a form which can be
executed. CSPM includes a functional programming language, but its primary
purpose is diﬀerent: it is there to support the description of parallel systems in
a form which can be automatically manipulated. CSPM scripts should, therefore,
be regarded as deﬁning a number of processes rather than a program in the usual
sense.
1 This Appendix was written by Bryan Scattergood, of Formal Systems (Europe) Ltd.

He is
the main developer and implementor of this version of CSP. Comments and queries about thenotation, and potential tool developers who wish to use his results, should contact him by email:bryan@fsel.com .

520

A guide to machine-readable CSP

B.2

Expressions

At a basic level, a CSPM script deﬁnes processes, along with supporting functions
and expressions. CSP draws freely on mathematics for these supporting terms, so
the CSPM expression-language is rich and includes direct support for sequences,sets, booleans, tuples, user-deﬁned types, local deﬁnitions, pattern matching andlambda terms.
We will use the following variables to stand for expressions of various types.
m, n
s, t
a, A
b
p, q
e
c
x

numbers
sequencessets (the latter a set of sets)booleanprocesses
eventschannelgeneral expression

When writing out equivalences, z and z’ are assumed to be fresh variables
which do not introduce conﬂicts with the surrounding expressions.
Identiﬁers
Identiﬁers in CSPM begin with an alphabetic character and are followed by any
number of alphanumeric characters or underscores optionally followed by any number of prime characters (’). There is no limit on the length of identiﬁers and caseis signiﬁcant. Identiﬁers with a trailing underscore (such as fnargle_) are reserved
for machine-generated code such as that produced by Casper [73].
CSPM enforces no restrictions on the use of upper/lower-case letters in identiﬁers (unlike some functional languages where only data type constructors can haveinitial capital letters.) It is, however, common for users to adopt some convention
on the use of identiﬁers. For example• Processes all in capitals (BUTTON, ELEVATOR_TWO)• Types and type constructors with initial capitals (User, Dial, DropLine)• Functions and channels all in lower-case (sum, reverse, in, out, open_door)
Note that while it is reasonable to use single character identiﬁers (P, c, T) for small
illustrative examples, real scripts should use longer and more descriptive names.

B.2

Expressions

521

Numbers
Syntax12
m+n, m-n-mm*nm/n, m%n

integer literalsum and diﬀerence
unary minus
product
quotient and remainder

Remarks
Integer arithmetic is deﬁned to support values between -2147483647 and 2147483647
inclusive, that is those numbers representable by an underlying 32-bit representation(either signed or twos-complement.) The eﬀect of overﬂow is not deﬁned: it may
produce an error, or it may silently wrap in unpredictable ways and so should not
be relied upon.
The division and remainder operations are deﬁned so that, for n = 0,m

= n ∗ (m/n) + m%n| m%n | < | n |m%n 0 (provided n > 0)so that, for positive divisors, division rounds down and the remainder operation
yields a positive result.
Floating point numbers (introduced experimentally for Pravda [70]) are notcurrently supported by FDR. Although the syntax for them is still enabled, it is
not documented here.
Sequences
Syntax<>, <1,2,3><m..n><m..>s^t#s, length(s)null(s)head(s)tail(s)concat(s)elem(x ,s)<x1 ,..., xn | x <-s, b>

sequence literals
closed range (from integer m to n inclusive)
open range (from integer m upwards)
sequence catenation
length of a sequence
test if a sequence is empty
the ﬁrst element of a non-empty sequence
all but the ﬁrst element of a non-empty sequencejoin together a sequence of sequences
test if an element occurs in a sequencecomprehension

522

A guide to machine-readable CSP

Equivalences
null(s)≡ s==<><m..n>≡ if m<=n then <m>^<m+1..n> else <>elem(x ,s)≡ not null(< z | z<-s, z==x >)< x | > ≡ < x >< x | b, ...>
< x | x <-s, ...>

≡ if b then < x | ...> else <>≡ concat(< < x | ...> | x  <-s >)Remarks
All the elements of a sequence must have the same type. concat and elem behave
as if deﬁned byconcat(s)= if null(s) then <> else head(s)^concat(tail(s))
elem(_, <>)= falseelem(e, <x>^s) = e==x or elem(e,s)
The following function tests if a sequence reads the same forwards and backwards
palindrome(<x>^s^<y>) = x==y and palindrome(s)palindrome(_)= trueSets
Syntax{1,2,3}{m..n}{m..}union(a1 ,a2 )inter(a1 ,a2 )diff(a1 ,a2 )Union(A)Inter(A)member(x ,a)card(a)empty(a)set(s)
Set(a)
Seq(a){x1 ,..., xn | x <-a, b}

set literalclosed range (between integers m and n inclusive)
open range (from integer m upwards)
set union
set intersection
set diﬀerence
distributed union
distributed intersection (A must be non-empty)
membership test
cardinality (count elements)
check for empty set
convert a sequence to a set
all subsets of a (powerset construction)
set of sequences over a (inﬁnite if a is not empty)
comprehension

B.2

Expressions

523

Equivalences
union(a1 ,a2 ) ≡ { z,z’ | z<-a1 , z’<-a2 }inter(a1 ,a2 ) ≡ { z | z<-a1 , member(z,a2 ) }diff(a1 ,a2 ) ≡ { z | z<-a1 , not member(z,a2 ) }Union(A)member(x ,a)Seq(a)≡ { z | z’<-A, z<-z’ }≡ not empty({ z | z<-a, z==x })≡ union({<>}, {<z>^z’ | z<-a, z’<-Seq(a)}){ x | } ≡ { x }{ x | b, ...}
{ x | x <-a, ...}

≡ if b then { x | ...} else {}≡ Union( { { x | ...} | x  <-a } )Remarks
In order to remove duplicates, sets need to compare their elements for equality, so
only those types where equality is deﬁned may be placed in sets. In particular, setsof processes are not permitted. See the section on pattern matching for an exampleof how to convert a set into a sequence by sorting.
Sets of negative numbers ({ -2}) require a space between the opening bracket
and minus sign to prevent it being confused with block comment.
Booleans
Syntax
true, false
b1 and b2
b1 or b2
not b
x1 ==x2 , x1 !=x2
x1 <x2 , x1 >x2 , x1 <=x2 , x1 >=x2
if b then x1 else x2

boolean literals
boolean and (shortcut)
boolean or (shortcut)
boolean notequality operations
ordering operations
conditional expression

Equivalencesb1 and b2≡ if b1 then b2 else false

b1 or b2

≡ if b1 then true else b2

not b≡ if b then false else true524

A guide to machine-readable CSP

Remarks
Equality operations are deﬁned on all types except those containing processes andfunctions (lambda terms).
Ordering operations are deﬁned on sets, sequences and tuples as follows
x1 >= x2≡

x2 <= x1

x1 < x2≡

x1 <= x2 and x1 != x2

a1 <= a2≡

a1 is a subset of a2

s1 <= s2≡

s1 is a preﬁx of s2(x1 ,y1 ) <= (x2 ,y2 ) ≡x1 < x2 or (x1 == x2 and y1 <= y2 )Ordering operations are not deﬁned on booleans or user-deﬁned types.
if b then {1} else <2>
is an error2 because both branches of a conditional expression must have the same
type.
TuplesSyntax(1,2), (4,<>,{7})pair and triple

Remarks
Function application also uses parentheses, so functions which take a tuple as theirargument need two sets of parentheses. For example the function which adds together the elements of a pair can be written either asplus((x,y)) = x+yor asplus(p) = let (x,y) = p within x + y
The same notation is used in type deﬁnitions to denote the corresponding
product type. For example, if we have
2 At the time of writing no type-checker has yet been produced for CSP (though the develM
opment of one is undoubtedly desirable). The parser does some limited type checking (it would
reject the above example), but sometimes type errors are only caught at run-time in FDR.

B.2

Expressions

525

nametype T = ({0..2},{1,3})
then T is{ (0,1), (0,3), (1,1), (1,3), (2,1), (2,3) }Local deﬁnitions
Deﬁnitions can be made local to an expression by enclosing them in a ‘let within’clause.
primes =letfactors(n) = < m | m <- <2..n-1>, n%m == 0 >is_prime(n) = null(factors(n))
within < n | n <- <2..>, is_prime(n) >Local deﬁnitions are mutually recursive, just like top-level deﬁnitions. Not
all deﬁnitions can be scoped in this way: channel and datatype deﬁnitions are only
permitted at the top-level. Transparent deﬁnitions can be localized, and this canbe used to import FDR’s compression operations on a selective basis. For example,
my_compress(p) =lettransparent normal, diamondwithin normal(diamond(p))
Lambda terms
Syntax\ x1 , ...xn @ x

lambda term (nameless function)

Equivalences
The deﬁnition
f(x,y,z) = x+y+z
is equivalent to the deﬁnition
f = \ x, y, z @ x+y+z526

A guide to machine-readable CSP

Remarks
There is no direct way of deﬁning an anonymous function with multiple branches.
The same eﬀect can be achieved by using a local deﬁnition and the above equivalence. Functions can both take functions as arguments and return them as results.
map(f)(s) = < f(x) | x <- s >twice(n) = n*2
assert map(\ n @ n+1)(<3,7,2>) == <4,8,3>
assert map(map(twice))(< <9,2>, <1> >) == < <18,4>, <2> >B.3

Pattern matching

Many of the above examples made use of pattern matching to decompose values.
The version of CSPM used by FDR2.1 introduced much better support for patternmatching; for example, we can write
reverse(<>)= <>reverse(<x>^s) = reverse(s)^<x>
as well as
reverse(s) = if null(s) then <> else reverse(tail(s)) ^ <head(s)>The branches of a function deﬁnition must be adjacent in the script, otherwise
the function name will be reported as multiply deﬁned.
Patterns can occur in many places within CSPM scripts• Function deﬁnitions (reverse above)• Direct deﬁnitions (x,y) = (7,2)• Comprehensions { x+y | (x,y) <- {(1,2),(2,3)} }• Replicated operators ||| (x,y):{(1,2),(2,3)} @ c!x+y->STOP• Communications d?(x,y)->c!x+y->STOPThe patterns which are handled in these cases are the same, but the behaviourin the ﬁrst two cases is diﬀerent. During comprehensions, replicated operators andcommunications we can simply discard values which fail to match the pattern: wehave a number of such values to consider so this is natural. When a function fails
to match its argument (or a deﬁnition its value) silently ignoring it is not an option
so an error is raised. On the other hand, functions can have multiple branches (asB.3

Pattern matching527

in the case of reverse) which are tried in top to bottom order while the otherconstructs only allow a single pattern. For example,
f(0,x) = x
f(1,x) = x+1
print f(1,2) -- gives 3
print f(2,1) -- gives an error
print { x+1 | (1,x) <- { (1,2), (2,7) } } -- gives {3}The space of patterns is deﬁned by
1. Integer literals match only the corresponding numeric value.
2. Underscore (_) always matches.
3. An identiﬁer always matches, binding the identiﬁer to the value.
4. A tuple of patterns is a pattern matching tuples of the same size. Attempting
to match tuples of a diﬀerent size is an error rather than a match failure.
5. A simple sequence of patterns is a pattern (<x,y,z>) matching sequences ofthat length.
6. The catenation of two patterns is a pattern matching a sequence which islong enough, provided at least one of the sub-patterns has a ﬁxed length.
7. The empty set is a pattern matching only empty sets.
8. A singleton set of a pattern is a pattern matching sets with one element.
9. A data type tag (or channel name) is a pattern matching only that tag.
10. The dot of two patterns is a pattern. (A.x)
11. The combination of two patterns using @@ is a pattern which matches a value
only when both patterns do.
12. A pattern may not contain any identiﬁer more than once.
For example, {}, ({x},{y}) and <x,y>^_^<u,v> are valid patterns. However, {x,y} and <x>^s^t are not valid patterns since the decomposition of the value
matched is not uniquely deﬁned. Also (x,x) is not a valid pattern by rule 12: theeﬀect that this achieves in some functional languages requires an explicit equality
check in CSPM .
When a pattern matches a value, all of the (non-tag) identiﬁers in the pattern
are bound to the corresponding part of the value.
The fact that tags are treated as patterns rather than identiﬁers can cause
confusion if common identiﬁers are used as tags. For example, given

528

A guide to machine-readable CSP

channel n : {0..9}f(n) = n+1
attempting to evaluate the expression f(3) will report that the function \ n @ n+1
does not accept the value 3. (It accepts only the tag n.)
Only names deﬁned as tags are special when used for pattern matching. For
example, given
datatype T = A | B
x = A
f(x) = 0f(_) = 1
g(A) = 0g(_) = 1
then f is not the same as g since f(B) is 0 while g(B) is 1.
The singleton-set pattern allows us to deﬁne the function which picks theunique element from a set aspick({x}) = x
This function is surprisingly powerful. For example, it allows us to deﬁne a sort
function from sets to sequences.
sort(f,a) =letbelow(x) = card( { y | y<-a, f(y,x) } )pairs= { (x, below(x)) | x <- a }select(i) = pick({ x | (x,n)<-pairs, i==n })within < select(i) | i <-<1..card(a)> >where the ﬁrst argument represents a <= relation on the elements of the second.
Because pick works only when presented with the singleton set, the sort function
is deﬁned only when the function f provides a total ordering on the set a.

B.4

Types

Simple types
Types are associated at a fundamental level with the set of elements that the typecontains. Type expressions can occur only as part of the deﬁnition of channels orother types, but the name of a type can be used anywhere that a set is required.

B.4

Types

529

For example, the type of integer values is Int and the type of boolean values
is Bool, so{0..3} <= Int{true, false} == BoolIn type expressions the tuple syntax denotes a product type and the dot
operation denotes a composite type so that({0,1},{2,3}){0,1}.{2,3}denotes {(0,2),(0,3),(1,2),(1,3)}
denotes {0.2, 0.3, 1.2, 1.3}

The Set and Seq functions which return the powerset and sequence space of
their arguments are also useful in type expressions.
Named types
Nametype deﬁnitions associate a name with a type expression, meaning that ‘.’and ‘( , , )’ operate on it as type constructors rather than value expressions. For
example,nametype Values = {0..199}
nametype Ranges = Values . Values
has the same eﬀect as
Values = {0..199}
Ranges = { x.y | x<-Values, y<-Values }If, on the other hand, we had left Values as an ordinary set, Values . Values
would have had the entirely diﬀerent meaning of two copies of the set Values
joined by the inﬁx dot. Similarly the expression (Values,Values) means either
the Cartesian product of Values with itself or a pair of two sets depending on thesame distinction.
Data types
Syntax
datatype T = A.{0..3} | B.Set({0,1}) | C
A.0, B.{0}, B.{0,1}, C

deﬁnition of typefour uses of type

530

A guide to machine-readable CSP

Remarks
Data types may not be parameterized (T may not have arguments).
The datatype corresponds to the variant-record construct of languages like
Pascal. At the simplest level it can be used to deﬁne a number of atomic constants
datatype SimpleColour = Red | Green | Bluebut values can also be associated with the tags
Gun = {0..15}
datatype ComplexColour = RGB.Gun.Gun.Gun | Grey.Gun | Black | White
Values are combined with ‘.’ and labelled using the appropriate tag, so that
we could write
make_colour((r.g.b)@@x) =if r!=g or g!=b then RGB.x else
if r==0 then Black else
if r==15 then White else Grey.r
to encode a colour as brieﬂy as possible.
Note that while it is possible to write
datatype SlowComplexCol = RGB.{r.g.b | r<-Gun, g<-Gun, b<-Gun} | ...
this is less eﬃcient and the resulting type must still be rectangular, that is expressible as a simple product type. Hence it is not legal to write
datatype BrokenComplexColour = -- NOT RECTANGULAR
RGB.{r.g.b | r<-Gun, g<-Gun, b<-Gun, r+g+b < 128 } | ...
Channels
Syntaxchannel flip, flopchannel c, d : {0..3}.LEVEL
Eventssimple channels
channels with more complex protocol
the type of all deﬁned events

Remarks
Channels are tags which form the basis for events. A channel becomes an event
when enough values have been supplied to complete it (for example flop above isan event). In the same way, given

B.4

Types

531

datatype T = A.{0..3} | ...
we know that A.1 is a value of type T, given
channel c : {0..3}
we know that c.1 is a value of type Event. Indeed, the channel deﬁnitions in ascript can be regarded as a distributed deﬁnition for the built-in Events data type.
Channels must also be rectangular in the same sense as used for data types.
It is common in FDR2 to make channels ﬁnite although it is possible to declareinﬁnite channels and use only a ﬁnite proportion of them.
Channels interact naturally with data types to give the functionality provided by variant channels in occam2 (and channels of variants in occam3.) For
example, given ComplexColour as above, we can write a process which strips out
the redundant colour encodings (undoing the work performed by make_colour)
channel colour : ComplexColour
channel standard : Gun.Gun.Gun
Standardize =colour.RGB?x -> standard!x -> Standardize[]
colour.Grey?x -> standard!x.x.x -> Standardize[]
colour.Black -> standard!0.0.0 -> Standardize[]
colour.White -> standard!15.15.15 -> Standardize
Closure operations
Syntaxextensions(x )productions(x ){|x1 ,x2 |}The set of values which will ‘complete’ x
The set of values which begin with x
The productions of x1 and x2

Equivalences

productions(x ){|x | ...|}≡ { x .z | z<-extensions(x ) }≡ Union( { productions(x ) | ...} )532

A guide to machine-readable CSP

Remarks
The main use for the {| |} syntax is in writing communication sets as part of thevarious parallel operators. For example, given
channel c : {0..9}
P = c!7->SKIP [| {| c |} |] c?x->Q(x)we cannot use {c} as the synchronization set; it denotes the singleton set containing
the channel c, not the set of events associated with that channel.
All of the closure operations can be used on data type values as well aschannels. They are deﬁned even when the supplied values are complete. (In thatcase extensions will supply the singleton set consisting of the identity value forthe ‘.’ operation.)

B.5

Processes

Syntax
STOP
SKIP
c->p
c?x ?x  :a!y->p
p;q
p/\q
p\a
p[]q
p|~|q
p[>q
b & p
p[[a<- b]]p|||qp[|a|]qp[a||a  ]qp[c<->c  ]q
;x :s@p[]x :a@p|~|x :a@p|||x :a@p[|a  |]x :a@p||x :a@[a  ]p[c<->c  ]x :s@p

no actions
successful termination
simple preﬁx
complex preﬁx
sequential compositioninterrupt
hidingexternal choiceinternal choiceuntimed time-out
boolean guard
renaming
interleaving
sharingalphabetized parallel
linked parallel
replicated sequential composition
replicated external choice
replicated internal choice (a must be non-empty)
replicated interleave
replicated sharing
replicated alphabetized parallel
replicated linked parallel (s must be non-null)B.5

Processes

533

Equivalences
As a consequence of the laws of CSP,p|||q≡ p[| {} |]q;x :<>@p≡ SKIP[]x :{}@p≡ STOP|||x :{}@p≡ SKIP[|a|]x :{}@p≡ SKIP||x :{}[a]p≡ SKIP

By deﬁnitionp[>q≡ (p[]q)|~|q

Remarks
The general form of the preﬁx operator is cf ->p where c is a communication channel, f a number of communication ﬁelds and p is the process which is the scope of
the preﬁx. A communication ﬁeld can be
!x
?x :A
?x

OutputConstrained input
Unconstrained input

Fields are processed left to right with the binding produced by any input ﬁelds
available to any subsequent ﬁelds. For example, we can write
channel ints : Int.Int
P = ints?x?y:{x-1..x+1} -> SKIP
Output ﬁelds behave as suggested by the equivalencec !x f -> p

≡ c.x f -> p

The proportion of the channel matched by an input ﬁelds is based only on
the input pattern. There is no lookahead, so ifchannel c : {0..9}.{0..9}.Bool
P = c?x!true -> SKIP -- this will not work
Q = c?x.y!true -> SKIP -- but this will

534

A guide to machine-readable CSP

then P is not correctly deﬁned. The input pattern x will match the next complete
value from the channel ({0..9}) and true will then fail to match the next copyof {0..9}. In the case of @@ patterns, the decomposition is based on the left-handside of the pattern.
If an input occurs as the ﬁnal communication ﬁeld it will match any remaining
values, as inchannel c : Bool.{0..9}.{0..9}
P = c!true?x -> SKIP -- this will work
Q = c!true?x.y -> SKIP -- this will also work
This special case allows for the construction of generic buﬀers.
BUFF(in,out) = in?x -> out!x -> BUFF(in, out)
is a one place buﬀer for any pair of channels.
Dots do not directly form part of a preﬁx: any which do occur are either
part of the channel c, or the communication ﬁelds. (FDR1 took the approach that
dots simply repeated the direction of the preceding communication ﬁeld. This is a
simpliﬁcation which holds only in the absence of data type tags.)
The guard construct ‘b & P’ is a convenient shorthand forif b then P else STOP
and is commonly used with the external choice operator ([]), as
COUNT(lo,n,hi) =lo < n & down -> COUNT(lo,n-1,hi)[]
n < hi & up -> COUNT(lo,n+1, hi)This exploits the CSP law that p[]STOP = p.
The linked parallel and renaming operations both use the comprehension
syntax for expressing complex linkages and renamings. For example,
p [ right.i<->left.((i+1)%n), send<->recv | i<-{0..n-1}] qp [[ left.i <- left.((i+1)%n), left.0<-send | i<-{0..n-1} ]]Both the links (c<->c’) and the renaming pairs (c<-c’, read ‘becomes’) takechannels of the same type on each side and extend these pointwise as required. For
exampleB.6

Special deﬁnitions535

p [[ c <- d ]]is deﬁned when extensions(c) is the same as extensions(d) and is then the sameasp [[ c.x <- d.x | x<-extensions(c) ]]The replicated operators allow multiple generators between the operator andthe @ sign in the same way as comprehensions. The terms are evaluated left toright, with the rightmost term varying most quickly. So; x:<1..3>, y:<1..3>, x!=y @ c!x.y->SKIP
is the same asc.1.2->c.1.3->c.2.1->c.2.3->c.3.1->c.3.2->SKIP
The linked parallel operator generalizes the chaining operator >>. For example, if COPY implements a single place buﬀer,
COPY(in,out) =in?x -> out!x -> COPY(in,out)then we can implement an n-place buﬀer by
BUFF(n,in,out) =[out<->in] i : <1..n> @ COPY(in, out)
The precedence rules for operators (both process and expression level) are
set out in Table B.1. The replicated versions of the process operators have thelowest precedence of all. The @@ pattern operator has a precedence just below thatof function application.

B.6

Special deﬁnitions

External
External deﬁnitions are used to enable additional ‘magic’ functions supported bya speciﬁc tool. Requiring a deﬁnition, rather than silently inserting names into
the initial environment, has two advantages: any dependencies on such functions
are made explicit and there is no possibility that users will introduce conﬂicting
deﬁnitions without being aware of it. For example, to make use of an (imaginary)frobnicate external function, we might say

536
Class
Application
Arithmetic

Sequence
Comparison
BooleanSequential

ChoiceParallelOther

A guide to machine-readable CSP
Operatorsf(0)[[ <- ]]*, /, %+, ^#<, >, <=, >===, !=
not
and
or
->
&
;
[>
/\
[]
|~|
[| |], [ || ], [ <-> ],|||if then else
let within\ @Descriptionfunction application
renaming
unary minus
multiplication
addition
catenation
lengthordering
equality
negationconjunction
disjunction
preﬁx
guard
sequence
untimed time-out
interrupt
external choiceinternal choiceparallelinterleaveconditional
local deﬁnitions
lambda term

Associativity

left
left

none
none

none

Table B.1 Operator precedence.: the operators at the top of thetable bind more tightly than those lower down.
external frobnicate
P(s) = c!frobnicate(s^<0>, 7) -> STOP
Without the external deﬁnition, frobnicate would be reported as an undeclared identiﬁer. Tools should report as an error any attempt to deﬁne an externalname which they do not recognize.
Transparent
As described in Section C.2, FDR uses a number of operators that are used toreduce the state space or otherwise optimize the underlying representation of a

B.6

Special deﬁnitions

537

process within the tool. While these could be deﬁned using external deﬁnitions,they are required to be semantically neutral. It is thus safe for tools which do
not understand the compression operations to ignore them. By deﬁning them astransparent, tools are able to do so; unrecognized external operations would betreated as errors. As an example,
transparent diamond, normal
squidge(P) = normal(diamond(P))
enables the diamond and normal compression operators in FDR2, while other tools
see deﬁnitions of the identity functions, as if we had written
diamond(P) = P
normal(P) = P
squidge(P) = normal(diamond(P))
AssertAssertions are used to state properties which are believed to hold of the otherdeﬁnitions in a script. (FDR1 scripts adopted a convention of deﬁning two processes
SPEC and SYSTEM, with the understanding that the check SPEC[=SYSTEM should be
performed. This has weaknesses: the correct model for the check is not always
apparent, and some scripts require multiple checks.) The most basic form of thedeﬁnition isassert b
where b is a boolean expression. For example,
primes= ...
take(0,_)= <>take(n,<x>^s) = <x> ^ take(n-1,s)assert <2,3,5,7,11> == take(5, primes)
It is also possible to express reﬁnement checks (typically for use by FDR)
assert p [m= qwhere p and q are processes and m denotes the model (T, F or FD for trace, failures
and failures/divergences respectively.) Note that reﬁnement checks cannot be usedin any other context. The (reﬁnement) assertions in a script are used to initialize
the list of checks in FDR2.
Similarly, we have

538

A guide to machine-readable CSP

assert p :[ deterministic [FD] ]assert p :[ deadlock free [F] ]assert p :[ divergence free ]for the other supported checks within FDR. Only the models F and FD may be usedwith the ﬁrst two, with FD assumed if the model is omitted.
Note that process tests cannot be used in any other context. The processassertions in a script are used to initialize the list of checks in FDR2.

Print
Print deﬁnitions indicate expressions to be evaluated. The standard tools in the
CSPM distribution include ‘check’ which evaluates all (non-reﬁnement) assertions
and print deﬁnitions in a script. This can be useful when debugging problems withscripts. FDR2 uses any print deﬁnitions to initialize the list of expressions for theevaluator panel.

B.7

Mechanics

CSPM scripts are expressible using the 7-bit ASCII character set (which forms partof all the ISO 8859-x character sets.) While this can make the representation ofsome operators ugly, it makes it possible to handle the scripts using many existing
tools including editors, email systems and web-browsers.
Comments can be embedded within the script using either end-of-line comments preceded by ‘--’ or by block comments enclosed inside ‘{-’ and ‘-}’. The
latter nest, so they can be safely used to comment out sections of a script.
If it is necessary to exploit an existing library of deﬁnitions, the ‘include’
directive performs a simple textual inclusion of another script ﬁle. The directive
must start at the beginning of a line and takes a ﬁlename enclosed in double quotes.
Block comments may not straddle ﬁle boundaries (comments cannot be opened in
one ﬁle and closed in another.)Deﬁnitions within in a script are separated by newlines. Lines may be split
before or after any binary token and before any unary token. (There are exceptions
to this rule, but they do not occur in practice.)
The attribute, embed, module and subtype keywords are currently reservedfor experimental language features.

B.8

B.8

Missing features

539

Missing features

Those familiar with functional languages such as Haskell will notice several omissions in CSPM .
Floating point
Floating point numbers are a natural part of the timed and probabilistic variantsof CSP, and the machine-readable dialect has a syntax to support them. However,as the current generation of tools have concentrated on the simpler variants of thenotation, the underlying semantics have not been implemented.
Strings
Real programming languages have string and character types, along with an input/output system. CSPM is not a programming language: input and output
introduce unnecessary complications when performing analysis of scripts.
Characters and strings could be useful for modelling some problem domains,
but no compelling example has yet to be demonstrated. Integers and sequences
provide workable alternatives.
Sections and composition
Operator sections and functional composition are a convenient shorthand allowing
the terse expression of some powerful constructs. This terseness conﬂicts with theneed for CSP process descriptions to be readable, often by new users of the language.
For now, it is felt that their utility is outweighed by their unreadability.

B.9

Availability

The research into tools for CSP has been sponsored by the US Oﬃce of Naval Research under N00014-87-J1242 and as such the basic results from that research arefreely available on request. It is hoped that this will help encourage a common input
syntax between CSP-based tools. The results include the machine-readable formof CSP complete with both denotational and operational semantics, a congruence
proof between the two semantic models using a bridging semantics, an implementation of a parser for the language using ﬂex and bison to produce a syntax-tree
in C++ and methods deﬁned over that tree which are suﬃcient to implement theoperational semantics.

Appendix C

The operation of FDR

Though the basic concept of what FDR does, namely reﬁnement checking, is simple,
the mechanisms it uses to make this eﬃcient are much more complex. Understanding them undoubtedly helps one to use the tool eﬀectively. This appendix, therefore,seeks to give the interested user some insight, frequently guided by the theory developed in Part II, about how it works. It is in no sense, however, a manual. The ﬁrst
part looks at the basic principles; the second deals with the compression functions
FDR provides to enable the user to check larger networks of processes than would
otherwise be in range.

C.1

Basic operation

C.1.1

Running the operational semantics eﬃciently

With the exception of its potential support for the prioritized view of time (as discussed in Sections 14.6 and 14.7) everything FDR does is rooted in the denotationalmodels of CSP described in Chapter 8. These are reﬁnement checking, determinism
checking and looking for deadlocks and divergences. There is, however, no direct
sense in which the tool calculates sets of traces, failures etc.; it manipulates processes
at the level of operational semantics and labelled transition systems, borrowing one
important idea (normalization) from the algebraic semantics. Thus all three of thesemantic methods described in Part II of this book are involved in its design.
While the operational semantics presented in Chapter 7 allow one to calculate
the transitions of any process at all, any implementation which treats all processes
the same is likely to be more ineﬃcient than one would like in both space andtime when running checks involving millions of states. The problem is, that inorder to treat such features as unfolding recursions properly, it is necessary to use

542

The operation of FDR

a symbolic representation of each state (probably as a syntax tree) and to use amethod probably not unlike the basic inference system over syntax seen in Chapter
7 in order to calculate transitions.
FDR therefore uses a two-level approach to calculating operational semantics;
it is important to appreciate the diﬀerences between these levels if you want to use
it eﬀectively. The low level is fully general but relatively ineﬃcient, whereas thehigh level is restricted (speciﬁcally, it cannot handle recursion) but much more
eﬃcient in space and time. When you ask FDR to perform a check it analyzes
the structure of the process or processes it is given and decides on an appropriate
cut-oﬀ point between the low and high levels. Everything below this level is fully
evaluated using the low-level compiler (i.e., each individual low-level component
has its full operational semantics evaluated). What the compiler outputs for thehigh-level structure is a series of recipes for combining together the transitions ofthese low-level components into transitions of the whole.
At the time of writing the division between low and high levels is decided by
a complex algorithm which is closely approximated by the following.
• All true recursions are low level. A true recursion is a process name (possibly parameterized) whose value depends (possibly through other recursive
expansions) on itself (where parameterized, with the same arguments). Thus
the recursion
P(n) = a -> P(if n==0 then N else n-1)
is low level (for 0 ≤ n ≤ N ) but
Q(n) = a -> if n==0 then STOP

else Q(n-1)

is not.
• Subject to the above over-riding principle, as many ‘high-level’ operators (allparallel operators, renaming and hiding) as possible are high level, but anyother operators are treated at low level unless they are forced to high level1
by being outside one of these. Thus, in the unlikely combination
LevelExample = a -> ((b -> STOP)|~|((c -> STOP) ||| Q))(where the identiﬁer LevelExample does not appear in Q), the processesb -> STOP and c -> STOP are both compiled at low level, while the internal
1 At the time of writing there is no high-level implementation of 2, so this forces a process to
low level irrespective.

C.1

Basic operation

543

choice |~| and the a -> construct are both high level because they areoutside the |||.
The ﬁrst principle arises from necessity: the high-level approach only works where
the set of basic structures a process might have is predictable and ﬁnite. The second
is pragmatic and designed to keep the number of these structures generated as small
as possible for typical examples.
Indeed, for a majority of practical examples this approach will produce just
one structure. These well-behaved examples fall into two categories: processes(often designed as speciﬁcations) with no high-level operators which are entirelycompiled at low level, and combinations of low-level processes using parallel, hiding
and renaming operations. The crucial point about a combination using only these
operators is that the overall process structure is unaﬀected by any action it performs.
Consider, for example, the solitaire board described in Section 15.1: for the standard
board, the process Puzzle on page 427 is a parallel composition of 34 processes atthe outset, and keeps the same basic structure throughout. It is only the statesof the individual components that change: every single state it goes through isequivalent to(|| (i,j):BoardCoords @ [Alpha(i,j)] Slot’(i,j))[|OffBoardMoves|] STOP
where Slot’(i,j) is one of the states of the original process Slot(i,j). In thiscase, of course, most of the processes have just two states2 and the other one, STOP,
has only one.
For this example, and any other with a single structure, the compiler in
FDR works out the complete state spaces of the component processes and the rules
under which actions of the components combine to give actions of the whole. In
this case you would get a rule that allowed a τ action of any individual process
to be promoted to a τ action of the whole, and rules for each visible action. For
each move in RealMoves the rule would simply say that it can happen just when
the three processes whose alphabet it is in can. (The introduction of hiding andrenaming operators can make these relationships more complex.) Except in rare
pathological cases the number of rules has the same order of magnitude3 as thealphabet of actions being used (including any hidden actions).
2 The operational semantics in Chapter 7 would give them four, the extra ones being createdby τ actions introduced on unfolding recursions. By default these are omitted by FDR since they
serve no purpose except in making sense of very badly deﬁned recursions as described on page 165.
3 In particular, this approach, based on combinations of events as opposed to states of the component processes, works well for many-way synchronization. The earlier version, FDR1, used thelatter approach which frequently caused a combinatorial explosion on timed systems (as describedin Chapter 14) where many processes have to synchronize on tock.

544

The operation of FDR

If there is more than one structure the system could go through as it evolved,
the rules have to encompass the transitions from one to another. For example, on
the assumption that Q is a process compiled at low level, the process LevelExample
deﬁned above would give four structures: the initial one (preﬁx), one in which the
choice is unresolved, and one each for after it has been resolved each way. Then,for example, the second of these would have two available τ actions, which resolve
it into the third or fourth.
Within the terminology of FDR, the individual structures the system can go
through are termed conﬁgurations, or formats and the rules which allow it to infer
the actions of one of these from those of its components are called supercombinators.
In the version of the tool current at the time of writing it is possible to switch oﬀ
the use of supercombinators, whereupon a mechanism rather closer to the basic
operational semantics is used to derive transitions. The slow-down this creates isgenerally spectacular.
Because all the low-level processes have been fully evaluated at compile time,as have all the potential structures, a single state of the complete system can be
represented by an indication of which structure this is and the indexes of the states
the components are in. Since in a typical run you may encounter a huge numberof states, it is desirable to store them as compactly as possible. Therefore FDR
packs this information so that each component process Pi with Si states only occupies k bits, where k is minimal such that 2k ≥ Si . Thus each of the two state
Slot processes in Puzzle occupies one bit. Some versions of the tool oﬀer further
compressions which exploit similarities between collections of states.
Once a process has been compiled the recipe for running it (i.e., the state
spaces of its components, its conﬁgurations and supercombinators, and of course
its initial state) are passed to another program which runs it. This might be toevaluate it for normalization, to check it against a speciﬁcation, or for compression.
The later sections of this appendix describe all of these possibilities.
A recipe like this is an implicit representation of an LTS, since it gives theinitial state and suﬃcient information to calculate all the transitions and all theother states. This is in contrast to the compiled low-level components, which areincluded as explicit LTSs (i.e., a list of states and transitions). It does not, ofcourse, matter to such a recipe how its components were generated, only that they
are explicit LTSs. You can think of such a recipe as some CSP context applied tosome processes represented as explicit LTSs.
In deciding how to structure a process for input into FDR, you should bear inmind the distinction between how it deals with high- and low-level state evaluation.
High level is many times more eﬃcient. At the time of writing a reasonable limiton the size of a low-level component to compile is in the range 1,000–5,000 states
depending on example.

C.1

Basic operation

545

The most likely source of problems in compiling (as opposed to any of the
post-compilation functions) a process on FDR is an over-large (perhaps inﬁnite)
low-level component. Bear in mind that since these components are evaluated infull, the fact that the context they are put in means they never reach most states
would not help in this (the archetypal example of this is the sequential coding of
the Spy1 process on page 479). It is also possible, but much rarer, for combinatorial
problems to arise in the enumeration of conﬁgurations or supercombinator rules.

C.1.2

Normalization

Suppose we have asked FDR to check the reﬁnement P
Q (the precise model ismore or less irrelevant). The ﬁrst thing it does is to compile P and Q, as describedin the previous section. It cannot do the reﬁnement check directly on the raw statemachines these would give when run: it has to transform P (only) into a normal
form. The normal form it aims at is essentially of the type described on page 287,
i.e., a state machine in which all states are semantically distinct (thanks to thefactorization by bisimulation) and which follows normal form structure rules. The
exact shape of the nodes varies depending on which model is being used, but they
always satisfy the basic principles that (i) there are no τ actions and (ii) each node
has a unique successor on each visible initial action it can perform.
The crucial point about normal form state machines is that they have aunique state for each trace: once we are told the present trace, there is only one
state it can be in.
There are two main diﬀerences with the normal forms seen in Chapter 11.
Firstly, they are now stored as state machines, with a node represented solely by
its index, its transitions, and perhaps refusal/divergence information, rather thanas highly stylized pieces of syntax. Secondly, rather than normalizing a processby algebraic transformation using laws, FDR performs this function (rather more
eﬃciently) by directly manipulating the transition diagram of the process.
If you carry out a normalization as described in Chapter 11 you will ﬁnd thatthe process you are left with to normalize after a trace s, namely P /s, ends up being
the nondeterministic choice of a number of states P can get into – namely, all thosestates it can be in after s. When we directly normalize an LTS, this corresponds tothe decision below to form a graph whose nodes are sets of nodes of the original.
Each set node of the normal form behaves like the nondeterministic choice of theoriginal nodes it contains. The normalization algorithm that FDR uses comes in
two stages.
Stage 1 Given a ﬁnite labelled transition system L = (V , E , v0 ), we form a graph
PL whose nodes are members of P(V ) as follows

546

The operation of FDR
• The initial node is τ ∗ (v0 ), where τ ∗ (v ) is deﬁned to be {w | v =⇒ w }, thenodes reachable under some sequence of τ ’s from v0 .
• For each node generated we have (if using the failures/divergences modelN ) to decide whether it is divergent: this is true if and only if it contains adivergent node of L. Techniques for deciding this are discussed in the next
section. A divergent normal form node over N has no successors. (Overother models divergence is ignored.)• If a node N is not divergent, we determine the set of non-τ actions possiblefor v ∈ N . For each such action a we form a new node, the set {τ ∗ (w ) |a∃ v ∈ N .v −→ w }, the set of all nodes reachable after action a and any
number of τ ’s from members of N .
• The search is completed when all ‘new’ nodes generated are ones that havebeen previously expanded.
The resulting graph will be termed the pre-normal form of L. It coincides with theoutput of the procedure for looking for a ﬁnite algebraic normal form described on
page 287, but it suﬀers from the same drawback, namely (as was the case with thenormal form N  derived for P1 there) that it may have equivalent nodes. FDR uses
the same solution as adopted there, namely to factor the pre-normal form by a strong
bisimulation calculated taking account of divergence and refusal information (where
relevant to the model). This strong bisimulation calculation comprises Stage 2.
The possible refusals of a pre-normal form node v are just the sets refusedby the stable v ∈ N . (Refusals are represented by the set of minimal acceptances,the complements of maximal refusals.)
The normalization process of an LTS corresponding to a data-free version of
COPY >> COPY >> COPY is shown in in Figure C.1. The left-hand graph shows
the states and transitions of the basic process, and the sets of nodes identiﬁed by
pre-normalization. These are mapped to the normal form transition diagram on
the right. Each node on the right is marked with its set of minimal acceptances (inthis case, as this is a deterministic process, there is just one of these for each node,
namely its set of initials).
In this case the pre-normal form nodes are all semantically distinct, and so
the ﬁnal bisimulation makes no further identiﬁcation.
The complexity of normalization
Given that the pre-normalization process builds a transition system over the powerspace of the original one, there is the possibility that the normal form will be
exponential in the size of the original system. This can indeed occur, as is shownC.1

Basic operation547{{left}}

left
right

right

left

τ

{{left,right}}
right

τ

right

left

left

{{left,right}}
left
right

τ

τ

left
right

right

{{right}}

left

Figure C.1 Normalizing a transition system.
by the example below. This possibility is to be expected given the result [63] thatchecking failures/divergences reﬁnement of transition systems is PSPACE-hard (acomplexity class at least as hard as NP).
Fortunately there are two mitigating factors that work in our favour, making
this particular obstacle more or less disappear.
1. ‘Real’ process deﬁnitions simply do not behave as badly as the pathologicalexample below. In practice it is rare for the normal form of a naturally
occurring process to have more states than the original transition system.
Indeed, the normal form is frequently signiﬁcantly smaller, oﬀering scope forintermediate compression. It seems that deciding reﬁnement is one of thatlarge class of NP-complete and similar problems where the hard cases arerare.
2. It is only the speciﬁcation end of the reﬁnement that we have to normalize.

548

The operation of FDR
In practice the simpler process is usually that one rather than the implementation. Frequently, indeed, the speciﬁcation is a representation of an
abstract property such as two events alternating or deadlock freedom, andhas a trivial number of states.
One would usually expect that a process playing the role of a ‘speciﬁcation’ is reasonably clearly and cleanly constructed, with understandable
behaviour. These aims are more-or-less inconsistent with the sort of nondeterminism that leads to an explosion in the normal form.

Example C.1.1 The potential for state explosion on normalization is shown in
extreme form by the following pathological system, deﬁned for any n > 0. We
construct a transition system with n + 1 states and n events {1, . . . , n} = B . If thek th state is Pk we deﬁne
P0
Pk
Pn

= STOP= ?r : B → Pk +1= ?r : B → P0
2?r : B → P1
2?r : B → Prk ∈ {1, . . . , n − 1}This system is illustrated in Figure C.2. The pre-normal and normal formsof this system (with initial state P1 ) both have precisely 2n − 1 states (one for each
non-empty subset A of the states P1 , . . . , Pn since, as can be proved by induction on
the size of A, there is for each such subset a trace sA such that the states reachable
on sA are A and perhaps P0 ). The role of the state P0 is to allow us to distinguishbetween these sets: if it is in the set reachable after a given trace, then P1 candeadlock after that trace, otherwise not. If the state P0 is removed we get a systemwith the same number of pre-normal form states but only one normal form state,since every one is then semantically equal to RUN B . (End of example)
The pragmatics of normalization
While you are never likely to happen upon a system which behaves as badly as theone above by accident, you are likely to come across some where normalization isslow and expands rather than contracts the process it is applied to. Fortunately
this happens much more often when normalization is being used as a compressionfunction (as described in the Section C.2) where it is optional, rather than when it
is being used on a speciﬁcation, where it is compulsory and automatic.
The size of system it is possible to normalize depends on the size of theunderlying system, the size of the sets comprising the pre-normal form nodes, andthe number of transitions and minimal acceptance sets, amongst other things. Thus
while you may have no problem normalizing a 50,000-state process, another one

C.1

Basic operation

549

P1
P2
2

P3

= all events

3

n-1

Pn-1
Pn
P0

Figure C.2 Transition system with pathological normalization.

of 5,000 can turn out to be too slow or demanding of memory. In any case thesubstantial transformation performed by normalization means that it can only beapplied to systems which are, at best, one or two orders of magnitude smaller thanthose which can be used on the right-hand sides of reﬁnement checks.
Bear in mind that hierarchical compression, as described in the next section,is at least as useful in helping the normalization of complex speciﬁcations as it ison the implementation side.

C.1.3

Checking reﬁnement

Given that determinism checking is reduced by the algorithm given on page 225
to reﬁnement checking, and both divergence freedom and deadlock freedom arenaturally expressed as reﬁnement checks, the only basic function of FDR we haveto detail further is reﬁnement checking.
Once the speciﬁcation end of a reﬁnement check has been normalized, thefollowing two phases are necessary to establish failures/divergence reﬁnement.

550

The operation of FDR• Establish which states of the implementation transition system are divergent,marking them as such.
• Model-check the implementation, thus marked, against the normal form.

Only the latter is necessary for reﬁnement checks over F and T . For N these twophases can (as was the case in early versions of FDR) be done one after the other,or interleaved.
A state P of a ﬁnite LTS is divergent if, and only if, the directed graphformed by considering only τ actions has a cycle reachable from P . There are twostandard algorithmic approaches to this problem: computing the transitive closureof the graph or taking advantage of the properties of depth-ﬁrst search (DFS).
A DFS algorithm can be used to ﬁnd the strongly connected components of thedirected graph formed by an LTS under τ actions: the maximal collections of nodes
which are mutually reachable. Subject to various assumptions about speed of array
access, etc., there are algorithms to do this, such as Tarjan’s algorithm, which
are essentially linear. Since any cycle is necessarily contained in a single strongly
connected component, this easily yields a method for identifying divergent nodes.
In the main, model-checking phase we have to discover whether all the behaviours of each implementation state are allowable in all the normal form statessuch that they have a trace in common. This is done by exploring the Cartesian
product4 of the normal form and implementation state machines as follows. (Herewe describe what is done for the failures/divergences model N ; the other models doessentially the same on the behaviours relevant to them. For simplicity we do notcover here the special cases required to deal with  actions.)
We maintain a set of checked pairs and a set of pending pairs; initially theformer is empty and the latter is the singleton set of the pair of initial states of thetwo systems. Until it is empty, we repeatedly inspect pairs from pending. The pairν, w  checks if (i) the normal-form state ν is divergent or (ii) the implementation
state w is non-divergent and• the set of initial actions of w is a subset of those of ν and• either w is unstable (has a τ -action) or the set of actions it refuses (thecomplement of its initials) is a subset of one of the maximal refusals of ν.
The set of all pairs reachable from ν, w  and not in checked is added to pending. A
pair ν  , w   is reachable from ν, w  if either
4 The fact that you are exploring the Cartesian product means that occasionally the model-

checking phase visits more ‘states’ than there are states in the implementation. This happens whenproving reﬁnement demands that a single implementation state reﬁnes more than one speciﬁcation
state. This is relatively rare in practice.

C.1

Basic operation

551

τ(a) w −→ w  and ν = ν  , oraaa(b) w −→ w  and ν −→ ν  for a = τ ; noting that whenever w −→ w  , then thisν  must exist and be unique.
If a pair is found which fails to check, then the proposed reﬁnement does nothold. If the above process completes without ﬁnding such a pair, then reﬁnement
does hold.
The ﬁrst case (failure of reﬁnement) is easy to see: the implementation has
a trace (the sequence of visible actions used to bring the Cartesian product to thefailing state-pair), which can bring it into a state with behaviours not possible forthe normal form. This means there is a divergence, a trace or a refusal of theimplementation that is not allowed in the speciﬁcation. Provided we have a wayof ﬁnding the trace that led to a speciﬁc pair ν, w  being considered, it is thus
possible to report not only the failure of reﬁnement but also a reason.
Conciseness being a virtue, it is as well to report the shortest possible sequence of actions that can lead to an error. This is achieved if we perform abreadth-ﬁrst search (BFS) during the model-checking phase. We will see later that
this brings other advantages.
The case of successful proof is a little more subtle. One can justify theclaim that reﬁnement always holds in these circumstances either operationally or
abstractly. If reﬁnement fails then, from an operational perspective, this is because
the implementation has some behaviour that is banned by the normal form. Thereis therefore some sequence of actions which exhibit this, potentially bringing theimplementation into some state w where it can (a) diverge illegally, (b) perform
an event that takes the traces outside the set permitted by the normal form or (c)refuse a set not refused by the normal form. It is clear that the unique normal form
state ν corresponding to this trace is such that ν, w  will be found in the search
above, leading to a failure to check.
Abstractly, one can show that the reﬁnement-checking process is simultaneously formulating and proving a sort of mutual recursion induction over the state
space of the implementation akin to those analyzed in Section 9.2.
Breadth-ﬁrst searching
In a large reﬁnement check you may have to search through state spaces with many
millions of states, with similar numbers of transitions being found for the states at
each level. It is of vital importance to manage these eﬃciently.
The algorithms FDR uses show an interesting diﬀerence between the DFS
used for divergence checking and the BFS used for model checking. Both of thesealgorithms rely on the maintenance of sets of which states have been visited before.

552

The operation of FDR

In a DFS we need a constantly updated representation of this set so that we candiscover whether the state we are looking at has been visited before. Since we
immediately look at the children of the most recently visited node, there is nopotential for grouping these tests. In order to perform this you either need a muchlarger and more complex representation of the LTS (such as that generated by the
explicate function described in the next section) or a hash table.
In performing a BFS there is a high latency between generating a pending
state and actually visiting it, if it is new. The test of whether it is new can be
performed at any time during this interval. A natural way of doing this is to lookat all successor states generated during a particular ‘layer’ of the search. If thecurrent list of visited states is stored as a sorted structure (a list or a B-tree5 ), thenwe can ﬁnd out which of the successors are new by sorting the successors (naturally,
removing duplicates) and then merging them into the established structure. Obviously the successors of each genuinely new state can be generated as it is mergedin.
This latter method has been found to be faster and more memory-eﬃcientthan the former. The greatest beneﬁt appears when the set of states becomes toolarge to ﬁt within the physical memory of the computer. Hash table representationsof sets map so badly onto virtual memory that they are eﬀectively unusable at thislevel. The sorted representation maps onto virtual memory extremely well: accessinto the lists or B-trees is sequential. Especially with the B-tree version, we havefound very little degradation in performance in checks when they are forced to use
virtual memory.
This fact has meant that it is often signiﬁcantly quicker to perform the modelchecking phase than the divergence-checking, and indeed the former can frequently
be performed on systems when the latter is not within reach. This is why it is frequently better to factor a FD check in FDR into a proof (perhaps not automated)of divergence freedom and a failures-only reﬁnement check.
One of the primary reasons for the introduction of the B-tree method ofstoring states in recent versions of FDR was the fact that the speed and memory
capacity of modern machines was making it all to easy to exceed the maximum
process size that operating systems permit (typcially 1 or 2 Gb) when all states
were contained within a single process. The B-trees make it easier to spread theaccumulated state space across a number of temporary ﬁles on disc, and indeed thatis what the latest versions of FDR do. The application of data-compression methods
on these ﬁles overcomes the ineﬃciency that B-trees are, by their nature, typically
only part-full. The space per state used by checks varies substantially depending
5 Versions of FDR2 before 2.60 used lists, and versions after have used B-trees, which has beenfound to carry signiﬁcant advantages in terms of eﬃciency.

C.2

Hierarchical compression

553

on the complexity of the processes being stored, but with this data compression
on reasonably simple process structures you might typically use 11 or 12 bytes perstate-pair, on a large check.

C.1.4

Parallel FDR

FDR has been modiﬁed to run on a cluster of PC’s. State-pairs are distributed
across a number of PC’s by using a hash function, and each processor is responsible
for looking after and working out the successors of the ones it is allocated. Periodically it sends those successors which do not belong to it over to the appropriate
processor in blocks. At the time of writing it is only the traces and failures reﬁnement checks that are parallelised, but more aspects such as divergence checking
may follow.
Experience has shown that the speed-up obtained is usually close to linear.
Readers wanting to know more about this development are advised to contact Formal Systems.

C.2

Hierarchical compression

The state spaces of systems described in CSP or any similar notation can grow very
quickly as the number of parallel components increases. In the worst case – onethat is unfortunately often experienced – this growth is exponential. Anyone who
experiments with many variable-sized systems on FDR will quickly encounter it anddiscover that it is all too easy to build networks which exceed the order 106 –107
states that can conveniently be handled on a typical workstation or PC.
If one wants to deal with larger state spaces then it is necessary to ﬁndsome way of avoiding visiting each state explicitly. Several clever approaches havebeen taken to this in the model-checking community as a whole; the ones that havebeen successfully used for reﬁnement checking CSP are Binary Decision Diagrams(BDDs), and hierarchical compression. BDDs provide a radically diﬀerent methodof reﬁnement checking to the one outlined in the previous section: in it, the statemachines and reﬁnement relations are encoded as logical formulae and checked inthat form. BDDs have proved very successful in many hardware design applications,see [23], for example. Several people have developed BDD-based tools for CSP, forexample [139]: it is hoped to include an up-to-date list of these in the web site sitereferenced in the Preface.
At the time of writing, FDR does not include BDD capability, though thismay change in the long term. It does, however, support hierarchical compression,

554

The operation of FDR

which is a technique directly rooted in the semantic theory of CSP6 . The basic idea
is to take the description of a complex CSP process, say P  Q, and instead ofX

calculating the state space given it by the operational semantics, ﬁnding smaller
LTSs representing P and Q and combining these. This is done by calculating thecomplete state spaces of P and Q and applying a compression function. If, forexample, P and Q are both 1,000 state processes but can be compressed to 100
each, this may have reduced the states of the complete system from 106 to 104 .
The crucial results which support this technique are the congruences between theoperational and denotational semantics (see Section 9.4), since that means that theoverall denotational semantics of any context C [P1 , P2 , . . . , Pk ] depends only on thedenotational semantics of P1 , . . . , Pk , not on the precise LTSs chosen to represent
them. Thus, if you have evaluated the operational semantics of the Pi , in building arecipe for an implicit machine to represent the complete context you can replace theresulting component LTSs with any smaller ones which happen to have equivalentsemantics.
C.2.1

Methods of compression

At the time of writing, FDR2 uses ﬁve diﬀerent methods of taking one LTS andattempting to compress it into a smaller one. Each of these is called by simply
applying a function to the process you want to compress. Since these do not change
the semantic value of the process they are applied to, FDR terms them transparent
functions. Each one you want to use has to be declared as such.
1. Normalization (normal(P)) is as discussed in Section C.1.2. It can givesigniﬁcant gains, but it suﬀers from the disadvantage that by going throughpowerspace nodes it can be expensive and lead to expansion.
2. Strong bisimulation (sbisim(P)): the standard notion deﬁned in Section 7.2
enriched (as necessary) by any labellings of minimal acceptances and/or divergences found on the nodes. FDR computes this relation by using explicit
iteration based on the proof of Tarski’s theorem for continuous functions (seepage 501) to ﬁnd the maximal bisimulation on the input LTS, which is thenfactored by this relation. Ordinarily, bisimulation is faster than normalization and can be applied to larger systems. The size of system it can beapplied to still depends somewhat an the application, though less so thanwith normalization.
6 It is possible to base similar compression methods on congruences for other languages thanCSP, as shown, for exmaple, in [43], and we were by no means the ﬁrst people to point out theadvantages of CSP equivalences for this purpose [133].

C.2

Hierarchical compression

555

Applied to the process shown in Figure C.1, strong bisimulation would
give no compression at all: it would not identify any nodes. The sort ofbehaviour it can compress is shown in Figure 7.4 on page 160.
3. τ -loop elimination (tau loop factor(P)): since a process may choose automatically to follow a τ action, it follows that all the processes on a τ -loop(or, more properly, a strongly connected component under τ -reachability) areequivalent. Therefore all the nodes on such a component can be identiﬁed.
As discussed in the previous section, this calculation is done via depth-ﬁrst
search algorithms.
Since this can only compress divergent processes, its stand-alone uses
are necessarily rather specialized. It exists mainly as a precursor to diamond,described below.
4. Diamond elimination (diamond(P)): this carries out a transformation whichcuts out all τ actions from an LTS. Like normalization, it produces an LTS
with explicitly marked minimal acceptance and divergence information, but
unlike normalization it never increases the number of nodes. (It can, on
occasion, have the drawback of creating large numbers of transitions between
states.)It applies τ -loop elimination as its ﬁrst step. A detailed description of
the diamond transformation can be found in [119].
Applied to the system of Figure C.1, diamond compression will produce identical results to normal, i.e., the four-state process.
It is often a good idea to apply strong bisimulation to the result of adiamond compression.
5. Factoring by semantic equivalence (model compress): the compositionalmodels of CSP we are using all represent much weaker congruences thanbisimulation. Therefore if we can aﬀord to compute the semantic equivalence
relation over states it will be at least as good a compression as bisimulation tofactor by this equivalence relation. A formal justiﬁcation of this method canbe found in [119]. As with normal, the degree of compression this function
gives depends on which model is being used.
The algorithm used to compute these equivalences is based on an extension to normalization. On the basis of our experience so far the cost of
this function (it is the slowest of all the compressions to compute) is not
usually worth the usually small extra beneﬁts. Therefore we will not discuss
it further here.
Some of these functions, if given an ordinary LTS, will return a Generalized LTS,an LTS where nodes may be marked with divergence or minimal acceptance infor-

556

The operation of FDR

mation. In fact, therefore, the whole of FDR is programmed to operate with these
GLTSs rather than the basic sort.
The range of options is supplied because the one that is most eﬀective varies
with example. In the author’s experience, the most eﬀective is usually either
normal(P) or sbisim(diamond(P)). Normalization tends to work well where theinternal choices present in P do not result in a lot of externally visible nondeterminism arising for subtle reasons. Diamond elimination, and to a lesser extent
normalization, work best on processes with many τ actions.
None of the compression techniques will aﬀect a normalized process: not only
the semantic value but also the transition system will be identical.
There is another transparent function supported by FDR that should be
mentioned, though not a compression function in the sense described above:• explicate(P) takes any description FDR can understand of a (G)LTS andturns it into an explicit list of states, transitions and minimal acceptance/
divergence markings. This is usually applied to any machine implemented
as an implicit supercombinator machine as described on page 544 before
carrying out other transformations. All of the compressions above explicate
their arguments before doing anything else.
It is typically beniﬁcial to explicate a transition system when, likethe compressions, you need to perform a reasonably complex calculation ortransformation of it.
Though chase, described on page 487, is used as a compression function, it
does not (as discussed there) preserve the semantics of nondeterministic processes.
It is therefore declared as external rather than transparent. The same is true ofthe prioritize function discussed on page 420, where implemented.
C.2.2

Using compression

The purpose of using these compression functions is to reduce the number of states
explored when checking or normalizing a complete system. Since the cause of state
explosion is almost invariably the multiplication that arises from parallel composition, the right place to apply compression is to a process that is to be put inparallel with another. These might either be individual sequential components or
subnetworks consisting of a number of these in parallel. You can of course compress
subnetworks built up of smaller ones that have themselves been compressed, and soon.
It is diﬃcult to give any hard and fast rules about when compression techniques will work eﬀectively. The author has frequently been surprised both at how

C.2

Hierarchical compression

557

well they work on some examples and at how badly they work on others. Some
examples are given below and the reader will ﬁnd many more in the ﬁles to befound on the web site, but there is no real substitute for personal experience.
Broadly speaking, you have a reasonable chance of success when the following
are all true:(a) Part of the alphabet of the process you are compressing has been hidden,
either because the hidden events are true internal actions or because they
have been abstracted as irrelevant to the speciﬁcation (following the principles set out in Section 12.2).
(b) It sometimes helps if these hidden actions represent progress within the process, as opposed to the resolution of nondeterminism.
(c) It is not the case that a large part of the state space of the process you arecompressing is never visited when it is put into the complete system. (Thedanger here is that you will expend too much eﬀort compressing irrelevant
states, or that the irrelevant states will make the subsystems too large tocompress. Some tricks for getting round this type of problem are illustrated
in example ﬁles.)The following principles7 should generally be followed when you are structuring a network for compression:
1. Put together processes which communicate with each other together early.
For example, in the dining philosophers, you should build up the system outof consecutive fork/philosopher pairs rather than putting the philosophers all
together, the forks all together and then putting these two processes together
at the highest level.
2. Hide all events at as low a level as is possible. The laws of CSP allow the
movement of hiding inside and outside a parallel operator as long as its
synchronizations are not interfered with. In general, therefore, any eventthat is to be hidden should be hidden the ﬁrst time that (in building up theprocess) it no longer has to be synchronized at a higher level. The reason forthis is that the compression techniques all tend to work much more eﬀectively
on systems with many τ actions.
We give three examples here, each of which indicates a diﬀerent class of
network where compression can be used with considerable success.
7 The second of these principles is easy to automate if the description of a network is input

into FDR in a format that allows it to apply the necessary laws. The best choices to follow in
automating the ﬁrst are rather more subjective, and the success in getting a program to makewhat turn out to be the ‘right’ decisions consequently more variable.

558

The operation of FDR

Figure C.3 Modular compression strategy.

Example C.2.1 Compression is likely to work well if some subcomponent of a
network is relatively self-contained. It may have complex internal behaviour, while
its external functionality is comparatively simple.
Imagine, for example, a communication service which uses a number of copiesof the alternating bit protocol to overcome an error-prone medium. We might havea ring of nodes Ni (i ∈ {0, . . . , K − 1}) with a channel between Ni and Ni⊕1 being
implemented by an ABP. There would thus be K copies of this process.
Each copy of the alternating bit protocol would have many fewer states once
compressed: if the type it operates over has size 2 (as is frequently justiﬁable
by data-independence as discussed in Section 15.3.2) the reduction (on applying
normal) will typically be from some 100’s or 1000’s of states to just 3 states. Thus
the overall reduction in state-space size is by a factor of perhaps 100K . The structureof this compression is illustrated in Figure C.3. For obvious reasons we might term
this strategy modular compression.
This speciﬁc case is, in a sense, too good in that it is easy to ﬁnd a di-

C.2

Hierarchical compression

559

FORK0

PHIL0
FORK 1

PHIL1

FORK2

PHIL2

Figure C.4 Inductive compression strategy applied to dining philosophers.

rect representation of the process an ABP compresses to (namely COPY ) and use
properties of reﬁnement eﬀectively to perform the compressions by hand (simply
substituting a COPY for each ABP in the program text). One does frequently,
however, come across cases where the reduced components are, while signiﬁcantly
more complex than this, still a great improvement on the originals.
The whole concept of hierarchical compression, but especially modular compression, has a lot in common with the idea of compositional development describedon page 47. The only diﬀerence is that here the intermediate speciﬁcation is computed automatically.
Example C.2.2 A second class of example which tends to work well is provided
by networks whose communication graph is basically one-dimensional, in the sensethat it either is a chain of processes or is built in a simple way by joining a few
chains together. These frequently, though not invariably, compress well provided
it is possible to build up the chains in a way that hides all or nearly all of thealphabets of the processes that are not at the ends of partially constructed chains.
A typical example of this is provided by the deadlock analysis of the dining

560

The operation of FDR

philosophers which can, of course, be built up as a chain until the two ends arejoined together. We use the fact, discussed in Section 8.4, that over the stable
failures model F a process P is deadlock-free if and only if P \ Σ is. The dining
philosophers network with all events hidden can be structured
K −1

(

i=0

(PandF i , APi )) \ Σ

where PandF i is the combination
PHILi  FORK i
AFi

We can take the process deﬁnitions to be either those used in Section 2.2.1 (which
deadlock) or as revised in Section 13.2.4 (made asymmetric so they do not). The
law hide-X Y -dist (3.7) is then used to push the hiding into the parallel network,
which can then be deﬁned with compression:
C1
Cn+1= PandF 0= compress(Cn \ (Σ  In )) In APn PandF n

for n < K

Here, In are the events that the chain Cn of the ﬁrst n philosopher/fork pairs has
to synchronize with other processes, namely{picksup.K −1.0, putsdown.K −1.0, picksup.n−1.n, putsdown.n−1.n}This leaves only APK −1 to hide at the outside. As mentioned earlier, in practicethe manipulation of hiding is done automatically.
If compress is chosen to be normalization, each Cn for n < K reduces tojust four states independent of n (basically one state for each combination of thefork at either end being up or down). Thus K philosophers can be checked in time
linear8 in K , though the uncompressed network has exponentially many states. The
inductive compression structure used here is shown in Figure C.4.
Example C.2.3 Our ﬁnal example is taken from Milner’s text [82]. Like the dining philosophers, it is a ring network, but it turns out to have rather diﬀerent
characteristics. The code given here is translated (trivially) from CCS.
It is a ‘scheduler’ which has the job of arranging two classes of event: a.i andb.i for i ∈ {0, . . . , N − 1}. It lets the a.i happen in strict rotation and (for every i )insists on precisely one b.i occurring between each pair of a.i ’s. Milner’s network
8 In fact, using a doubling-up technique rather than adding one at a time, you can check 2K
philosophers in O(K ) time: see [119].

C.2

Hierarchical compression

561

achieves this with a ring of simple cell processes connected using an extra, internal
channel c:Cell (0) = a.0 → c.1 → b.0 → c.0 → Cell(0)Cell (i ) = c.i → a.i → c.i ⊕ 1 → b.i → Cell (i ) if i > 0
The diﬀerent case for 0 reﬂects that the rotation of the a.i starts with a.0. The
alphabet ACi is just the four events Cell (i ) uses, in the network description
N −1

Scheduler = (i=0(Cell (i ), ACi )) \ {| c |}There are various speciﬁcations one might wish to prove of this: that it isdeadlock-free,9 that the a.i do in fact rotate, and something about the relationships
between a’s and b’s. Like the dining philosophers, the number of states in thisnetwork grows exponentially with its size (it is, in fact, N 2N ), so in order to deal
with a large one it is necessary to use compressions.
Essentially the same inductive strategy as over the dining philosophers works
reasonably well for proving deadlock freedom: one adds a Cell at a time while hiding
all events not needed for external synchronization. (The external events of the cells
from 0 to n − 1 are {c.0, c.n}.) In this case the number of states of a partiallyconstructed network grows linearly with size, resulting in an overall quadratic (i.e.,O(N 2 )) check.
To prove that the a.i rotate we use a trace speciﬁcation with alphabet {| a |}:ASpec(0) where
ASpec(n) = a.n → ASpec(n ⊕ 1)
leading to the reﬁnement check
ASpec(0)T

Scheduler \ {| b |}Interestingly, in this case, the inductive strategy fails badly with the state spaces ofthe partially constructed networks growing exponentially. The reason for this turns
out to be a possibility we mentioned earlier: it is actually the case that with the
network Scheduler , properties of the entire network prevent partially constructed
chains getting into many of the states they could reach if working by themselves.
The operation of this system is rather like a token ring (as discussed, for example, on
page 311), with the token currently being held by the Cell i that has communicated
9 Note that it is, in fact, a cyclic communication network of the type described in Section
13.2.2. The methods given there easily establish deadlock freedom, should you wish to follow thatapproach.

562

The operation of FDR

c.i more recently than c.i ⊕ 1. The complete ring maintains the invariant that there
is only one token, and this simpliﬁes its state space considerably. The problem isthat, rather like the incomplete railway network in Figure 13.10, the partial networks
built up in the inductive approach do not enjoy this simplifying property.
Fortunately, a simpler approach, which one might term leaf compression
works very well in this case. The only compressions are applied to the individualcomponents of the network after distributing the abstraction of irrelevant events.
In this case this gives the check:ASpec(0)

N −1

T

(

i=0

(normal(Cell (i ) \ {b.i }), ACi )) \ {| c |}This gives a linear time check (with 2N states), and in fact the same approach(where the set hidden on Cell i becomes {a.i , b.i }) works better than inductive
compression for deadlock freedom, since it is now a linear time check (with N
states).
If presented with a speciﬁcation involving all the events in {| a, b |}, suchas the assertion that the total number of b’s lies between the number of a’s andthat number minus N , there seems to be no compression of Scheduler which will domuch good. Too many essentially diﬀerent states exist with respect to the alphabet
we need to see to decide the speciﬁcation. You can, however, successfully deal withchecks involving only a few events, such as showing that the number of a.i and b.j(for any chosen pair (i , j )) never diﬀer by more than 2. (End of example)
Leaf compression, thanks to its simplicity and the fact that it is very unlikely to lead to computational problems in the calculation of the compressions
themselves, is probably the ﬁrst thing you should try on a system for which it ispossible to abstract a reasonable number of events that are speciﬁc to individualcomponents (i.e., unsynchronized with others). This approach would have produced
a substantial reduction in the number of states checked in the dining philosophersfrom the uncompressed version, but the number of states would still have grownexponentially.10 Thus diﬀerent methods work well in diﬀerent circumstances: theexamples given here are indicative of the type of places where you can expect thevarious strategies to succeed or fail, but as we said earlier it is not possible at thetime of writing to give any hard and fast rules.
The example ﬁles contain these examples and more, and include generalpurpose high-level functions for implementing inductive and leaf compression, generalizations of them using mixed abstraction rather than just hiding, and further
strategies we have not had space to describe here.
10 The growth slows from approximately 6N to approximately 2N .

Notation

This glossary sets out some of the mathematical notation in this book. Descriptions
marked thusI have a reference in the main index, and those marked thusP have one
in the process index; in either case further information can be obtained by referringto that. For notation, such as initials(P ), with an obvious alphabetical place in theindexes, you should refer directly there.
Many pieces of notation whose use is relatively localized (to a single chapter
or section) are not included below.
Sets and numbers
a ∈x
x ⊆y
{}
{a1 , . . . , an }x ∪ y,Xx ∩ y,X (X = {})x yset membership (true iﬀ a is in x )subset (∀ a.a ∈ x ⇒ a ∈ y)
the empty set
set containing these elements
union
intersection
diﬀerence (= {a ∈ x | a ∈ y})

P(x )
x ×y
x →y

powerset (= {y | y ⊆ x })Cartesian product (= {(a, b) | a ∈ x ∧ b ∈ y})
the space of all functions from x to y

N
Z
R
R+

natural numbers ({0, 1, 2, . . .})integers ({. . . , −2, −1, 0, 1, 2, . . .})real numbers
non-negative real numbers⊕,addition and subtraction modulo the appropriate base564 Notation
Logic
x ∧y
x ∨y
¬x
x ⇒y
x ⇔y
∀ x .χ
∃ x .χ

conjunction (x and y)
disjunction (x or y)negation (not x )implication (≡ (¬x ∨ y))double implication ((x ⇒ y) ∧ (y ⇒ x ))universal quantiﬁcation (χ holds for all x )existential quantiﬁcation (χ holds for at least one x )Communications
Σ(SigmaI ): alphabet of all communications
(tick) terminationI signal
τ(tauI ): the invisible actionΣ ∪ {}ΣΣ ∪ {, τ }
Σ,τ
a.b.c
c?x
c!e
{| a, b |}compound event (see page 26)
inputI
outputI
events associated with channels (see page 27)

Sequence/trace notation (see pages 36 and 43)
A∗
A∗
Aω

set of all ﬁnite sequences over A
A∗ ∪ {sˆ | s ∈ A∗ }set of all inﬁnite sequences over Aa1 , . . . , an 
sˆt
s\X
sX
#s
s↓a
s↓c

the empty sequence
the sequence containing a1 ,. . . , an in that orderconcatenation of two sequences
hiding: all members of X deleted from s
restriction: s \ (Σ  X )length of s
(if a is an event) number of a’s: #(s  {a})(c a channel) sequence of values communicated on c in ss≤ts  t (⊆ Σ∗ )(≡ ∃ u.sˆu = t) preﬁx order
generalized parallelIX

s ||| t (⊆ Σ∗ )interleavingI

S

closureI of S (= S ∪ {u ∈ Σω | ∀ s < u.s ∈ S })Note that sequence-like notation is also used to denote vectors indexed by arbitrary
sets, usually with reference to mutual recursion, for example Bs∞ | s ∈ T ∗ .

Notation
Processes
For machine-readable CSP, see Appendix B.
µ p.P
a→P
?x : A → P(a → P | b → Q)
P 2Q
P Q,
S
P<
b>
Q
I I
P Q
P X Y Q
P Q

recursionI
preﬁxingI
preﬁx choiceI
guarded alternativeI
external choiceI
nondeterministic choiceI
conditional choiceI
synchronous parallelI
alphabetized parallelI
generalized parallelI

X

P ||| Q
P \X
f [P ]
P [[R]]
P [[a /b ]]a.PP; QP >> Q
P //X QP //m : Q
P Q
P aQ

interleavingI
hidingI
renamingI (functional)
renamingI (relational)
renamingI (relational, by substitution)
process namingI
sequential compositionI
pipingI (or chaining)
enslavementI
enslavementI (of a named process)‘time-out’ operator (sliding choice)I
interruptI

P [x /y]P /sP ↓nsubstitution (for a free identiﬁer x )‘after’I operator
restrictionI to depth n (model dependent)

LH (P )
EH (P )MSH (P )lazy abstractionI
eager abstractionI
mixed abstractionI565

566 Notation
Transition systems (see Section 7.2)
ĈaP −→ QsP =⇒ QtP −→ Q

The set of nodes in transition system C .
(a ∈ Σ,τ ) single action transition(s ∈ Σ∗ ) multiple action transition with τ ’s removed(t ∈ (Στ )∗ ) multiple action transition with τ ’s retainedτ ∗ (P )P ref B
P div({Q | P =⇒ Q}) τ -expansion of P (see page 545)
P refuses B
P diverges

Semantic models
T
traces modelIN
failures/divergences modelIF
stable failures modelII
inﬁnite traces/divergences modelIU
failures/divergences/inﬁnite traces modelI
⊥N
F

P ≤Q

bottom elements of modelsP
top elements of modelsP
traces reﬁnement
failures/divergences reﬁnement
failures reﬁnement (i.e., over F)
reﬁnement over I
reﬁnement over U
reﬁnement over whatever model is clear from the context(with a special meaning in parts of Chapter 12, and witha default of FD )strong orderI (over N or U)

D
Td

set of deterministicI processes
possibly deterministic members of T (see page 222)

(etc.)(etc.)T
FD
F
I
U

Partial orders
X least upper bound
X greatest lower boundµf
least ﬁxed point of f

Bibliography[1] L. Aceto and M. Hennessy, Termination, deadlock and divergence, Proceedings of
MFPS89, Springer LNCS 442, 1989.
[2] P.G. Allen, A comparison of non-interference and non-deducibility using CSP, Proceedings of the 1991 IEEE Computer Security Workshop, IEEE Computer Society
Press, 1991.
[3] R. Alur and T. Henzinger, Logics and models of real time: a survey, in ‘Real time:
theory in practice’ (de Bakker et al, eds), Springer LNCS 600, 1992.
[4] K.R. Apt and D.C. Kozen, Limits for automatic veriﬁcation of ﬁnite-state concurrent
systems, 307–309, Information Processing Letters 22, 6, 1986.
[5] G. Barrett, The ﬁxed-point theory of unbounded nondeterminism, Formal Aspects ofComputing, 3, 110–128, 1991.
[6] G. Barrett and M.H. Goldsmith, Classifying unbounded nondeterminism in CSP, in‘Topology and category theory in computer science’ (Reed, Roscoe and Wachter,eds), Oxford University Press, 1991.
[7] G. Barrett and A.W. Roscoe, Unbounded nondeterminism in CSP, Proceedings of
MFPS89, Springer LNCS 442, 1991.
[8] J.D. Beasley, The ins and outs of peg solitaire, Oxford University Press, 1985.
[9] J.A. Bergstra and J.W. Klop, Process algebra for synchronous communicaction, Information and Control, 60, 109–137, 1984.
[10] J.A. Bergstra and J.W. Klop, Algebra for communicating processes with abstraction,
Theoretical Computer Science, 37, 1, 77–121, 1985.
[11] R.S. Bird, Introduction to functional programming using Haskell, second edition,
Prentice Hall, 1998.
[12] S.R. Blamey, The soundness and completeness of axioms for CSP processes, in‘Topology and category theory in computer science’ (Reed, Roscoe and Wachter,eds), Oxford University Press, 1991.

568 Bibliography[13] P.J. Broadfoot and A.W. Roscoe, Embedding agents within the intruder model todetect parallel attacks, Journal of Computer Security, 12, 2004.
[14] N.A. Brock and D.M. Jackson, Formal veriﬁcation of a fault tolerant computer,
Proceedings of 1992 Digital Aviation Systems Conference, IEEE Computer Society
Press, 1992.
[15] S.D. Brookes, A model for communicating sequential processes, Oxford University
D.Phil thesis, 1983. (Published as a Carnegie-Mellon University technical report.)[16] S.D. Brookes, Fair communicating processes, in ‘A classical mind: essays in honourof C.A.R. Hoare’, Prentice Hall, 1994.
[17] S.D. Brookes, The essence of Parallel Algol, Proceedings of the 11th IEEE LICS,
1996.
[18] S.D. Brookes, C.A.R. Hoare and A.W. Roscoe, A theory of communicating sequential
processes, Journal of the ACM 31, 3, 560–599, 1984.
[19] S.D. Brookes and A.W. Roscoe, An improved failures model for CSP, Proceedingsof the Pittsburgh seminar on concurrency, Springer LNCS 197, 1985.
[20] S.D. Brookes and A.W. Roscoe, Deadlock analysis in networks of communicatingprocesses, in ‘Logics and models of concurrent systems’ (K.R. Apt, ed.) NATO ASI
series F, Vol. 13, Springer, 1985.
[21] S.D. Brookes and A.W. Roscoe, Deadlock analysis in networks of communicatingprocesses, Distributed Computing, 4 209–230, 1991.
[22] S.D. Brookes, A.W. Roscoe and D.J. Walker, An operational semantics for CSP,
Technical report, 1988.
[23] J.R. Burch, E.M. Clarke, K.L. McMillan, D.L. Dill and L.J. Hwang, Symbolic model
checking: 1020 states and beyond, 142–170, Information and Computation 98, 2,
1992.
[24] E.M. Clarke, R. Enders, T. Filkorn and S. Jha, Exploiting symmetry in temporal
logic model checking, Formal Methods in System Design, 9, 77–104, 1996.
[25] G. Colouris, J. Dollimore and T. Kindberg, Distributed systems, concepts and design,
Addison-Wesley, 1994.
[26] S. Creese and A.W. Roscoe, Verifying an inﬁnite family of inductions simultaneously using data independence and FDR, Proceedings of Formal Description Techniques for Distributed Systems and Communication Protocols and Protocol Speciﬁcation, Testing and Veriﬁcation (FORTE/PSTV’99), October 5-8 1999, Beijing,
China. Published by Kluwer Academic Publishers.
[27] S. Creese and A.W. Roscoe Data independent induction over stuctured networks,
Proceedings of PDPTA2000[28] N. Dathi, Deadlock and deadlock-freedom, Oxford University D.Phil thesis, 1990.
[29] J.W.M. Davies, Speciﬁcation and proof in real-time CSP, Cambridge University
Press, 1993.

Bibliography569[30] J.W.M. Davies, D.M. Jackson, G.M. Reed, A.W. Roscoe and S.A. Schneider, Timed
CSP: theory and applications, in ‘Real time: theory in practice’ (de Bakker et al,eds), Springer LNCS 600, 1992.
[31] J.W.M. Davies and S.A. Schneider, A brief history of Timed CSP, Oxford University
Computing Laboratory technical monograph PRG-96, 1992.
[32] R. de Nicola and M. Hennessy, Testing equivalences for processes, Theoretical Computer Science 34, 1, 83–134, 1987.
[33] E.W. Dijkstra and C.S. Scholten, A class of simple communication patterns, in‘Selected writings on computing’, EWD643, Springer-Verlag, 1982.
[34] E.A. Emerson and A.P. Sistla, Utilizing symmetry when model checking under fairness assumptions: an automata-theoretic approach, 309–324, Proceedings of the 7th
CAV, Springer LNCS 939, 1995.
[35] E.A. Emerson and A.P. Sistla, Symmetry and model checking, Formal Methods in
System Design, 9, 105–131, 1996.
[36] H.B. Enderton, Elements of set theory, Academic Press, 1977.
[37] R. Focardi and R. Gorrieri, Comparing two information-ﬂow properties, Proceedingsof 1996 IEEE Computer Security Foundations Workshop, IEEE Computer Society
Press, 1996.
[38] R. Forster, Non-interference properties for nondeterministic systems, Oxford University D.Phil. thesis, 1999.
[39] Formal Systems (Europe) Ltd, Failures-Divergence Reﬁnement: FDR2 Manual,
1997.
[40] N. Francez, Fairness, Springer, 1986.
[41] , H. Garcia-Molina, Elections in a distributed computing system, IEEE transactions
on Computers, January 1982.
[42] S. Graf, Veriﬁcation of a distributed cache memory by using abstractions, Proceedings of the 6th CAV, Springer LNCS 818, 1994.
[43] S. Graf and B. Steﬀen, Compositional minimisation of ﬁnite-state systems, Proceedings of CAV ’90, Springer LNCS 531, 1990.
[44] J.C. Graham-Cumming, The formal development of secure systems, Oxford University D.Phil thesis, 1992.
[45] I. Guessarian, Algebraic semantics, Springer LNCS 99, 1981.
[46] F. Harary, Graph theory, Addison-Wesley, 1969.
[47] He Jifeng and C.A.R. Hoare, From algebra to operational semantics, Information
Processing Letters, 46, 2, 1993.
[48] He Jifeng, C.A.R. Hoare and A. Sampaio, Normal form approach to compiler design,
Acta Informatica, 30, 701–739, 1993.

570 Bibliography[49] C.L. Heitmeyer and R.D. Jeﬀords, Formal speciﬁcation and veriﬁcation of real-timesystem requirements: a comparison study, U.S. Naval Research Laboratory technicalreport, 1993.
[50] A. Hojati and R.K. Brayton, Automatic datapath abstraction in hardware systems,
98–113, Proceedings of the 7th CAV, Springer LNCS 939, 1995.
[51] M. Hennessy, Algebraic theory of processes, MIT Press, 1988.
[52] M. Hennessy and H. Lin, Symbolic bisimulations, 353–389, Theoretical Computer
Science, 138, 2, 1995.
[53] M.G. Hinchey and S.A. Jarvis, Concurrent systems: formal development in CSP,
McGraw-Hill, 1995.
[54] C.A.R. Hoare, Communicating sequential processes, Communications of the ACM,
21, 8, 666–677, 1978.
[55] C.A.R. Hoare, A model for communicating sequential processes, in ‘On the construction of programs’ (McKeag and MacNaughten, eds), Cambridge University Press,
1980.
[56] C.A.R. Hoare, Communicating sequential processes, Prentice Hall, 1985.
[57] Inmos Ltd., occam2 reference manual, Prentice Hall, 1988.
[58] C.N. Ip and D.L. Dill, Better veriﬁcation through symmetry, Formal Methods in
System Design, 9, 41–75, 1996.
[59] K. Jensen, Condensed state spaces for symmetrical coloured Petri nets, Formal Methods in System Design, 9, 7–40, 1996.
[60] G. Jones and M.H. Goldsmith, Programming in occam2, Prentice Hall, 1988.
[61] B. Jonsson and J. Parrow, Deciding bisimulation equivalences for a class of nonﬁnite-state programs, Information and Computation 107, 2, 272–302, 1993.
[62] A. Jung, ed, Domains and denotational semantics: history, accomplishments andopen problems, 1996.
[63] P.C. Kanellakis and S.A. Smolka, CCS expressions, ﬁnite state processes and threeproblems of equivalence, Information and Computation 86, 43–68, 1990.
[64] R.S. Lazić, A semantic study of data-independence with applications to the mechanical veriﬁcation of concurrent systems, Oxford University D.Phil thesis, to appear
in 1997.
[65] R.S. Lazić, Theorems for mechanical veriﬁcation of data-independent CSP, Oxford
University Computing Laboratory technical report, 1997.
[66] R.S. Lazić, T. Newcomb and A.W. Roscoe, Polymorphic Systems with Arrays, 2Counter Machines and Multiset Rewriting, Proceedings of INFINITY 2004.
[67] R.S. Lazić and A.W. Roscoe, Using logical relations for automated veriﬁcation ofdata-independent CSP, Proceedings of the Workshop on Automated Formal Methods(Oxford, U.K.), Electronic Notes in Theoretical Computer Science 5, 1997.

Bibliography571[68] R.S. Lazić and A.W. Roscoe, A study of data-independence in CSP, Submitted for
publication, 1997.
[69] N.G. Leveson and J.L. Stolzy, Analyzing safety and fault tolerance using timed Petrinets, Proceedings of TAPSOFT, Springer, 1985.
[70] G. Lowe, Pravda: a tool for verifying probabilistic processes, Proceedings of theWorkshop on Process Algebra and Performance Modelling, 1993.
[71] G. Lowe, Breaking and ﬁxing the Needham-Schroeder public-key protocol using FDR,
Proceedings of TACAS ’96, Springer LNCS 1055, 1996.
[72] G. Lowe, Some new attacks upon security protocols, Proceedings of 1996 IEEE Computer Security Foundations Workshop, IEEE Computer Society Press, 1996.
[73] G. Lowe, Casper: a compiler for the analysis of security protocols, Proceedingsof 1997 IEEE Computer Security Foundations Workshop, IEEE Computer Society
Press, 1997.
[74] G. Lowe, Towards a completeness result for model checking of security protocols,
ournal of Computer Security, Volume 7, Numbers 2, 3, pages 89-146, 1999. An earlier version appeared in Proceedings of 11th IEEE Computer Security Foundations
Workshop, pages 96-105, 1998.
[75] G. Lowe and A.W. Roscoe, Using CSP to detect errors in the TMN protocol, University of Leicester Dept. of Mathematics and Computer Science technical report
1996/34, and to appear in the Journal of Computer Security.
[76] W.F. McColl, Scalable computing, in ‘Computer science today: recent trends anddevelopments’, Springer LNCS 1000, 1995.
[77] K. McMillan, Symbolic model checking, Kluwer Academic Publishers, 1993.
[78] J.M.R. Martin, The design and construction of deadlock-free concurrent systems,
University of Buckingham D.Phil thesis, 1996.
[79] R. Milner, Fully abstract models of typed lambda-calculi, Theoretical Computer Science 4, 1–22, 1977.
[80] R. Milner, A calculus of communicating systems, Springer LNCS 92, 1980.
[81] R. Milner, Lectures on a calculus for communicating systems, Proceedings of thePittsburgh seminar on concurrency, Springer LNCS 197, 1985.
[82] R. Milner, Communication and concurrency, Prentice Hall, 1989.
[83] R. Milner, J. Parrow and D. Walker, A calculus of mobile processes, I and II, Information and Computation 100, 1, 1–77, 1992.
[84] M.W. Mislove, A.W. Roscoe and S.A. Schneider, Fixed points without completeness,
Theoretical Computer Science 138, 2, 273–314, 1995.
[85] J.J. Mitchell, Type systems for programming languages, in ‘Handbook of theoreticalcomputer science’ (van Leeuwen, ed), Elsevier, 1990.
[86] Mukkaram, A., A refusal testing model for CSP, Oxford University D.Phil thesis,
1993.

572 Bibliography[87] E.R. Olderog and C.A.R. Hoare, Speciﬁcation-oriented semantics for communicatingprocesses, Acta Informatica, 23, 9–66, 1986.
[88] J. Ouaknine, Discrete analysis of continuous behaviour in real-time concurrent systems, Oxford University D.Phil thesis, 2001.
[89] D. Park, On the semantics of fair parallelism, in ‘Abstract software speciﬁcations’(Bjorner, ed), Springer LNCS 86, 1980.
[90] W.W. Peterson and E.J. Weldon, Jr., Error-correcting codes, M.I.T. Press, 1972.
[91] Phillips, I., Refusal testing, Theoretical Computer Science 50 pp241–284 (1987).
[92] G.D. Plotkin, LCF considered as a programming language, Theoretical Computer
Science 5, 223–255, 1977.
[93] G.D. Plotkin, Lambda-deﬁnability in the full type hierarchy, in ‘To H.B. Curry: essays on combinatory logic, lambda calculus and formalism’ (Seldin and Hindley,eds), Academic Press, 1980.
[94] G.D. Plotkin, A structured approach to operational semantics, DAIMI FN–19, Computer Science Dept., Aarhus University, 1981.
[95] A. Pnueli and E. Shahar, A platform for combining deductive with algorithmic veriﬁcation, 184–195, Proceedings of the 8th CAV, Springer LNCS 1102, 1996.
[96] D.K. Probst and H.F. Li, Using partial order semantics to avoid the state explosion
problem in asynchronous systems, Proceedings of CAV ’90, Springer LNCS 531,
1990.
[97] G.M. Reed, A uniform mathematical theory for real-time distributed computing, Oxford University D.Phil thesis, 1988.
[98] G.M. Reed and A.W. Roscoe, A timed model for communicating sequential processes,
Theoretical Computer Science 58, 249-261, 1988.
[99] G.M. Reed and A.W. Roscoe, Analysing TMFS : a study of nondeterminism in realtime concurrency, in ‘Concurrency: theory, language and architecture’ (Yonezawa
and Ito, eds), Springer LNCS 491, 1991.
[100] J.C. Reynolds, Types, abstraction and parametric polymorphism, Information Processing 83, 513–523, North-Holland, 1983.
[101] A.W. Roscoe, A mathematical theory of communicating proceses, Oxford University
D.Phil thesis, 1982.
[102] A.W. Roscoe, Denotational semantics for occam, Proceedings of the Pittsburgh
seminar on concurrency, Springer LNCS 197, 1985.
[103] A.W. Roscoe, Routing messages through networks: an exercise in deadlock avoidance, Proceedings of 7th occam User Group technical meeting, IOS B.V., Amsterdam, 1987.
[104] A.W. Roscoe, An alternative order for the failures model, in ‘Two papers on CSP’,technical monograph PRG-67, Oxford University Computing Laboratory, July 1988.
Also Journal of Logic and Computation 2, 5, 557–577, 1992.

Bibliography573[105] A.W. Roscoe, Unbounded nondeterminism in CSP, in ‘Two papers on CSP’, technical monograph PRG-67, Oxford University Computing Laboratory, July 1988. Also
Journal of Logic and Computation, 3, 2 131–172, 1993.
[106] A.W. Roscoe, Maintaining consistency in distributed databases, Oxford University
Computing Laboratory technical monograph PRG-87, 1990.
[107] A.W. Roscoe, Topology, computer science and the mathematics of convergence, in‘Topology and category theory in computer science’ (Reed, Roscoe and Wachter,eds), Oxford University Press, 1991.
[108] A.W. Roscoe, Model checking CSP, in ‘A classical mind: essays in honour of C.A.R.
Hoare’, Prentice Hall, 1994.
[109] A.W. Roscoe, CSP and determinism in security modelling, Proceedings of 1995 IEEE
Symposium on Security and Privacy, IEEE Computer Society Press, 1995.
[110] A.W. Roscoe, Modelling and verifying key-exchange protocols using CSP and FDR,
Proceedings of 1995 IEEE Computer Security Foundations Workshop, IEEE Computer Society Press, 1995.
[111] A.W. Roscoe, Intensional speciﬁcations of security protocols, Proceedings of 1996
IEEE Computer Security Foundations Workshop, IEEE Computer Society Press,
1996.
[112] A.W. Roscoe, Finitary reﬁnement checks for inﬁnitary speciﬁcations, Proceedingsof CPA 2004.
[113] A.W. Roscoe, Proving security protocols with model checkers by data independence
techniques, Proceedings of CSFW 1998.
[114] A.W. Roscoe, Seeing beyond divergence, Proceedings of “25 Years of CSP”, LNCS
3525 (2005).
[115] A.W. Roscoe, On the expressiveness of CSP reﬁnement, to appear in FAC.
[116] A.W. Roscoe, Revivals, stuckness and responsiveness, to appear, 2005[117] A.W. Roscoe and P.J. Broadfoot, Proving security protocols with model checkers
by data independence techniques, (expanded version of [113]) Journal of Computer
Security 7, 1999.
[118] A.W. Roscoe and N. Dathi, The pursuit of deadlock freedom, Information and Computation 75, 3, 289–327, 1987.
[119] A.W. Roscoe, P.H.B. Gardiner, M.H. Goldsmith, J.R. Hulance, D.M. Jackson and
J.B. Scattergood, Hierarchical compression for model-checking CSP or how to check1020 dining philosophers for deadlock, Proceedings of the 1st TACAS, BRICS Notes
Series NS-95-2, Department of Computer Science, University of Aarhus, 1995. (Also
Springer LNCS 1019.)[120] A.W. Roscoe and M.H. Goldsmith, The perfect ‘spy’ for model-checking cryptoprotocols, Proceedings of DIMACS workshop on the design and formal veriﬁcationof cryptographic protocols, 1997.

574 Bibliography[121] A.W. Roscoe and C.A.R. Hoare, The laws of occam programming, Theoretical Computer Science, 60, 177-229, 1988.
[122] A.W. Roscoe and H. MacCarthy, Verifying a replicated database: A case study inmodel-checking CSP, Formal Systems technical report, 1994.
[123] A.W. Roscoe, J.C.P. Woodcock and L. Wulf, Non-interference through determinism, Journal of Computer Security 4, 1, 27–54, 1996 (revised from Proceedings of
ESORICS 94, Springer LNCS 875).
[124] A.W. Roscoe and L. Wulf, Composing and decomposing systems under security properties, Proceedings of 1995 IEEE Computer Security Foundations Workshop, IEEE
Computer Society Press, 1995.
[125] P.Y.A. Ryan, A CSP formulation of non-interference, Cipher, 19–27. IEEE Computer Society Press, 1991.
[126] J.B. Scattergood, Tools for CSP and Timed CSP, Oxford University D.Phil thesis,
forthcoming 1997.
[127] S.A. Schneider, Correctness and communication in real-time systems, Oxford University D.Phil thesis, 1989.
[128] W.A. Sutherland, Introduction to metric and topological spaces, Oxford University
Press, 1975.
[129] H. Tej and B. Wolﬀ, A corrected failure-divergence model for CSP in Isabelle/HOL,
To appear in the Proceedings of FME97.
[130] L.G. Valiant, A bridging model for parallel computation, Communications of theACM, 33, 8 103–111, 1990.
[131] A. Valmari, Stubborn sets for reduced state space generation, Proceedings of 10th
International conference on theory and applications of Petri nets, 1989.
[132] A. Valmari, The weakest deadlock-preserving congruence, Information Processing
Letters 53, 341–346, 1995.
[133] A. Valmari and M. Tienari An improved failures equivalence for ﬁnite-state systems with a reduction algorithm, Protocol Speciﬁcation, Testing and Veriﬁcation XI,
North-Holland, 1991.
[134] P.L. Wadler, Theorems for free!, 347–359, Proceedings of the 4th ACM FPLCA,
1989.
[135] D.J. Walker, An operational semantics for CSP, Oxford University M.Sc. dissertation, 1986.
[136] P.H. Welch, G.R.R. Justo and C.J. Willcock, High-level paradigms for deadlock-freehigh-performance systems, Transputer Applications and Systems ’93, IOS Press,
1993.
[137] P. Wolper, Expressing interesting properties of programs in propositional temporal
logic, 184–193, Proceedings of the 13th ACM POPL, 1986.

Bibliography575[138] L. Wulf, Interaction and security in distributed computing, Oxford University D.Phil
thesis, 1997.
[139] J.T. Yantchev, ARC – A tool for eﬃcient reﬁnement and equivalence checking for
CSP, IEEE 2nd Int. Conf. on Algorithms and Architectures for Parallel Processing,1996.
[140] J.T. Yantchev and C.R. Jesshope, Adaptive, low latency, deadlock-free packet routing
for processor networks, IEE Proc. E, May 1989.
[141] I. Zakiuddin, An FDR analysis of a fault-tolerant information system, Proceedingsof AAS ’97, ACM, 1997.

How to obtain the tools mentioned in this book
The following details are believed to be correct at the time of writing, but potential
users are advised in the case of diﬃculty to consult the web site given in the Preface.
The web site should also contain details of further tools.
• FDR: this is a product of Formal Systems (Europe) Ltd. At the time ofwriting the release is 2.11. Much of what is described in this book does not
apply to the earlier FDR 1. For details please email enquiries@fsel.com.
• ProBE: at the time of writing this animator is under beta-test by Formal
Systems (Europe) Ltd, with a formal release expected later in 1997. For
details please email enquiries@fsel.com.
• Jeremy Martin’s Deadlock Checker (see Section 13.6) operates (at the time ofwriting) on the more restricted syntax used by FDR 1. It is hoped to rectify
this. You can obtain it through the web site with URL
http://users.ox.ac.uk/~jeremy/Deadlock/index.html• Gavin Lowe’s Casper (a security protocol compiler, as discussed in Section
15.4) can be obtained through the web site with URL
http://www.mcs.le.ac.uk/~gl7/Security/Casper/index.html

Main index

Entries in bold face are the primary reference(s) to the item concerned, while italic
entries denote references in exercises. Note that processes have a separate index,
following this one.
abstraction, 24, 82, 89, 295–328, 364,
376–378, 532
eager, 296, 400, 428
lazy, 297–327, 400, 407, 412, 428
mixed, 302–305, 326, 387, 401, 428,
538
over T (hiding), 296, 306
acceptance sets, 278, 522, 530
acknowledgement messages, 128
ACP, 269
actions
invisible (τ ), 48, 77, 78, 80, 92, 136,
160, 178, 410, 463, 530
visible, see communications‘after’ operator (P /s), 47
algebraic semantics, 29–35, 39, 149, 269–
293, 517
alphabet, 13
process, 55, 76
transformation, see renamingalphabetized parallel (X Y ), 55–65, 380
as conjunction of trace speciﬁcations,
70–74, 333, 396
in terms of , 68, 70
Xindexed, 57
laws of, 57, 82, 88, 142, 276
termination of, 139traces of, 60
with intrinsic alphabets, 76
alternating bit protocol, 128–133, 211–
213, 221, 259, 309–311, 358, 403–
409, 533
animator, 48
articulation point, 372
ASCII version of CSP, see machine-readable
CSP
ATM (Automated Teller Machine), see
cash-point machines
attack (on a crypto-protocol), 449, 450,
455, 460, 461, 464, 465
authentication, 446, 447, 460
axiom, 229
D1, 192, 204, 207, 246
D2, 192, 198, 204, 207, 246
D2 , 246
D3, 192, 196, 246
D4, 246
F1, 192
F2, 192

578 Main index
F3, 192, 219, 251
F4, 192, 198
I1, 253
I1 , 246
I2, 254
T1, 208, 246
T2, 208
T3, 208
axiom of choice, 474bag, 67, 124
Banach’s theorem, see contraction mapping theorem
Barrett, Geoﬀ, 256–257, 268
biconnected components, 372
binary decision diagram (BDD), 529
binary switching network, 363–364, 378
bisimulation, 154–158, 284, 521, 522,
529
Blamey, Stephen, 268
breadth-ﬁrst search (BFS), 527–528
Brookes, Stephen, 178, 214, 292, 380
BSP (Bulk Synchronous Parallelism), 5
buﬀer, 18, 78, 81, 85, 103, 113–134
characteristic process, 115
failures/divergences speciﬁcation of,114
inﬁnite, 18, 103, 188laws, 116–121, 125–126, 207
speciﬁcation is inﬁnite state, 50
tolerance, 125–128, 133, 430
trace speciﬁcation of, 43, 46, 104,
113
weak, 116
busy network, 334, 371, 378
Byzantine failure, 312cache, 465
coherency, 441–446
miss, 442
replacement policy, 442
cash-point machines, 20–21, 24, 28, 53–
54, 55, 63–64, 65, 68, 82–83,
388, 409

Casper, 461, 550
Cauchy sequence, 490
CCS, 5, 154, 178, 214, 536
chain, 473
chaining, see piping
channels, 18, 26, 27, 99, 334, 376
arrays of, 27, 63
conﬂict-free, 339
internal and external, 58, 77
type discipline restricts practicalityof >> and //, 110
Chaos , 29, 42, 214, 299, 309, 312, 314,
323–324, 428
is non-divergent, 83
characteristic process, 46, 65, 97, 115chase(P), 462–464, 531
choiceconditional, see conditional choiceexternal, see external choiceguarded, see guarded alternative
nondeterministic, see nondeterministic choicesliding, see ‘time-out’ operator
client/server networks, 347
closed CSP term, 159
closed set, 489–490
closure of trace set, 172
combinatorial exploration, 416, 422
comms(e), 160
communication graph, 58, 62, 335, 342,
343, 353, 362, 370, 533
communication media, 320
insecure, 446
unreliable, 103, 104, 118, 129–130,
212, 260, 309–310, 404
communications, 8–10, 13, 20–21
agreement with environment on, 13,152
are instantaneous, 13
multi-part, 17, 26
communications protocols, 102, 113, 128,
211
layering of, 103
completeness of a set of laws, 270

Main index
compositional development, 46, 533
compression of state spaces, 306, 307, 378,
463, 525, 528–538
inapplicable with priority, 412
concurrency, theory of, 1
concurrent systems, 1
conditional choice, 25–26, 49
for collapsing case deﬁnitions, 25
laws of, 30–34
conﬁdentiality, 446, 460
conﬁgurations, 520
conﬂict, 337–339, 341, 364
freedom from, 337, 341, 344, 347,
349, 350, 360, 371
congruence, 180–181, 200, 238, 269
consistency (of distributed data), 423–
430
constraints via parallel composition, 71,
72, 131, 420–422
constructiveness, 39, 53, 84–85, 103, 122–
123, 186–189, 196, 203, 206,
220, 225, 250, 266–267, 493
contexts, 46, 180, 208, 228, 232–238, 412
continuity, 184–186, 204–206, 206, 211,
476–478, 481, 483–485
disappears with unbounded nondeterminism, 248
of predicates, 225
contraction map, 491–494
contraction mapping theorem, 181, 224–
225, 491–494
convergence, 473, 488
covert channel, 317
timing, 323
cpo, see partial order, complete
critical regions, 308
crypto-protocols, 446–466
CSP (1978 version), 5
CSP, modern version, 5cycle of ungranted requests, 336–379
cycle-cutting set, 362
cyclic communication network, 349–353,
358, 360, 362, 366–367, 379, 536
generalized, 350

579

data structures implemented as networks,
107
data type, 17, 27, 430–440
data types for symbolic encryption, 449
data-independence, 295, 376, 423, 430–
440, 443–446, 464, 533
weak, 434
Dathi, Naiem, 380
Davies, J.W.M. (Jim), 413
de Nicola, Rocco, 214
deadlock, 3, 10, 62, 65, 131, 180, 234–
238, 306, 331–382, 428
compression in checking, 533
failures speciﬁcation of deadlock freedom, 97
fundamental principle of, 342, 343,
347, 365, 371
hereditary deadlock freedom, 373–
375
is static, 332, 335
represented by STOP, 54
Rule 1, 342, 370, 373
Rule 2, 344, 345, 346, 358, 361, 372,
373, 377
Rule 3, 347, 348, 358, 372, 373
Rule 4, 349, 358, 360, 372, 373, 380
Rule 5, 349, 351, 372, 373
Rule 6, 351, 352, 373
Rule 7, 354, 355, 372, 373
Rule 8, 357, 365, 373, 425, 427
Rule 9, 359, 360, 361, 364, 372, 373,
379
Rule 10, 362, 364, 372, 373
Rule 11, 365, 373
Rule 12, 366, 367
Rule 13, 371
Rule 14, 371
Rule 15, 377
Rule 4, 358
Rule 5, 358
state, 335–338, 340–341
Deadlock Checker, 378–379, 550
declarative semantics, 19, 136, 138, 150
deductions(X), 456

580 Main index
denotational semantics, 149, 179–216,
517
denseness, 228
depth-ﬁrst search (DFS), 526, 527, 530
derived operator, 99
det(P ), 219, 254, 255
determinism, 3, 23, 96, 97, 194, 204, 217–
222, 243, 252, 257, 258, 299–
301, 305, 312, 316–328, 439–
440, 463
algorithm for deciding, 222
FDR as a checker of, 325
over F , 217, 325, 440
diamond elimination, 530, 531
diamond(P), 530
Dijkstra, E.W., 380
dining philosophers, 3, 60–63, 65, 67,
86, 338–339, 353–355
compression of, 532, 533
directed set, 184, 194, 195, 205, 473, 482,
490
disconnecting edge, 370–372
distributed database, 423–430, 464
distributed termination, 139–140, 142,
178
operational semantics of, 164
distributivity (over ), 30, 54, 183–184,
202–203, 206
div, 83, 96, 135, 209
laws of (over N ), 275–276
laws of (over T and F ), 290
divergences, 3, 10, 83, 92–98, 130, 131,
137, 161, 170, 191, 195, 204,
209, 236–238, 428, 522, 526
in timed processes, 398
seeing past, 207, 211
strictness after, 95, 172, 192, 193,
200, 204, 205, 207, 276
divergences(P ), 95, 191, 192
calculation of, 197–202
divide and conquer, 108
dynamic networks, 103, 107, 188, 332,
342
usually inﬁnite state, 110

encryption, 446, 455, 465
algebraic identities over, 461
public-key, 447, 448, 452
symbolic representation of, 449
symmetric, 447, 452
enslavement (//), 105–111, 138, 342, 441
builds tree networks, 107environment (external), 13, 24, 145, 387
environment (semantic), 160, 239
error correcting codes, 128
error correction, 119
essential component, 370–372
Events, 49
eventsinvisible, see actions, invisible
visible, see communications
events(c), 27
eventuality, 264
explicate(P), 528, 531
explode(P), 456
expressibility, 229–232, 253
external choice, 22–23, 94, 183, 206
ambiguous initial events, 23
laws of, 30–34, 86, 90, 141, 276
operational semantics of, 161
fact (data type for encryption), 449
failure modes, 312
failures, 92–98, 192, 251, 398
stable, 191, 207–214
failures(P ), 92, 171, 246
calculation of, 210
failures ⊥ (P ), 95, 171, 191, 192
calculation of, 197–202
failures/divergences model (N ), 95, 144–
145, 191–207, 209, 214, 217–
219, 255, 275, 522, 526
applicability of, 200, 231
expressibility of elements, 231–232
full abstraction, 235–237
lazy abstraction over, 297
normal forms for, 281–285
failures/divergences/inﬁnite traces model(U ), 245–268, 303

Main index
lazy abstraction over, 298–299, 305
Fair (A, B ), 259
fairness, 131, 259–266
fault tolerance, 309–316, 325, 409, 435
abstract deﬁnition of, 314
of replicated processor, 312
FDR, xi, 7, 48–50, 60, 97, 98, 306, 325,
375, 413, 415–466, 517–538,
550
compiler, 519
ﬁnite state machine, see state machine,transition system
ﬁxed point induction, 124, 134, 223–226,
250, 266–267
ﬁxed points, 38, 84, 158, 181, 196, 223–
228, 471–479, 491
for mutual recursions, 38
positive and negative, 190, 203–204
ﬁxed-point induction, 122–123, 181
FOR loop, 138
formats, see conﬁgurations
full abstraction, 180, 228–238, 243, 253–
255, 289, 291
aﬀected by adding operators, 235
function, 89
injective, 87
spaces, 483–485
strict, 472
functional programming language, 19, 150,
415, 495–515
game theory, 254
generalized parallel ( ), 68–70
X

laws of, 69, 82, 88, 142, 276, 288
traces of, 69, 144
Gofer, 495
greatest lower bound, 193, 209, 246, 255,
469–471, 481
guarded alternative, 15–17, 18, 22, 49
representable using 2, 22
guardedness, see constructivenesshalting problem, 135, 277, 430

581

handshaken communication, 5, 6, 9, 20,
51, 71, 126
Haskell, 19, 495
Hasse diagram, 468
He, Jifeng, 293
head normal form (hnf), 271–277, 278,
282, 285, 287, 289, 291, 292
Hennessy, Matthew, 214
hiding, 77–86, 199–202, 333, 380, 532
never hidden, 140
continuity over N , 205discontinuous over T , 184, 190
divergences of over U and I, 247
inﬁnite, 83, 176
laws of, 78–82, 88, 141, 276, 288
negates guardedness, 84
operational semantics of, 162
traces of, 83
high level implementation, 518
hnf, see head normal form
Hoare, C.A.R. (Tony), xi, 5, 43, 76, 140,
214, 293, 302
identiﬁers
non-process, 25, 37, 159
binding of, 19, 34
change of, 272
scope of, 136
process, 14, 161, 228, 238, 239
independence, 317, 327, 465
lazy, 317, 325
mixed (or transaction), 317
inductive compression, 536
inference system
via parallel composition, 458–464
inﬁnite traces/divergences model (I), 246–
250
inﬁnites(P ), 172
calculation of, 247
inﬁx dot, 18, 26
initials(P ), 47, 193, 278
initiator, 451
input, 18–19, 27, 99–102, 302, 346, 385,
387

582 Main index
interaction, 2, 51
interface parallel, see generalized parallelinterleaving (|||), 65–68
as abbreviation for disjoint parallel,67
as abstraction mechanism, 326
in terms of , 68X

laws of, 66, 142, 276
operational semantics of, 169
recursion through, 66
traces of, 67, 144internal choice, see nondeterministic choiceinterrupt operator (), 235, 286
intruder (spy), 446, 449, 450, 453–461
invariant (of a network), 374
iterationparallel, 102
sequential, 137
Jackson, David M., 413
Jategoankar, Lalita, 216, 243
knowledge, deduction of, 455–464
König’s lemma, 173, 205, 242, 258
labelled transition system, see transition
systemlambda (λ-) calculus, 232lattice, 470
complete, 182, 209, 246, 470–471,
473
law, 29, 34, 39, 78, 149, 206, 269, 285,
292, 333, 380
associative, 29, 57
commutative, 29
distributive, 29
idempotence, 29
step, 32, 79–81
symmetry, 29, 57
unit, 29
zero, 29, 276
Lazić, Ranko, 150, 433, 437, 439, 465
lazy spy, 458–464
leaf compression, 537

least upper bound, 194, 209, 469–471,
481
level crossing, 388–397, 413
livelock, see divergences
liveness, see speciﬁcation, livenesslogical relations, 432, 465
low level implementation, 518
low-deterministic process, 324
Lowe, Gavin, 460, 461, 550
lower bound, 469
LTS, see transition system
machine-readable CSP, 8, 19, 25, 27, 48–
49, 74, 89, 98, 109–111, 415,
495–515
Martin, Jeremy, 378–380, 550
matrix multiplication network, 351–352,
362–363, 376
maximal progress, 410
memory device, 303
memory model, 441–443
mergesort network, 109
message-passing ring, 355–357, 425
metric spaces, 181, 186–187, 220, 224–
225, 250, 486–494
complete, 490
Meyer, Albert, 216, 243
Milner, Robin, 5, 536–537
model checking, 17, 75, 82, 422, 464, 526
model compress(P), 530
modular compression, 533
monitor, 313, 325
monotonicity, 116, 195, 202, 204, 211,
257, 472–479, 481, 483–485
and reﬁnement, 46
is implied by distributivity, 184
mutual exclusion, 4, 308
Needham–Schroeder Public-Key protocol,
447–461
Newton’s method, 102, 104
node ordering, 344
NoEqT (no equality tests), 433
non-Archimedean metric, 488

Main index
non-destructiveness, 104, 187, 196, 206,
493
non-expanding map, 491–494
non-interference, see independence
nonce, 448, 455
nondeterminism, 2, 10, 23, 24, 152angelic, 261
ﬁnite, 23inevitable in concurrency theory, 83
introduced by 2, 219
introduced by , 220
X

introduced by abstraction, 24, 296
introduced by external choice, 23
introduced by hiding, 80, 82, 220
introduced by renaming, 89, 220
unbounded, 23, 83, 89, 176, 195,
196, 200, 215, 231, 243, 245–
268, 299
nondeterministic choice, 23–25, 94, 183,
471
fair, 261–262
inﬁnite, 176
laws of, 30–34, 276
operational semantics of, 160
nondeterministic selection ($), 433, 435
nondeterministic systems
are untestable, 3Norm (normality conditions), 435, 436
normal form, 277–286, 289, 291, 465,
521, 524
one-step, 281, 289
normal(P), 529, 533
normalization, 281, 306, 432, 517, 521–
525, 529–531
can be exponential, 524
occam, 5, 22, 78, 293, 357, 380
Olderog, E.-R., 243Ω (Omega): terminated process, 159
open set, 489
operating system, 4operational semantics, 78, 149–178, 190,
250, 432, 465, 517–521

583

congruence with denotational semantics, 238–243
via algebraic reduction, 271–277,
292
order isomorphism, 468
output, 18–19, 27, 99–102, 346, 385, 387
as signal events, 302
pantomime horse, 55, 64, 65
parallel communication, 350–352
parallel computers, 1, 2
parallel networks, 331–343
parallel processes
can be sequentialized, 52, 58
parameterization, 63, 87
parameterized veriﬁcation problem (PVP),
430, 445
parameters, process, 19, 49, 150, 430
parametricity, 432, 465
partial order, 181, 195, 224, 255–257, 344,
467–486
bottom (⊥), 468
complete (cpo), 194, 195, 473–475
maximal element, 468, 474, 479
minimal element, 468
top (), 468
partial order methods (in model checking), 464
philosophers, dining, see dining philosophers
piping (>>), 99–105, 109, 116, 207, 342
laws of, 100–102, 142
traces of, 102
Plotkin, Gordon, 178
point-to-point communication, 78, 333
polymorphism, 76, 431
post-ﬁxed point, 257, 478
pre-deterministic process, 256
pre-ﬁxed point, 158, 478
pre-normal form, 522, 524
preﬁx choice, 17–19, 49
preﬁx order on sequences, 468
preﬁxing, 14
laws of, 30–34

584 Main index
operational semantics of, 159
prioritize(P), 413, 531
priority, 409–413
limits applicability of denotationalmodels, 411
ProBE, 8, 48–49, 110, 177, 550
process algebras, 5, 6, 154, 214, 269
process naming (a.P ), 87, 98, 105
product of partial orders, 480–486
projection, 297
public key, 447, 450
puzzles, 416
quicksort network, 108, 191, 343
railways, 9, 73, 373–375, 388, 416
recursion, 14–15, 122, 203, 223–228
and ﬁxed points, 37, 181, 188–190,
195, 203, 248–250
equational and µ styles, 15
guarded, see constructivenessill-formed, 83, 188–190, 203, 204
is not distributive, 31
laws of, 34
mutual, 14, 38, 41, 59, 122, 480
inﬁnite, 16, 66
operational semantics of, 161, 178
parameterized, 19, 38, 53, 63, 480
tail, see tail recursion
through sequential composition, 137
trace proof rules, 44
reduction strategy, 271
Reed, G.M. (Mike), 413
reﬁnement, 24, 300
checking, 525–527
is PSPACE-hard in worst case,523
failures, 94, 95, 97
failures/divergences, 96–98, 203
FDR as checker of, 49
over U , 255
properties of, 46
provable algebraically, 47
trace, 45, 48, 97, 182, 184reﬁnement paradox, 324
reﬂexivity, 468
refusal set, 92, 93, 171, 192, 204, 207,
215
maximal, 93, 231, 278, 279
may contain , 145
relationship with acceptance sets, 278
relationship with inﬁnite traces, 254
refusals(P ), 92, 193
relation, 89, 182, 468
composition of, 90
domain and range of, 89
relational representations of operators, 182–
188, 202, 204, 206, 207, 210,
254
remote procedure call, 105renaming, 86–92, 333, 380, 453, 460, 461
never aﬀected, 140
as an abstraction mechanism, 295,
377–378
inﬁnite-to-one, 176
injective, 87–88
inverse function, 89
laws of, 88, 90–91, 141, 276
non-injective, 88–89
traces of, 91, 143
request, 335, 341
selective, 365
ungranted, 335–339, 341, 362, 365
resource sharing, 353–355
responder, 451
restriction space, 186–188, 196, 206, 224–
225, 488
complete, 490
routeing algorithms, 344, 348, 363, 376
RUN , 29, 42, 47, 265, 306, 309, 326
safety, see speciﬁcation, safetysat, 43, 46, 47
sbisim(P), 529
Scattergood, Bryan, 150, 495
scheduler ring, 536–537
Schneider, Steven, 7, 413
Scholten, C.S., 380

Main index
SDD, see state dependency digraphsecret key, 447, 450
security
information ﬂow, 316–328
limitations of CSP models, 323–325
protocols, 446–466
semantic equivalence factoring, 530
semaphore, 4semi-separable, 325
SemiFair (A, B ), 265, 298
separability, 300–302, 318, 321, 324, 325,
327
sequence notation, 36, 43
sequential composition (; ), 135–143, 206,
286–290
laws of, 140–143, 276
operational semantics of, 162
traces of, 143, 182, 184
server, 448
session, 452
session key, 447, 452
set process, 107
settle time, 409
shared-variable concurrency, 4
Σ (Sigma), 8, 13, 49, 78
Σ , 135
signal (undelayable) events, 145, 302–304,
307
signal events, 387
signature, cryptographic, 447–449
SKIP , 135, 286–290
laws of, 140–143, 288
operational semantics of, 159
traces of, 143sliding choice, see ‘time-out’ operator
snapshot graph (of deadlock), 335
solitaire, 416–422, 519–520
soundness of a set of laws, 270
speciﬁcation
behavioural, 42, 45, 97, 114, 314
compression of, 525
failures, 95, 97, 306–309, 398, 428
failures/divergences, 97, 114
inﬁnite state, 115–116

585

inﬁnite trace, 258–259
liveness, 45, 207
timed, 397
of a subset of the alphabet, 306–309
operators primarily for, 9partial correctness, 45
processes as, 9safety, 45, 395, 429, 451
timed, 388–397
total correctness, 45
trace, 42–47, 48, 65, 66, 97, 115,
306, 536
limitations of, 45, 113
untimed of timed process, 398–403
spy, see intruder
stable failures model (F ), 207–216, 217,
246, 306–307, 340, 378, 526, 534
applicability of, 211
expressibility of elements, 229–230
full abstraction, 234–235, 237
lazy abstraction over, 299–300
normal form for, 292
relationship with algebraic semantics, 290–292
without traces, 238
stable node, 92, 191
cannot perform , 151, 171
stack, 124, 143
state
exploration, 17, 59, 168, 416, 464,
521
explosion, 74, 420
motivates local analysis of networks,
336
space, 19, 168
state dependency digraph (SDD), 379
state identiﬁers, see identiﬁers, non-processstate machine
explicit, 531
ﬁnite, 16, 17, 49–50, 115–116, 154
implicit, 531
normal form, 521
stepwise reﬁnement, 47

586 Main index
STOP, 14, 29, 32, 44, 45, 47, 83, 135,
231, 334
operational semantics of, 159
strictness, 162, 276
strong conﬂict, 337–339, 341, 364, 378
freedom from, 337, 341, 362
structural induction, 177
sub-process values, 272
subs(a, e, P ), 160
supercombinators, 520, 521, 531
synchronization tree, 154
synchronous parallel ( ), 51–55
is not idempotent, 54
laws of, 52
traces of, 54
syntactic approximation, 285
systolic arrays, 349
tactic processes, 420
tail recursion, 19, 41
one step, 19, 282
Tarski’s theorem, 158, 181, 257, 484, 491,
494
for complete lattices, 472–473
for continuous functions, 477–478
for cpo’s, 475–476
τ (tau) action, see actions, invisible
τ -loop elimination, 530
termination ( ), 135–145, 151–154, 162,
178, 192, 215, 265, 286–290
as a signal, 145
testing equivalence, 214
theory of concurrency, 6threshold, 432–440, 445–446
time-out, 21, 129, 404–406, 407
controller, 405‘time-out’ operator (), 80, 86, 141, 287,
290, 404
operational semantics of, 165
time-stop, 386
time: discrete vs continuous, 383–384,
413
Timed CSP, 6–7, 35, 383–384, 412, 413
timed systems, 6–7, 383–413, 461

timing consistency check, 386, 395, 408,
410
timing constraints, 384, 389–394
inconsistent, 385, 387
tock , 384
token ring, 307, 356, 358, 537
tools, xi, 7–8, 48–50, 74–75, 98, 109–111,
133–134, 177–178, 325–326, 375–
379, 412–413, 439, 461, 495, 517,
550
total order, 468, 474, 479
trace
inﬁnite, 201
notation, see sequence notation
traces, 35–47, 92, 143, 208, 383
are inadequate for reasoning about
deadlock, 331
ﬁnite, 35
inﬁnite, 35, 171–177, 245–268, 299
proof rules for, 43
timed and untimed, 35
traces model (T ), 36, 45, 47, 84, 143–
144, 182–191, 203, 209, 214,
217, 526
expressibility of elements, 229
full abstraction, 233, 237
inadequacy of, 37, 40, 54, 92
is a complete lattice, 470
normal form for, 291
relationship with algebraic semantics, 290–292
Traces(P ), 172, 247
traces(P ), 35–39, 42, 170, 203, 208
traces ⊥ (P ), 95, 171, 203transition system, 78, 87, 92, 151–158,
165–177, 192, 222, 242, 463, 521,
526
deterministic, 93, 221
explicit, 520
ﬁnitely branching, 172, 195, 201
generalized, 531
implicit, 520
transitivity, 468
transitivity of reﬁnement, 46

Main index
transparent functions, 529, 531
tree network, 342, 370
triangle inequality, 487, 488
triple-disjoint networks, 332, 335
tuples, 480
UFP rule, see unique ﬁxed points
ultra-metric, 488
unbounded nondeterminism, see nondeterminism, unboundedunique ﬁxed points, 40, 52, 53, 55, 59,
68, 84, 97, 142, 143, 181, 187,
220, 250, 251, 266–267, 478, 494
unstable node, 92, 151
upper bound, 469
urgency of hidden actions, 409
Valmari, Antii, 216, 243variants, 358–370, 378
weak, 366–370
vector, 38–41, 44, 142, 187, 480
virtual memory, 441
virtual network routeing, 344, 358, 363,
376–377
VLSI, 1, 9
vocabulary of network, 335
web site, xi, 8, 133, 378
Wolper, Pierre, 464
Woodcock, J.C.P. (Jim), 326
wormhole routeing, 347–349
Wulf, Lars, 326
Yantchev, Jay, 344
Zorn’s lemma, 474, 475

587

Index of named processes

This book contains many CSP process deﬁnitions, some of which are used manytimes. The following index is a reference to the main uses of a selection of theprocesses that we have given distinctive names. The notational conventions are asin the main index.
⊥U , 255⊥I , 246
I , 246
F , 209, 211, 213, 217, 230, 231, 234⊥F , 208⊥N , 193, 201, 203, 211, 227, 236, 275
ABP, 131, 133, 212
ABPE , 311
ABS 1 , 25
ABS 2 , 25
A∞ , 200, 248
AROUND, 41
A∗ , 200, 232, 248, 255, 267
ATM 1, 20, 28, 53
ATM 2, 24, 54, 55, 65, 82
ATM ref n , 63, 65, 82
B + , 103, 122, 123, 134, 188
Bi2 , 85
BCOUNT , 189
BetweenSets(A, B , C ), 396
Bs∞ , 19, 28, 38, 43, 46, 49, 115, 122, 259
BLOCK (r , s)n,m , 72

BUFF , 445
BUFF s , 28, 115, 116, 122, 134, 259
BUFF Ns , 115, 134, 259, 436
BUTLER, 338, 373
Cu [·], 255
C(s,X ) [·], 236
C (a, b), 130, 212, 260, 310
CE (a, b), 310, 316
Cfin (a, b), 260
CN (a, b), 130, 212, 316
C ∗ (a, b), 260
Cache(ps,A,V,N), 442
CC i , 59
CC i , 59, 85
CF(s,X ) [·], 234
CFD(s,X ) [·], 237
Chaos , see main index
Comm 1 , 320
Comm 2 , 321
Comm 3 , 321
Comm 4 , 321, 323
ControllerUp, 392

590 Index of named processes
COPY , 18, 28, 43, 48, 70, 100, 115, 126,
133, 166, 304, 399
COPY  (a, b), 57, 59, 63, 77, 81
COPY  (i), 63
COUNT n , 16, 17, 25, 28, 38, 43, 49, 54,
66, 67, 87, 91, 137, 142, 304
Counter (n, m), 26, 54
CP(b, n), 121
CSYSTEM , 409
CTs [·], 233
CT 2(n, m), 67
CTs [·], 234
CTs [·], 236
Ctr , 66
CUST 1, 53
CUST 2, 54, 82
CUST spend n , 63, 82
DDB(x,T), 429
DF , 97, 375, 428
DF , 375
Di (node in non-blocking ring), 356
div, see main index
Ei , 118, 130
EnterWhenDown, 396
ER L (T ), 408
F(s,X ) , 230, 234
Fair (A, B ), see main index
FinBUFF s , 259
FINITE A , 254, 305
FORK i , 61, 338
FORKS , 67
FTP , 312
GateAndController , 394
GateStillWhenTrain, 396
GateUp, 394
Initialize, 17
Int F(T ,F ) , 230, 232
Int N(F ,D) , 231, 232, 284
Int TS , 229, 232
IP (b, n), 121

ITER, 102
IterBuﬀ 2 , 138
Limit(E , A, N , M ), 313, 316
Medium, 320
Medium2, 320
Medium3, 321
Mem(s), 303
Memory(A,V,f), 443
N0(i,E,T) (node in distributed database),
426
NDN , 367
NoFaults, 314, 327, 435
OneLoc, 444
OnlyDups, 438
OutsideSets(A, B , C ), 396
P 1–P 6 (simple security examples), 318
PCOUNT , 189
PHILi , 61, 65, 338, 354
PHIL4 , 354
PHILS , 67
POS , 137, 143
Puzzle, 420
Qsort, 108
R (ABP), 130
RecH , 320
RecH 4, 321
RecL, 320
RecL4, 321
RegTIMP, 401
RemDups, 436
REPEAT , 17, 51, 54
Resp(id,ns) (NSPK protocol), 452
Rest(n), 281
RING(T) (distributed database), 427
Ring (token), 308
Rmaj , 119
ROBOT i,j , 71
RTIMP, 401

Index of named processes
RUN , see main index
S (ABP), 130
Safety, 396
SemiFair (A, B ), see main index
Send(id,ns) (NSPK protocol), 451
SendH , 320
SendH 3, 321
SendH 4, 321
SendL, 320
SendL4, 321
SET , 107, 109
Sink, 439
SKIP , see main index
Slot(i,j), 419
Smaj , 119
SpecReg, 402
SpeedReg(j ), 390
SPLIT , 88
Spy, 459
Spy1(X), 457
SS, 429
STOP, see main index
Sw , 364
Ts , 229, 233, 252, 254
Ts , 230
Ts , 236
TABP, 407, 409
Tactic1, 420
Tactic2(n), 421
TB, 138
TCOPY 1, 385, 386, 387
TCOPY 2, 385, 409
TCOPY 3, 385, 386, 387
TCOPY 4, 386
TE , 404
TF , 404
TimedNetwork , 391
TimingConsistency, 407
TIMP, 399
TLimiter (N , M ), 385
TOC , 405
TOCKS , 386, 387, 395

591

TOCKS , 387
TR, 399
Track (j ), 389
Tracks, 389
Train(t, j ), 389
Trains, 389
TS , 399
TSpec, 402
User(id,ns) (NSPK protocol), 451
VAR(x ), 106
WBUFF Ns , 116, 128, 134, 436
ZCOUNT n , 41
ZERO, 137, 142, 143, 169
Zero // , 108
Zi (under-deﬁned recursions), 188, 204