A Science of Concurrent Programs
Leslie Lamportversion of 7 June 2024

The 1 March 2024 version was an extensive rewriting of theprevious versions, with Chapter 2 much shorter and somemath introduced later in the book as needed. The current
version contains minor changes, including moving the former
Section 2.9 to Math V.
If you have any errors to report, comments to make, or questions to ask, please contact me by email. But when you do,
include the version date. Anyone who is the first to report
any uncorrected error will be thanked in the book. If you
find an error, please include in your email your name as you
wish it to appear, and be sure to include the version date.

Contents
About This Book (unfinished) . . . . . . . . . . . . . . . . . . . . . vii
Acknowledgments (unfinished) . . . . . . . . . . . . . . . . . . . . viii
1 Introduction
1.1 Who Am I? . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Who Are You? . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3 The Origin of the Science . . . . . . . . . . . . . . . . . . . .
1.3.1 The Origin of the Theory . . . . . . . . . . . . . . . .
1.3.2 The Origin of the Practice . . . . . . . . . . . . . . . .
1.4 Correctness . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5 A Preview . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.6 Why Math? . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
1
2
2
2
3
5
6
9

2 Ordinary Math
12
2.1 Arithmetic as a Mathematical Theory . . . . . . . . . . . . . 14
2.2 The Mathematical Theory of Algebra . . . . . . . . . . . . . 15
2.3 Mathglish . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4 Boolean Arithmetic (Propositional Logic) . . . . . . . . . . . 18
2.5 ZF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6 Meaningless Expressions . . . . . . . . . . . . . . . . . . . . . 23
2.7 Quantification and Bound Variables . . . . . . . . . . . . . . 25
2.7.1 Quantification . . . . . . . . . . . . . . . . . . . . . . 25
2.7.2 Bound Variables . . . . . . . . . . . . . . . . . . . . . 27
2.8 Defining Mappings and Functions . . . . . . . . . . . . . . . . 29
2.8.1 Mappings . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.8.2 Functions . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.8.3 Sequences and Tuples . . . . . . . . . . . . . . . . . . 31
2.9 Some Useful Notation . . . . . . . . . . . . . . . . . . . . . . 32
2.9.1 if/then/else . . . . . . . . . . . . . . . . . . . . . 32
2.9.2 Conjunction and Disjunction Lists . . . . . . . . . . . 33
i

CONTENTS

ii

3 Describing Abstract Programs with Math34
3.1 The Behavior of Physical Systems . . . . . . . . . . . . . . . 34
3.2 Behaviors of Digital Systems . . . . . . . . . . . . . . . . . . 37
Math I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.2.1 From Continuous to Discrete Time . . . . . . . . . . . 37
3.2.2 An Example: Sqrs . . . . . . . . . . . . . . . . . . . . 40
3.2.3 A Finer-Grained Example: FGSqrs . . . . . . . . . . . 44
3.3 Nondeterminism . . . . . . . . . . . . . . . . . . . . . . . . . 46
Math II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.3.1 Sources of Nondeterminism . . . . . . . . . . . . . . . 47
3.3.2 An Example: Increment . . . . . . . . . . . . . . . . . 48
3.4 Temporal Logic . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Math III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.4.1 The Logic of Actions . . . . . . . . . . . . . . . . . . . 53
3.4.1.1 Eliminating State Numbers . . . . . . . . . . 53
3.4.1.2 The Semantics of the Logic of Actions . . . . 55
3.4.1.3 The Prime Operator . . . . . . . . . . . . . . 56
3.4.1.4 Action Composition . . . . . . . . . . . . . . 58
3.4.2 The Temporal Logic RTLA . . . . . . . . . . . . . . . 59
3.4.2.1 Simple RTLA . . . . . . . . . . . . . . . . . 60
3.4.2.2 The Complete RTLA . . . . . . . . . . . . . 62
3.4.2.3 The 2 Operator . . . . . . . . . . . . . . . . 63
3.4.2.4 Eventually (3) . . . . . . . . . . . . . . . . . 64
3.4.2.5 Eventually Always (32) . . . . . . . . . . . 66
3.4.2.6 Infinitely Often (23) . . . . . . . . . . . . . 66
3.4.2.7 The End of the Line . . . . . . . . . . . . . . 67
3.4.2.8 Leads To (;) . . . . . . . . . . . . . . . . . 68
3.4.2.9 Warning . . . . . . . . . . . . . . . . . . . . 69
3.5 TLA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Math IV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.5.1 The Problem . . . . . . . . . . . . . . . . . . . . . . . 71
3.5.2 The Solution . . . . . . . . . . . . . . . . . . . . . . . 72
3.5.3 Stuttering Insensitivity . . . . . . . . . . . . . . . . . 74
3.5.4 The Definition of TLA . . . . . . . . . . . . . . . . . . 75
4 Safety, Liveness, and Fairness
78
4.1 Safety and Liveness . . . . . . . . . . . . . . . . . . . . . . . . 78
Math V . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.1.1 Definitions . . . . . . . . . . . . . . . . . . . . . . . . 79
4.1.2 A Completeness Theorem . . . . . . . . . . . . . . . . 81

CONTENTS

4.2

4.3

4.4

iii

4.1.3 The Operator C . . . . . . . . . . . . . . . . . . . . . . 83
4.1.4 What Good is Liveness? . . . . . . . . . . . . . . . . . 84
Fairness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
4.2.1 Traditional Programs and Enabled . . . . . . . . . . . 85
4.2.2 Concurrent Programs . . . . . . . . . . . . . . . . . . 86
4.2.2.1 Mutual Exclusion . . . . . . . . . . . . . . . 87
4.2.2.2 Machine Closure . . . . . . . . . . . . . . . . 91
4.2.3 Weak Fairness . . . . . . . . . . . . . . . . . . . . . . 92
4.2.4 Temporal Logic Reasoning . . . . . . . . . . . . . . . . 94
4.2.5 Reasoning With Weak Fairness . . . . . . . . . . . . . 95
4.2.5.1 Liveness for Mutual Exclusion . . . . . . . . 96
4.2.5.2 The One-Bit Algorithm . . . . . . . . . . . . 96
4.2.5.3 Proving Liveness . . . . . . . . . . . . . . . . 98
4.2.6 Strong Fairness . . . . . . . . . . . . . . . . . . . . . . 103
4.2.6.1 Starvation Free Mutual Exclusion . . . . . . 103
4.2.6.2 The Definition of Strong Fairness . . . . . . 104
4.2.6.3 Using a Strongly Fair Semaphore . . . . . . . 105
4.2.7 Properties of WF and SF . . . . . . . . . . . . . . . . 106
4.2.8 What is Fairness? . . . . . . . . . . . . . . . . . . . . 108
Possibility and Accuracy . . . . . . . . . . . . . . . . . . . . . 109
4.3.1 Possibility Conditions . . . . . . . . . . . . . . . . . . 109
4.3.2 Expressing Possibility in TLA . . . . . . . . . . . . . . 110
4.3.3 Checking Accuracy . . . . . . . . . . . . . . . . . . . . 112
Real-Time Programs . . . . . . . . . . . . . . . . . . . . . . . 113
Math VI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
4.4.1 Fischer’s Algorithm . . . . . . . . . . . . . . . . . . . 115
4.4.2 Correctness of Fischer’s Algorithm . . . . . . . . . . . 118
4.4.3 Fairness and Zeno Behaviors . . . . . . . . . . . . . . 119
4.4.4 Discrete Time . . . . . . . . . . . . . . . . . . . . . . . 121
4.4.5 Hybrid Systems . . . . . . . . . . . . . . . . . . . . . . 123

5 Refinement
124
5.1 A Sequential Algorithm . . . . . . . . . . . . . . . . . . . . . 125
Math VII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
5.1.1 A One-Step Program . . . . . . . . . . . . . . . . . . . 127
5.1.2 Two Views of Refinement Mappings . . . . . . . . . . 129
5.1.3 A Step and Data Refinement . . . . . . . . . . . . . . 130
5.2 Invariance Under Refinement . . . . . . . . . . . . . . . . . . 133
5.3 An Example: The Paxos Algorithm . . . . . . . . . . . . . . . 134
5.3.1 The Consensus Problem . . . . . . . . . . . . . . . . . 135

CONTENTS

iv

5.3.2

5.4

5.5

The Paxos Consensus Algorithm . . . . . . . . . . . . 137
5.3.2.1 The Specification of Consensus . . . . . . . . 137
5.3.2.2 The Voting Algorithm . . . . . . . . . . . . . 138
5.3.2.3 The Paxos Abstract Program . . . . . . . . . 141
5.3.3 Implementing Paxos . . . . . . . . . . . . . . . . . . . 143
Proving Refinement . . . . . . . . . . . . . . . . . . . . . . . 144
Math VIII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
5.4.1 The Refinement Mapping . . . . . . . . . . . . . . . . 146
5.4.2 Refinement of Safety . . . . . . . . . . . . . . . . . . . 147
5.4.3 Refinement of Fairness . . . . . . . . . . . . . . . . . . 150
5.4.4 A Closer Look at E . . . . . . . . . . . . . . . . . . . 153
5.4.4.1 A Syntactic View . . . . . . . . . . . . . . . 153
5.4.4.2 Computing E . . . . . . . . . . . . . . . . . 155
5.4.4.3 The Trouble With E . . . . . . . . . . . . . 157
A Warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160

6 Auxiliary Variables
161
6.1 Variable Hiding . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Math IX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
6.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . 162
6.1.2 Reasoning About ∃ . . . . . . . . . . . . . . . . . . . 164
6.1.3 The Definition . . . . . . . . . . . . . . . . . . . . . . 165
6.2 History Variables . . . . . . . . . . . . . . . . . . . . . . . . . 167
6.2.1 How to Add a History Variable . . . . . . . . . . . . . 167
6.2.2 History Variables and Fairness . . . . . . . . . . . . . 171
6.2.3 A Completeness Result for History Variables . . . . . 172
6.3 Stuttering Variables . . . . . . . . . . . . . . . . . . . . . . . 173
Math X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
6.3.1 The Example . . . . . . . . . . . . . . . . . . . . . . . 174
6.3.2 Adding Stuttering Steps After an Action . . . . . . . 176
6.3.3 Adding Stuttering Steps Before an Action . . . . . . . 180
6.3.4 Fairness and Stuttering Variables . . . . . . . . . . . . 181
6.3.5 Infinite-Stuttering Variables . . . . . . . . . . . . . . . 184
6.4 Prophecy Variables . . . . . . . . . . . . . . . . . . . . . . . . 185
Math XI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
6.4.1 Simple Prophecy Variables . . . . . . . . . . . . . . . 186
6.4.2 Predicting the Impossible and Liveness . . . . . . . . . 190
6.4.3 General Prophecy Variables . . . . . . . . . . . . . . . 191
6.4.3.1 A Sequence of Prophecies . . . . . . . . . . . 192
6.4.3.2 A Set of Prophecies . . . . . . . . . . . . . . 195

CONTENTS

6.5

6.6

v

6.4.3.3 Further Generalizations . . . . . . . . . . . . 198
6.4.4 The Existence of Refinement Mappings . . . . . . . . 200
The FIFO Queue . . . . . . . . . . . . . . . . . . . . . . . . . 201
6.5.1 Fifo – A Linearizable Specification . . . . . . . . . . . 201
6.5.2 POFifo – A More General Specification . . . . . . . . 203
6.5.2.1 The Background . . . . . . . . . . . . . . . . 203
6.5.2.2 Program POFifo . . . . . . . . . . . . . . . . 205
6.5.3 Showing IPOFifo Implements Fifo . . . . . . . . . . . 209
6.5.3.1 The Prophecy Variable . . . . . . . . . . . . 210
6.5.3.2 The History Variable qBar . . . . . . . . . . 211
6.5.3.3 Stuttering and the Refinement Mapping . . . 214
Prophecy Constants . . . . . . . . . . . . . . . . . . . . . . . 215

7 Loose Ends
218
7.1 Reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
7.1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . 218
7.1.1.1 What Reduction Is . . . . . . . . . . . . . . 218
7.1.1.2 The TLA Approach . . . . . . . . . . . . . . 220
7.1.2 An Example . . . . . . . . . . . . . . . . . . . . . . . 221
7.1.2.1 The Reduced Behaviors . . . . . . . . . . . . 223
7.1.2.2 The Program S ⊗S R . . . . . . . . . . . . . . 224
7.1.2.3 The Invariant . . . . . . . . . . . . . . . . . . 228
7.1.3 Reduction In General . . . . . . . . . . . . . . . . . . 230
7.1.4 The Hypothesis 23¬L . . . . . . . . . . . . . . . . . . 234
7.1.5 Adding Liveness . . . . . . . . . . . . . . . . . . . . . 234
7.1.5.1 Fairness of Subactions of E R . . . . . . . . . 235
7.1.5.2 Fairness of Subactions of M R . . . . . . . . . 238
7.1.5.3 The Reduction Theorem with Fairness . . . . 241
7.1.6 An Example: Making Critical Sections Atomic . . . . 242
7.1.7 Another Example: Pipelining . . . . . . . . . . . . . . 245
7.2 Decomposing and Composing Programs . . . . . . . . . . . . 249
7.2.1 Decomposing Programs . . . . . . . . . . . . . . . . . 251
7.2.1.1 Writing a Program as a Conjunction . . . . . 251
7.2.1.2 Decomposing Proofs . . . . . . . . . . . . . . 253
7.2.2 Composing Components . . . . . . . . . . . . . . . . . 259

CONTENTS

vi

Appendix264

A Miscellany
264
A.1 Ordinary Math Summary . . . . . . . . . . . . . . . . . . . . 264
A.1.1 Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . 264
A.1.2 Propositional Logic . . . . . . . . . . . . . . . . . . . . 264
A.1.3 Predicate Logic . . . . . . . . . . . . . . . . . . . . . . 265
A.1.4 Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
A.1.5 The choose Operator . . . . . . . . . . . . . . . . . . 266
A.1.6 Functions . . . . . . . . . . . . . . . . . . . . . . . . . 267
A.1.7 Sequences . . . . . . . . . . . . . . . . . . . . . . . . . 267
A.1.8 Notation . . . . . . . . . . . . . . . . . . . . . . . . . . 268
A.1.9 Recursive Definitions . . . . . . . . . . . . . . . . . . . 268
A.2 Structured Proofs . . . . . . . . . . . . . . . . . . . . . . . . . 269
A.3 Why Not All Mappings Are Sets . . . . . . . . . . . . . . . . 272
A.4 How Not to Write x 000 . . . . . . . . . . . . . . . . . . . . . . 273
A.5 Hoare Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
A.6 Another Way to Look at Safety and Liveness . . . . . . . . . 277
A.6.1 Metric Spaces . . . . . . . . . . . . . . . . . . . . . . . 277
A.6.2 The Metric Space of Behaviors . . . . . . . . . . . . . 280
B Proofs
282
B.1 Invariance Proof of Increment . . . . . . . . . . . . . . . . . . 282
B.2 Proof of Theorem 4.3 . . . . . . . . . . . . . . . . . . . . . . . 285
B.3 Proof of Theorem 4.4 . . . . . . . . . . . . . . . . . . . . . . . 287
B.4 Proof of Theorem 4.5 . . . . . . . . . . . . . . . . . . . . . . . 288
B.5 Proof of Theorem 4.6 . . . . . . . . . . . . . . . . . . . . . . . 289
B.6 Proof of Theorem 4.7 . . . . . . . . . . . . . . . . . . . . . . . 289
B.7 Proof of Theorem 4.8 . . . . . . . . . . . . . . . . . . . . . . . 291
B.8 Proof Sketch of Theorem 4.9 . . . . . . . . . . . . . . . . . . 293
B.9 Proof of Formula (5.4) . . . . . . . . . . . . . . . . . . . . . . 293
B.10 Proof of Theorem 6.2 . . . . . . . . . . . . . . . . . . . . . . . 294
B.11 Proof Sketch of Theorem 6.3 . . . . . . . . . . . . . . . . . . 296
B.12 Proof Sketch of Theorem 6.6 . . . . . . . . . . . . . . . . . . 297
B.13 Proof of Theorem 7.2 . . . . . . . . . . . . . . . . . . . . . . . 300
B.14 Proof of Theorem 7.3 . . . . . . . . . . . . . . . . . . . . . . . 301
Bibliography

303

Index

308

CONTENTS

vii

About This Book (unfinished)
I hope that this book will be published, but that the pdf version will befree and only the printed version will be sold. In the published version, thissection will contain practical information about reading the book. Here issome practical information for reading the current version.
• The pdf version contains links to other places in the book. They arecolored like this. I have not decided in what color links should be.
Besides links to numbered things like equations, there are a few otherlinks in the text from terms to where they are defined or introduced. I
have not decided whether there should be more or none of those otherlinks.
• There will be an index in the published version, but there is none inthis preliminary version. In the pdf version, page numbers in the index
will be uncolored links to those pages.
• The appendix contains some hopefully interesting digressions and theproofs of most theorems, as well as a summary of the ordinary maththat is used in the book.
• Almost all the examples are tiny, so the reader can concentrate on theprinciples without being distracted by complications in the examples.
These tiny examples have been written in TLA+ and verified by model
checking; any errors in what is asserted about them are the result ofincorrect transcriptions of what has actually been verified. The TLA+
versions of the examples will be made available on the Web.
• The book contains a few marginal notes. The marginal notes in thisversion colored like this are notes to myself for things to be checked
when preparing the published version.

CONTENTS

viii

Acknowledgments (unfinished)
Because the ideas in this book were developed over several decades, it’s impossible for me to give credit to everyone who influenced their development.
I will therefore restrict this section to acknowledging only people who werecoauthors of papers of which I’ve been an author. They will be listed alphabetically. I haven’t decided whether to simply list them, or to indicate what
their influence has been. I currently expect there to be between 16 and 24
people listed, but I may change my mind on who might be included.
I will also add acknowledgments to people who read preliminary versions
and reported errors or sent me comments that led to significant changes.

Chapter 1

Introduction
1.1

Who Am I?

Dear Reader. I am inviting you to spend many pages with me. Before
deciding whether to accept my invitation, you may want to know who I am.
I was educated as a mathematician; my doctoral thesis was on partial
differential equations. While a student, I worked part-time and summers as aprogrammer. At that time, almost all programs were what I call traditional
programs—ones with a single thread of control that take input, produce
output, and stop.
After obtaining my doctorate, I began working on concurrent algorithms—
ones comprising multiple independent threads of control, called processes,that are executed concurrently. The first concurrent algorithms were meant
to be executed on a single computer, and processes communicated through ashared memory. Later came distributed algorithms—concurrent algorithms
designed to be executed on multiple computers in which processes communicate by message passing.
This is not the place for modesty. I was very good at concurrency—both
writing concurrent algorithms and developing the theory underlying them.
The first concurrent algorithm I wrote, published in 1974, is still taught atuniversities. In 1978 I published what is probably the first paper on thetheory of distributed computing. I have received many awards and honors
for this work, including a Turing award (generally considered the Nobel
prize of computer science) for “fundamental contributions to the theory andpractice of distributed and concurrent systems.”

1

CHAPTER 1. INTRODUCTION

1.2

2

Who Are You?

You probably belong to one of two classes of people who I will call scientists and engineers. Scientists are computer scientists who are interested inconcurrent computing. If you are a scientist, you should be well-prepared
to decide if this book interests you and to read it if it does.
Engineers are people involved in building concurrent programs. If you
are an engineer, you might have a job title such as programmer, software
engineer, or hardware designer. I need to warn you that this book is abouta science, not about its practical application. Practice is discussed only to
explain the motivation for the science. If you are interested just in using
the science, you should read about the language TLA+ and its tools, which
are the practical embodiment of the science [27, 34]. But if you want tounderstand the underlying science, then this book may be for you.
Like many sciences, the book’s science of concurrent programs is basedon mathematics. The book assumes only that you know the math one learns
before entering a university. The basics of all the ordinary math you will
need, which is math not part of the science, is explained in Chapter 2.
Some additional ordinary mathematics is introduced later as needed. Mostof this math is taught at universities in an introductory math course forcomputer science students, though probably not the way it is presented
here. Scientists should be used to reading math. You may find the mathhard if you’re an engineer. But unless miseducation has burdened you withan insurmountable fear of mathematics, I encourage you to give the book atry. Learning the math will improve your thinking.

1.3

The Origin of the Science

The science that is the subject of this book, which I will call our science,is a mathematical theory with a practical goal. That goal is to help build
concurrent programs that work correctly. Exactly what “working correctly”
means and why it’s an important goal are explained in Section 1.4. The
origin of our science explains how I came to believe it’s a good foundation
for trying to achieve that goal.

1.3.1

The Origin of the Theory

The first concurrent algorithm was published in 1965 by Edsger Dijkstra [9].
I started writing concurrent algorithms around 1973, and I quickly learned

CHAPTER 1. INTRODUCTION

3

that they were hard to get right. The many possible orders in which the operations of different processes can be executed leads to an enormous numberof possible executions that have to be considered. The only way to ensurethat the algorithm worked correctly was to prove that it did.
By the 1970s, a standard approach had been developed for proving correctness of traditional programs. Around 1975, I and a few other computerscientists began extending that approach to concurrent algorithms [4, 23, 28,44]. Concurrent algorithms were usually written in pseudocode plus some
informal explanation of what the pseudocode meant. I came to realize that
all these methods for proving correctness could be explained by describing
a concurrent algorithm as what I am now calling an abstract program; andan abstract program could be described mathematically.
Correctness of an algorithm was expressed by properties required of its
executions. I came to realize that correctness can also be expressed by
an abstract program—a more abstract, higher-level one than describes thealgorithm. Proving correctness means showing that the abstract program
describing the algorithm implements the abstract program describing its
correctness, and I developed a method for doing that.
This work culminated around 1990 with a way to write an abstract program as a single formula [31]. The formula is written in an obscure formof math called temporal logic. The particular temporal logic is called TLA(for the Temporal Logic of Actions). Most of the TLA formula for an abstract program consists of ordinary math that expresses essentially what
was described by pseudocode. Temporal logic replaces the informal explanation of the pseudocode. That one abstract program implements anotheris expressed as logical implication together with mathematical substitution.
Throughout this period, I was writing correctness proofs of the algorithms I was inventing. This showed me that my way of reasoning with
abstract programs worked in practice. However, I discovered that as myalgorithms got more complicated and the formulas describing them became
larger, the method of writing proofs used by mathematicians became unreliable. It could not ensure that all the details were correct. I had to devise
a method of hierarchically structuring proofs to keep track of those details.

1.3.2

The Origin of the Practice

I have spent most of my career as a member of industrial research labs. The
computer science I have done has been motivated by the problems facing
system builders—sometimes before they were aware of those problems. I
have devoted the last part of my career to developing tools to help them—

CHAPTER 1. INTRODUCTION

4

both intellectual tools to help them think better and programs to help themdetect errors before they are implemented in code. These tools are based onwhat I learned by writing and reasoning about concurrent algorithms.
Programming is not just coding. It requires thinking before we code.
Writing algorithms taught me that there are two things we need to decide
before writing and debugging the code: what the program should do andhow the program should do it. Most programmers think that the code
itself adequately describes “how the program should do it”, but I learned
that we need a higher-level, more abstract description of what the program
does. To emphasize that programming is more than just coding, I now
use the name coding language for what are commonly called programming
languages. That name is used in this book.
An algorithm is an example of a description of how a program should dosomething. Concurrent algorithms are hard to understand. To invent them,
I had to be able to write them in the simplest way possible. Algorithms wereusually written in pseudocode to avoid the complexity that real code requires
to permit efficient execution. I developed a way to describe concurrent
algorithms in math that was more precise and no harder to understandthan pseudocode.
Engineers who build complex systems usually recognize the need fordescribing what their programs do in a simpler, more abstract way thanwith code. I decided that abstract programs written in math provided sucha way for describing the aspects of a system that involve concurrency. By
about 1995, I had designed a complete language called TLA+ that engineers
could use to write abstract programs in TLA.
The abstract programs I know of that have been written by engineers to
describe what a system should do generally consist of about 200–2000 lines
of TLA+. All but a few of those lines are ordinary math, not temporal logic.
As with code, those formulas are made easy to understand by decomposing
them into smaller pieces. This is done using simple definitions, rather thanthe more complex constructs of coding languages.
To formalize mathematics and make it easier to write long formulas, I
had to add to TLA+ some concepts and syntax not present in the math commonly used by mathematicians—for example, variable declarations, grouping definitions into modules, and notation for substitution. This book uses
TLA, but not TLA+, because the examples with which it illustrates ourscience are short and simple.
The kind of hierarchically structured proofs I devised can also be written in TLA+, and there is a program for checking the correctness of those
proofs. However, with today’s proof-checking technology, writing machine-

CHAPTER 1. INTRODUCTION

5checked proofs takes more time than engineers generally have. By the time
I designed TLA+, model checking had become a practical tool for checking
the correctness of abstract programs. A model checker can essentially checkcorrectness of all possible executions of a very small instance of an abstract
program. This turns out to be very effective at detecting errors. There
are two model checkers for abstract programs written in TLA+, using twocomplementary approaches. Model checking is the standard way engineers
check those programs.
A program’s code can, in principle, be described by a (concrete) abstract
program and could, in principle, be written as a TLA+ formula. For a simple
program (or part of a program), the code can be hand-translated to TLA+
and checked with the TLA+ tools. Usually, the length of the program andthe complexity of the coding language makes this impractical.
From the point of view of our science, it makes no difference how long a
formula an abstract program is. We therefore consider a program written ina coding language to be an abstract program. And since we are considering
only abstract programs, we will let program mean abstract program. We
will call an (abstract) program written in code a concrete program.
Although we don’t write them as formulas, viewing concrete programs as
abstract programs provides a new way of thinking about them. One benefitof this way of thinking is that understanding what it means for a concrete
program to implement a higher-level abstract program can help avoid coding
errors.

1.4

Correctness

Thus far, our science has been described as helping to build concurrent
programs that work correctly. Working correctly is a vague concept. Hereis precisely what we take it to mean.
We define a behavioral property to be a condition that is or is not satisfied by an individual execution of a program. For example, termination
is a behavioral property. An execution either terminates or else it doesn’t
terminate, meaning that it keeps executing forever. We say that a programsatisfies a behavioral property if every possible execution of the program satisfies it. A program is considered to work correctly, or simply to be correct,
if it satisfies its desired behavioral properties.
That every possible execution of a program satisfies its behavioral properties may seem like an unreasonably strong requirement. I would be happy
if a program that I use does the right thing 99.99% of the times I run it. For

CHAPTER 1. INTRODUCTION

6

many programs, extensive testing can ensure that it does. But it can’t formost concurrent programs. What a concurrent program does can depend on
the relative order in which operations by different processes are executed.
This makes the program nondeterministic, meaning that different executions
can do different things, even if the program receives identical inputs. Thiscan result in an enormous number of possible executions, and testing can
examine only a tiny fraction of them. Moreover, a concurrent program thathas run correctly for years can start producing frequent errors because asmall change to the computer hardware, the operating system, or even theother programs running at the same time causes incorrect executions thathave never occurred before. The only way to prevent this is to ensure thatevery possible execution satisfies the behavioral properties.
Model checking is more effective at finding errors in concurrent programs
than ordinary testing because it checks all possible executions. However,it does this only on a few small instances of the program—for example,
an instance with few processes or one that allows only a small number ofmessages to be in transit at any time.1 Engineering judgment is required
to decide if correctness of those instances provides enough confidence in thecorrectness of the program.
There is one way testing could find errors in concrete programs. Whenbuilding a concurrent system, an abstract program is often used to model
how the processes interact with one another, and correctness of that program is checked. The concrete program is then coded by implementing eachprocess of the more abstract program by a separate process in the code.
Since there is no concurrency within an individual process, testing that theconcrete program implements the more abstract program has a good chanceof finding coding errors. Research on this approach is in progress.

1.5

A PreviewTo give you an idea of what our science is like, this section describes informally a simple abstract program for Euclid’s algorithm—a traditionalalgorithm that computes a value and stops. It’s a very simple concurrent
program in which the number of processes equals 1. Our science applies tosuch programs, although there are simpler sciences that work quite well forthem.
1

There are techniques for proving the correctness of a program by model checking asimpler program, but they have not been implemented for abstract programs written in
TLA+.

Is there acitation forthis?

CHAPTER 1. INTRODUCTION

7

Euclid’s algorithm computes the greatest common divisor (GCD) of two
positive integers that we will call M and N . For example, the GCD of 12 and16, written GCD(12, 16), equals 4 because 4 is the largest integer such that
12 and 16 are both multiples of that integer. The algorithm is an abstract
program containing two variables that we name x and y. Here is its prose
description.
Start with x equal to M and y equal to N and repeatedly perform thefollowing action until the program stops:
If the values of variables x and y are equal, then stop; otherwise,
subtract from the variable having the larger value the value of theother variable.2
I believe most engineers and many scientists can’t explain why an executionof Euclid’s algorithm computes GCD(M , N ), which means that they don’t
understand the algorithm. Here is the explanation provided by our science,
beginning with how we view executions.
We consider an execution to be a sequence of states. For Euclid’s algorithm, a state is an assignment of values to the program variables x and y.
We write the state that assigns 7 to x and 42 to y as [x :: 7, y :: 42]. Here is
the sequence of states that is the execution of Euclid’s algorithm for M = 12
and N = 16.
"#

x :: 12y :: 16"→#x :: 12y :: 4"→#x :: 8y :: 4"→#x :: 4
y :: 4The states in the sequence are separated with arrows because we naturally
think of an execution going from one state to the next. But in terms of ourscience, the algorithm and its execution just are; they don’t go anywhere.
What an algorithm does in the future depends on its current state, noton what happened in the past. This means that in the final state of theexecution, in which x and y are equal, they equal GCD(M , N ) because ofsome property that is true of every state of the execution. To understandEuclid’s algorithm, we must know what that property is.
That property is GCD(x , y) = GCD(M , N ). (Chapter 3 explains how
we show that every state satisfies this property.) Because an execution
stops only when x and y are equal, and GCD(i , i ) equals i for any positive2
You may have seen a more efficient modern version of Euclid’s algorithm that replaces
the larger of x and y by the remainder when it is divided by the smaller. For the purposeof this example, it makes little difference which we use.

CHAPTER 1. INTRODUCTION

8integer i , this property implies that x and y equal GCD(M , N ) in the final
state of the execution.
That the formula GCD(x , y) = GCD(M , N ) is true in every state of aprogram’s execution is a behavioral property. A behavioral property that
asserts a formula is true in all states of an execution is called an invarianceproperty, and the formula is called an invariant of the program. Correctnessof any concurrent program depends on it satisfying an invariance property.
To understand why the program is correct, we have to know the invariantof the program that explains its correctness.
The invariant GCD(x , y) = GCD(M , N ) shows that, if Euclid’s algorithm terminates, then it produces the correct output. A traditional program must also satisfy the behavioral property of termination. The two
behavioral properties• The program produces correct output if it terminates.
• The program terminates.
are special cases of the following two classes of behavioral properties thatcan be required of a concurrent program:
Safety What the program is allowed to do.
Liveness What the program must eventually do.
These two classes of properties are defined precisely in Section 4.1. Termination is the only liveness property required of a traditional program. There
are many kinds of liveness properties that can be required of concurrent
programs.
Euclid’s algorithm satisfies its safety requirement (being allowed to terminate only if it has produced the correct output) because the only thing
it is allowed to do is start with x = M and y = N and execute its action.
That is, it satisfies its safety requirement because it is assumed to satisfy thesafety property of doing only what the description of the algorithm allows
it to do.
Euclid’s algorithm satisfies its liveness requirement (eventually terminating) because it is assumed to satisfy the liveness property of eventually performing any action that its description allows it to perform. (Section 3.4.2.8
shows how we prove that the algorithm terminates.)
I have found it best to describe and reason about safety and livenessin different ways. In our science, temporal logic plays almost no role inhandling safety, but it is central to handling liveness. The TLA formula forCHAPTER 1. INTRODUCTION

9an abstract program is the logical conjunction of a safety property and aliveness property.
A single-process algorithm that computes a value and stops doesn’t seemto be a good example for a science of concurrent programs. So, let’s consider
a concurrent version of Euclid’s algorithm. It’s a two-process version of thealgorithm, suitable for execution on a single computer with the processes
communicating through shared variables. We call the two processes the x
process and the y process. The algorithm uses the same program variables
as the one-process version of Euclid’s algorithm and it begins in the samestarting state, with x = M and y = N . If the x process hasn’t stopped, it
is allowed to execute the following action whenever the when condition istrue:
When x ≥ y, stop if x = y, else subtract the value of y from x .
Process y is the same as process x , except with x and y interchanged.
Written in pseudocode, this version of Euclid’s algorithm looks different from the one-process version. However, if we consider the executionsof the two versions, we see that they are the same. That is, they have thesame sequence of states, where a state is an assignment of values to x and y.
Whether we view Euclid’s algorithm as a one- or two-process algorithm may
affect how we implement it with a concrete program. An implementationof the two-process algorithm with a two-process concrete program would
probably be less efficient than a single-process implementation of the oneprocess algorithm. Since these two versions of the algorithm have the same
executions, from the point of view of correctness they are the same algorithm. Both versions are written as the same TLA formula. More precisely,
their formulas are equivalent. There are many equivalent ways to write amathematical formula. How we choose to write the TLA formula for Euclid’s algorithm can depend on whether we view it as a one- or two-process
algorithm.

1.6

Why Math?

The science of bridge building has a mathematical basis, but bridge designers don’t represent a bridge by a mathematical formula. Why should we
describe an abstract program with one? The simple answer is, because wecan. A concrete program is not a physical object; it’s a concept. Code isjust one representation of that concept. While possible in theory, writing amathematical representation of a concrete program is not practical. How-

CHAPTER 1. INTRODUCTION

10

ever, for simpler abstract programs, it is possible; and I’ve found it to be agood way to represent them.
Math has been developed over thousands of years to be simple and expressive. An abstract program ignores many implementation details, which
often means allowing multiple possible implementations. This is simple toexpress in math. Code is designed to describe one way of computing something. It can be hard or even impossible to write code that allows all thosepossibilities. Being based on concepts from coding languages, pseudocode
also lacks the simplicity and expressiveness of math.
One place we want to allow many possible implementations is in describing what the environment can do. A program can’t work in an arbitrary
environment. An implementation of Euclid’s algorithm will not produce thecorrect answer if the operating system can arbitrarily modify the variables x
and y. A concurrent program can interact with its environment in complicated ways, and we have to state explicitly what the program assumes about
its environment to know if its correct. We usually want to assume as little asnecessary about the environment, which means the abstract program should
allow it to have many different behaviors.
Unanticipated behavior of the environment is a serious source of errors
in concurrent programs. Part of the environment of a program is likely tobe another program, such as an operating system. Avoiding errors may
require finding answers to subtle questions about exactly what that otherprogram does. This is often difficult, because the only description of what
it does other than its code is likely to be imprecise prose. When writing theabstract program to describe what our concrete program does, describing
what the environment can do will tell us what questions we have to ask.
The expressiveness of math, embodied in TLA, provides a practicalmethod of writing and checking the correctness of high-level designs of systems. Such checking can catch errors early, when they are easier to correct.
TLA+ is used by a number of companies, including Amazon [41], Microsoft,
and Oracle. Math also provides a new way of thinking about programs thatcan lead to better programming. There is usually no way to quantify the
result of better thinking, but it was possible in the following instance.
Virtuoso was a real-time operating system. It controlled some instruments on the European Space Agency’s Rosetta spacecraft that explored acomet. Its creators decided to build the next version from scratch, startingwith a high-level design written in TLA+. They described their experiencein a book [48]. The head of the project, Eric Verhulst, wrote this in an email
to me:

CHAPTER 1. INTRODUCTION

11

The [TLA+] abstraction helped a lot in coming to a much cleaner architecture. One of the results was that the code size is about 10× lessthan in [Virtuoso].3
This result was unusual. It was possible only because the design of theentire system was described with TLA+. Usually, TLA+ is used to describe
only critical aspects of a system that involve concurrency, which represent
a small part of the system’s code. But this example dramatically illustrates
that describing abstract programs with mathematics can produce better
programs.

3

The book states the reduction in code size to be a factor of 5–10. Verhulst explained
to me that it was impossible to measure the reduction precisely, so the book gave aconservative estimate; but he believes it was actually a factor of 10.

Chapter 2

Ordinary Math
We will write an abstract program as a mathematical formula. A program
can be quite complex, leading to a long formula. A long formula with a lotof esoteric mathematics would be impossible to understand. Almost all themath used in our formulas is ordinary math, consisting of arithmetic, simple
logic, sets, and functions. You should know most of it already if you took
an introductory university math course for computer science or engineering
students. Ordinary math does not include the temporal logic introduced in
Sections 3.4 and 3.5.
This chapter explains the foundation of the ordinary math used in thisbook. It describes the math needed to begin our study of abstract programs. Later chapters introduce additional math as needed, in special sections named Math I through Math XII. Math introduced in one chapter
may be used in later chapters. A brief summary of all the ordinary mathused in the book is in Appendix Section A.1. Longer and perhaps easier tounderstand intuitive explanations of most of the math we will use can befound on the Web.
An abstract program is written as a TLA formula. While most of that
formula consists of ordinary math, TLA is a temporal logic, and temporal
logic is not ordinary math. The meaning of TLA formulas will be explainedin terms of ordinary math. However, although not hard to understand,temporal logic doesn’t satisfy all the properties of ordinary math. Avoiding mistakes when using it requires understanding what its formulas mean.
Giving a meaning to the formulas of a logic is called defining a semanticsof the logic. This chapter explains how to define a semantics by defining
the meaning of formulas of ordinary math. Even if you’re familiar with themath presented here, the explanation of its semantics may be new to you.

12

CHAPTER 2. ORDINARY MATH

13

Therefore, you should at least skim this chapter carefully.
In mathematics, the truth of an assertion is established by proof. A
mathematician’s proof is usually a sequence of paragraphs. This way ofwriting proofs is adequate for simple proofs. However, it’s not reliable forcomplicated proofs. It’s particularly unsuited to handling the many details
in a proof of correctness of a program. This book uses a way of writing
structured proofs that makes proofs easier to read, and therefore makes it
harder to prove things that aren’t true. Ordinary paragraph proofs are used
only to prove simple results, and for proof sketches that aren’t meant to be
proofs.
Most of the proofs in this book are in the appendix. Before reading
them, you should read Appendix Section A.2, which explains our structured
proof style. I hope that, some day, all engineers will be able to write proofsof correctness of their abstract programs. The proofs mathematicians write
are too unreliable to provide confidence that a program is correct. Engineers
will have to use some way of structuring proofs like the one described in thisbook. Scientists would also benefit from using it.
Understanding a science of program correctness requires understanding
how to prove correctness of a program. Later chapters of the main text
therefore contain some proofs. Those chapters explain what you need toknow about our proof style to understand their proofs.
The description of Euclid’s algorithm in Chapter 1 used the program
variables x and y. Program variables are different from the variables ofordinary math, such as the ones used in elementary algebra. The values ofthe program variables x and y in Euclid’s algorithm change during executionof the algorithm. The values of the variables x and y of elementary algebra
remain the same throughout a calculation. They are like the constants M
and N of Euclid’s algorithm. For now, we will use the term variable to meana variable of ordinary math, like the ones of elementary algebra.
We begin with what I believe is the hardest math that you will have toknow—a branch of math that takes people years to learn. It’s much too
difficult to explain here, so I will have to assume that you’ve already learned
it. It’s called arithmetic.

CHAPTER 2. ORDINARY MATH

2.1

14

Arithmetic as a Mathematical Theory

Arithmetic is about numbers. The first numbers you learned about are thepositive integers 1, 2, 3, etc. You then learned about more and more kinds ofnumbers until eventually you learned about the real numbers, which √includeintegers, rational numbers like 3/4, and lots of other numbers like − 2 andπ (which equals 3.14159. . . ). Although the numbers we will use are almost
always integers, most of our discussion here applies to all real numbers, so
we let number mean real number.
We use the same notation for the operators of arithmetic that you learnedin school—for example +, / (division), and ≥ ; except that multiplication is
written “∗” because mathematicians use × to mean something else.
An operator like ∗ is what we call a mapping. A mapping M takes somefixed number of arguments. If M takes two arguments, then M (v , w ) is avalue for some values v and w . For the mapping ∗, if v and w are numbers,
then ∗(v , w ) equals the number we usually write v ∗ w . For the mapping= , if v and w are numbers, then =(v , w ) is a value we call true if v equals
w , and it’s a different value we call false if v doesn’t equal w .1 The values
true and false are called Booleans. A mapping such as = whose value isa Boolean for all values of its arguments is called a predicate.
A mathematical theory contains expressions. An expression in the theoryof arithmetic is a syntactically correct sequence of numbers, the operators ofarithmetic, and parentheses—for example 2 ∗ (3 + 42). It’s best to think of
2 ∗ (3 + 42) as a way of writing the expression ∗(2, +(3, 42)). Since it’s thenormal way of writing expressions, we’ll write 2 ∗ (3 + 42); but we’ll thinkof it as ∗(2, +(3, 42)).
An expression like 2∗(3+42) whose value is a number is called a numericexpression. An expression like 2 + 2 > 22 whose value is a Boolean is calleda Boolean expression or, more commonly, a formula.
The semantics of a mathematical theory is a mapping that assigns ameaning to each expression. We write the meaning of an expression exp as[[exp]]. But you spent years learning the meaning of arithmetic expressions,so there’s no need for me to explain it to you. If I define something in termsof arithmetic expressions, then you will understand it.
1

Arithmetic has two different operators named −, one takes two arguments, and−(v , w ) equals the number we usually write v − w ; the other takes a single argument,and −(v ) is the number we write −v .

CHAPTER 2. ORDINARY MATH

15

I have been told that many engineers freak out when they see a
Greek letter like Υ in a formula. If you’re one of them, now is thetime to get over it. You had no trouble dealing with π as a child;
you can now handle a few more Greek letters. They’re usedsparingly in this book, but sometimes representing a particularkind of object with Greek letters makes the text easier to read.
Here are all the Greek letters used in the book, along with theirEnglish names. You don’t have to remember their names; youjust need to distinguish them from one another.
Lowercaseα alphaλ lambda
β betaµ mu
δ deltaν nu
 epsilon (also written ε)

π pi
ρ rho
σ sigma

τ tau
φ phi
ψ psi

UppercaseΛ Lambda∆ Delta

Π Pi

Φ Phi

Υ Upsilon

Figure 2.1: Greek letters used in this book.

2.2

The Mathematical Theory of Algebra

By algebra, we mean here elementary algebra, which you probably learned
as a teenager. In addition to numbers, algebra has variables that “standfor” numbers. For example, 3 ∗ x − 2 ∗ y is a numeric expression of algebra,
and 3 ∗ x − 2 ∗ y = 7 is an algebraic formula, where x and y are variables.
The meaning of an algebraic expression is the value obtained by substituting arbitrary numbers for the variables. To state this precisely, we define
an interpretation to be a mapping from variables to numbers. The meaning of an expression of algebra is a mapping from interpretations to values,
where a value is a number or a Boolean. If exp is an expression and Υ is an If you’re notinterpretation, then [[exp]](Υ) equals the value of the arithmetic expression used to reading
obtained by replacing each variable v that occurs in exp with Υ(v ). For formulas withGreek letters,
example, suppose Υ is an interpretation such that Υ(x ) equals 1 and Υ(y) go now toequals −2, then [[3 ∗ x − 2 ∗ y]](Υ) equals 3 ∗ 1 − 2 ∗ (−2), which equals 7. Figure 2.1.
Observe that the ∗ and − in [[3∗x −2∗y]](Υ) are different operators thanthe ∗ and − in 3 ∗ 1 − 2 ∗ (−2). In [[. . .]](Υ) they are operators of algebra; in
3 ∗ 1 . . . they are operators of arithmetic. The meaning of the operator ∗ ofalgebra is defined in terms of the operator ∗ of arithmetic by the rule that,

CHAPTER 2. ORDINARY MATH

16

for any algebraic expressions exp 1 and exp 2 and any interpretation Υ:[[exp 1 ∗ exp 2 ]](Υ) = [[exp 1 ]](Υ) ∗ [[exp 2 ]](Υ)
There are similar rules for − and the other operators of algebra. There arealso two other rules:• [[v ]](Υ) equals Υ(v ), for any variable v .
• [[exp]](Υ) equals exp, if exp contains no variables (so it’s an expressionof arithmetic).
We can apply these rules to compute [[3 ∗ x − 2 ∗ y]](Υ) as follows:[[3 ∗ x − 2 ∗ y]](Υ)= [[3 ∗ x ]](Υ) − [[2 ∗ y]](Υ)

by the rule for −= [[3]](Υ) ∗ [[x ]](Υ) − [[2]](Υ) ∗ [[y]](Υ)

by the rule for ∗= 3 ∗ Υ(x ) − 2 ∗ Υ(y)by the two rules above

An important class of formulas are ones that equal true no matter whatvalues are substituted for their variables. Such a formula is said to be valid ;and the assertion that F is valid is written |= F . For example, we write(2.1) |= p ∗ (q + r ) = p ∗ q + p ∗ r
The thing we write as |= F is not a formula of algebra. It’s an assertion about
the formula F . Formally, |= F is a metamathematical formula or metaformula. We usually call it something else like an assertion or a condition.
When |= F is true for an interesting formula F , mathematicians generally
call F a theorem.2 We might call (2.1) a theorem of algebra. An axiom isa theorem that we take to be an assumption. I will sometimes call |= F ameta-formula to remind you that it’s not a formula.
A proof rule tells us how to deduce the validity of one formula fromthe validity of one or more other formulas. A basic proof rule of algebra isthat if a formula is valid, then the formula obtained by substituting numericexpressions for the formula’s variables is also valid. For example, we candeduce from (2.1) the following meta-formula, for any numeric expressions
exp 1 , exp 2 , and exp 3 ,|= exp 1 ∗ (exp 2 + exp 3 ) = exp 1 ∗ exp 2 + exp 1 ∗ exp 32
Logicians call a formula a theorem only if it it can be proved from some collection of
axioms and proof rules.

CHAPTER 2. ORDINARY MATH

17

Implicit in the informal definition of an interpretation given above is thatan interpretation assigns values to all possible variables, not just the onesin any particular expression. The value of [[F ]](Υ) for a formula F depends
only on the values the interpretation Υ assigns to variables that occur in
F . But letting an interpretation assign values to all variables simplifies
things, because it means we don’t have to keep track of which variables aninterpretation is assigning values to.
We assume that there are infinitely many variables. We do this for thesame reason we assume there are infinitely many integers even though weonly ever use relatively few of them: it makes things simpler not to have toworry about running out of them.

2.3

Mathglish

Math is precise, but this book isn’t written in math. It’s written in Englishthat explains math. Explaining the precise meaning of math in the imprecise
language of English is not easy. To help them do this, English-speaking
mathematicians speak and write in a dialect of English I call Mathglish. (Iexpect mathematicians use similar dialects of other languages.) Mathglish
differs from English in two ways: It eliminates some of the imprecision ofEnglish by giving a precise meaning to some imprecise English words, and it
makes the written language more compact by using mathematical formulas
to replace English phrases.
This book is written in Mathglish. This chapter explains the Mathglish
you need to know to read the book. This section discusses the second featureof Mathglish—the use of formulas to replace prose.
Consider these two sentences that might appear in a math book:
1. Substituting y + 1 for z in formula (42) yields x ≥ y + 1.
2. Formula (42) shows us that x ≥ y + 1.
Grammatically, we can see that the two uses of “x ≥ y + 1” are different.
In sentence 1 it’s a noun, while in sentence 2 it’s a complete clause. In
sentence 1, “x ≥ y + 1” is a formula; in sentence 2 it’s an abbreviation for“x is greater than or equal to y + 1”. This grammatical difference tells usthat the two sentences have very different meanings. Sentence 2 asserts thatthe formula x ≥ y + 1 is true. The first doesn’t tell us whether it’s true or
false. For example, sentence 1 could be followed by:Since (41) implies x < y + 1, this proves that (42) is false.

CHAPTER 2. ORDINARY MATH

18

It isn’t always possible to tell from the grammar which way a formula isbeing used in a sentence. Sometimes we have to look at the context inwhich the sentence appears. The formula x ≥ y + 1 can be true only in acontext in which some assumptions have been made about the values of x
and y—assumptions that are expressed by formulas that are assumed to betrue. Without such assumptions, the formula can be used only as a formula,which may be true or false. I have tried to make it clear by grammar orcontext what it means when a formula appears in a sentence in this book.

2.4

Boolean Arithmetic (Propositional Logic)

Arithmetic is about numbers. Boolean arithmetic is about Boolean values. Since there are only two Boolean values, true and false, Boolean
arithmetic is infinitely simpler than ordinary arithmetic. A lot of mathematical reasoning can be described as Boolean arithmetic calculation. In
fact, Boolean arithmetic is also called propositional logic. We’ll first see how
it’s used in algebra.
We obtained an operator of algebra such as + from the corresponding operator + of arithmetic by defining [[exp 1 + exp 2 ]](Υ) to equal[[exp 1 ]](Υ) + [[exp 2 ]](Υ), for any numeric expressions exp 1 and exp 2 and any
interpretation Υ. We can do the same thing with the operators of Boolean
algebra. For example, the operator ∧ of Boolean algebra, which is defined
below, can be made an operator of algebra by defining [[F ∧ G]](Υ) to equal[[F ]](Υ) ∧ [[G]](Υ) for any formulas (Boolean-valued expressions) F and G
and any interpretation Υ.
When you studied algebra, you learned how to solve equations such as(2.2) 3 ∗ x − 2 ∗ y = 7 and 7 ∗ x + 3 ∗ y = 1
You would have found that the solution is x = 1 and y = −2. In calculatingthat solution, you actually proved that that’s the only solution. That is,you proved that the equations (2.2) imply x = 1 and y = −2. The conceptsof and and imply are expressed by the operators ∧ and ⇒ of Boolean logic.
In solving equations (2.2), you proved this theorem:(2.3) |= (3 ∗ x − 2 ∗ y = 7) ∧ (7 ∗ x + 3 ∗ y = 1) ⇒ (x = 1) ∧ (y = −2)
Mathematical theories generally have formulas, and the operators of Boolean
arithmetic are turned into operators on formulas in all those theories thesame way it’s done with elementary algebra.

CHAPTER 2. ORDINARY MATH

19

Since you probably already know them, the operators of Boolean arithmetic are presented only briefly. Here are the operators, their names, andhow they’re read in Mathglish:¬∧∨

negationconjunction
disjunction

not
and
or

⇒
≡

implicationequivalence

implies
if and only if

Implication is sometimes written → or ⊃, and ≡ is sometimes written ⇔or ↔. Negation and conjunction are defined by¬ true = false¬ false = true

true ∧ true = true
true ∧ false = false
false ∧ true = false
false ∧ false = false

The other operators can be defined in terms of ¬ and ∧. In these definitions,∆
A and B represent Boolean values and = means equals by definition:∆

A ∨ B = ¬(¬A ∧ ¬B )∆A ⇒ B = (¬A) ∨ B∆
A ≡ B = (A ⇒ B ) ∧ (B ⇒ A)
If you’re not familiar with Boolean arithmetic, you should write out thecomplete definitions of ∨, ⇒, and ≡, the way it’s done above for ¬ and ∧.
Here is a brief explanation of what these operators and their Mathglish
counterparts mean—where is true means equals true.
¬A asserts that A is not true, where not means the same thing in English
and Mathglish.
A ∧ B asserts that A is true and B is true, where and has the same meaning
in both languages.
A ∨ B asserts that A is true or B is true (or both A and B are true). Unlike
or in English, or in Mathglish allows the possibility that both formulas
are true.
A ⇒ B asserts that A is true implies B is true. This means that B mustbe true if A is true, but says nothing about B if A is false. Thus,
false ⇒ true and false ⇒ false both equal true. Reading ⇒as implies is confusing because A implies B in English means that A
being true causes B to be true, while implies in Mathglish does not.

CHAPTER 2. ORDINARY MATH

20

Only in Mathglish would we say that 2 + 2 = 5 implies 2 + 2 = 4.
A good way to understand ⇒ and the Mathglish implies is that we
want⇒(x > 20) implies(x > 10)to be true for all numbers x , and substituting different numbers for x
shows that we want A ⇒ B to equal true except when A = true and
B = false. Observe that in (2.3), the formula to the left of the ⇒equals false for an interpretation Υ unless Υ(x ) = 1 and Υ(y) = −2.
A ≡ B asserts that A is true if and only if B is true. Thus, ≡ is theequality relation for Boolean values. We read ≡ as is equivalent to.
Because we often want to express equivalence, written Mathglish has
the abbreviation iff for if and only if. We sometimes write equals
instead of is equivalent to because it’s shorter.
Boolean arithmetic is often described as arithmetic with the two numbers
0 and 1, where false is 0 and true is 1. There is the following correspondence between the Boolean operators on false and true and the arithmetic
operators on 0 and 1
∧ ↔ ∗

∨ ↔ +

⇒ ↔ ≤

≡ ↔ =

except that 1+1 is taken to equal 1. Under this correspondence, the following
laws of ordinary arithmetic become the following laws of Boolean arithmetic,
where A, B , and C are any Boolean values:∧ and ∨ are associate and commutative—where an operator ? is associative iff (A ? B ) ? C equals A ? (B ? C ) , and ? is commutative iff
A ? B equals B ? A .
⇒ and ≡ are transitive, where ? is transitive iff A ? B and B ? C
imply A ? C . Transitivity is often used in proofs. For example, it
allows us to prove A ⇒ Z by proving A ⇒ B and B ⇒ C and . . .
and Y ⇒ Z .
∧ distributes over ∨ , which means that A ∧ (B ∨ C ) equals(A ∧ B ) ∨ (A ∧ C ) .
Boolean arithmetic also has the extra rule that ∨ distributes over ∧ .

CHAPTER 2. ORDINARY MATH

21

Negation is related to subtraction by ¬A ↔ 1 − A, which leads to thefollowing rules of Boolean arithmetic:¬(A ∧ B ) equals (¬A) ∨ (¬B )¬(A ∨ B ) equals (¬A) ∧ (¬B )All expressions of Boolean arithmetic are Boolean valued, so they areformulas. When parsing these formulas, ¬ has higher precedence (binds
more tightly) than ∧ and ∨, which have higher precedence than ⇒ and ≡.
Thus¬A ∧ B ⇒ C ∨ D

equals((¬A) ∧ B ) ⇒ (C ∨ D)

I don’t know how the following expressions should be parsed, so don’t writethem:A∧B ∨CA≡B ⇒CWhen these operators are incorporated into algebra, they have lower precedence than arithmetic operators like + and >. However, it’s best to put
parentheses around purely algebraic formulas (like those of (2.2)) when using operators from Boolean arithmetic.
I like the name Boolean arithmetic because it makes the subject sound as
simple as it really is. However, it’s usually called propositional logic, so that’s
what we’ll call it from now on. You can find propositional logic calculatorson the Web that will check whether a formula like (A ⇒ B ) ⇒ (¬B ⇒ ¬A)
is true for all Boolean values A and B . They can help you become facile
with propositional logic.

2.5

ZF

Computers do a lot more than numerical computation. To describe what
computer systems do mathematically, our math needs more kinds of values
than just numbers. The simplest way I know to make the math we needrigorous is to base it on what is called ZF set theory or simply ZF, where Z
and F stand for the mathematicians Ernst Zermelo and Abraham Fraenkel.
One thing that makes ZF simple is that every value is a set. In ZF, the terms
set and value mean exactly the same thing. Sometimes I will write set/value
instead of set or value to remind you that the two words are synonyms.
You’ve probably learned that a set is a collection of things. In ZF, those
things are sets, so a set is a collection of sets. However, we will see belowthat not all collections are sets—in particular, the collection of all sets isn’t
a set. The fundamental operator on sets is ∈, which is read is an element

CHAPTER 2. ORDINARY MATH

22of or simply in. For every value/set S , the formula e ∈ S equals true iff
e is one of the values/sets that S is a collection of. We call the values in a
set S the elements of S . Two values/sets are equal iff they have the sameelements.
Two sets that we√will use are the set R of all real numbers and the set
I of integers. Thus, 2 is an element of R but not an element of I. Since
the elements of a set are sets, this means a number must be a set. Logicians
have used the operators of ZF set theory to define the set of real numbers.
There’s no need for us to do that; we just assume the real numbers exist
and the√arithmetic operators satisfy their usual properties. This means that
42 and√ 2 are sets, but we don’t specify what their elements are. We knowthat 2 ∈ 42 equals either true or false, but we don’t know which. The
Booleans true and false are also values.3 We generally use the term value
for a set/value like 42 or true for which we don’t know what its elements
are; and we use the term set for a set/value when we know what its elementsare.
We define the semantics of ZF the same way we defined the semantics
of algebra. The meaning [[exp]] of an expression exp of ZF is a mappingfrom interpretations to values, where an interpretation is a mapping fromvariables to values. The operators of propositional logic are incorporated
into ZF the same way they were incorporated into algebra. A formula is anexpression F such that [[F ]](Υ) is a Boolean for every interpretation Υ.
You’ve probably learned a number of operations on sets, and you willneed them if you want to write abstract programs that describe real systems.
But the examples in this book are so simple that we’ll need few of them.
We often speak of one set being a subset of another—for example, I is asubset of R because every integer is a real number. The assertion that S isa subset of T is written ⊆. It is effectively defined by this axiom:|= S ⊆ T ≡ ((v ∈ S ) ⇒ (v ∈ T ))where S , T , and v are variables.
A simple way to describe a set is by enumerating its elements. If
v 1 , . . . , v n are any values, then they are the (only) elements of the set{v 1 ,√. . . , v n }. This set need not have n elements. For√ example, the set
only the three elements 2, 3, and 42. It is{3, 2, 3, 2+1, 42, 3} contains√
equal to the set {42, 42, 3, 2}. (It is as silly to say that a set has two copiesof the number 42 as it is to say that a football team has two copies of one
3

As usually defined, ZF does not consider true and false to be sets. Making themsets will allow the value of a program variable to be a Boolean.

CHAPTER 2. ORDINARY MATH

23

of its players.) For n = 0, this defines {} to be the empty set, which has noelements.
ZF contains the construct that mathematicians call set comprehension,
but that I prefer to call subsetting. The expression {v ∈ S : F } equals theset whose elements are all the elements in the set S for which the formula
F is true. For example, we can define the set N of natural numbers, which
consists of all non-negative integers, by:∆

N = {n ∈ I : n ≥ 0}
In the expression {v ∈ S : F }, the symbol v is what is called a bound variable.
It can be used only in the formula F , but not in S . Bound variables are
discussed in Section 2.7.
A kind of set that is often used in describing programs is a finite set ofconsecutive integers, such as {−1, 0, 1, 2} . This set is written −1 . . 2. In
general, we define:∆m . . n = {i ∈ I : m ≤ i ≤ n}This definition implies that m . . n equals the empty set {} if m > n.
It’s an axiom of ZF that if S is a set, then {v ∈ S : F } is a set for any
formula F . This axiom implies that the collection of all sets can’t be aset. To show this, we assume the collection V of all values/sets is a set
and obtain a contradiction. If V is a set, then {v ∈ V : ¬(v ∈ v )} is a set;
let’s call that set S . Since S is a set, the definition of V implies S ∈ V istrue. The definition of the subsetting construct then implies S ∈ S is true
iff ¬(S ∈ S ) is true, which is impossible since true doesn’t equal false.
Therefore, V can’t be a set. This argument is called Russell’s paradox,
because it was discovered by the mathematician and philosopher Bertrand
Russell. Intuitively, the collection of all sets is too big to be a set.

2.6

Meaningless Expressions

The formula x + y = y + x is a valid formula of algebra. However, validityof a formula in ZF means that it is true for every interpretation, where
an interpretation is an assignment of a value/set to every variable. For
x + y = y + x to be a valid formula of ZF, N + true = true + N would
have to equal true; and there’s no reason why it should. What should bea valid formula of ZF is:(x ∈ R) ∧ (y ∈ R) ⇒ (x + y = y + x )CHAPTER 2. ORDINARY MATH

24

But for this formula to be valid, this formula should be true:(2.4) ( N ∈ R) ∧ (true ∈ R) ⇒ ( N + true = true + N)
and (2.4) contains the meaningless expressions N + true and true + N.
This seems to be a problem.
Most computer scientists would say that the problem is solved by using
types. The variables x and y in the formula x + y = y + x should havetype real number, so validity of that formula means that it’s true for interpretations that assign real numbers to x and y. Types would make (2.4) an
illegal formula.
I believe types are wonderful in a coding language, and I wouldn’t want
to write code in an untyped language. However, I have found the kindof types provided by coding languages to be unsuitable for representing
abstract programs. For example, type correctness for Euclid’s algorithm
means that the values of the variables x and y are positive integers. The
simple type systems of most coding languages don’t allow a type like positive
integer. Moreover, those type systems are overly restrictive, disallowing
some reasonable expressions.
There are type systems that allow the type positive integer and are not
restrictive. They are needed to formalize the kind of math that mathematicians do, so their proofs can be checked by computer. However, those typesystems are so complicated that I never tried to learn them. I didn’t have tobecause I realized that they are not needed for the math used to describe andreason about abstract programs. Instead, type correctness can be treatedas a simple invariance property of programs. For example, type correctnessof Euclid’s algorithm is the invariance of the formula (x ∈ N+ ) ∧ (y ∈ N+ ),where N+ is the set {n ∈ I : n > 0} of positive integers.
The solution to the problem of the meaningless formula (2.4) is to realizethat it’s not a problem, and formula (2.4) equals true. The expressions
N + true and true + N are meaningless only in the sense that we havenot assigned them a meaning. All we know about them is that they arevalues/sets. But that’s enough to tell us that N + true = true + N equals
either true or false. We don’t know whether or not N and true arenumbers. We know that 42 is a set, but we don’t know what its elementsare. It’s possible that 42 is the set N, or that it equals the value/set true.
However, it doesn’t matter if N and true are numbers. If either or bothof the them is not a number, then (2.4) equals false ⇒ ( N + true =true + N), which equals true since N + true = true + N is a Boolean.
The other possibility is that N and true are both numbers. In that case,no matter what numbers they are, N + true = true + N equals true.

CHAPTER 2. ORDINARY MATH

25

Since we haven’t given the expression N + true a meaning, we will callit meaningless. But there’s nothing harmful in writing such a meaninglessexpression. The expression is just useless because we don’t know what itmeans. If correctness of a program depends on the value of a meaninglessexpression, then we can’t prove that the program is correct. Moreover, a toolfor checking correctness should report an error because it has to determine
the value of a meaningless expression to decide if the program is correct. In
practice, the kind of error in an abstract program that a simple type checker
can catch is almost always quickly caught by model checking, and it is easily
caught when trying to prove something about a type-incorrect expression.
Though not described in this way, ZF is usually considered to have atype system containing two types: Boolean and non-Boolean. For example,
the commutativity of ∧ is expressed as(2.5) |= (A ∧ B ) ≡ (B ∧ A) .
The assumption that A and B are Booleans isn’t needed because it can beinferred that A and B have type Boolean.4 We can maintain that simplicity
without having to introduce types by assuming that rules of predicate logic
like (2.5) are true for all values A and B , not just for Booleans. We do thatby assuming a mapping Bool such that Bool (true) = true, Bool (false) =false, and Bool (v ) ∈ {true, false} for all values v . We can then define
predicate logic operators like ∧ such that v ∧w equals Bool (v )∧Bool (w ) for
all values v and w . This means that, although we don’t know what 2 ∧ {3}equals, we know that it’s a Boolean value and that it equals {3} ∧ 2.

2.7

Quantification and Bound Variables

2.7.1

Quantification

Math has two Boolean-valued constructs called quantifiers whose symbols,
names, and Mathglish pronunciation are:∀∃universal quantification
existential quantification

for allthere exists

They have the following meanings, where v is a variable and F is any formulaof ZF:
4
The rules of Boolean algebra were described in Mathglish in Section 2.4. They couldn’t
be expressed there as theorems because we had not yet introduced Boolean-valued variables.

CHAPTER 2. ORDINARY MATH

26

∀ v : F is true iff F is true when any value is substituted for v .
∃ v : F is true iff there is some value that, when substituted for v ,makes F true.
These are called unbounded quantifiers because they make an assertion about
all values.5 As we saw with the formula x + y = y + x , we are seldom interested in formulas that are satisfied by all values of a variable. We usuallywant to assert that a formula is true for all values in some set. It’s also oflittle use to know that there exists a value of x such that x 2 = 2 if we don’tknow that that value is a number, since it’s possible that true2 = 2 even iftrue isn’t a number. We therefore usually use the two bounded quantifiers∀ v ∈ S and ∃ v ∈ S , defined by:∆∀v ∈ S :F= ∀ v : (v ∈ S ) ⇒ F∃v ∈ S :F= ∃ v : (v ∈ S ) ∧ F∆

For example, the following formula asserts that there exists a (real) number
whose square equals y :(2.6) ∃ x ∈ R : y = x 2
Since x 2 is a non-negative real number for any real number x , and a real
number y has a square root (that’s a real number) iff y ≥ 0, this formula isequivalent to y ≥ 0.
The two bounded quantifiers are related by these theorems:(2.7) |= (∀ v ∈ S : F ) ≡ (¬ ∃ v ∈ S : ¬F )|= (∃ v ∈ S : F ) ≡ (¬ ∀ v ∈ S : ¬F )You should be able to check that they follow from the quantifiers’ informal
definitions. You should also be able to check that ∀ v ∈ {} : F equals trueand ∃ v ∈ {} : F equals false for any formula F .
When parsing a formula, the scope of a quantifier extends as far as
possible—for example, until terminated by the end of the formula or by aright parenthesis whose matching left parenthesis precedes the quantifier.
We abbreviate ∀ v ∈ S : ∀ w ∈ T : F as ∀ v ∈ S , w ∈ T : F , and we abbreviate ∀ v ∈ S : ∀ w ∈ S : F as ∀ v , w ∈ S : F , with similar abbreviations for∃ and for the unbounded quantifiers.
Quantifiers and the rules for reasoning about them form what is called
predicate logic. Predicate and propositional logic are the basis for reasoning
5

The bound in unbounded bears no relation to the bound in bound variable.

CHAPTER 2. ORDINARY MATH

27

in ordinary mathematics. A valid formula whose validity is based solely on
the laws of predicate and propositional logic, and not on the meanings ofany other operators in the formula, is called a tautology. For example, thetruth of|= (∃ v ∈ N : M (v , x ) ∧ (v +1 > x )) ⇒ (∃ v ∈ N : M (v , x ))doesn’t depend on the definitions of N and the mapping M , or on themeaning of the arithmetic operators + and >. It follows from the rule|= A ∧ B ⇒ A of propositional logic and the predicate logic rule that|= F ⇒ G implies |= (∃ v ∈ S : F ) ⇒ (∃ v ∈ S : G). The theorems of predicate and propositional logic themselves are also called tautologies.

2.7.2

Bound Variables

As in the subsetting constructor {v ∈ S : F }, the v in the formulas ∀ v ∈ S : F
and ∃ v ∈ S : F is a bound variable that can appear only in F , not in S . Moreprecisely, these expressions declare v to be a variable whose scope is the formula F . Bound variables are somewhat subtle and must be used with care.
To understand why, we need to examine variables and scoping.
Like coding languages, formal languages for mathematics usually have
explicit variable declarations, and a variable can be used only within thescope of its declaration. In this book and in almost all math books, mostof those declarations are implicit. For example, in the discussion of Euclid’s algorithm in Section 1.5, the program variables x and y are implicitly
declared with scopes that lie entirely within that section. Those program
variables are unrelated to the mathematical variables x and y that appear
in Section 2.6.
Every expression we write occurs in a context, which specifies the variable declarations within whose scope the expression occurs. For example,
the context of the subformula y = x 2 of formula (2.6) contains the same
variable declarations as the complete formula (2.6), except it includes thedeclaration of x made by the quantifier ∃ x . A bound variable of a formula
F is one that is declared by a quantifier or a subsetting constructer within
F . A variable that is not bound in F is called a free variable of F . For
example, x is a bound variable and y a free variable of formula (2.6).
Things get complicated if formula (2.6) occurs within the scope of another declaration of x . It’s best to view the x declared in the context of(2.6) and the x declared by its quantifier as two different variables with thesame name. (This means that an interpretation must be a mapping fromvariables to values, not from variable names to values. That should seemCHAPTER 2. ORDINARY MATH

28

natural if you’ve done any programming, because a program’s code can contain multiple program variables with the same name that may have different
values.)Having two different variables with the same name can produce errors
if you’re not careful. For example, formula (2.6) is equivalent to y ≥ 0.
Therefore, substituting an expression exp for y in that formula should yield
the formula exp ≥ 0. Let’s take exp to be x 2 +1, where x is the variable whose
declaration’s scope contains formula (2.6). Naively substituting x 2 + 1 fory in (2.6) produces ∃ x ∈ R : x 2 + 1 = x 2 , which equals false, rather thanx 2 +1 ≥ 0. The problem is that we should have substituted for y in (2.6) the
formula x 2 + 1 in which x is the variable declared outside the formula, notthe formula’s bound variable. Such a substitution would produce a formula
that’s equivalent to x 2 + 1 ≥ 0; but that formula would contain two different
variables named x , and our math provides no way to write such a formula.6
Logicians call the error produced by the naive substitution variable capture.
Fortunately, there’s an easy way to avoid variable capture. The underlying mathematics doesn’t depend on what we name variables. If we change
the name of the bound variable in (2.6) to anything other than y, for example writing it as ∃ w ∈ R : y = w 2 , then we get an equivalent formula.
Naively substituting x 2 + 1 for y in that formula yields a formula equivalent
to x 2 + 1 ≥ 0, as it should.
We can avoid having to rename the bound variable in (2.6) if we use aname different from the name of any variable declared in its context. Thatis, we can avoid such variable capture by obeying this rule:
Safe Scoping Rule Never declare a bound variable within the scopeof a declaration of a variable with the same name.
The rule prevents writing (2.6) in any context in which we could write aformula like x 2 + 1 to substitute for y.
The Safe Scoping Rule will help keep you out of trouble, but it isn’t
enough. There are unlikely situations involving definitions in which thisrule alone will not prevent variable capture. Section 2.8.1 below mentions
another way variable capture can still occur. So when writing hand proofs,
you should always be aware that variable capture is a potential problem,
and it may require renaming bound variables to avoid it.
6

There are ways to write quantification without using bound variables that allow writing such formulas, but they’re inconvenient to use.

CHAPTER 2. ORDINARY MATH

2.8

Defining Mappings and Functions

2.8.1

Mappings

29

Programs can be quite complex. The way to handle complexity is by hierarchical composition. Mathematics has a very simple and very powerfulmechanism for hierarchical composition: the definition. We now examine
definitions.
∆
We introduced the symbol = , meaning is defined to equal, and defined∆∨ by writing A ∨ B = . . . . The Boolean operator ∨ is a mapping that takes
two arguments, and A ∨ B is an abbreviation of ∨(A, B ). We also defined N∆
by writing N = . . . . We can consider N to be a mapping that takes zeroarguments, so every definition defines a mapping.
The definition∆(2.8) M (a, b) = a 2 + b 2
defines the mapping M such that M (exp 1 , exp 2 ) equals (exp 1 )2 + (exp 2 )2 ,for any expressions exp 1 and exp 2 . A mapping that has one or more arguments is not a value. The string M + 42 is not an expression; it’s nonsense,
like 3 + = 7. (Appendix A.3 explains why mappings can’t all be values.)
The mapping M can appear in an expression only in a subexpression of
the form M (exp 1 , exp 2 ). However, (2.8) defines this subexpression to equal(exp 1 )2 + (exp 2 )2 , for all expressions exp 1 and exp 2 — even if exp 1 equals R
and exp 2 equals false.
The symbols a and b in (2.8) are called the parameters of the definition.
Definition parameters are bound variables, whose scope is the right-handside of the definition. However, they pose no problem of variable capture
because they are replaced by expressions when the defined symbol appears
in a formula. The Safe Scoping Rule should still be applied to them because
the definition (2.8) would be confusing if it appeared within the scope of thedeclaration of a variable named a or b.
While definition parameters are bound variables that can’t do any “capturing”, variable capture is still possible with a definition such as∆

P (a, b) = (a > b) ∧ ∃ x ∈ R : b = x 2
whose right-hand side declares the bound variable x . The Safe Scoping Rule
ensures that this definition does not occur in the scope of a variable named
x . However, P may later be used in an expression that is in the scope of avariable x . Avoiding variable capture when substituting in that expression
may require changing the name of the bound variable in the definition of P .

CHAPTER 2. ORDINARY MATH

30

A fundamental rule of mathematics you may have learned as a teenager
is that circular definitions are forbidden. We can’t define M in terms of P ,and P in terms of Q, and Q in terms of M . The obvious way to enforce
this rule is to require that a definition use only previously defined mappings.
However, to understand the definitions, it’s often best to write them in the
opposite order, so higher-level concepts are defined before defining the lowerlevel concepts on which they are built. So, we will order definitions to makethem easier to understand, while avoiding circular definitions.
A special class of circular definitions are allowed in which a mappingis defined in terms of itself. They’re called recursive definitions and are
introduced in Section 3.5.

2.8.2

Functions

You may have learned about functions, and you undoubtedly did if you
studied calculus. If you did learn about them, you may have wondered why
I use the term mapping rather than function. Most mathematicians consider
them to be the same. We’ll see why they must be different.
Here, we describe functions of a single argument. Functions of multiple
arguments are defined in Section 2.8.3 below. We consider a function to bea special kind of mapping that differs from other mappings in two ways:• A function f has a domain, called domain(f ), and the value of f (v )can be specified only for values v in domain(f ).
• A function is a value; other mappings need not be.
The first difference implies that the mapping M defined by∆

M (S ) = N ∈ S
defines M (S ) to equal the Boolean N ∈ S for all values S because its valueis specified for all sets/values S . We know that M (S ) equals N ∈ S , which
is a Boolean, for any value S . But M is not a function because its domain
would have to be the set of all values/sets, and we saw in Section 2.5 thatthe collection of all sets can’t be a set.
If you’ve studied calculus, you’ve seen functions like the function f , whose
domain is the set {x ∈ R : x 6= 0} of non-zero real numbers, defined by letting f (x ) equal 1/x 2 for all numbers x in that set. Mathematicians seem tohave no convenient notation for writing such a function. We will write thatfunction f as v ∈ {x ∈ R : x 6= 0} 7→ 1/v 2 . In general,f∆= v ∈ S 7→ exp

CHAPTER 2. ORDINARY MATH

31

defines f to be the function with domain(f ) equal to S such that f (v ) = exp
for all x ∈ S . In the expression v ∈ S 7→ exp, v is a bound variable whose
scope is the expression exp. This definition tells us nothing about the valueof f (v ) if v is not an element of S . However, f is a value. This is importantbecause the value of a program variable must be a value, so we can use
functions as ordinary values, just like numbers, when describing abstract
programs.
Mathematicians generally define a function to be a set of pairs of values.
However, while a function is a set/value, I prefer not to specify what its
elements are—in part, because I prefer to define a pair as a function. All
we know about a function is that it is completely determined by its domain
and the value it assigns to elements of that domain. Thus, if f and g are
two functions with domain S and f (v ) = g(v ) for all v ∈ S , then the twofunctions are equal.

2.8.3

Sequences and Tuples

Lists are omnipresent—from shopping lists to lists of transactions on a bankstatement. A list is represented mathematically as a sequence, which isa function f whose domain is a consecutive sequence of natural numbers,
where f (i ) is element number i of the sequence. We will use two kinds ofsequences that are numbered in different ways:
Ordinal The items of an ordinal sequence are numbered starting withitem 1. The sequence represents a list whose items are naturally namedwith the ordinal numbers first, second, third, etc. For example, in alist of people waiting to be served, the second person to be served isnaturally called person number 2.
Cardinal The items of a cardinal sequence are numbered starting withitem 0. It represents a list in which it is natural to name an item byits distance from an item numbered 0. For example, in the list of floors
in a building, the ground floor is naturally named floor 0, and floor
number 2 is two floors above it.
When I started describing abstract programs with mathematical formulas, I
discovered that the formulas were usually simpler if I described finite lists asordinal sequences. However, the meaning and properties of the formulas aredefined in terms of infinite sequences and finite prefixes of those sequences;and the math is simpler if those are cardinal sequences. So, we will use bothkinds of sequences.

CHAPTER 2. ORDINARY MATH

32

Mathematicians often use tuples. We represent a tuple as a finite ordinal sequence. Mathematicians enclose tuples in parentheses, but parentheses are used for lots of other things, so we make formulas containing
tuples easier to read by using angle brackets h and i instead. Thus, the ordinal sequence hJohn, Mary, John i is the function with domain 1 . . 3 suchthat hJohn, Mary, John i(2) equals Mary. The empty sequence, which is
the unique function whose domain is the empty set, is written h i. It is
the one sequence that is both an ordinal and a cardinal sequence. The
Cartesian product operator × is used to describe sets of tuples. For example, S × T × U is the set of all triples (3-tuples) hs, t, u i such that s ∈ S ,t ∈ T , and u ∈ U .
A mapping with n arguments can be considered to be a mapping with asingle argument that is an n-tuple. There is no need to do that for arbitrary
mappings, but we do it for functions. We define a function of n arguments
to be a function whose domain is a set of n-tuples, where f (v 1 , . . . , v n ) isan abbreviation for f (hv 1 , . . . , v n i). By a rule of ZF that hasn’t yet been
introduced, any set of n-tuples is a subset of the Cartesian product of nsets.
The lists that we will represent by cardinal sequences consist of things
that happen one after the other. They will be written with their items separated by → symbols, as in the sequence of four states that is the executionof Euclid’s algorithm shown in Section 1.5.

2.9

Some Useful Notation

Here are two pieces of notation that mathematicians don’t seem to need,but that I find essential for writing formulas that describe programs.

2.9.1

if/then/else

A programmer who read enough math would notice that mathematicianslack anything corresponding to the if /then/else statement of coding languages. Instead, they use either prose or a very awkward typographicalconvention. We let the expression
if P then exp 1 else exp 2
equal exp 1 if P = true and exp 2 if P = false.

CHAPTER 2. ORDINARY MATH

33

While it’s inspired by the if /then/else coding language statement, you
should not think of an if/then/else expression as instructions for computing something. It’s somewhat like the expression written in the C language
and its descendants as P ? exp 1 : exp 2 . However, coding languages usuallyspecify the order in which the expressions P , exp 1 , and exp 2 are evaluated.
In mathematics there is no concept of evaluation. An expression simply has
a value for any particular interpretation.

2.9.2

Conjunction and Disjunction Lists

Abstract mathematical descriptions of real systems can be quite long. Definitions are used to decompose them into shorter formulas that are easierto understand. However, those shorter formulas can still be a few dozenlines long. They are understandable because mathematical formulas havea natural hierarchical structure. To take full advantage of that structure,
we use a simple bit of notation that mathematicians and many computerscientists find heretical, but that engineers appreciate.
There are two simple ideas: a list of formulas bulleted by ∧ or ∨ represents the conjunction or disjunction, respectively, of those formulas; andindentation is used to replace parentheses. For example, if A, B , . . . , J areformulas, then:∧ ∨ A∧B∨C∧D ⇒E∧ ∨ ∃x : F∨∧G ≡H∧J(A ∧ B )∨ C)∧ (D ⇒ E )∧ ((∃ x : F )∨ ((G ≡ H )∧ J) )(equals

Note how the implicit parentheses in the bulleted lists delimit the scope ofthe ⇒ and ∃ x operators in this formula.
Making indentation significant is a feature of the currently popular Python
coding language, but it works even better in this notation because the useof ∧ and ∨ as “bullets” makes the logical structure easier to see.

Chapter 3

Describing Abstract
Programs with Math
3.1

The Behavior of Physical Systems

Programs are meant to be executed on physical computers. I have been
guided by the principle that any statement I make about a program should
be understandable as a statement about its execution on one or more computers. I believe this was the principle that guided Turing in defining theTuring machine as an abstraction of a physical computing device.
The description of our science of concurrent programs begins by examining the physics of computing devices. We don’t care about the actual
details of how transistors and digital circuits work. We are just interested
in how scientists describe physical systems. As a simple example, we lookat a planet orbiting a star the way an astronomer might.
We consider the one-planet system’s behavior starting at some time t 0 ,after the star and planet have been formed and the planet has settled into
its current orbit. We assume that the planet remains in that orbit forever.
Let R≥ be the set {r ∈ R : r ≥ t 0 } of all real numbers r with r ≥ t 0 . The
behavior of the one-planet system is described by its state at each instantof time. We assume the star is much more massive than the planet, so we
can assume that it doesn’t move. We also assume that there are no otherobjects massive enough to influence the orbit of the planet, so the state of
the system is described by the values of six state variables: three describing
the three spatial coordinates of the planet’s position and three describing thedirection and magnitude of its momentum. Let’s call those state variables
v 1 , . . . , v 6 ; we won’t worry about which of the six values each represents.
The quantities these variables represent change with time, so the value ofeach variable v i is a function, where v i (t) represents the value at time t.
34

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

35

The behavior of the system is described mathematically by the function σwith domain R≥ such that σ(t) is the tuple hv 1 (t), . . . , v 6 (t)i of numbers,
for every t ∈ R≥ . Physicists call σ(t) the state of the system at time t.
In this description, the planet is modeled as a point mass. Real planets are more complicated, composed of things like mountains, oceans, andatmospheres. For simplicity, the model ignores those details. This limits
the model’s usefulness. For example, it’s no good for predicting a planet’s
weather. But models of planets as point masses are sometimes used to plan
the trajectories of a real spacecraft. It’s also not quite correct to say that themodel ignores details like mountains and oceans. The mass of the model’s
point mass is the total mass of the planet, including its mountains andoceans, and its position is the planet’s center of mass. The model abstracts
those details, it doesn’t ignore them.
The laws that determine the point-mass planet’s behavior σ are expressed by six differential equations of this form:
(3.1)

dv i
(t) = f i (t)dtwhere t ∈ R≥ and each f i is a function with domain R≥ such that f i (t)is a formula containing the expressions v 1 (t), . . . , v 6 (t). Don’t worry if you
haven’t studied calculus and don’t know what equation (3.1) means. All
you need to know is that it asserts the following approximate equality forsmall non-negative values of dt:(3.2) v i (t + dt) ≈ v i (t) + f i (t) ∗ dt
and the approximation gets better as dt gets smaller, reaching equality whendt = 0. The differential equations (3.1) have the property that for any timet > t 0 and any time r > t, the values of the six numbers v i (t) and thefunctions f i completely determine the six values v i (r ) and hence the valueof σ(r ). That is, the equations imply:
History Independence For any time t ∈ R≥ , the state σ(r ) of the system
at any time r > t depends only on its state σ(t) at time t, not onanything that happened before time t.
The generalization from a planetary system to an arbitrary physical systemstarting at time t 0 is straightforward. The system is described by statevariables v 1 , . . . , v n , and its behavior σ is described mathematically as thefunction with domain R≥ such that σ(t) equals hv 1 (t), . . . , v n (t)i. History

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

36

independence is satisfied by any isolated physical system—that is, by any
system that is assumed not to be influenced by anything outside the system.1
There is one way our one-planet system differs from most systems. For
this system, it is possible to solve the differential equations (3.1) to write
the functions v i as formulas in terms of ordinary mathematical operations.
Even for two planets around a star that is not much heavier than them, it
is impossible to write such a solution. The functions v i can be proved toexist and be unique, but the best we can do in general is find very close
approximations to those functions for some finite interval of time.
Physics describes systems with math. Remember that in math, there areinfinitely many variables. A description of any particular system contains
only a finite number of them—the system variables. The description (3.1) ofa planet orbiting a star contains only the six system variables describing theplanet’s state. It doesn’t say that there is nothing else in the universe. It justsays nothing about any other planets. Instead of thinking of (3.1) and (3.2)
as describing a planet orbiting a star, it’s more accurate to think of themas describing a universe in which the planet is orbiting the star. They also
describe a universe containing both the planet and a spacecraft that orbits
the star; they just say nothing about the spacecraft, since the spacecraft is
too small to affect the planet’s motion. (The spacecraft’s motion could be
affected by the planet.) Formulas (3.1) and (3.2) just say nothing about the
spacecraft.
Physical science is descriptive. The laws of physics describe how a planet
moves; they don’t instruct the planet. Programs are prescriptive; they tell acomputer what to do. This may make it seem strange to use physical science
as a guide to a science of programs. But being descriptive or prescriptive
is not a property of the math. It’s just how we choose to view that math.
We can view the equations of planetary motion not only as a description of
how a planet moves, but also as commands given to the planet by nature.
The math is agnostic. Our science views a program as a description of what
behaviors it allows, not as commands for producing those behaviors. Thisview allows much more freedom in describing programs.
1

In classical physics, the state at time t0 uniquely determines the system’s subsequent
behavior. The situation is less clear in quantum physics where multiple subsequent behaviors seem possible, but the set of those behaviors is completely determined by thestate.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

3.2

37

Behaviors of Digital Systems

Math IThe Operator % For any integers m and n with n > 0, the value ofm % n is defined to be the remainder when m is divided by n. The precise
definition is that m % n equals the unique integer r satisfying(m = d ∗ n + r ) ∧ (0 ≤ r < n)for some integer d . The operator % is pronounced modulo and is written
mod by mathematicians.
Mathematical Induction You have probably encountered mathematicalinduction; if not, you may want to read about it on the Web. Simple mathematical induction proves that a formula is true for all n ∈ N by provingthat it is true for n = 0 and that if it is true for n then it is true for n + 1.
It is stated more precisely by this proof rule, where P is any mapping:|= P (0) and |= ∀ n ∈ N : P (n) ⇒ P (n + 1) implies |= ∀ n ∈ N : P (n)This rule is a meta-formula, and the Mathglish terms and and implies areused to represent the Boolean operators ∧ and ⇒ to make it clear that it isa meta-formula and not a formula.
Strong mathematical induction allows proving that the formula is true
for n + 1 by assuming that it is true for all numbers in 0 . . n, not just true
for n. It is stated as:|= ∀ n ∈ N : (∀ m ∈ 0 . . (n − 1) : P (m)) ⇒ P (n)implies |= ∀ n ∈ N : P (n)In this rule, for n = 0 the hypothesis implies|= (∀ m ∈ 0 . . − 1 : P (m)) ⇒ P (0)which equals |= P (0) , since ∀ m ∈ {} : P (m) equals true.

3.2.1

From Continuous to Discrete Time

Digital systems are physical systems, usually electromagnetic, in which certain stable states represent a collection of one-bit values. For example, ata certain point in a circuit, 0 volts may represent a 0 and 3.3 volts may
represent a 1. Classical physics describes the behavior of physical systems

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

38

as continuous.2 If the voltage at some point√ in a circuit changes from 0 volts
to 3.3 volts, it must pass through 1 and 2 volts.
Computers and other digital systems are designed so that each bit canbe thought of as passing instantaneously from one stable state to the next.
This means that we can think of there being a sequence of discrete times t 0 ,t 1 , t 2 , . . . that are the only times at which the value of a bit can change.
(We assume there is an event at time t 0 that initializes all the bits of thedevice.) We pretend that between times t j and t j +1 , the part of the circuit
representing each bit is in a stable state. Moreover, whether a bit changes
its value at time t j +1 depends on the (stable) values of the bits immediately
before time t j +1 .3 Thus, the system is history independent.
Although built from one-bit registers, digital systems are designed
so that larger components can also be viewed as changing their state
instantaneously—for example, a 128-bit register or even all the bits in achip controlled by a single clock. We can pretend that the entire component
changes its value in discrete steps that can occur only at the times t j . Thus,
we can view a digital system as one whose components are represented bystate variables that can have more than two values.
When a digital system is executing a program, the state of the program
does not correspond directly to the state of the system. The value of aprogram variable might be represented by different parts of the system at
different times. For example, its value may at some times be stored in amemory chip, at some times it may be in a register of a processor chip, andat some times it might be stored on a disk. Later, we’ll see what it means
mathematically for a digital system to implement a program in this way.
For now, consider a concrete program to be just a digital system describedby discretely changing variables whose values are not just bits but may be
any data structure provided by the language—for example, 128-bit integers.
An abstract program is the same, except the√value of a variable may be
any value—for example a real number such as 2, not just a finite-precision
approximation like 1.414213562. Modeling a science of programs on thescience of physical systems ensures that it can address real problems, andwe are not just creating a science of angels dancing on the head of a pin.
2Here, classical physics includes relativity but not quantum mechanics. I believe thatquantum mechanics also describes a continuous universe, but a discussion of that would
take us too far afield.
3
The tj are pretend times, not exact physical times. Two bits that change at thesame pretend time may change at different physical times because the clock pulse thatgenerates the change may reach one of them a fraction of a nanosecond before the other.
Chip designers must ensure that we can pretend that they change at the same time.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

39(However, the science should be able to describe any discretely behaving
angels, wherever they might be dancing.)
We are seldom interested in the actual times t j at which state variables
can change. To simplify things, we consider only the sequence of states
through which the system passes, ignoring the times at which it enters andleaves those states. We call the state created at time t j state number j .
Instead of letting a state variable v be a function that assumes the value
v (t) at time t, we consider it to be a function that assumes the value v (j ) instate number j . In other words, the value of a state variable v is a sequenceof values. A behavior σ of a program is also a sequence, where σ(j ), its state
number j , describes the values of the device’s variables in that state.
If a program or a digital device runs forever, then the sequence of times
t j is infinite and therefore so is the sequence σ of its states. But if a program terminates, then those sequences can be finite. Other than parallel
programs, in which concurrency is added to a traditional program so it canrun faster by using multiple processors, most concurrent programs are notsupposed to stop. A concrete concurrent program will not really run forever, but we describe it as running forever for the same reason there are an
infinite number of integers even though we only use a finite number of them:it makes things simpler.
Still, some concurrent programs are supposed to stop, so we have todescribe them. For simplicity, we describe those programs as well with
infinite state sequences. Exceptionally observant readers will have noticed
that while the times t j had to be chosen so we can pretend that the statechanges only at those times, we did not require that the state had to change
at each of those times. There can be times t j at which none of the program
variables’ values change. In particular, if the program stops, we can add an
infinite number of times t j after it has stopped. This leads to an infinite
sequence of states such that, for some k , the values of the program’s variables
after state number k are the same. We call a pair hσ(j ), σ(j +1)i of successive
states in a behavior σ a step of σ. A step in which the values of the program’s
variables do not change is called a stuttering step of the program.
We call a behavior ending in infinitely many stuttering steps a halting
behavior of the program. It describes an execution in which the program
stops. There are many reasons a program might stop—for example, an error
might cause it to abort. If the program stops because it has completed what
it was supposed to do, we say that it terminates. The term halting covers
all cases when the program stops.
Mathematically, a behavior of a digital system or an abstract programis an infinite cardinal sequence of states, where each state is an assignment

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

40

variables x = 1, y = 1;
while true doa: x : = x + y + 2 ;y := y + 2
end while
Figure 3.1: The simple abstract program Sqrs.
of values/sets to variables. There is a natural tendency to think of state
number j of a behavior as occurring at time j on some clock that ticks at
a constant rate. Don’t think of it like that. A microsecond might elapse
between when the system reaches state number j and when it reaches state
number j +1, and a day or a femtosecond might then elapse before it reaches
state number j + 2. All we know is that the system can’t reach state number
j + 1 before it reaches state number j .
By removing any information about the physical time at which things
happen, it may appear that we have eliminated the possibility of describing
how much actual time it takes for something to happen. That’s not the case,and Section 4.4 explains how it’s done. However, correctness of few programs
depends on exactly how long it takes the program to do something, and I
know of no commonly used coding language that allows us to write suchprograms. To my knowledge, nothing in the definition of the Java coding
language assures us that executing the statement x = x+1 takes less than acentury.

3.2.2

An Example: Sqrs

Our first example is a very simple abstract program called Sqrs that is
described in Figure 3.1 with pseudocode. The variables statement describes
the program variables and their initial values (their values in state 0). In
this example, the program variables are x and y, and their initial values areboth 1. The program’s code consists of a while true loop, which meansthat the body of the loop is repeatedly executed forever. Program Sqrs is
an abstract program because it runs forever, producing a behavior with an
infinite number of states, unlike a concrete program that would halt withan error when x became too big.
In a science, it would be crazy to let “=” mean anything other than what
it has meant in mathematics for several centuries, so we use “:=” to mean
assignment. Except for the label a that you can ignore for the moment,
it should be obvious what an execution of the loop body does. What’s

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

41

not obvious in most pseudocode and in virtually all real code is how torepresent the execution in a behavior—which means as a sequence of states.
In particular, how many different steps in the behavior describe a single
execution of the loop body?
We would expect to describe execution of the loop body of Sqr with atleast one step. But should there be more? For example, should evaluatingx +y in the first assignment statement be a separate step? Coding languages
seldom answer this question because it makes no difference to the result
computed by a traditional program. However, it can make a big difference
for concurrent programs.
We will adopt the PlusCal algorithm language’s [36] convention of usinglabels to indicate what the separate steps of a behavior are. The rule is that
execution from one label to the next constitutes a single step. This meansthat a step begins and ends with program execution at a label. For program
Sqrs, this implies that execution of the entire loop body, starting from labela and finishing when the program reaches a again, is a single step. With
this choice of what constitutes a step in the behavior, the values x (j ) andy(j ) of the variables in each state j of the behavior are determined by two
formulas:(3.3) (x (0) = 1) ∧ (y(0) = 1)(3.4) ∀ j ∈ N : ∧ x (j + 1) = x (j ) + y(j ) + 2∧ y(j + 1) = y(j ) + 2
We call (3.3) the initial predicate. It determines the initial state. Formula(3.4) is called the step predicate. It’s the discrete analog of the differential
equations (3.1) that describe the orbiting planet. Instead of describing how
the values of the variables change in the continuous behavior when timeincreases by the infinitesimal amount dt, the step predicate (3.4) describes
how they change when the state number of the discrete behavior increases
by one.
You can check that (3.3) and (3.4) define a behavior that begins asfollows where, for example, [x :: 16, y :: 7]3 indicates that state number 3
assigns the values 16 to x and 7 to y, and the arrows are purely decorative.
"#

x :: 1y :: 10"#

x :: 4→
y :: 3"

1#

x :: 9→y :: 52"#

x :: 16→y :: 7

3"#

x :: 25→
y :: 9→ ···4These first few states of the behavior suggest that in the complete behavior,

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

42

x and y equal the following functions:(3.5) x = (j ∈ N 7→ (j + 1)2 )y = (j ∈ N 7→ 2 ∗ j + 1)
To prove that (3.3) and (3.4) imply (3.5), we must prove they imply:(3.6) ∀ j ∈ N : (x (j ) = (j + 1)2 ) ∧ (y(j ) = 2 ∗ j + 1)
A proof by mathematical induction that (3.3) and (3.4) imply (3.6) is a niceexercise in algebraic calculation.
We can think of (3.5) as the solution of (3.3) and (3.4), just as the formulas describing the position and momentum of the planet at each time t
are solutions of the differential equations (3.1). It is mathematically impossible to find solutions to the differential equations describing arbitrary
multi-planet systems. It is mathematically possible to write explicit descriptions of variables as functions of the state number like (3.5) for the abstract
programs written in practice, but those descriptions are almost always muchtoo complicated to be of any use. Instead, we reason about the initial predicate and the step predicate, though in Section 3.4.1 we’ll see how to write
them in a more convenient way.
The interesting thing about program Sqrs is that the sequence of values
assumed by x in an execution of the program is the sequence of all positive integers that are perfect squares, and this is accomplished using only
addition. This is obvious from (3.5), but for nontrivial examples we won’t
have such an explicit description of each state of a behavior. Rememberthat history independence implies that, at any point in a behavior, what
the program does in the future depends only on its current state. What is
it about the current state that ensures that if x is a perfect square in thatstate, then it will equal all greater perfect squares in the future? There isa large body of work on reasoning about traditional programs, initiated byRobert Floyd in 1967 [14], that shows how to answer this question. If you’refamiliar with that work, the answer may seem obvious. If not, it may seem
like it was pulled out of a magician’s hat. Obvious or magic, the answer isthat the following formula is true for every state number j in the behavior
of Sqrs:(3.7) ∧ (x (j ) ∈ N) ∧ (y(j ) ∈ N)
∧ y(j ) % 2 = 1
y(j ) + 1 2∧ x (j ) =2

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

43This formula implies that x (j ) is a perfect square, since the first two conjuncts imply that y(j ) is an odd natural number. Moreover, since y(j + 1) =y(j ) + 2, the last conjunct implies that x (j + 1) is the next larger perfectsquare after x (j ). So, the truth of (3.7) for every state number j explains
why the algorithm sets x to all perfect squares in increasing order.
A predicate like (3.7) that is true for every state number j of a behavior
is called an invariant of the behavior. By mathematical induction, we canprove that a predicate is an invariant by proving these two conditions:
I1. The predicate is true for j = 0.
I2. For any k ∈ N, if the predicate is true for j = k then it’s true forj = k + 1.
For (3.7), I1 follows from the initial predicate (3.3), and I2 follows from thestep predicate (3.4). (You should have no trouble writing the proof if you’reused to writing proofs; otherwise, it might be challenging.)
A predicate that can be proved to be an invariant by proving I1 from an
initial predicate and I2 from a step predicate is called an inductive invariant.
Model checkers can check whether a state predicate is an invariant of small
instances of an abstract program. But the only way to prove it is an invariant
is to prove that it either is or is implied by an inductive invariant. For
any invariant P , there is an inductive invariant that implies P . However,writing an inductive invariant for which we can prove I1 and I2 is a skill
that can be acquired only with practice. Tools to find it for you have beendeveloped [15, 39], but I don’t know how well they would work on industrial
examples.
The first conjunct of the invariant (3.7) asserts the two invariantsx (j ) ∈ N and y(j ) ∈ N. An invariant of the form v (j ) ∈ S for a variable v
is called a type invariant for v . An inductive invariant almost always must
imply a type invariant for each of its variables. For example, without the
hypotheses that x (j ) and y(j ) are numbers, we can deduce nothing about
the values of x (j + 1) and y(j + 1) from the step predicate (3.4).
Most mathematicians would not bother to write the first conjunct of(3.7), simply assuming it to be obvious. However, mathematicians aren’t
good at getting things exactly right. They can easily omit some uninteresting corner case—for example, the assumption that a set is nonempty. Those“uninteresting corner cases” are the source of many errors in programs. To
avoid such errors, we need to state explicitly all necessary requirements,
including type invariants.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

44

variables x = 1, y = 1, pc = a;while true doa: x : = x + y + 2 ;b: y : = y + 2
end while
Figure 3.2: The finer-grained abstract program FGSqrs.

3.2.3

A Finer-Grained Example: FGSqrs

Now consider a modified version of our abstract program Sqrs in which
the execution of each assignment statement in the body of the while loop
is represented as a separate step of the behavior. This is specified in thepseudocode by adding a label right before the second assignment statement.
The label is b and the program is called FGSqrs.
The natural way to describe the state of FGSqrs is with the variables x
and y and an additional variable to specify which assignment statement is
the next one to be executed.4 Such a variable isn’t needed in Sqrs becausethat program has just a single label. The variable we add is traditionallycalled pc (for program counter). We will let its value equal the label fromwhich the execution described by the next step begins. (That execution
ends when it reaches the following label.) We assume that a and b are two
arbitrary distinct values.
The pseudocode for FGSqrs is in Figure 3.2. The variables declaration
contains pc and its initial value, even though we know pc is needed because
there’s more than one label, and program execution is normally assumed tostart at the beginning of the code. But, a little redundancy doesn’t hurt. A
little redundancy doesn’t hurt.
Here is the mathematical description of the behavior of program FGSqrs.
As with Sqrs, it consists of an initial predicate and a step predicate.
Initial Predicate (x (0) = 1) ∧ (y(0) = 1) ∧ (pc(0) = a)
Step Predicate
4

In program FGSqrs, an additional variable isn’t needed because which statement
should be executed next can be deduced from the values of the variables x and y, but
that’s not the case in most programs written in pseudocode.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

45∀ j ∈ N : if pc(j ) = a
then ∧ x (j + 1) = x (j ) + y(j ) + 2∧ y(j + 1) = y(j )∧ pc(j + 1) = b
else ∧ x (j + 1) = x (j )∧ y(j + 1) = y(j ) + 2∧ pc(j + 1) = a
When they see this step predicate, most programmers and many computerscientists think that the conjuncts y(j + 1) = y(j ) and x (j + 1) = x (j ) areunnecessary. They think that not saying what the new value of a variableequals should mean that it equals its previous value. But if that were thecase, then what we wrote wouldn’t be math. We would be giving up the
benefits of centuries of mathematical development—the benefits that are
the reason science is based on math. An essential aspect of math is thata formula means exactly what it says—nothing more and nothing less. If
the step predicate didn’t say what y(j + 1) equals when pc(j ) = a is true,
then there√would be no more reason for it to equal y(j ) than for it to equali ∈ N 7→ −42.
You may find it discouraging that the mathematical description of
FGSqrs is more complicated than its pseudocode in Figure (3.2). Pleasebe patient. You will see in Section 3.4.1 how a little notation can simplify
it. We can always write an abstract program more compactly in pseudocode
than in math, as long as we don’t have to explain precisely what the pseudocode means. But science is precise, and a science of abstract programsmust explain exactly what they mean. Moreover, tools can’t check an imprecise description of a program. Math is the simplest way to explain things
precisely.
PlusCal is a precise language for describing abstract programs in whatlooks like pseudocode. (However, it’s infinitely more expressive than ordinary pseudocode because its expressions can be any mathematical expressions—even uncomputable ones.) A PlusCal program is translated to amathematical description of the program in TLA+. I often find it easier towrite an abstract program in PlusCal than directly in TLA+. However, I
reason about the TLA+ translation, not the PlusCal code. And for many
abstract programs, including most distributed algorithms, it’s easier to write
the program directly in TLA+ than in PlusCal.
The code whose execution is described as a single step of the behavior iscalled an atomic operation. Because a single step in a behavior describing
the execution of Sqrs is replaced by two steps in the behavior describing
the execution of FGSqrs, we say that FGSqrs has a finer grain of atomicity

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

46

than Sqrs. Having a finer grain of atomicity implies that the step predicate
is more complicated.
Having a finer grain of atomicity also implies that the inductive invariant
that explains why the abstract program works will be more complicated.
However, there is a trick for obtaining the invariant for FGSqrs from theinvariant (3.7) of Sqrs. Define yy(j ) to equal y(j ) if execution FGSqrs is atlabel a, and to equal the value y(j ) will have after executing statement b if
execution is at b. The mathematical definition is:∆yy(j ) = if pc(j ) = a then y(j ) else y(j ) + 2
Observe that x and yy are changed at the same time by statement a of
FGSqrs exactly the same way that the loop body of Sqrs changes x andy. Statement b of FGSqrs leaves x and yy unchanged. This implies that,
because (3.7) is an inductive invariant of Sqrs, the formula obtained from
(3.7) by substituting yy for y satisfies condition I2 for FGSqrs. It’s easy
to check that this formula also satisfies I1, so it is an inductive invariant of
FGSqrs. This trick of finding an expression (such as yy(j )) that is changedby the fine grained program the way the coarse-grained program changes
a variable (such as y) can often be used to obtain an invariant for a finergrained abstract program from an invariant of a coarser-grained one. It isalso at the heart of program refinement, the subject of Chapter 5.

3.3

Nondeterminism

Math II
The # Operator The operator # is defined so that if S is a finite set,
then #(S ) equals the number of elements of S . If S is not a finite set (so it
must be an infinite set), then #(S ) is a meaningless expression.
More About Functions For any sets D and S , ZF defines D → S to be
the collection, which is assumed to be a set, of all functions f with domain
D such that f (x ) ∈ S for all x ∈ D. A value f is a function with domain D
iff f equals v ∈ D 7→ f (v ). Therefore, this is an axiom of ZF:|= f ∈ (D → S ) ≡ ∧ f = (v ∈ D 7→ f (v ))∧ ∀ v ∈ D : f (v ) ∈ S
An array in modern coding languages is described mathematically as a function, where the expression f [x ] in the language means f (x ). For a variable

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

47

f whose value is an array/function, assigning the value 4.2 to f [14] changes
the value of f to a new array/function that we can write as:x ∈ domain(f ) 7→ if x = 14 then 4.2 else f (x )Mathematicians have little need to write such a function, but it occurs often when math is used to describe programs, so we need a more compact
notation for it. We write it like this:f except 14 7→ 4.2

3.3.1

Sources of Nondeterminism

The laws of classical physics, such as the laws of planetary motion, aredeterministic. Given the initial values of all the variables, their values at any
later time are completely determined. Causes of nondeterminism are either
negligible because they have an insignificant effect—for example, meteor
showers—or are simply assumed not to happen—for example, cataclysmic
collisions with errant asteroids.
A program is nondeterministic if the initial state of a behavior doesn’t
determine the complete behavior. Even when executed on supposedly deterministic digital systems, nondeterminism is the norm in programs—especiallyconcurrent ones. Here are some sources of nondeterminism in programs:
User Input The user giving a value to the program is usually described as
an action of the program that nondeterministically chooses the value
provided by the user. The user can also be described as a separate
process that nondeterministically chooses the value to provide.
Random Algorithms Some algorithms can achieve better average performance by making random choices. The science of programs presented
here is not meant for describing average properties of possible behaviors, so it can’t distinguish this case from one in which random choices
are the result of user input.
Generality We may want an abstract program to allow multiple possible
implementations. Those possibilities appear as nondeterminism in the
abstract program.
Faults Physical devices don’t always behave the way they’re supposed to.
In particular, they can fail in various ways. Programs that tolerate
failures describe a failure as an operation that may or may not be
executed.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

48

Timing Uncertainty The time taken to perform operations in an individual process can vary from one execution to another for several reasons,
including (i) being run on different hardware and (ii) competition forresources with other processes in the same program or in concurrently
executed programs. This results in multiple behaviors in which operations in different processes are executed in different orders. Thosedifferent orders can lead to very different behaviors.
Timing uncertainty is the most important source of errors due to nondeterminism that affects all concurrent programs (not just fault-tolerant ones).
Let’s examine a simple example of it.

3.3.2

An Example: Increment

The example is a trivial abstract multiprocess program called Increment. It
has a variable x that initially equals 0, and each process just increments x
by 1 and terminates. A process does this in two steps: the first step reads
the current value of x , and the second step sets x to one plus the value it
read. You should convince yourself that with N processes, an execution canterminate with x having any value from 1 through N . The final value of x
will be N if each process executes its two steps with no intervening step by
any other process. The final value will be 1 if all processes read x before
any process sets the value of x .
This abstract program is described with pseudocode in Figure 3.3, where
Procs is the set of processes. (Procs is really a set of process identifiers,
but for convenience we call its elements processes.) The only assumption
we make about this set is that it is finite and nonempty. The processstatement declares that there is a process for every element of Procs, andit gives the code for an arbitrary process p in Procs. The variables t andpc are local to process p, each process having its own copy of these twovariables. Variable x is global, accessed by all the processes. Process psaves the result of reading x in its variable t. The initial value of t doesn’t
matter, but letting all variables have reasonable initial values makes a typeinvariant simpler, so we let t initially equal 0.
The mathematical description of the abstract program Increment is in
Figure (3.4). The process-local variables t and pc are represented by mathematical variables whose values in each state are functions with domain Procs,
where t(p) and pc(p) are the values of those variables for process p. The
initial predicate, describing the values of the variables in state number 0,
is simple. The possible steps in a behavior are described by a predicate

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

49

variables x = 0 ;process p ∈ Procs
variables t = 0, pc = a ;a: t : = x ;b: x : = t + 1
end process
Figure 3.3: The Increment abstract program for a set Procs of processes.

Initial Predicate∧ x (0) = 0∧ t(0) = (p ∈ Procs 7→ 0)∧ pc(0) = (p ∈ Procs 7→ a)
Step Predicate∀ j ∈ N : PgmStep(j ) ∨ Stutter (j )where∆PgmStep(j ) = ∃ p ∈ Procs : aStep(p, j ) ∨ bStep(p, j )∆aStep(p, j ) = ∧ pc(j )(p) = a∧ x (j + 1) = x (j )∧ t(j + 1) = (t(j ) except p 7→ x (j ))∧ pc(j + 1) = (pc(j ) except p 7→ b)∆

bStep(p, j ) = ∧ pc(j )(p) = b∧ x (j + 1) = t(j )(p) + 1∧ t(j + 1) = t(j )∧ pc(j + 1) = (pc(j ) except p 7→ done)∆

Stutter (j ) = ∧ ∀ p ∈ Procs : pc(j )(p) = done
∧ hx (j + 1), t(j + 1), pc(j + 1)i = hx (j ), t(j ), pc(j )iFigure 3.4: The Increment abstract program in math.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

50

that, for each j , gives the values of x (j + 1), t(j + 1), and pc(j + 1) for
any assignment of values to x (j ), t(j ), and pc(j ). It asserts that there are
two possibilities, described by formulas PgmStep(j ) and Stutter (j ), that are
explained below.
PgmStep(j ) describes the possible result of some process executing one step
starting in state j . The predicate equals true iff there exists a process
p for which aStep(p, j ) or bStep(p, j ) is true, where:
aStep(p, j ) describes a step in which process p executes its statement
labeled a in state number j . Its last three conjuncts describe thevalues of the three variables x , t, and p in state j +1. Many people
are tempted to write t(j + 1)(p) = x (j ) and pc(j + 1)(p) = b
instead of the third and fourth conjuncts. But that would permitt(j +1)(q) and pc(j +1)(q) to equal any values for q 6= p. Instead
we must use the except operator defined in Section 2.8.2. The
first conjunct is a predicate that is true or false of state j . It is anenabling condition, allowing the step described by the following
three conjuncts to occur iff that condition is true.
bStep(p, j ) describes a step in which process p executes its statement
labeled b in state number j . It is similar to aStep(p, j ). Its
enabling condition is pc(j )(p) = b. The step sets pc(j + 1)(p)to done, which is a value indicating that the process has reached
the end of its code and terminated.
Stutter (j ) describes a stuttering step starting in state j . It is enabled iffpc(j )(p) equals done for all p ∈ Procs, so all processes have terminated. At that point, PgmStep(j ) is not enabled, so only an infinite
sequence of stuttering steps can occur, as required for a terminatedabstract program. Note that the second conjunct in the definition of
Stutter (j ) uses the fact that two tuples are equal iff their corresponding elements are equal to write the following formula more compactly:(x (j + 1) = x (j )) ∧ (t(j + 1) = t(j )) ∧ (pc(j + 1) = pc(j ))A property we might like to prove about abstract program Increment is that,when it has terminated, the value of x lies between 1 and the number ofprocesses. Let’s define N to equal #(Procs), the number of processes. Sincea process has terminated iff its local pc variable equals done, the property
we want to prove is that this formula is an invariant of Increment—that is,true for every j ∈ N:
(3.8) (∀ p ∈ Procs : pc(j )(p) = done) ⇒ (x (j ) ∈ 1 . . N )CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

51

This is not an inductive invariant because condition I2 is not satisfied. For
example, suppose the following is true:• pc(j )(p) = b and pc(j )(q) = done for all q 6= p
• t(j )(p) = N
Then (3.8) is true in state number j , but false in state number j + 1.
To show that (3.8) is an invariant of Increment, we must find an inductive
invariant that implies it. Stopping now and trying to find that inductive
invariant by yourself is a good exercise. But it’s not easy if you don’t havepractice finding inductive invariants and don’t have a tool to check if what
you think is an inductive invariant actually is one. So, I will write one foryou.
An inductive invariant almost always requires a type invariant for eachvariable. We start by defining TypeOK to assert a type invariant for eachof the three variables:∆

TypeOK (j ) = ∧ x (j ) ∈ 0 . . N∧ t(j ) ∈ (ProcSet → 0 . . N )∧ pc(j ) ∈ (ProcSet → {a, b, done})
TypeOK is an invariant, but not an inductive invariant. For example, if
x (j ) = 1, t(j )(p) = N , and pc(j )(p) = b, then TypeOK (j ) is true but a step
satisfying bStep(p, j ) makes TypeOK (j + 1) false. We can make TypeOK an
inductive invariant by weakening it, replacing the two occurrences of 0 . . Nwith N. However, I prefer a stronger, more informative type invariant.
To write the rest of the inductive invariant, we define NumberDone(j )to be the number of processes that have terminated in state j . The precise
definition is:∆

NumberDone(j ) = #({p ∈ Procs : pc(j )(p) = done})The complete inductive invariant, which we call Inv , is defined by:∆(3.9) Inv (j ) = ∧ TypeOK (j )∧ ∀ p ∈ Procs :(pc(j )(p) = b) ⇒ (t(j )(p) ≤ NumberDone(j ))∧ x (j ) ≤ NumberDone(j )To prove that Inv is an inductive invariant of program Increment, we must
prove I1 and I2. I1 asserts that the initial predicate implies Inv (0), and I2
asserts that the step predicate implies Inv (j ) ⇒ Inv (j + 1). We will notconsider how these conditions are proved until we have a more convenient
way of writing them.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

3.4

52

Temporal Logic

Math III
Proof by Contradiction An ordinary proof of P ⇒ Q assumes that
P is true and proves Q is true. A proof by contradiction proves P ⇒ Q
by assuming that P ∧ ¬Q is true and proving false. Russell’s paradox,
explained in Section 2.5, is a proof by contradiction of:{v ∈ S : F } is a set for any formula F
implies the collection of all sets isn’t a set
Proof by contradiction is an application of this theorem of propositional
logic:|= (P ⇒ Q) ≡ (P ∧ ¬Q ⇒ false)
Many mathematicians dislike proofs by contradiction because they find theminelegant. If you write a proof to make sure that what you’re trying to proveis true, then you should always write a proof by contradiction. It’s neverharder and can make it easier to write the proof. I like to view proofs bycontradiction in terms of this theorem of propositional logic:|= (P ⇒ Q) ≡ (P ∧ ¬Q ⇒ Q)
It asserts that to prove P implies Q, we can assume both P and ¬Q andprove Q. This gives us an additional hypothesis. Moreover, it’s a verystrong hypothesis. If P ⇒ Q is true, then P implies that ¬Q is equivalent
to false, which is the strongest possible hypothesis (since false implies
anything). If you wind up not using the additional hypothesis, you can justdelete it.
Structured Proofs The simplest structured proof consists of a sequenceof numbered steps. Each step consists of an assertion and its proof, exceptthat the assertion of the last step is Q.E.D., which stands for the goal of
the proof—that is, what the final step must prove. Each step’s proof is an
ordinary paragraph proof. It can use rules of logic, previously assumed orproved theorems, assumptions in the statement of the theorem, and assertions of previous steps in the proof. It must explicitly mention every theorem, assumption, and previous step’s assertion that is needed by the step’s
proof. This requirement makes a structured proof easier to understand thana typical mathematician’s proof.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

3.4.1

The Logic of Actions

3.4.1.1

Eliminating State Numbers

53

There’s an easy way to simplify initial predicates, step predicates, and invariants: remove the explicit state numbers. It’s obvious that an initial
predicate is about state number 0, so we can eliminate every “(0)” in it. An
invariant is true for all states, so we don’t have to say which states it’s about.
For a step predicate, we just have to distinguish between v (j ) and v (j + 1)
for a variable v . A notation for doing this that dates back at least to theearly 1980s is to replace v (j ) by v and v (j + 1) by v 0 . The initial and step
predicates of program Increment have been rewritten this way in Figure 3.5,
where they’ve been given the names Init and Next. The inductive invariant(3.9) is also rewritten without the “(j )” and named Inv . (The “(j )” hasbeen implicitly removed from the definition of NumberDone.) Make surethat you understand Figure 3.5 by comparing it with Figure 3.4.
Mathematically, the big leap from Figure 3.4 to Figure 3.5 is removing
the explicit mention of state numbers—for example, writing x instead ofx (j ). In Figure 3.4, Procs and x are both ordinary mathematical variables.
The value of Procs is a set of processes and the value of x is a function whose
domain is N. In Figure 3.5, the value of Procs is a set of processes—thesame set throughout a behavior of the program. However, the value of x
depends on the state of the behavior.
The price of removing explicit state numbers from our formulas is leaving
the domain of ordinary math, with a single kind of variable, and entering a
new kind of math in which there are two kinds of variables: mathematicalvariables like Procs, whose values are the same in every state of a behavior,and program variables like x that are implicit functions of the state. Program variables like x look weird to mathematicians. In math, the value of avariable x is fixed. We’ve seen in Chapter 2 that when a mathematician does
something else and introduces a variable x , it’s really a completely different
variable that happens also to be written “x ”. Of course, you’re familiar with
program variables because they’re the variables of coding languages, whose
values change in the course of a computation.
Since this book is about a science of programs, we will henceforth use thename variable for program variables. Mathematical variables like Procs will
be called constants. When describing a program mathematically, variables
correspond to what we normally think of as program variables. Constants
are parameters of the program, such as a fixed set of processes. Early coding
languages had constants as well as variables. In modern coding languages,

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

54

Initial Predicate∆

Init = ∧ x = 0∧ t = (p ∈ Procs 7→ 0)∧ pc = (p ∈ Procs 7→ a)
Step Predicate∆

Next = PgmStep ∨ Stutter
where∆
PgmStep = ∃ p ∈ Procs : aStep(p) ∨ bStep(p)∆aStep(p) = ∧ pc(p) = a∧ x0 = x∧ t 0 = (t except p 7→ x )∧ pc 0 = (pc except p 7→ b)∆

bStep(p) = ∧ pc(p) = b∧ x 0 = t(p) + 1∧ t0 = t∧ pc 0 = (pc except p 7→ done)∆

Stutter = ∧ ∀ p ∈ Procs : pc(p) = done
∧ hx 0 , t 0 , pc 0 i = hx , t, pc i
Inductive Invariant∆

Inv = ∧ TypeOK∧ ∀ p ∈ Procs : (pc(p) = b) ⇒ (t(p) ≤ NumberDone)∧ x ≤ NumberDone
Figure 3.5: Abstract program Increment and its invariant Inv in simpler
math.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

55

constants are buried in the code, where they are called static final variablesof an object.
In this book, the variables in pseudocode are explicitly declared, and undeclared identifiers like Procs are constants. For formulas, the text indicates
which identifiers are variables and which are constants.
In addition to having both variables and constants, the formulas in Figure 3.5 have primed variables, like x 0 . An expression that may contain
primed and unprimed variables, constants, and the operators and values ofordinary math (which means everything described in Chapter 2) is called astep expression. A Boolean-valued step expression is called an action. The
math whose formulas are actions is called the Logic of Actions, or LA for
short.
3.4.1.2

The Semantics of the Logic of Actions

As we did in defining the semantics of elementary algebra in Section 2.2,
we define the meaning [[exp]] of an expression of LA to be a mapping on
interpretations. An interpretation assigns values to variables. Since LA has
both constants and variables, there are two parts to an interpretation: an
assignment of values to constants and an assignment of values to variables.
Since constants are ordinary mathematical values, and we have alreadydiscussed the semantics of ordinary math, we will ignore the part of an interpretation for LA that assigns values to them. When discussing a formula ofLA, we assume that there is some fixed interpretation Υ that assigns values
to the constants. Constants are usually assumed to satisfy some conditions.
For example, the constants M and N of Euclid’s algorithm in Section 1.5
are assumed to be positive integers, and the constant Procs of program
Increment in Section 3.3 is assumed to be a finite set. We assume thatthe fixed interpretation Υ satisfies those assumptions. We define |= F for a
formula F of LA to mean that [[F ]] is true for all interpretations in which
the assignment of values to the constants satisfies the assumptions.
In LA, there are effectively two kinds of variables: unprimed and primed.
An interpretation of LA assigns values to each of those kinds of variables,
where the values assigned to v and v 0 are independent of one another.
We have defined a state to be an assignment of values to program variables. So, since we’re neglecting constants, an interpretation for an LA
formula is a pair of states—the first assigning values to the unprimed variables and the second assigning values to the primed variables. We have used
the term step to mean a pair of successive states in a behavior. We now let
it mean any pair of states. We will write the step consisting of the states sCHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

56

and t as s → t rather than hs, t i because that makes it clear that s and t
are states.
To define the semantics of LA, we therefore have to define [[exp]](s → t)
for any states s and t. We have not yet defined any operators for LA,
so the only operators that can appear in an LA expression are ordinary
mathematical operators like + and Tail . They have the usual semantics in
LA. For example∆[[exp1 + exp2]](s → t) = [[exp1]](s → t) + [[exp2]](s → t)
For an unprimed variable v , we define [[v ]](s → t) to equal s(v ), the value
assigned to variable v by state s. For a primed variable v 0 , we define[[v 0 ]](s → t) to equal t(v ).
We call an LA expression a step expression and an LA formula an action.
For an action A and step s → t, we say that s → t satisfies A or is an A
step iff [[A]](s → t) equals true.
A state expression is an LA expression that contains no primed variables, and a state formula is a Boolean-valued state expression. For a state
expression exp, the value of [[exp]](s → t) depends only on s, so we can write
it as [[exp]](s).
Because the meaning of an LA expression assigns different values to v
and v 0 , we can treat v and v 0 as two unrelated variables. This means that
we can reason about LA formulas as if constants, unprimed variables, andprimed variables were all different mathematical variables. Thus, for LA as
defined so far, we can regard LA as ordinary math with some mathematicalvariables having names like v 0 ending with 0 .
3.4.1.3

The Prime Operator (0 )In Figure 3.5, only variables are primed. In the Logic of Actions, we canprime not just a variable but any state expression—that is, any expression
containing no primes. For a state expression exp, the value of the step
expression exp 0 on a step s → t is the value of exp on t. More precisely, themeaning of exp 0 is defined by [[exp 0 ]](s → t) = [[exp]](t). This means thatexp 0 is equivalent to the step expression obtained by priming all the variables
in exp. The priming operator (0 ) can be applied only to state expressions.
In LA, priming an expression that contains a prime is a syntax error. Thatmeans that it is illegal to prime an expression containing a defined symbol
whose definition contains a prime. For example, if e is defined to equal
x 0 + 1, then e 0 is syntactically illegal.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

57

A constant has the same value in both states of a step. Therefore,|= c 0 = c is true for any constant c. More generally, a constant expression isan expression with no (primed or unprimed) variable; and |= exp 0 = exp istrue for any constant expression exp. The bound identifiers of predicate logic
are like ordinary mathematical variables, which means they are treated likeconstants in the Logic of Actions. For example, (∃ i ∈ N : y = x + i )0 equals∃ i ∈ N : y 0 = x 0 + i . We therefore call bound identifiers bound constants.
Appendix Section A.4 gives an example of how you can get into trouble byforgetting that bound identifiers are constants.
The semantics of LA imply that the prime operator distributes over
the operators and constructs of ordinary math—for example, that (F ∨ G)0
equals F 0 ∨ G 0 . By expanding all definitions and distributing primes in thisway, we obtain a formula in which the prime operator is applied only to variables. We don’t have to expand all definitions to obtain such a formula. We
need only expand definitions that contain a prime or that appear within aprimed expression and contain a variable. Once we have reached an expression in which only variables are primed, we can reason about the resulting
expression as if constants, variables, and primed variables were all ordinary
mathematical variables. We therefore need no additional rules for reasoning
about LA formulas.
Section 3.2.2 defined an inductive invariant Inv of a program to be astate predicate satisfying conditions I1 and I2, which we can restate as:
I1. Inv is implied by the program’s initial state.
I2. If Inv is true in a state, then the program’s next-state predicate implies
that it is true in the next state.
For program Increment, whose initial predicate is Init and whose next-state
action is Next, these two conditions can be expressed in LA as:(3.10) |= Init ⇒ Inv|= Inv ∧ Next ⇒ Inv 0
The proof of these conditions for program Increment is discussed in Appendix Section B.1.
Thus far, the correctness properties of programs that have concerned us
have been invariance properties. All the reasoning we have done to verify
that a program satisfies an invariance property is naturally expressed in
LA. The safety property usually proved of a traditional program is that it
cannot produce a wrong answer—which is expressed as the invariance ofCHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

58

the property asserting that the program has not terminated with a wrong
answer. The most popular way of proving such a property is Hoare logic [21].
Appendix Section A.5 explains Hoare logic and its relation to the Logic of
Actions.
3.4.1.4

Action Composition

The Logic of Actions contains another operator that is almost never usedin describing abstract programs and will not play a major role for us until
Section 7.1. However, it does make brief appearances in Sections 4.3.2 and5.4.4.3, so it is explained here.
For actions A and B , the action A · B is defined to be true of a steps → t iff there is a state u such that s → u is an A step and u → t isa B step. If actions A and B describe two pseudocode statements S a andS b , then A · B describes the statement S a ; S b executed by executing S afollowed by S b . For example, the statements labeled a and b in process p ofprogram Increment shown in Figure 3.3 are described by actions aStep(p)and bStep(p) of Figure 3.5, and:5
aStep(p) · bStep(p) ≡ ∧ pc(p) = a∧ x 0 = t(p) + 1∧ t 0 = (t except p 7→ x )∧ pc 0 = (pc except p 7→ done)
Replacing the actions aStep(p) and bStep(p) with aStep(p) · bStep(p) in thedefinition of the next-state action Next of program Increment produces a
program with a coarser grain of atomicity. Choosing the grain of atomicity
of an abstract program involves a tradeoff between making the program
detailed enough to be useful and simple enough to be usable. Section 7.1
addresses this tradeoff using action composition.
The operator “·” is associative, meaning (A · B ) · C = A · (B · C ) for any
actions A, B , and C . We can therefore omit parentheses and simply write
A·B ·C .
For any action A, we define the action A+ to be satisfied by a step s → t
iff state t can be reached from state s by a sequence of one or more A steps.
In other words:∆

A+ = A ∨ (A · A) ∨ (A · A · A) ∨ (A · A · A · A) ∨ . . .
5

If you believe that the second and third conjuncts in this formula are in the wrong
order, then you’re thinking in terms of coding languages, not math. Remember that F ∧G
is equivalent to G ∧ F .

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

3.4.2

59

The Temporal Logic RTLA

In 1977, Amir Pnueli [47] had the idea of using an obscure branch of mathematics called temporal logic to express time-dependent properties without
explicitly mentioning times or state numbers. He used a temporal logic
containing the single temporal operator 2 and operators defined in termsof 2. You can read 2 as always, but when you become more familiar withit you’ll probably just call it box. Intuitively, the formula 2F asserts thatthe formula F is true at all times. For example, if P is a state predicate,then 2P asserts that P is true in all states of a behavior.
From now on, we will be discussing and using temporal logic. We willcontinue to ignore assignments of values to constants, assuming some fixedinterpretation satisfying the assumptions made about those constants.
In the kind of temporal logic Pnueli used, called linear-time temporal
logic, the meaning of a formula is a predicate on behaviors, where a behavior
is an infinite cardinal sequence of states. In other words, a behavior σ isa function from N to states. We think of σ(n) as the state at time n, so
the first state of σ is σ(0). But remember, the only resemblance of thestate number n to a time is that state σ(n) does not occur later than stateσ(n + 1). (In Section 4.4, we’ll see that they could both occur at the sametime.) We’ll sometimes write σ as σ(0) → σ(1) → · · · .
RTLA is the temporal logic containing the same temporal operators as
Pnueli’s original logic, all defined in terms of 2, but having the formulasof LA as the basic formulas. The formulas of RTLA can all be written as
LA formulas and formulas obtained from them using the operator 2 andthe usual Boolean operators and quantifiers of ordinary math. The only
expressions of RTLA are formulas. Prime (0 ) can appear only in the basic
LA formulas. It’s illegal to prime a formula containing a 2.
The TLA in RTLA stands for Temporal Logic of Actions. The R stands
for Raw, in the sense of unrefined. We’ll see later that RTLA allows us
to write formulas that we shouldn’t write. TLA is the logic obtained by
restricting RTLA to make it impossible to write those formulas. But that’s
a complication we don’t need to worry about now, so we’ll start with thesimpler “raw” logic.
In temporal logic formulas, the operator 2 binds more tightly than theoperators of propositional logic. For example, 2F ∨G is parsed as (2F )∨G.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS
3.4.2.1

60

Simple RTLA

In RTLA, the operator 2 can be applied to any RTLA formula, so we canwrite formulas like 2(A ⇒ 2B ) where A and B are actions. We will begin
by considering simple RTLA, in which the operator 2 is applied only toactions, not to formulas containing 2.
A formula of a temporal logic is called a temporal formula. For any
assignment of values to constants, the meaning [[F ]] of a temporal formula
is a behavior predicate—that is, a mapping that assigns Boolean values tobehaviors. An action A is a formula of RTLA, where it is viewed as abehavior predicate. As a formula of LA, we’ve viewed A as a step predicate.
As a formula of RTLA, we view it as a behavior predicate that is true on a
behavior iff, viewed as a step predicate, it is true of the behavior’s first step.
To state that precisely, let [[A]]LA be the meaning of A as an LA formula.
We define its meaning [[A]]RTLA as an RTLA formula as follows. For any
behavior σ, which equals σ(0) → σ(1) → σ(2) → · · ·, we define∆(3.11) [[A]]RTLA (σ) = [[A]]LA (σ(0) → σ(1))
From now on, [[F ]] means [[F ]]RTLA for all RTLA formulas, including actions.
We will explicitly write [[A]]LA to denote the meaning of A as an LA formula.
For an action A, we define 2A to be the temporal formula that is trueof a behavior iff A is true of all steps of the behavior. In other words, wedefine the meaning [[2A]] of the RTLA formula 2A by∆(3.12) [[2A]](σ) = ∀ n ∈ N : [[A]]LA (σ(n) → σ(n + 1))
Like most logics, RTLA contains the propositional logic operators, where
they have their standard meanings. For example, [[F ∧ G]](σ) equals[[F ]](σ) ∧ [[G]](σ). We will write a quantified formula like ∃ i ∈ S : F with
F a temporal formula only when S is a constant expression, in which case[[∃ i ∈ S : F ]](σ) equals ∃ i ∈ [[S ]] : [[F ]](σ) , where [[S ]] is the value of S under
the assumed assignment of values to constants. As in LA, bound identifiers are called bound constants and they act like constants, having the samevalue in all states of a behavior.
It’s important to remember that a behavior is any cardinal sequence ofstates. It doesn’t have to be a behavior of any particular program. Since
any step is the first step of lots of behaviors, it’s obvious that if A is an LA
formula, then |= A is true when A is viewed as an RTLA formula iff it’s true
when A is viewed as an LA formula.
Now let’s return to the description of program Increment in Figure 3.5.
It tells us that a behavior σ is a behavior of the program iff (i) the initial

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

61

predicate Init is true of its first state σ(0) and (ii) the step predicate Next
is true for every step σ(n) → σ(n + 1) of σ. Condition (i) is expressedby [[Init]], since (3.11) tells us that [[Init]](σ) equals [[Init]]LA (σ(0) → σ(1));
and since Init is a state predicate, it’s true of a step iff it’s true of the firststate of the step. By (3.12), condition (ii) is expressed as [[2Next]]. Thus(the meaning of) the formula Init ∧ 2Next is true of a behavior σ iff σ is abehavior of program Increment.
Of course, this is true for an arbitrary program. The behaviors thatsatisfy a program with initial predicate Init and next-state action Next
are described by the simple RTLA formula Init ∧ 2Next. Any program is
described by an RTLA formula of this form. As promised, we can write any
program as a mathematical formula. It’s an RTLA formula rather than a
TLA formula, and we’ll see that it needs to be modified. But for now, it’sclose enough to the final TLA formula.
By (3.12), the state predicate Inv is true in all states of a behavior iff
2Inv is true of that behavior. That Inv is an invariant of Increment means
that, for any behavior σ, if σ is a behavior of Increment then Inv is true inall states of σ. Thus, that Inv is an invariant of Increment is expressed bythis condition:(3.13) |= Init ∧ 2Next ⇒ 2Inv
Remember that in (3.10) and (3.13), when Init, Next, and Inv are the formulas defined in Figure 3.5, |= F means that F is true for all interpretations
satisfying the assumptions we made about the constants of Increment—
namely, that Procs is a nonempty finite set and the implicit assumptionthat the values of a, b, and done are different from one another.
In general, the conditions I1 and I2 for showing that a state predicate Inv
is an invariant of a program Init ∧ 2Next are expressed in LA by conditions(3.10). It is an RTLA proof rule that these conditions imply (3.13). When we
prove a safety property like (3.13), the major part of the reasoning depends
on the definitions of the formulas Init, Next, and Inv . That reasoning isreasoning about actions, which is formalized by LA. The temporal logic
reasoning, which is done in RTLA, is trivial. Describing the program with asingle formula is elegant. But it is really useful only when verifying livenessproperties, which requires nontrivial temporal reasoning.
Because it’s often forgotten, it is worth repeating that a state is any
assignment of values to variables, and a behavior is any infinite sequence ofstates. Even when we are discussing program Increment,“state” means any√
state, including states in which x has the value h 2, 1 . . 147i. In (3.13), |=means true for any behavior, even behaviors in which the initial value of x

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

62√
is h 2, 1 . . 147i.
√ It is true for those behaviors because Init equals false forthem (unless h 2, 1 . . 147i happens to equal 0, which it might).
3.4.2.2

The Complete RTLA

Simple RTLA suffices for reasoning about safety properties, but not for
liveness properties. For example, we want to express the liveness property
of program Increment that a process p eventually terminates. Terminationof p means that pc(p) eventually equals done and remains equal to done
forever. In terms of explicit state numbers, where pc(n) is the value of pc
in state number n, this property can be written:(3.14) ∃ j ∈ N : ∀ k ∈ N : pc(j + k )(p) = done
To write it without explicit state numbers, we need full RTLA, in which
2 can be applied to any RTLA formula, not just to an action. To define
the meaning of all RTLA formulas, we first define σ +n, for any behavior σ
and natural number n, to be the behavior obtained by removing the first nstates from the sequence σ. That is, σ +n is the behavior
σ(n) → σ(n + 1) → σ(n + 2) → · · ·so σ +n equals i ∈ N 7→ σ(i + n) .
For any RTLA formula F , the RTLA formula 2F is true of a behavior
σ iff it is true of the behaviors σ +n for all n ∈ N. In other words:∆(3.15) [[2F ]](σ) = ∀ n ∈ N : [[F ]](σ +n )for any behavior σ. When F is an action A, this is the same definition as(3.12) because the first step σ +n (0) → σ +n (1) of σ +n is σ(n) → σ(n + 1) .
Although 2 has a simple definition, temporal formulas can be hard tounderstand at first. It helps to think of a temporal formula as an assertion
about the present and future. The state σ(n) of a behavior σ is the state attime n, and the behavior σ +n is the part of the behavior σ that begins attime n. We can then think of [[F ]](σ +n ) as asserting that F is true at timen of behavior σ. Thus, [[F ]](σ) asserts that F is true at time 0 of σ, and[[2F ]](σ) asserts that F is true at all times of σ. The formula 2F therefore
asserts that F is true at all times—that is, F is always true. (Rememberthat time n is just some instant of time; it is not n time units after time 0.)
We now drop the [[ ]] and think about temporal logic the same way wethink about ordinary math, conflating a formula with its meaning. So, we’ll
think of a temporal formula F as a Boolean-value function on behaviors.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

63

However, we will still turn to the formal meaning (3.15) of 2 when it isuseful.
Since we will now be working with temporal logic formulas, we consider
a tautology to be any valid formula whose validity depends only on theorems of temporal logic, which include theorems of ordinary predicate andpropositional logic. We will therefore call theorems of temporal logic tautologies. Sections 3.4.2.3–3.4.2.8 below examine 2 and temporal operators
defined in terms of 2. They present quite a few temporal logic tautologies. Understanding intuitively why those tautologies are true will makeyou comfortable reading temporal logic formulas and thinking in terms ofthem.
3.4.2.3

The 2 Operator

We first consider some temporal logic tautologies—theorems about arbitrary
temporal formulas. If they are not obvious, rewrite them in terms of themeanings of the formulas. The first tautology asserts the obvious fact that
if F is always true, then it is true now:
(3.16) |= 2F ⇒ F
The next tautology asserts that F ∧ G true at all times is equivalent to F
true at all times and G true at all times:(3.17) |= 2(F ∧ G) ≡ (2F ) ∧ (2G)
You should check that (3.17) follows from the definition (3.15) of 2 and thepredicate-logic tautology:|= (∀ n ∈ S : P ∧ Q) ≡ (∀ n ∈ S : P ) ∧ (∀ n ∈ S : Q)
Observe that 2(F ∨ G) and (2F ) ∨ (2G) are not equivalent. For example,2(F ∨ G) is true of a behavior in which F is true only in the initial state and
G is false in the initial state and true in all other states. However, neither
2F nor 2G is true of that behavior.
We can generalize (3.17) to any conjunction, including an infinite conjunction—that is, quantification over an infinite set of formulas. If F i is atemporal formula for all i ∈ S , then:(3.18) |= 2(∀ i ∈ S : F i ) ≡ (∀ i ∈ S : 2F i )The next tautology should also be obvious. It asserts that if F implies G istrue at all times, then F is true at all times implies G is true at all times:(3.19) |= 2(F ⇒ G) ⇒ (2F ⇒ 2G)

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

64

Perhaps less obvious is this proof rule, which is sort of a converse of (3.16):(3.20) |= F implies |= 2F
The assertion |= F means that F is true of all behaviors. The assertion|= 2F asserts that for any behavior, F is true of the part of that behavior
starting at any time. But that part of the behavior is itself a behavior, so|= F implies that F is true of it. If this is not obvious to you, then you
may be thinking of a behavior as a behavior of some program. A behavior
is any infinite sequence of states, so if you remove the first n states of any
behavior, you get a behavior.
From (3.19) and (3.20) we easily derive:(3.21) |= F ⇒ G implies |= 2F ⇒ 2G
This rule lies at the heart of much temporal logic reasoning.
We now examine some additional temporal assertions that can be definedusing 2.
3.4.2.4

Eventually (3)The operator 3 is defined to be the dual of 2 :(3.22) 3F = ¬2¬F∆

Like 2, the operator 3 binds more tightly than the operators of propositional
logic, so 3F ∧ G is parsed as (3F ) ∧ G. To understand 3, we derive themeaning [[3F ]] of a formula 3F from (3.15):[[3F ]](σ) ≡ [[¬2¬F ]](σ)≡ ¬ [[2¬F ]](σ)≡¬ ∀ n ∈ N : [[¬F ]](σ +n )by definition of 3
by the meaning of ¬by (3.15)≡ ¬ ∀ n ∈ N : ¬ [[F ]](σ +n )by the meaning of ¬∃ n ∈ N : [[F ]](σ +n )by (2.7) of Section 2.7≡

Hence, 3F asserts that F is true at some time—either now or in the future.
We read 3 as eventually, where by being eventually true we include thepossibility of being true only now. Corresponding to the tautologies (3.16)
and (3.17) for 2 are these tautologies for 3:(3.23) |= F ⇒ 3F|= 3(F ∨ G) ≡ (3F ∨ 3G)

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

65

Make sure you understand why they are true from the meaning of 3 as
eventually. These two tautologies can be derived from (3.16) and (3.17).
For example:(3.24) (F ⇒ 3F ) ≡ (¬(¬F ) ⇒ ¬(2¬F ))≡ (2¬F ⇒ ¬F )By logic and the definition of 3.
By propositional logic.

and |= 2¬F ⇒ ¬F follows from (3.16). You should convince yourself that3(F ∧ G) and (3F ) ∧ (3G) need not be equivalent. The equivalence of3(F ∨ G) and 3F ∨ 3G generalizes to arbitrary disjunctions:|= 3(∃ i ∈ S : F i ) ≡ (∃ i ∈ S : 3F i )Here are three tautologies relating 3 and 2. The first is obtained by negating
3F and its definition; the second by substituting ¬F for F in that definition;and the third by substituting ¬F for F in the first:(3.25) |= ¬3F ≡ 2¬F|= ¬2F ≡ 3¬F|= 2F ≡ ¬3¬F

They should be obvious from thinking of 2 as always and 3 as eventually.
The first two tell us that moving ¬ over a temporal operator 2 or 3 changes
2 to 3 and 3 to 2. Note the similarity between 2/3 and ∀ /∃ , a similaritythat arises from the meanings of 2 and 3. Here is another tautology that
follows from the intuitive meanings of 2 and 3 :(3.26) |= (2F ∧ 3G) ⇒ 3(2F ∧ G)
It asserts that if F is true from now on and G is true at some time in the
future, then at some time in the future F is true from then on and G is truethen.
We can express liveness properties with 3. For example, the assertion
that some state predicate P is eventually true is a liveness property. The
assertion that the program whose formula is F satisfies this property is|= F ⇒ 3P . Since the assertion that something eventually happens is aliveness property, most of the formulas we write that contain 3 express
liveness.
The equivalence of ¬3P and 2¬P for any formula P implies the tautology |= 3P ∨ 2¬P . This tautology is central to many liveness proofs. To
prove that a program described by formula F satisfies the liveness property
3P , we must prove |= F ⇒ 3P . The tautology |= 3P ∨ 2¬P and propositional logic imply that we can prove this by proving |= F ∧ 2¬P ⇒ 3P .
This is a proof by contradiction, allowing us to use the additional hypothesis 2¬P , which should be false. For example, if P is a state predicate, thisgives us an invariant ¬P that can be used to prove other invariants.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS
3.4.2.5

66

Eventually Always (32)

Recall that termination of process p of program Increment means that pc(p)eventually equals done and remains forever equal to done, a property expressed with explicit state numbers by (3.14). It can be stated as: It’s eventually true that pc(p) = done is always true. This is expressed in RTLA as
32(pc(p) = done). You should check that [[32(pc(p) = done)]](σ) is equivalent to (3.14) because (σ +j )+k equals σ +(j +k ) , so pc(j + k )(p) in (3.14)
equals [[pc(p)]](σ +(j +k ) ).
We can think of 32 as a temporal operator meaning eventually always.
Convince yourself that this is a tautology:|= 32(F ∧ G) ≡ (32F ) ∧ (32G)
3.4.2.6

Infinitely Often (23)It should now seem natural to think of 23F as meaning always eventually
F is true. If you’re not used to thinking about infinite sequences, it may
not be obvious that always eventually is equivalent to infinitely often. So,
let’s prove it.
Theorem 3.1 F is infinitely often true iff it is always eventually true.
Define S σ to be the set of times at which F is true of a behavior σ.
1. F is infinitely often true of σ iff S σ is an infinite set.
Proof: By definition of infinitely often.
2. S σ is an infinite set iff for every time n, there is a time m ≥ n such thatm ∈ Sσ .
Proof: A set of natural numbers is infinite iff it has no largest element.
3. The statement that for every time n there exists a time m ≥ n such thatm ∈ S σ is equivalent to the statement that F is always eventually true.
Proof: By the definitions of S σ and always eventually.
4. Q.E.D.
Proof: By propositional logic, because steps 1–3 are of the form A iff B ,B iff C , and C iff D, and the theorem asserts A iff D.
It is usually most helpful to think of 23 as meaning infinitely often rather
than always eventually. For example, consider the formula 23(F ∨ G). It
asserts that F ∨ G is true infinitely often, which means that F or G is true

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

67

infinitely often. But F or G is true infinitely often iff at least one of themis true infinitely often. This yields the following tautology:(3.27) |= 23(F ∨ G) ≡ (23F ) ∨ (23G)
The rules for moving ¬ over 2 and 3 that are implied by the first two
tautologies of (3.25) yield the following two tautologies. For example, thefirst comes from ¬23F ≡ 3¬3F ≡ 32¬F .
(3.28) |= ¬23F ≡ 32¬F
3.4.2.7|= ¬32F ≡ 23¬F

The End of the LineYou might expect that we can keep constructing more and more complicated operators like 233232 with sequences of 2 and 3. We can’t. Anysuch sequence is equivalent to 2, 3, 23 or 32. To see this, first observethat always always is the same as always. That is, 22F is equivalent to
2F . That’s because ∀ i , j ∈ N : P (i + j ) is equivalent to ∀ k ∈ N : P (k ), for
any P .
Similarly, eventually eventually is the same as eventually, so 33F isequivalent to 3F . The equivalence of 33 and 3 also follows from thedefinition of 3 and the equivalence of 22 and 2 by:
33F ≡ ¬2¬¬2¬F ≡ ¬22¬F ≡ ¬2¬F ≡ 3F
So, we can only get a new operator by alternating 2 and 3. However, 23
and 32 is as far as we can go because of the following tautologies:(3.29) |= 323F ≡ 23F|= 232F ≡ 32F

The first one is obvious if we read 323 as eventually infinitely often, because
F is true at infinitely many times iff it is true at infinitely many times aftersome time has passed. You can convince yourself that the second is true
by realizing that infinitely often F always true is equivalent to F being
always true starting at some time. Alternatively, you can show that thefirst tautology implies the second by figuring out why each of the following
equivalences is true:
232F ≡ ¬3¬¬2¬¬3¬F ≡ ¬323¬F ≡ ¬23¬F≡ ¬¬3¬¬2¬¬F ≡ 32F

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS
3.4.2.8

68

Leads To (;)

Although there are no more operators to be defined by directly stacking 2
and 3, there is another useful temporal operator defined in terms of them:the operator ;, read leads to, defined by:
F ; G = 2(F ⇒ 3G)∆

The operator ; is parsed like ⇒.
Formula F ; G asserts of a behavior that, whenever F is true, G is true
then or later. You should convince yourself that ; is transitive, meaning:|= (F ; G) ∧ (G ; H ) ⇒ (F ; H )Here are two additional tautologies that should be obvious:(3.30) |= ((F ∨ G) ; H ) ≡ (F ; H ) ∧ (G ; H )|= (F ; G) ∧ 2(G ⇒ H ) ⇒ (F ; H )The first of these tautologies generalizes to:(3.31) |= ((∃ i ∈ S : F i ) ; H ) ≡ (∀ i ∈ S : (F i ; H ))Here are three more tautologies involving ;; try to understand why they’retrue.
(3.32) (a) |= 2F ∧ (F ; G) ⇒ 23G(b) |= (F ; G) ≡ (F ∧ 2¬G ; G)(c) |= (F ∧ 2G ; H ) ≡ (F ∧ 2G ; H ∧ 2G)
Here’s how I understand them:(a) F ; G implies that whenever F is true, G is true then or later; and2F implies that F is always true. Therefore, 2F ∧ (F ; G) implies
G is true infinitely often.
(b)

F ;G

≡
≡
≡
≡

2(F ⇒ 3G)
2(F ∧ ¬3G ⇒ 3G)
2(F ∧ 2¬G ⇒ 3G)
F ∧ 2¬G ; GDefinition of ; .
Propositional logic.
By (3.25).
Definition of ; .

(c) F ∧ 2G ; H asserts that, for all t, if F ∧ 2G is true at time t, thenH is true at some time u ≥ t; and 2G true at time t implies it is stilltrue at time u, so H ∧ 2G is true at time u.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

69

Observe that tautology (b) justifies a proof by contradiction: to prove that
F true implies G is eventually true, we can assume that G is never true.
Proving ; properties is at the heart of liveness proofs. For example,
here’s how we prove termination of Euclid’s algorithm, discussed in Section 1.5. The algorithm terminates because while x 6= y is true, the sumof x and y keeps decreasing, which can’t continue forever because the algorithm satisfies the invariant that x and y are positive integers. Therefore,
eventually x = y and the algorithm terminates. This argument is formalized
in RTLA as follows.
To prove termination, we must prove that every behavior of the algorithm
satisfies 3(x = y). The proof uses this tautology, which follows from themeanings of the operators 2, ;, and 0 :(3.33) |= 2(P ⇒ Q 0 ) ⇒ (P ; Q)
The tautology |= 3P ∨ 2¬P allows us to prove 3(x = y) by assuming thata behavior of the algorithm satisfies 2(x 6= y) and obtaining a contradiction.
Let R i be the state predicate x + y ≤ i . We prove that 2(x 6= y) and theinvariant that x and y are positive integers imply that, for all i > 0, theprogram satisfies 2(R i ⇒ (R i−1 )0 ). By (3.33), this implies R i ; R i−1 . By
the transitivity of ; and mathematical induction, this implies R M +N ; R 0 .
Since the program implies that R M +N is true in the initial state, this implies that 3R 0 is true, contradicting the invariant that x and y are always
positive.
3.4.2.9

Warning

Although elegant and useful, temporal logic is weird. It’s not ordinary math.
In ordinary math, any operator Op we can define satisfies the condition,
sometimes called substitutivity, that the value of an expression Op(e 1 , . . . , e n )is unchanged if we replace any e i by an expression equal to e i . If Op takes
a single argument, substitutivity means that
(3.34) |= (exp 1 = exp 2 ) ⇒ (Op(exp 1 ) = Op(exp 2 ))is true for any expressions exp 1 and exp 2 . For example, (3.34) is true
for the operator Tail . However, the temporal operator 2 is not substitutive. For example let exp 1 and exp 2 be the state predicates x = 0 and
y = 0, respectively; and let σ be a behavior such that for each j ∈ N, thestate σ(j ) assigns the value 0 to x and the value j to y. Then exp 1 andexp 2 both equal true for σ because they are both true for σ(0). FormulaCHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

70

2exp 1 is true for σ because x = 0 is true in all its states, but 2exp 2 isfalse for σ because y = 0 is true only in the first state σ(0). Hence, thevalue of the formula (exp 1 = exp 2 ) ⇒ (2exp 1 = 2exp 2 ) for this behavior
is (true = true) ⇒ (true = false), which equals false. The operator
0 (prime) is similarly not substitutive, so it too is weird. This weirdness
affects all temporal logics and makes temporal logic reasoning tricky.

3.5

TLA

Math IV
Simple Recursive Definitions A recursive definition of a mapping M
is one in which M appears in its definition. (Mathematicians call them
inductive definitions.) A simple recursive definition defines a function fwith domain N by defining the value of f (0) to equal some expression notcontaining f and, for every n > 0, defining f (n) in terms of f (n − 1). The
classic recursive definition is that of n ! (pronounced n factorial ), whichequals the product of the numbers from 1 through n, with 0! defined toequal 1. If we consider n ! to be an abbreviation of !(n) for the function !,we can define ! by∆

! = n ∈ N 7→ if n = 0 then 1 else n ∗ !(n − 1)∆

An arbitrary definition f = n ∈ N 7→ exp where f appears in the expression
exp does not necessarily define f to equal n ∈ N 7→ exp. For example, if
I had written !(n + 1) instead of !(n − 1) in the definition of !, then it’s
not obvious what that definition would mean. (Its meaning is defined inAppendix Section A.1.9.) But all you need to know is that it would define!(n) to be a meaningless expression for any value n.6
The actual definition given above does define ! to be a function that
equals the right-hand side of its definition. The intuitive reason is that thedefinition allows us to compute !(n) in a finite number of steps for any
natural number n. For example, we can compute !(42) by computing !(41),which we can compute by computing !(40), which we can compute by . . . ,which we can compute by computing !(0), which equals 1.
6This particular definition would define ! to be a function with domain N, but with!(n) a meaningless expression for any n. However, its usually not the case that such a
non-terminating recursion defines a function.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

3.5.1

71

The Problem

There is something terribly wrong with our RTLA descriptions of abstract
programs, because there is something terribly wrong with the descriptions
like the one in Figure 3.4 that we wrote using explicit step numbers. To
see why, let’s return to the discussion in Section 3.1 of how astronomers
describe a planet orbiting a star. As explained there, the mathematicaldescription of the orbiting planet is best thought of as describing a universe
containing the planet, saying nothing about what else is or is not in theuniverse. In particular, that description applies just as well to a universe
in which there is a spacecraft close to the star that orbits it very fast—
perhaps going around the star 60 times every time the planet goes around
it once. Since the spacecraft is too small to affect the motion of the planet,
we would obtain a description of the system composed of the planet and thespacecraft by adding (conjoining) a description of the spacecraft’s motion
to the description of the planet’s motion. The description of the planet’s
motion remains an accurate description of that planet in the presence ofthe spacecraft. It would be crazy if we had to write different formulas todescribe the planet because of the spacecraft that has no effect on it.
Now consider the descriptions of abstract programs we’ve been writing.
In particular, consider an RTLA formula HM describing how the values of
the hour and minute displays of a 24-hour clock change. Using the variables
hr and min to describe the current hour and minute being displayed, wemight define HM to equal Init ∧ 2Next, where:∆(3.35) Init = (hr = 0) ∧ (min = 0)∆

Next = ∧ min 0 = (min + 1) % 60
∧ hr 0 = if min = 59 then (hr + 1) % 24 else hr
But suppose that the clock also displays seconds. The RTLA formula HMS
that also describes the second display might use a variable sec to describethat display. A behavior σ allowed by HMS would not be allowed by HM
because HM requires every step to change the value of min, while σ mustchange the value of sec in every step and the value of min in only every 60th
step.
It is just as crazy for an abstract program describing an hour-minuteclock not to describe a clock that also displays seconds as it is for a description of a planet’s motion no longer to describe that motion because of aspacecraft that doesn’t affect the planet. It means that anything we’ve said
about the hour and minute display might be invalid if there’s also a second
display. And it doesn’t matter if the minute display is on a digital clock on

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

72

my desk and the second display is on a phone in my pocket. More generally,
it means if we’ve proved things about completely separate digital devices
and we look at those two devices at the same time, nothing we’ve proved
about them remains true unless those devices are somehow synchronized to
run in lock step. The more you think about it, the crazier it seems.

3.5.2

The Solution

To figure out how to fix this problem, let’s first see where we went wrong.
It happened in Section 3.2.1, when we went from a sequence t 0 , t 1 , t 2 , . . .
of times to a sequence 0, 1, 2, . . . of state numbers. We were writing adescription of a particular system. But math and science don’t describe asystem; they describe a universe containing that system. And that universe
can contain many systems. A different system might lead to a different
sequence u 0 , u 1 , u 2 , . . . of times, with only t 0 and u 0 equal. Our error
was converting two possibly different times t i and u i into the same state
number. The result was that when we thought we were writing a descriptionof a particular system, we were actually writing a description of a universe
in which the values of all variables, including ones describing other systems,
could change only when the variables of that particular system changed.
You might think that because the error occurred when we were throwing
away times, we need to represent the time at which a state holds, not justa state number. Fortunately, there is a simpler solution. It’s the one weused to eliminate finite behaviors and consider only infinite behaviors. We
observed that we could do that by adding stuttering steps at the end of afinite sequence of states—steps that just repeat the previous state of the
program. Eliminating finite behaviors was not simply a matter of convenience. The real reason to do it was to eliminate one source of craziness.
Since a behavior is not just a behavior of a particular program but a behavior of the entire universe, a finite behavior is one in which everything in theuniverse stops changing. The description of a halting program execution asa finite behavior therefore asserts that the entire universe halts when the
program does. Those infinitely many stuttering steps, in which the valueof no variable of the program changes, allows other programs’ variables tokeep changing.
We can add those stuttering steps because of the observation that theconversion from times to state numbers requires that a program variable
be allowed to change only at time t i for some i . It does not require thatany variable does change at that time. The mistake was writing descriptions
that, until the program halts, requires some variable to change value at eachCHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

73

time t i . Instead, we should have added to the sequence of times t i times atwhich no program variable changes. Adding such a time adds a step in which
other variables describing other programs can change while the program’s
variables remain unchanged. Thus, if the description allows a behavior σ,then it should allow the behavior obtained by inserting stuttering steps ofthe program in σ. This is easy to do. For the description of the hour/minutedisplay, we just change the definition of HM to
HM = Init ∧ 2(Next ∨ ((hr 0 = hr ) ∧ (min 0 = min)))∆We can write this formula more compactly as(3.36) HM = Init ∧ 2(Next ∨ (hhr , min i0 = hhr , min i))∆

because hhr , min i0 equals hhr 0 , min 0 i, and two tuples are equal iff theircorresponding components are equal.
We can similarly fix every other example we’ve seen so far by changing
the next-state action Next in its RTLA description to Next ∨ (v 0 = v ), where
v is the tuple of all variables that appear in the RTLA formula. Since thiswill have to be done all the time, we abbreviate A ∨ (v 0 = v ) as [A]v for any
action A and state expression v .
We can add stuttering steps to a pseudocode description of an algorithm
by adding a separate process that just takes stuttering steps. However,
we won’t bother to do this. We will just consider all pseudocode to allow
stuttering steps.
When HM is defined by (3.36), if HMS is true of a behavior then HM
is also true of the behavior. This remains true when HMS is modified toallow stuttering steps. Thus, HMS implements HM , and |= HMS ⇒ HM istrue. Implementation is implication. How elegant!
There is an apparent problem with formula HM of (3.36). It allows
behaviors in which the program takes a finite number of steps (possibly zero
steps) and then takes nothing but stuttering steps. In other words, it allows
behaviors in which the clock stops. Most computer scientists will say that
we should never allow behaviors in which an abstract program stops when
it is possible for it to continue executing. This is because they are used
to thinking about traditional programs. In many cases, we don’t want torequire a concurrent abstract program to do something just because it can.
Never stopping is a liveness property. Taking only steps satisfying [Next]v
is a safety property. My experience has taught me that we should describe
safety properties separately from liveness properties because we reason about
them differently and we should think about them differently. Formula HM

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

74

describes the safety property that the hour-minute clock should satisfy. We
will see later how we conjoin a liveness property to HM if we want to require
the clock to run forever. It is a feature not a problem that this definition of
HM asserts only what the clock may do and not what it must do.
In general, the safety property of an abstract program is written in theform Init ∧ 2[Next]v , where Init is the initial predicate and [Next]v is thenext-state action. The formula 2[Next]v always allows stuttering steps because [Next]v has the form . . .∨(v 0 = v ) , and v 0 = v allows stuttering steps.
However, v 0 = v allows lots of non-stuttering steps. In particular, it allows
steps in which any variable that does not appear in v can have any values
in the two states of the step. To describe an abstract program, the state expression v in 2[Next]v must ensure that v 0 = v allows only steps that do notchange any of the program’s variables. Therefore, unless stated otherwise,
in a formula of the form 2[Next]v where Next is the next-state action of aprogram, the subscript v is assumed to be the tuple of all program variables.
(However, that subscript need not be called v .)3.5.3

Stuttering Insensitivity

We have seen that the safety property of an abstract program should havethe form Init ∧ 2[Next]v , so it allows stuttering steps. But what can we say
in general about formulas for describing systems or abstract programs?
Stuttering steps are created by adding extra times t i at which we reportthe values of a program’s variables. A stuttering step does not represent the
program doing anything. It’s just a mathematical way to allow the descriptions of the universe with which we describe different abstract programs to
be made consistent with one another. Therefore, any assertion we makeabout a behavior of an abstract program should not depend on whether we
add or remove steps that leave the program’s variables unchanged. Since theassertion depends only on the values a behavior assigns to the program’s variables, this condition is satisfied iff the assertion does not depend on whether
we add or remove steps that leave all variables unchanged. We’ve used theterm stuttering step to mean a step that leaves a program’s variables unchanged. We will now call such a step a stuttering step of the program. We
define a stuttering step to be a step that leaves all variables unchanged.
A sensible predicate F on behaviors should satisfy the condition that thevalue of [[F ]](σ) is not changed by adding stuttering steps to, or removing
them from, a behavior σ. This means that the value of [[F ]](σ) is not changed
even if an infinite number of stuttering steps are added and an infinite
number removed. (However, the behavior must still be infinite, so if σ ends

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

75

in an infinite number of stuttering steps, those steps can’t be removed.) A
predicate on behaviors satisfying this condition for all behaviors σ is called
stuttering insensitive, or SI for short. When describing abstract programsor the properties they satisfy, we should use only SI predicates on behaviors.
To define SI precisely, we first define \(σ) to be the behavior obtained byremoving from the behavior σ all stuttering steps except those belonging toan infinite sequence of stuttering steps at the end. We do this by defining\(σ)(n) to equal σ(f σ (n)) where f σ is defined recursively by f σ (0) = 0 andf σ (n) for n > 0 is the smallest value i greater than f σ (n − 1) such that σ(i )is unequal to σ(f σ (n − 1)), or i equals f σ (n − 1) + 1 if σ stutters foreverafter state number f σ (n − 1).
To write the definition of f σ , we first let Min(S ) be the smallest elementof S for any set S of natural numbers. Such a smallest element exists forany nonempty subset S of N, even if S is infinite. We next let n > be theset {i ∈ N : i > n} of all natural numbers greater than n. The recursive
definition of f σ is then:∆f σ = n ∈ N 7→
if n = 0then 0else if ∀ i ∈ f σ (n −1)> : σ(i ) = σ(f σ (n −1))then f σ (n −1) + 1
else Min( {i ∈ f σ (n −1)> : σ(i ) 6= σ(f σ (n −1))} )A predicate on behaviors is defined to be SI iff, for any behavior σ, thepredicate is true of σ iff it is true of \(σ). SI is a semantic condition—that is,a condition on the meanings of formulas. Since we are conflating formulas
and their meanings, saying that a formula F is SI means that [[F ]] is SI.
We have been using the term property informally to mean some conditionon the behaviors of a system or abstract program. We now define it to meanan SI predicate on behaviors. Behavior predicate still means any predicate
on behaviors, not just SI ones.

3.5.4

The Definition of TLA

We now define TLA to be a language that is a sublanguage of RTLA in which
every formula is a property—that is, an SI formula. Defining a languagemeans giving syntactic rules for a formula to belong to the language.
We begin by defining a state predicate to be a TLA formula. Viewed as atemporal formula, a state predicate is SI because it depends only on the firstCHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

76

state of a behavior, which isn’t changed by adding or removing stuttering
steps.
The operators of propositional logic applied to SI formulas produce
SI formulas. For example, if adding or removing stuttering steps doesn’tchange whether formulas F and G satisfy a behavior, then they don’t change
whether F ∧ G satisfies the behavior. So we let TLA include all formulas
obtained by applying propositional logic operators to TLA formulas. Similarly, we can let TLA include all formulas obtained by applying the ordinary
operators of predicate logic. For example, ∃ x ∈ S : F is a TLA formula if F
is one and S is a constant expression.7
It’s easy to find actions A that, when viewed as a temporal formula,
are not SI. For example, x 0 6= x is not SI because if σ is a behavior thatsatisfies x 0 6= x , then the behavior obtained by adding a stuttering step tothe beginning of σ doesn’t satisfy it. However, the formula 2[A]v is SI for
any action A and state expression v , so we let TLA contain all such formulas.
The formula 2[A]v asserts that an action, namely one of the form [A]v ,is true of all steps of a behavior. For reasoning about liveness, we will needto assert that an action is eventually true in some step of a behavior. The
formula 3A is not SI for an arbitrary action A because if A is true onsome stuttering step, then 3A might be false on a behavior σ and true on
a behavior obtained by adding such a stuttering step to σ. However, if A
does not allow stuttering steps, then 3A is SI. In particular, the formula3(A ∧ (v 0 6= v )) is SI for any state expression v . We define hAiv to equalA ∧ (v 0 6= v ); and we let TLA contain all formulas 3hAiv , for any action A
and state expression v .
You can convince yourself that adding or removing stuttering steps
from a behavior doesn’t change whether it satisfies 3hAiv . However, since¬2[¬A]v is SI, the following theorem shows that 3hAiv is SI:(3.37) |= 3hAiv ≡ ¬2[¬A]v
This equivalence follows from the definition of 3 and the following assertion,
which can be proved by propositional logic from the definitions of [. . .]v andh. . .iv :|= hAiv ≡ ¬[¬A]v
From (3.37) we see that ¬3hAiv is equivalent to 2[¬A]v . This means that
an hAiv step never occurs in a behavior iff every step of the behavior is a7

We could let S be a state expression, but there is no need to.

CHAPTER 3. DESCRIBING ABSTRACT PROGRAMS

77[¬A]v step. This fact is used in proofs by contradiction of formulas of theform 3hAiv .
The only temporal operator we have defined besides 2 and 3 is ;. We
define F ; 3hAiv to be a TLA formula if F is one, A is an action, and v
is a state expression. This formula is SI, since expanding the definition of; in it produces what we have already defined to be a TLA formula.
Combining all this, we see that a TLA formula is one of the following:• A state predicate.
• Obtained by applying propositional logic operators to TLA formulas.
• ∀∃ c : F or ∀∃ c ∈ S : F where ∀∃ is ∀ or ∃ , for a bound constant c,
a TLA formula F , and a constant expression S .
• 2[A]v , 3hAiv , or F ; 3hAiv , for an action A, a state expressionv , and a TLA formula F .
Abstract programs and the properties they satisfy should be TLA formulas. However, we can use RTLA proof rules and even RTLA formulas
when reasoning about TLA formulas. For example, we can prove that Inv
is an invariant of Init ∧ 2[Next]v by substituting [Next]v for Next in the
RTLA proof rule that (3.10) implies (3.13). This yields the following rule:|= (Init ⇒ Inv ) ∧ (Inv ∧ [Next]v ⇒ Inv 0 )implies |= Init ∧ 2[Next]v ⇒ 2Inv
In this rule, the first |= means validity in LA while the second |= means
validity in TLA. A feature of TLA is that as much reasoning as possible isdone in LA, which becomes ordinary mathematical reasoning when the necessary definitions are expanded and primes are distributed across operators
so only variables are primed.

Chapter 4

Safety, Liveness, and Fairness
4.1

Safety and LivenessMath V
Assume/Prove Proof Steps We usually prove a formula of the formF ⇒ G by assuming F is true and proving G is true. In our structured
proof style, we write such a proof with the following proof step:
Assume: F
Prove: G
Proof: . . .
This step asserts the truth of F ⇒ G. However, the proof of a step that
asserts the formula F ⇒ G has as its goal to prove F ⇒ G. (It might
do that by proving F ⇒ H and H ⇒ G for some H .) The proof of thisAssume/Prove step has as its goal to prove G, using the assumption that
F is true. The statement of a theorem is sometimes written as such an
Assume/Prove. It has the same meaning as for a proof step, assertingF ⇒ G and that the proof assumes F and proves G.
Instead of being a single formula, the Assume clause can be a list ofassertions—sometimes a numbered list. That’s equivalent to assuming the
conjunction of those assertions. A paragraph proof should state what previous steps and assumptions it uses, identifying them by step and assumption
numbers.
Countable Sets A countable set is one whose elements can be counted.
That is, a set S is countable iff we can assign a different natural number toeach of its elements. More precisely, a set S is countable iff there exists a
78

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

79

function f ∈ N → S such that ∀ s ∈ S : ∃ n ∈ N : f (n) = s . All finite setsare countable. Here is a function f that shows that the set I of all integers
is countable.
n: 0↓
f (n) : 0

1 2 3 4 5 6 7 8 ...
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓1 −1 2 −2 3 −3 4 −4 . . .

We will need this theorem:
Theorem 4.1 If S is a countable set, then there is a function f in N → S
such that for every s ∈ S , there are infinitely many n ∈ N with f (n) = s.
Proof: Since S is countable, we can number its elements s 0 , s 1 , s 2 , . . . . If
S is finite, we can let f equal n ∈ N 7→ s n % #(S ) . Therefore, we can assume
S is infinite. Here is a picture that shows how such a function f can be
defined:n:0lf (n) : s0

1 2
l l
s0 s1

3 4 5
l l l
s0 s1 s2

6 7 8 9l l l ls0 s1 s2 s3

...
...

However, I don’t see an easy way to define that function mathematically.
Here’s an easy way to define a function f that works. Let g be the function
in N → N such that g(n) is the largest integer satisfying g(n)2 ≤ n, so∆g(n 2 ) = n and g(n)2 ≤ n < (g(n) + 1)2 for all n ∈ N. Define f (n) =s n−g(n)2 for all n ∈ N. This function has the desired property because forany n ∈ N, for any m ≥ n there exists i ∈ m 2 . . ((m + 1)2 − 1) such thatf (i ) = s n . End Proof

4.1.1

Definitions

Safety and liveness properties have been described intuitively as specifying
what the program is allowed to do and what it must do. To define themprecisely, we begin by observing that they have these characteristics:
Safety If a behavior doesn’t satisfy a safety property, then we can point to
the place in the behavior where it violates the property. For example,
if a behavior doesn’t satisfy an invariance property, it violates theproperty in the first state in which the invariant is false.
Liveness We have to look at an entire infinite behavior to see that it doesn’tsatisfy a liveness property. For example, we can’t see that the property

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

80

x eventually equals 42 is violated by looking at a finite part of the
behavior.1
This characterization was turned into precise definitions of safety and liveness for arbitrary behavior predicates by Alpern and Schneider [3]. Since
we’re interested only in properties (which are SI), we will use a somewhat
simpler definition of safety. But first, we need a few preliminary definitions.
We call a finite, nonempty cardinal sequence of states a finite behavior.
(A behavior, without the adjective finite, still means an infinite cardinalsequence of states.) We’ll write a finite behavior ρ as ρ(0) → · · · → ρ(n).
A nonempty finite prefix of a behavior is a finite behavior. We define thecompletion ρ↑ of a finite behavior to be the behavior obtained by repeating
the last state of ρ infinitely many times—that is, adding infinitely many
stuttering steps. A finite behavior ρ is defined to satisfy a behavior predicate
iff its completion ρ↑ satisfies it. We can now precisely define safety andliveness.
Safety A property F is a safety property iff it satisfies the following condition: A behavior satisfies F iff every nonempty finite prefix of the
behavior satisfies F .
Liveness A property F is a liveness property iff every finite behavior is theprefix of a behavior that satisfies F .
A state predicate is a safety property because it is satisfied by a behavior
iff the state predicate is true on the initial state, and a behavior and all its
nonempty prefixes have the same initial state. The formula 2[A]v is a safety
property for any action A and state expression v ; here is the proof that every
nonempty finite prefix of a behavior σ satisfies 2[A]v iff σ satisfies 2[A]v .
1. Assume: Every nonempty finite prefix of σ satisfies 2[A]v .
Prove: σ satisfies 2[A]v
Proof: σ satisfies 2[A]v iff every step of σ satisfies [A]v , and every step of
σ is a step of some finite prefix of σ, so it satisfies 2[A]v by the assumption.
2. Assume: σ satisfies 2[A]v
Prove: Every nonempty finite prefix of σ satisfies 2[A]v .
1
Remember that a behavior means any infinite sequence of states, not just one thatsatisfies some program. If we know that a behavior satisfies the program, we can often tellthat 3(x = 42) is false by looking at the behavior predicate that describes the program,without looking at the behavior at all.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

81

Proof: Every step of a nonempty finite prefix of σ is either a step ofσ, so it satisfies [A]v by the assumption, or it is a stuttering step, which
satisfies [A]v by definition of [. . .]v .
3. Q.E.D.
Proof: Obvious, by steps 1 and 2.
It also follows easily from the definition of safety that the conjunction ofsafety properties is a safety property. Therefore, as expected, the formula
Init ∧ 2[Next]v that we have been calling the safety property of a programis indeed a safety property.
The property that asserts that a program halts is a liveness property.
That property is true of a behavior σ iff σ ends with infinitely many steps
that leave the program’s variables unchanged. It’s a liveness property because every finite behavior ρ is a prefix of its completion ρ↑ , which satisfies
the property.
Safety and liveness are conditions on properties, which are SI behavior
predicates. When we say that a TLA formula 2[A]v is a safety property, weare conflating the formula with its meaning. We should remember that it’s
actually [[2[A]v ]] that is the safety property.

4.1.2

A Completeness Theorem

TLA is quite simple, adding only the two operators 0 (prime) and 2 toordinary math. In theory, this simplicity makes it quite inexpressive. For
example, here is a property F12 that neither TLA nor RTLA can express:
the value of x must equal 1 before it can equal 2. It’s expressed in terms of
explicit states as:∆(4.1) F12 = ∀ j ∈ N : (x (j ) = 2) ⇒ ∃ k ∈ N : (k < j ) ∧ (x (k ) = 1)
This behavior predicate is a property because it’s SI; adding or removing
stuttering steps doesn’t affect whether a behavior satisfies it. Property F12
is a safety property because it’s not satisfied by a behavior σ iff there’s apoint in σ at which it’s violated—namely, a state σ(j ) in which x = 2 andx 6= 1 in all the states σ(0), . . . , σ(j − 1).
If TLA is inexpressive, how can we describe programs with it? The
answer is, by using variables. We can express F12 as an abstract program
described by a TLA formula S 12 if we add a Boolean-valued variable, let’scall it y, whose value is true iff x equals 1 or has previously equaled 1. We
let the initial predicate Init of S 12 assert that x 6= 2 and that y = true iff

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

82

x = 1. The next-state relation Next allows x 0 to equal 2 only if y = true,and it sets y to true if x = 1. Here are the definitions:(4.2)

S 12 = Init ∧ 2[Next]hx ,y i∆∆

Init = (x 6= 2) ∧ (y = (x = 1))∆

Next = ∧ (x 0 = 2) ⇒ y∧ y 0 = (y ∨ (x = 1))
It’s not obvious in what sense formula S 12 expresses property F12 , since
S 12 contains the variables x and y while F12 describes only the values of x .
Intuitively, S 12 makes the same assertion as F12 if we ignore the value of y.
Section 6.1 describes a TLA operator ∃ such that ∃ y : S 12 means S12 if we
ignore the value of y. We’ll then see that [[∃ y : S 12 ]] equals F12 . However,there’s no need to introduce ∃ here. The relevant condition that S 12 satisfies
is that if G is any TLA formula that does not contain the variable y, then|= F12 ⇒ [[G]] iff |= S 12 ⇒ G
The idea of adding a variable to express a property works in general.
We state it now only for safety properties. We can’t express every safety
property as a TLA formula. A formula is a finite string of finitely many
symbols, and there are only a countable number of such strings; but there areuncountably many safety properties. (For example, there are uncountably
many real numbers, so there are uncountably many properties asserting thatthe initial value of x is a particular real number.) What we can show is thatany safety property (which is a predicate on behaviors) that can be describedby a mathematical formula—that is, by a formula of ZF—can be expressed
as a TLA formula. We do that by showing that if the mapping F frombehaviors to Boolean values is a safety property, then we can use F to write
a TLA formula that describes it the way S 12 describes F12 in our example.
One condition satisfied by a mathematical formula is that it contains only
a finite number of variables, and its value depends only on the values of
those variables. Remember that we are assuming that the language LA for
writing actions contains all the operators of ZF.
The theorem is expressed with the convention of letting a boldface identifier like x be the list x 1 , . . . , x n of subscripted non-bold versions of theidentifier, for some n. Thus, hxi is the tuple of those identifiers. The theorem is a special case of Theorem 4.9 in Section 4.2.7 below, so the proof isomitted.
Theorem 4.2 Let x be the list x 1 , . . . , x n of variables and let F be a safety
property such that F (σ) depends only on the values of the variables x in a

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

83

behavior σ. There exists a formula S equal to Init ∧ 2[Next]hx,y i , where Init
and Next are defined in terms of F , y is a variable not among the variables
x, and the variables of S are x and y, such that |= F ⇒ [[G]] iff |= S ⇒ G,
for any property G.
This theorem is a completeness result, showing that TLA can express as an
abstract program any safety property that can be expressed semantically.
While this shows that there is no fundamental lack of expressiveness in
TLA, it is of little practical significance. The proof assumes a descriptionof the property F and uses it to write F as an abstract program. If there
were a better way to describe properties mathematically than with abstract
programs, we should use it. There are other temporal logics that can express
the simple property F12 with a formula that’s easier to understand than S 12 .
However, S 12 is not hard to understand, and abstract programs are the only
practical way I know to express all the properties of concrete concurrent
programs that we need to describe.2

4.1.3

The Operator C

We now define the operator C so that C(F ) is the strongest safety property
implied by F , for any property F . Remember that property G stronger
than property H means every behavior satisfying G satisfies H —that is,|= G ⇒ H . The operator C is not part of the TLA language; we do notuse it to write abstract programs. What we do is show that under certain
conditions some G equals C(F ) for some other program F . It would bebetter to write that [[G]] equals C([[F ]]), but we won’t bother because weregularly conflate a formula and its meaning.
If we want C(F ) to be the strongest safety property implied by F , itshould be satisfied by the behaviors satisfying F plus the fewest additional
behaviors needed to make it a safety property. The appropriate definition
is: A behavior σ satisfies C(F ) iff every finite prefix of σ is a prefix of abehavior that satisfies F . For example, suppose F is the property satisfied
only by behaviors in which x initially equals 0, x keeps being incremented
by 1, and eventually the behavior halts. For this property F , the property
C(F ) is satisfied by a behavior that either satisfies F or in which x initiallyequals 0 and keeps being incremented by 1 forever. The following theorem
shows that this is the correct definition of C. Its proof is in the Appendix.
2
Remember that property means predicate on behaviors. There are many conditions
we want programs to satisfy besides properties.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

84

Theorem 4.3 If F is a property, then C(F ) is a safety property such that|= F ⇒ C(F ) and, for any safety property G, if |= F ⇒ G then |= C(F ) ⇒ G.
Alpern and Schneider proved that every property is the conjunction of asafety property and a liveness property.3 They actually proved this stronger
result, whose proof is in the Appendix:
Theorem 4.4 Every property F is equivalent to C(F ) ∧ L for a livenessproperty L.
We have been describing abstract programs by formulas of the form
Init ∧ 2[Next]v , which are safety properties. As we’ve observed, like any
safety property, this formula allows behaviors that halt at any point in the
behavior. We usually don’t want to allow such behaviors, so we must conjoin
a liveness property to this formula to describe most abstract programs. For
example, we can rule out behaviors of program Increment that don’t haltprematurely with the liveness property∀ p ∈ Procs : 3(pc[p] = done)
However, we’ll see later why that’s not a good liveness property to use.
There’s another method of describing safety and liveness that helps me
understand them intuitively. It’s based on topology. The method and thenecessary topology are explained in Appendix Section A.6.

4.1.4

What Good is Liveness?

Safety predicates constrain the finite behavior of a system. They describe
what must be true of finite prefixes of a behavior. Liveness properties say
nothing about finite prefixes; they describe what must be true if the systemruns forever. Since we don’t live forever, why should we care about livenessproperties?
In theory, liveness is useless; but in practice it’s useful. Consider the
liveness property required of a traditional program: it eventually terminates.
In theory, that’s useless because it might not terminate in a billion years.
In practice, proving that a program will terminate within a given amountof time isn’t easy. Proving that it eventually terminates is easier, and it isuseful because the program is certainly not going to terminate soon enough if
it never does. But proving liveness provides more than that. Understanding
why a program eventually terminates requires understanding what it must
3

Their result was stated for arbitrary behavior predicates, not properties.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

85

do in order to finish. That understanding helps you decide if it will terminate
soon enough. This applies to other liveness properties as well.
Using a model checker doesn’t give you the understanding that you getfrom writing a proof. However, using a model checker to check liveness properties is a good way to detect errors—both in the program you intended towrite and in what you actually wrote. A program that does nothing satisfies most safety properties, and an error in translating your intention into
mathematics might disallow behaviors in which the program fails to satisfy
a safety property. Checking that the program satisfies liveness properties
that it should can catch such errors, as well as errors in the program you
wanted to write.

4.2

Fairness

Expressing mathematically the way computer scientists and engineers described their algorithms and programs led us to describe the safety property
satisfied by an abstract program with the formula Init ∧ 2[Next]v , where v
is the tuple of all the program’s variables. We must conjoin to that formulaanother formula to describe the program’s liveness property. To see how
this should be done, we first examine how scientists and engineers expressed
liveness.

4.2.1

Traditional Programs and the Enabled Operator E

We start with traditional programs. It was assumed, usually without needing to be stated explicitly, that a program kept executing statements until it
terminated. If termination is expressed by pc = done, then this assumption
can be stated as the requirement that when pc 6= done, a Next step must
eventually occur. This is expressed by the TLA formula(4.3) (pc 6= done) ; hNext iv
The h. . .iv is a bit of a nuisance, but it’s required by TLA to prevent a
liveness property from being satisfied by a stuttering step, which would makeno sense. Usually, the next-state action Next does not permit stuttering
steps, so (4.3) is equivalent to the RTLA formula (pc 6= done) ; Next .
Formula (4.3) assumes a particular way of expressing termination. In
general, termination of a traditional program means it’s no longer possible
for the program to take steps. We should replace (4.3) by E ; hNext iv ,where E is a state predicate that is true in a state iff it’s possible to take aCHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

86

hNext iv step in that state. We write that state predicate E as EhNext iv ,where E is read enabled.
In general, for any action A, we define E(A) to be the state predicatethat is true in a state s iff there exists a state t such that s → t is an A
step. In other words, E is an LA operator, where for any action A the statepredicate E(A) is defined by:∆[[ E(A)]](s) = ∃ t : [[A]](s → t)
In the common case when A has the form hB iv , we omit the parentheses
and write simply EhB iv . The liveness property assumed of a traditional
program whose safety property is described by the formula Init ∧ 2[Next]v
is EhNext iv ; hNext iv .

4.2.2

Concurrent Programs

In traditional programs, when the program hasn’t terminated there is justone program statement that can be executed. In multiprocess programs,
it is usually possible for there to be multiple statements that can be executed, each in a different process. Moreover, a process can stop not justbecause it has terminated, but because it is waiting for another process to
do something. The liveness property EhNext iv ; hNext iv ensures that the
program keeps executing statements as long as some process hasn’t halted.
It is satisfied if one process keeps executing statements. It allows other processes to halt, even if they could keep executing statements. Those otherprocesses are said to be starved.
It was generally accepted that processes should be treated “fairly”. Multiprocess programs were usually executed on computers having fewer processors than there were processes—for many years, usually just a single processor. It was sometimes proposed that fairness should guarantee the stronger
condition that each process gets a fair share of processor time. However,it came to be generally accepted that fairness should not specify how long(in terms of program steps) a process that can execute a statement might
wait before executing it. Therefore, fairness came to mean simply that noprocess should be starved.
In a program with a set Procs of processes, the next-state action isdefined by∆

Next = ∃ p ∈ Procs : PNext(p)where PNext(p) is the next-state action of process p. The obvious generalization of the liveness requirement for a traditional program suggests that

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

87

fairness for all the processes in a multiprocess program should mean:(4.4) ∀ p ∈ Procs : EhPNext(p)iv ; hPNext(p)iv
However, this is not the way fairness should be expressed, and it is not anappropriate liveness property for multiprocess programs. To see why, we
consider mutual exclusion algorithms.
4.2.2.1

Mutual Exclusion

The concept of fairness in a concurrent program appeared implicitly in Edsger Dijkstra’s seminal 1965 paper that launched the study of concurrent
algorithms [9]. That paper defined mutual exclusion and presented the firstalgorithm that implemented it.
In mutual exclusion, we assume a set of processes that each alternately
executes two sections of code called the noncritical and critical sections. A
mutual exclusion algorithm must ensure that no two processes can be executing their critical sections at the same time. For example, the processes may
occasionally print output on the same printer, and two processes printing
at the same time would produce an unreadable mixture of the two outputs.
To prevent that, the processes execute a mutual exclusion algorithm, and aprocess prints only when in its critical section.
The outline of a mutual exclusion algorithm is shown in Figure 4.1,
where Procs is the set of processes. We don’t care what the processes doin their noncritical and critical sections, so we represent them by atomic
skip statements labeled ncs and cs that do nothing when executed except
change the value of pc. The nontrivial part of the algorithm consists of thetwo sections of code, the waiting and exiting sections, that begin with thelabels wait and exit. Each of those sections can contain multiple labeledstatements, using variables declared in the two variables statements.
The safety property that a mutual exclusion algorithm must satisfy isthat no two processes are executing their critical sections at the same time—
meaning that pc(p) and pc(q) cannot both equal cs for two different processes p and q. This is an invariance property. A cute way of expressing it
compactly is:(4.5) 2 ( ∀ p, q ∈ Procs : (p 6= q) ⇒ ({pc(p), pc(q)} =6 {cs}) )We will not yet state a precise liveness condition a mutual exclusion algorithm should satisfy. All we need to know for now is that if some processes
enter the waiting section, they can’t all wait forever without entering thecritical section.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

88

variables . . . ;global variables
process p ∈ Procs
variables pc = ncs, . . . ;process-local variables
while true doncs: skip ;noncritical section
wait: ..
waiting section.
cs: skip ;exit: ..
.
end while
end process

critical section
exiting section

Figure 4.1: The outline of a mutual exclusion algorithm.
Most people viewing the outline in Figure 4.1 will think this is an unrealistic description of a mutual exclusion algorithm because, by describing
the execution of the critical section with a single skip step, we are assumingthat the entire critical section is executed as a single step. Of course, we
realize that this isn’t the case. It no more says that the critical section is
executed as a single step than our description of an hour-minute clock saysthat nothing else happens between the step that changes the clock’s display
to 7:29 and the step that changes it to 7:30. Just as 59 changes to a seconds
display can occur between those two steps, process p can print the entire
Bhagavad Gita while pc(p) equals cs. A mutual exclusion algorithm simply
describes all that printing as stuttering steps of the algorithm.
Figure 4.2 describes a program named UM , which is an abbreviation of
Unacceptable Mutual exclusion algorithm. Technically, it’s a mutual exclusion algorithm because it satisfies property (4.5) with Procs equal to theset {0, 1} of processes. But for reasons that will be discussed later, it isn’t
considered to be an acceptable algorithm.
This pseudocode program is the first one we’ve seen with an await statement. For a state predicate P , the statement await P can be executed only
when control is at the statement and P equals true. We could write thestatement a : await P as:
a: if ¬P then goto a end if
Executing this statement in a state with P equal to true just moves control
to the next statement. Executing it in a state with P equal to false does
not change the value of any program variable, so it’s a stuttering step of theCHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

89

variables x = (p ∈ {0, 1} 7→ false) ;process p ∈ {0, 1}
variables pc = ncs ;while true doncs: skip ;wait: x [p] : = true ;w 2: await ¬ x [1 − p] ;cs: skip ;exit: x [p] : = false
end while
end process
Figure 4.2: The unacceptable mutual exclusion algorithm UM.
program. Since a stuttering step is always allowed, executing the statement
await P when P equals false is the same as not executing it. So, while we
can think of the statement await P continually evaluating the expression
P and moving to the next statement iff it finds P equal to true, mathematically that’s equivalent to describing it as an action A such that E(A)equals (pc = a) ∧ P .
This is also the first pseudocode we’ve seen with explicit array variables.
An array variable x is an array-valued variable, where an array is a function
and x [p] just means x (p). We’ve already seen implicit array variables—
namely, the local variables t and pc of program Increment are represented
by function-valued variables in Figure 3.5. I have decided to write x [p] instead of x (p) in pseudocode to make the pseudocode look more like real code.
However, the value of an array variable can be any function, not just a finite
ordinal sequence; and we write x (p) instead of x [p] when discussing the program mathematically. As we’ve seen in Figure 3.5, an assignment statementx [p] := . . . is described mathematically as x 0 = (x except p 7→ . . .).
Algorithm UM is quite simple. The processes communicate through thevariable x , with process p writing to x (p). The initial value of x (p) for eachprocess p is false. To enter the critical section, process p sets x (p) to true
and then enters its critical section when x (1 − p) (the array element writtenby the other process) equals false.
It’s easy to see that the two processes cannot be in their critical sections
at the same time. If they were, the last process p to enter its critical section
would have read x (1 − p) equal to true when executing statement w 2,
so it couldn’t have entered its critical section. Since mutual exclusion is an

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

90

invariance property, it can be proved mathematically by finding an inductive
invariant that implies mutual exclusion. You can check that the following
formula is such an inductive invariant of UM :(4.6) ∧ TypeOK∧ ∀ p ∈ {0, 1} : ∧ (pc(p) ∈ {w 2, cs}) ⇒ x (p)∧ (pc(p) = cs) ⇒ (pc(1 − p) 6= cs)
where TypeOK is the type-correctness invariant:∆

TypeOK = ∧ x ∈ ({0, 1} → {true, false})∧ pc ∈ ({0, 1} → {ncs, wait, w 2, cs, exit})
Let UMSafe be the safety property described by the pseudocode. We
want to conjoin a property UMLive to UMSafe to state a fairness requirement of the program’s behaviors. Let’s make the obvious choice of defining
UMLive to be formula (4.4) with Procs equal to {0, 1} and v equal to hx , pc i.
This implies that both processes keep taking steps forever, executing theircritical sections infinitely often, which makes it seem like a good choice.
Actually, that makes it a bad choice.
Algorithm UM is unacceptable because formula UMSafe, which describes the pseudocode, permits deadlock. If both processes execute statement wait before either executes w 2, the algorithm reaches the deadlocked
state in which neither await statement is enabled. Conjoining UMLive to
UMSafe produces a formula asserting that such a deadlocked state cannot
occur. It ensures the liveness property we want, that processes keep executing their critical sections. However, it does this not by requiring only thatprocesses keep taking steps, but also by preventing them from taking somesteps—namely, ones that produce a deadlocked state. A fairness property
shouldn’t do that.
Before going further, let’s see why UMSafe ∧ UMLive doesn’t allow sucha deadlocked state to be reached. The reason is that the formula satisfies
this invariant:(4.7) ¬(pc(0) = pc(1) = w 2)
This is an invariant of UMSafe ∧ UMLive because it is true initially andit can be made false only by a step in which a process p executes its waitstatement in a state s with pc(1 − p) = w 2; and we now show that such a
step cannot occur.
It’s an invariant of UMSafe, and hence of UMSafe ∧ UMLive, thatpc(p) = wait implies x (p) = false. Hence, pc(1−p) = w 2 and x (p) = false

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

91

in state s, which implies EhPNext(1 − p)iv is true. Therefore, UMLive implies that 3hPNext(1 − p)iv must be true at state s of the behavior. Thisimplies that the process p step can’t occur, because it would lead to deadlock which would make such a hPNext(1 − p)iv step impossible. Therefore,
no step of the program can make (4.7) false. Since it is true in an initialstate, (4.7) is an invariant of UMSafe ∧ UMLive.
Thus, UMLive should not be the fairness property for algorithm UM ,because it disallows a program step allowed by UMSafe. Before determining
what the fairness property should be, let’s characterize exactly what’s wrong
with property UMLive.
4.2.2.2

Machine Closure

The general principle illustrated by program UM is that fairness for a program should require only that something eventually happens, so it should
rule out only infinite behaviors in which that thing never happens. It should
not rule out finite behaviors.
A liveness property by itself does not rule out any finite behaviors. A
liveness property L by definition allows any finite behavior to be completed
to a behavior that satisfies L. Property UMLive is a liveness property, so thefinite behavior in which the program reaches a deadlocked state can be completed to a behavior satisfying UMLive. For example, we can concatenate
to that finite behavior a complete behavior satisfying UMSafe ∧ UMLive.
(There are many behaviors of UMSafe that don’t deadlock.) Since that concatenation contains infinitely many steps of each process, it satisfies UMLive.
However, it doesn’t satisfy UMSafe because the step between the last stateof the deadlocked finite behavior (which is a deadlocked state) and the firststate of a complete behavior does not satisfy the program’s next-state action.
It is impossible to complete that deadlocked behavior to a behavior satisfying both UMLive and UMSafe because the next-state action of UMSafe
does not allow any non-stuttering step from a deadlocked state.
For a liveness property L to be a fairness property for UMSafe, it should
not just require that any finite behavior can be completed to a behavior
satisfying L; it should require that any finite behavior that satisfies UMSafe
can be completed to a behavior that satisfies UMSafe ∧ L.
In general, a pair hS , Li, where S is a safety property and L a livenessproperty, is defined to be machine closed iff every finite behavior satisfying
S can be completed to a behavior satisfying S ∧L. We require that a fairness
property for a program having the safety property S be a liveness property
L such that hS , Li is machine closed. The following theorem, proved in theCHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

92

Appendix, provides a nice mathematical characterization of machine closure.
Theorem 4.5 If S is a safety property and L a liveness property, thenhS , Li is machine closed iff |= C(S ∧ L) ≡ S .

4.2.3

Weak Fairness

Let’s now see how to describe fairness with a machine-closed liveness property. Using the requirement(4.8) EhPNext(p)iv ; hPNext(p)iv
worked fine for program Increment. It failed for program UM . The reason it
worked for program Increment is that when PNext(p) is enabled, it remains
enabled until a PNext(p) step occurs. In program UM , process p can reacha state in which pc(p) equals w 2 and PNext(p) is enabled, but process 1 − p
can then take a step that disables action PNext(p).
To obtain a machine-closed condition, we have to weaken (4.8) so it rules
out fewer behaviors. The obvious way to do that is by requiring a PNext(p)step to occur not if PNext(p) just becomes enabled, but only if it remains
enabled until a PNext(p) step occurs. Let F U G be the temporal formulaasserting that F is true until G is true. (We’ll discuss later exactly what U
means.) As our choice of fairness property, we will replace property (4.8)by:(4.9) ( EhPNext(p)iv U hPNext(p)iv ) ; hPNext(p)iv
However, rather surprisingly, (4.9) is equivalent to:(4.10) 2 EhPNext(p)iv ; hPNext(p)iv
To prove this, we first have to examine the definition of U. When we saythat E is true until P is true, we usually mean that P is eventually trueand E is true until P becomes true. But if E U P implies that 3P is true,
then (4.9) would be trivially true and thus useless, since it would assert thathPNext(p)iv conjoined with some other condition leads to hPNext(p)iv . So
we have to interpret E U P to mean that either P is eventually true and E
is true until it is, or P is not eventually true and E is true forever. Thus,
whatever the precise meaning of U is, we have:(4.11) |= (E U P ) ≡ (3P ∧ E U P ) ∨ (¬3P ∧ 2E )The equivalence of (4.9) and (4.10) follows from this RTLA theorem, which
is proved in the Appendix.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

93Theorem 4.6 (4.11) implies |= ((E U P ) ; P ) ≡ (2E ; P ) for any
formulas E and P .
A liveness property commonly assumed of multiprocess algorithms, called
weak fairness, is that (4.10) is true for every process p. We generalize thisconcept to define weak fairness of an arbitrary action A to be the formula
WFv (A) defined by:(4.12) WFv (A) = 2 EhAiv ; hAiv∆

Another form of fairness called strong fairness that is sometimes assumed
is discussed later. We will see how weak and strong fairness are used towrite machine-closed descriptions of abstract programs. A special caseof the general result is that if S is the formula Init ∧ 2[Next]v and Next
equals ∃ p ∈ Procs : PNext(p), then hS , ∀ p ∈ Procs : WFv (PNext(p)i is machine closed. But before we get to all that, let’s examine weak fairness.
The first thing we observe is that for a multiprocess program describedwith pseudocode, weak fairness of a process’s next-state action is equivalent to the conjunction of weak fairness of all the actions described by theprocess’s statements. That is, if PNext(p) equals ∃ i ∈ I : Ai (p) for a set
I , action Ai (p) describes the statement with label i , and v is the tuple ofprogram variables, then:(4.13) |= WFv (PNext(p)) ≡ ∀ i ∈ I : WFv (Ai (p))
This is because hPNext(p)iv is enabled iff hApc(p) (p)iv is enabled, in whichcase pc(p) can be changed only by an hApc(p) (p)iv step. Thus, in any stateof a behavior with pc(p) = i , the formula EhPNext(p)iv ⇒ 3hPNext(p)iv
is equivalent to EhAi (p)iv ⇒ 3hAi (p)iv . A rigorous justification of (4.13)
is that it is a special case of Theorem 4.8 in Section 4.2.7 below.
The following tautology is useful for deducing properties from weak fairness assumptions:(4.14) |= WFv (A) ≡ (32 EhAiv ⇒ 23hAiv )It makes weak fairness look stronger than the definition because 23hAiv
is a stronger property than 3hAiv . Here’s an informal proof of (4.14).
The definition of WFv (A) implies the right-hand side of the equivalence because 32 EhAiv implies that eventually hAiv is always enabled, whereupon
WFv (A) keeps forever implying that an hAiv step occurs, so there must be
infinitely many hAiv steps, making 23hAiv true. The opposite implication is true because 2 EhAiv implies 32 EhAiv , so the right-hand side ofCHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

94

the equivalence implies that 23hAiv is true and hence 3hAiv is true. A
rigorous proof of (4.14) is by the following RTLA4 reasoning, substituting
EhAiv for F and hAiv for G:
2F ; G ≡ 2(2F ⇒ 3G)≡ 2(¬2F ∨ 3G)≡ 2(3¬F ∨ 3G)≡ 23(¬F ∨ G)
≡ 23¬F ∨ 23G≡ ¬23¬F ⇒ 23G≡ 32F ⇒ 23G

by definition of ;by propositional logicby ¬2F = 3¬F (3.25)
by (3.23)
by (3.27)
by propositional logic¬23¬F ≡ 3¬3¬F ≡ 32¬¬F by (3.25)

The following tautology is useful for proving a weak-fairness formula, because it has an additional hypothesis in the implication:(4.15) |= WFv (A) ≡ (2 EhAiv ∧ 2[¬A]v ; hAiv )It is proved by expanding the definition of ; and applying the propositional logic tautology |= (F ⇒ G) ≡ (F ∧ ¬G ⇒ G) and the TLA tautology |= ¬3hAiv ≡ 2[¬A]v . Using (4.15) to prove WFv (A) is essentially aproof by contradiction.
Proving these kinds of temporal logic tautologies is a good exercise.
However, there are temporal logic theorem provers that can do it for you.

4.2.4

Temporal Logic Reasoning

Thus far, the only properties we’ve verified that programs satisfy have been
invariance properties. Proving invariance requires no temporal logic reasoning. To prove |= Init ∧ 2[Next]v ⇒ 2Inv we prove the LA formulas|= Init ⇒ Inv and |= Inv ∧ [Next]v ⇒ Inv 0 and then apply a single temporal
logic proof rule.
Nontrivial temporal logic reasoning is required for proving that programs
satisfy liveness properties. We often prove liveness properties of the form
P ; Q. This property asserts that something is true at all “times” in a
behavior—namely, whenever P is true, Q is eventually true. The description
Init ∧ 2[Next]v of a program cannot be used directly to prove P ; Q
because it asserts only that something is true initially. For that reason, thefirst thing we do when proving P ; Q is to prove that some formula Inv isan invariant of the program, so the program implies 2Inv ∧ 2[Next]v . We
then use 2Inv ∧ 2[Next]v to prove P ; Q.
4

With these definitions of F and G, the formula 23(¬F ∨ G) is not a TLA formula.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

95

A formula F that asserts something is true at all times is called a 2
formula. The formula 2Inv ∧ 2[Next]v is a 2 formula because it’s equivalent to the RTLA formula 2(Inv ∧ [Next]v ). Because of the tautology|= 22F ≡ 2F , we can define F to be a 2 formula iff it’s equivalent to
2F . By (3.17), the conjunction of 2 formulas is a 2 formula. In general,(3.18) implies ∀ i ∈ S : F i is a 2 formula if each F i is a 2 formula.
In a proof, we almost always want every temporal logic formula asserted
by a statement to be a 2 formula. A theorem with statement F asserts|= F . The proof rule (3.16) tells us that |= F implies |= 2F . This meansthat whenever we prove F , we have proved 2F . However, that does notmean that when we have proved a step in a proof that asserts F , we have
proved 2F . When we prove a step
4.2.7. G ; H
we have not proved |= G ; H . We have proved |= Asp ⇒ (G ; H ), whereAsp is the conjunction of all the assumptions in effect at statement 4.2.7. By
the proof rule (3.21), |= Asp ⇒ (G ; H ) implies |= 2Asp ⇒ 2(G ; H ).
If Asp is a 2 formula, so it’s equivalent to 2Asp, then proving 4.2.7 proves|= Asp ⇒ 2(G ; H ). Therefore proving 4.2.7 is equivalent to proving
4.2.7. 2(G ; H )if Asp is a 2 formula. Since the conjunction of 2 formulas is a 2 formula,Asp is a 2 formula if all the assumptions in effect at statement 4.2.7 are 2
formulas.
We assure that every statement that asserts a temporal formula F asserts
2F by making every temporal formula in an assume clause be a 2 formula.
Any temporal formula F asserted by a statement can then be considered toassert 2F . The following are 2 formulas for all temporal formulas F andG, state expressions v , and actions A: 23F (obviously), 32F by (3.29),
F ; G by definition of ;, and WFv (A) by the definition (4.12) of WF.

4.2.5

Reasoning With Weak Fairness

We now see how to show that an abstract program with weak fairness conditions satisfies a liveness property. We will do this with a modificationof algorithm UM called the One-Bit algorithm that is an acceptable mutual exclusion algorithm. But first, we examine what liveness condition thealgorithm should satisfy.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS
4.2.5.1

96

Liveness for Mutual Exclusion

The liveness condition Dijkstra required of the mutual exclusion algorithm
outlined in Figure 4.1 was that if some process is at statement wait, theneventually some process enters its critical section—expressed by:(4.16) (∃ p ∈ Procs : pc(p) = wait) ; (∃ p ∈ Procs : pc(p) = cs)
This condition is usually called deadlock freedom. That’s a misuse of theterm, because deadlock freedom is actually the safety property asserting thatthe program never reaches a deadlocked state—one in which no process
can take a step. Property (4.16) also rules out what is called livelock, inwhich no process enters its critical section although some processes keep
executing statements in their waiting sections. However, when discussing
mutual exclusion, we will use deadlock freedom to mean property (4.16).
This condition allows one or more processes to be starved—that is, to remain
forever in their waiting section—while other processes enter and leave thecritical section.
Dijkstra also required that processes be allowed to remain forever intheir noncritical sections. Just because a process might send output to theprinter, we don’t want to insist that it does. This requirement rules out
simple algorithms in which processes take turns entering the critical section.
A process that does not want to enter its critical section cannot be required
to do anything to allow other processes to enter their critical sections.
4.2.5.2

The One-Bit Algorithm

The basic idea of the One-Bit algorithm is to modify algorithm UM to prevent deadlock by having process 1 wait when both processes are concurrently
trying to enter the critical section. This is done by modifying process 1 sothat if it sees that x [0] equals true in statement w 2, then it sets x [1] tofalse and waits until x [0] equals false (so process 0 has exited its critical section) before going back to statement wait and trying again. The
pseudocode for the algorithm, which we call OB is in Figure 4.3.5
Algorithm OB satisfies mutual exclusion because processes use the same
protocol to enter the critical section as algorithm UM : Each process p setsx [p] to true and can then enter the critical section only if x [1 − p] equals
false. In fact, that OB satisfies mutual exclusion can be proved with thesame inductive invariant (4.6) as UM except that the type invariant TypeOK
5

Algorithm OB is the two-process case of an N -process algorithm that was discovered
independently by James E. Burns and me in the 1970s, but not published until later [7, 29].

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

97

variables x = (p ∈ {0, 1} 7→ false) ;process p ∈ {0, 1}
variables pc = ncs ;while true doncs: skip ;wait: x [p] : = true ;w 2: if p = 0 then await ¬ x [1]else if x [0] then w 3: x [1] : = false ;w 4: await ¬ x [0] ;goto wait
end ifend if ;cs: skip ;exit: x [p] : = false
end while
end process
Figure 4.3: Algorithm OB.
must be modified because pc(1) can now also equal w 3 or w 4. For algorithm
OB , we define:6∆(4.17) TypeOK = ∧ x ∈ ({0, 1} → {true, false})∧ pc ∈ ({0, 1} → {ncs, wait, w 2, w 3, w 4, cs, exit})∧ pc(0) ∈/ {w 3, w 4}
However, the resulting inductive invariant isn’t strong enough for proving
liveness. We now consider liveness.
Let OBSafe, the safety property of OB described by the pseudocode, be
the formula Init ∧ 2[Next]v , where v equals hx , pc i and∆

Next = ∃ p ∈ {0, 1} : PNext(p)The fairness condition we want OB to satisfy is weak fairness of each process’s next-state action except when the process is in its noncritical section.
A process p remaining forever in its noncritical section is represented in ourabstract program by no PNext(p) step occurring when pc(p) equals ncs.
The fairness condition we assume of program OB is therefore:∆

OBFair = ∀ p ∈ {0, 1} : WFv ((pc(p) 6= ncs) ∧ PNext(p))
6
For any infix predicate symbol like = or ∈, putting a slash through the symbol negatesit, so e ∈/ S means ¬(e ∈ S ).

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

98

The formula OBSafe ∧ OBFair , which we call OB , satisfies the livenessproperty that if process 0 is in its waiting section, then it will eventuallyenter its critical section. That is, OB implies:(4.18) (pc(0) ∈ {wait, w 2}) ; (pc(0) = cs)
This implies deadlock freedom, because if process 0 stops entering and leaving its critical section, then it eventually stays forever in its noncriticalsection. If process 1 is then in its waiting section, it will read x [0] equal tofalse and enter its critical section.
The inductive invariant obtained from the inductive invariant of UM
isn’t strong enough because it doesn’t assert that x [p] = false when process
p is in its noncritical section, which is at the heart of why OB is deadlock
free. For that we need this stronger invariant, where TypeOK is defined by(4.17):(4.19) ∧ TypeOK∧ x [0] ≡ (pc[0] ∈ {“w2”, “cs”, “exit”})∧ x [1] ≡ (pc[1] ∈ {“w2”, “w3”, “cs”, “exit”})∧ ∀ p ∈ {0, 1} : (pc[p] = “cs”) ⇒ (pc[1 − p] 6= “cs”)
4.2.5.3

Proving LivenessWe will now see how to reason more rigorously about liveness. Even if
you never write rigorous correctness proofs, learning how to reason about
liveness will help you better understand liveness properties.
There are two kinds of liveness properties that we prove: that a program
implies leads-to properties such as (4.16), and that a program implies thefairness properties of a more abstract program. Here we consider leads-to
properties. Proving fairness properties is discussed in Section 5.4.
The proof of a leads-to formula is usually decomposed into proving simpler leads-to formulas. Figure 4.4 shows how we decompose the proof offormula (4.18) using what we call a leads-to lattice.
First, let’s pretend that the box and the formula labeling it aren’t there.
We then have just a directed graph whose nodes are formulas. A formula F
and its outgoing edges represent the assertion that F leads to the disjunctionof the formulas those edges point to. (The edges are numbered so we canrefer to them.) Thus, the two edges numbered 1 assert the formula:(pc(0) ∈ {wait, w 2}) ; ((pc(0) = wait) ∨ (pc(0) = w 2))

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

99

2Inv ∧ 2[Next]v ∧ OBFair
1

pc(0) ∈ {wait, w 2}
PP
q
1 P

- pc(0) = w 2
1


2

3 - pc(0) = cs

pc(0) = wait

Figure 4.4: Leads-to lattice for the proof of (4.18).
By the meaning of leads to, the property asserted by each formula F in thegraph means that if the program is ever in a state for which F is true, thenit will eventually be in a state satisfying a formula pointed to by one of theoutgoing edges from F . The graph has a single sink node (one having nooutgoing edge). Every path in the graph, if continued far enough, leads tothe sink node. By transitivity of the ; relation, this means that if all theproperties asserted by the diagram are true of a behavior, then the behavior
satisfies the property F ; H , where H is the sink-node formula and F
is any formula in the lattice. In particular, the properties asserted by the
diagram imply formula (4.18). By (3.31), that every formula in the graphleads to the sink-node formula means that the disjunction of all the formulasin the graph leads to the sink-node formula.
Now to explain the box. Let Λ equal 2Inv ∧ 2[Next]v ∧ OBFair , theformula that labels the box. Formula Λ is implicitly conjoined to each of theformulas in the graph. It is a 2 formula, since the conjunction of 2 formulas
is a 2 formula, and OBFair is the conjunction of WF formulas, which are
2 formulas.
Since Λ is conjoined to every formula in it, the leads-to lattice makes
assertions of the formΛ ∧ G ; (Λ ∧ H 1 ) ∨ . . . ∨ (Λ ∧ H j )Since Λ equals 2Λ, and once 2Λ is true it is true forever, this formula isequivalent to Λ ∧ G ; H 1 ∨ . . . ∨ H j . (This follows from (3.32c) andpropositional logic.)
If H is the unique sink node of the lattice, then proving the assertions
made by the lattice proves |= Λ ∧ G ; H for every node G of the lattice. Since Λ equals 2Λ, it’s easy to see that a behavior that satisfiesΛ ∧ G ; H must satisfy Λ ⇒ (G ; H ), so proving |= Λ ∧ G ; H
proves |= Λ ⇒ (G ; H ). All this is true only because the formula Λ is a
2 formula. In general, we label a box in a leads-to lattice only with a 2
formula.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

100

Remember what the proof lattice of Figure 4.4 is for. We want to provethat OB implies (4.18). By proving the assertions made by the proof lattice,
we show that the formula Λ labeling the box implies (4.18). By definition of
OB and because OB implies 2Inv , formula Λ is implied by OB . Therefore,
by proving the leads-to properties asserted by the proof lattice, we prove that
OB implies (4.18). Note how we had to use the 2 formula 2Inv ∧ 2[Next]v
instead of OBSafe, which is true only initially.
To complete the proof that OB implies (4.18), we now prove the leadsto properties asserted by Figure 4.4. The leads-to property asserted by theedges numbered 1 is:Λ ∧ (pc(0) ∈ {wait, w 2}) ; ((pc(0) = wait) ∨ (pc(0) = w 2))
It is trivially true, since pc(0) ∈ {wait, w 2} implies that pc(0) equals waitor w 2, and 2(F ⇒ G) implies F ; G.
The formula Λ ∧ (pc(0) = wait) ; (pc(0) = w 2) asserted by edge number 2 is true because Λ implies 2Inv ∧ 2[Next]v and the weak fairness
assumption of process 0, which imply (pc(0) = wait) ; (pc(0) = w 2).
The formula(4.20) Λ ∧ (pc(0) = w 2) ; (pc(0) = cs)
asserted by edge number 3 is the interesting one. Its proof is decomposedwith the proof lattice of Figure 4.5.
The property asserted by the edges numbered 1 in this leads-to lattice has
the form Λ ∧ F ; (G ∨ (F ∧ 2¬G)). This formula is a tautology. Intuitively,
it’s true because if F is true now, then either G is true eventually or F istrue now and ¬G is true from now on. It’s proved by:Λ ∧ F ⇒ F ∧ (3G ∨ 2¬G)
⇒ 3G ∨ (F ∧ 2¬G)
⇒ 3G ∨ 3(F ∧ 2¬G)
≡ 3(G ∨ (F ∧ 2¬G))

3G ∨ 2¬G equals trueby propositional logicby (3.23)
by (3.23)

which shows |= (Λ ∧ F ⇒ 3(G ∨ (F ∧ 2¬G)), from which we can deduce|= Λ ∧ F ; (G ∨ (F ∧ 2¬G)) by (3.20) and the definition of ;.
The leads-to formula asserted by edge 2 is an implication. It’s true because 2Inv ∧2[Next]v implies that, if pc(0) = w 2 and 2(pc(0) 6= cs) are evertrue, then pc(0) = w 2 must remain true forever, which by 2Inv implies x (0)must equal true forever. It is proved by proving that (pc(0) = w 2) ∧ x (0)CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

101

2Inv ∧ 2[Next]v ∧ OBFair(pc(0) = w 2)
1?

1

(pc(0) = w 2) ∧ 2(pc(0) 6= cs)2?

2((pc(0) = w 2) ∧ x (0))
2((pc(0) = w 2) ∧ x (0))


3 


)


@3
@

pc(1) ∈ {cs, exit, ncs}
4
?

PP
4
PP
PP
q

2(pc(1) = ncs)

@
@
R
@

pc(1) ∈ {wait, w 2, w 3, w 4}
6
?

Z
Z

2(pc(1) = w 4)

Z
5ZZ


7

)

Z
~
Z

2¬x (1)8?

pc(0) = cs Figure 4.5: Leads-to lattice for the proof of (4.20).
is an invariant of an abstract program. The initial predicate of this programis Inv ∧ (pc(0) = w 2). Its next-state relation is:
Next2 = Inv ∧ Next ∧ (pc(0) 6= cs)0∆

The formula 2[Next2]v is implied by 2Inv and 2[Next]v and the conjunct2(pc(0) 6= cs) of the formula at the tail of the edge 2 arrow. (Note that theprime in this formula is valid because pc(0) 6= cs always true implies thatit’s always true in the next state.) We are using an invariance property of
one program to prove a liveness property of another program. This would
seem strange if we were thinking in terms of code. But we’re thinking
mathematically, and a mathematical proof contains lots of formulas. It’s
not surprising if one of those formulas looks like the formula that describes
a program.
The edges numbered 3 enter a box whose label is the same formula fromwhich those edges come. In general, an edge can enter a box with a label
2F if it comes from a formula that implies 2F . This is because a box

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

102

labeled 2F is equivalent to conjoining 2F to all the formulas in the box,
and 2F ; (G 1 ∨ . . . ∨ G n ) implies 2F ; ((2F ∧ G 1 ) ∨ . . . ∨ (2F ∧ G n )).
An arrow can always leave a box, since removing the formula it points tofrom the box just weakens that formula.
Proofs of the assertions represented by the rest of the lattice’s edges are
sketched below.
edges 3 The formula represented by these edges is true because the disjunction of the formulas they point to asserts that pc(1) is in the set{ncs, wait, w 2, w 3, w 4, cs, exit}, which is implied by 2Inv .
edges 4 If pc(1) equals cs or exit, then 2Inv ∧ 2[Next]v and the fairness
condition for process 1 imply that it will eventually be at ncs. Either
pc(1) equals ncs forever or eventually it will not equal ncs. In thelatter case, 2[Next]v implies that the step that makes pc(1) = ncs
false must make pc(1) = wait true.
edge 5 This is an implication since 2Inv implies that if process 1 is foreverat ncs, then x (1) is forever false.
edge 6 If process 1 is at wait, w 2, or w 3, then its weak fairness condition
implies it is eventually at w 4. When process 1 is at w 4, formulas
2[Next]v and 2x (0) (from the label of the inner box) imply that it
must remain forever at w 4.
edge 7 This is an implication, because Inv and pc(1) = w 4 imply ¬x (1).
edge 8 2¬x (1), 2(pc(0) = w 2) (implied by the inner box’s label), andOBFair imply that a process 0 step that makes pc(0) equal to cs must
eventually occur. (Equivalently, these three formulas are contradictory, so they imply false which implies anything.)
The proof sketches of the properties asserted by edges 4 and edge 6 skim
over more details than the proofs of the other the properties asserted by thelattice. A more detailed proof would be described by a lattice in which eachof the formulas pointed to by the edges numbered 3 were split into multiple
formulas—for example, the formula pc(1) ∈ {cs, exit, ncs} would be split
into the formulas pc(1) = cs, pc(1) = exit, and pc(1) = ncs. A good checkof your understanding is to draw the more detailed lattice and write proof
sketches for its new edges.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

103

variables sem = 1 ;process p ∈ Procs
while true doncs: skip ;wait: P (sem) ;cs: skip ;exit: V (sem)end while
end process
Figure 4.6: Program LM : mutual exclusion with a semaphore.

4.2.6

Strong Fairness

4.2.6.1

Starvation Free Mutual Exclusion

Mutual exclusion was not motivated by sharing a printer. It’s needed when
multiple processes perform operations on the same data. As we saw fromthe Increment example of Section 3.3, even sharing a simple counter without
synchronization can result in increment operations being lost. An easy way
to synchronize data sharing is to put every operation to the shared data ina critical section.
The One-Bit Algorithm OB implements mutual exclusion with processes
that communicate using only simple reads and writes of shared variables.
Synchronizing processes in this way is inefficient. Dijkstra proposed thecommunication mechanism called a binary semaphore or lock. A lock is avariable that can have two values, traditionally taken to be 0 and 1. Let’scall that variable sem. Initially sem equals 1. A process can execute two
atomic operations, P (sem) and V (sem), to the lock. These operations canbe described in pseudocode as:
P (sem)await sem = 1;
sem : = 0

V (sem)sem : = 1

Locks were originally implemented with operating system calls. Modern
multiprocessor computers provide machine instructions to implement them.
Using a lock, mutual exclusion for any set Procs of processes can be implemented with the trivial algorithm LM of Figure 4.6.
Let PNext(p) now be the next-state action of process p of program LM .
With weak fairness of (pc(p) 6= ncs) ∧ PNext(p) for each process p as its

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

104

fairness property, algorithm LM satisfies the deadlock freedom condition(4.16). However, deadlock freedom allows individual processes to be starved,
remaining forever in the waiting section.
Let Wait(p), Cs(p), and Exit(p) be the actions described by the statements in process p with the corresponding labels wait, cs, and exit. Weakfairness of (pc(p) 6= ncs)∧PNext(p) is equivalent to the conjunction of weak
fairness of the actions Wait(p), Cs(p), and Exit(p). Program LM allows
starvation of individual processes because weak fairness of the actions ofeach process ensures that if multiple processes are waiting to execute that
action, then some process will execute it. But if processes continually reach
the wait statement, some individual processes p may never get to execute
Wait(p).
It’s reasonable to require the stronger condition of starvation freedom,which asserts that no process starves. This is the property(4.21) ∀ p ∈ Procs : (pc(p) = wait) ; (pc(p) = cs)
which asserts that any process reaching wait must eventually enter its criticalsection. For LM to satisfy this property, it needs a stronger fairness property
than weak fairness of the Wait(p) actions.
4.2.6.2

The Definition of Strong Fairness

By the usual meaning of fair, the fairest lock would be one in which processes
execute their Wait(p) actions in the order in which they set pc(p) to wait.
Some implementations of locks ensure this property. However, we don’t
consider it to be a fairness property because it produces a description ofprogram LM that is not machine closed. It rules out finite behaviors in which
processes execute their Wait(p) actions in the wrong order—executions inwhich a process p reaches the wait statement after process q, but p enters
the critical section before q does. Machine closure means that the livenesscondition does not forbid any finite behaviors allowed by the program’ssafety property described by the pseudocode.
There is a standard way to strengthen weak fairness that produces machine closed program descriptions. Weak fairness of an action A assertsthat if ever A is always enabled, then an A action must eventually occur.
To strengthen this condition, we replace the requirement that A be always
enabled by the weaker requirement that it be infinitely often enabled. We
therefore define strong fairness of A by:(4.22) SFv (A) = 23 EhAiv ; hAiv∆

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

105

Analogous to formulas (4.14) and (4.15) for weak fairness are:(4.23) |= SFv (A) ≡ (23 EhAiv ⇒ 23hAiv )(4.24) |= SFv (A) ≡ (23 EhAiv ∧ 2[¬A]v ; hAiv )The informal justification and the proof of (4.23) are similar to the ones for(4.14). The proof of (4.24) is essentially the same as that of (4.15).
4.2.6.3

Using a Strongly Fair Semaphore

To make program LM starvation free, meaning that it satisfies (4.21), we
conjoin to the safety property LMSafe defined by the pseudocode the fairness
property LMFair equal to ∀ p ∈ Procs : LMPFair (p), where LMPFair (p) is
the fairness requirement for process p. If we let LMPFair (p) be the conjunction of strong fairness of Wait(p) and weak fairness of Cs(p) and Exit(p),then the following argument shows LMSafe ∧LMFair implies starvation freedom. Starvation means that a process p waits forever with pc(p) = wait.
That is possible only if other processes keep entering and leaving their critical sections. But whenever a process executes the Exit action, it sets sem
to 1, which makes EhWait(p)iv true. Thus EhWait(p)iv must be true infinitely often, which by strong fairness of Wait(p) implies that Wait(p) is
eventually executed, so p must enter its critical section.
There are several ways of writing formula LMPFair (p). First, we observe that weak and strong fairness are equivalent for the actions Cs(p) andExit(p). This is because the action is enabled iff pc(p) has the appropriate
value, so it remains enabled until a step of that action occurs to change
pc(p). Thus, when the action is enabled, it is continuously enabled until it
is executed. We can therefore write LMFair as the conjunction of strong
fairness of the three actions Wait(p), Cs(p), and Exit(p).
The same sort of reasoning that led to (4.13) of Section 4.2.3, as well as
Theorem 4.8 of Section 4.2.7, imply that the conjunction of strong fairnessof these three actions is equivalent to strong fairness of their disjunction.
Therefore, we can write LMFair as strong fairness of their disjunction, whichequals (pc(p) 6= ncs) ∧ PNext(p).
While SFv ((pc(p) 6= ncs) ∧ PNext(p)) is compact, I prefer not to define
LMPFair (p) this way because it suggests to a reader of the formula thatstrong fairness of Cs(p) and Exit(p) is required, although only weak fairness
is. Usually, the process’s next-state action will be the disjunction of many

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

106

actions, and strong fairness is required of only a few of them. I would define
LMFair to equal
WFv ((pc(p) 6= ncs) ∧ PNext(p)) ∧ SFv (Wait(p))
This is redundant because the first conjunct implies weak fairness of Wait(p)and the second conjunct asserts strong fairness of it. But a little redundancy
doesn’t hurt, and its redundancy should be obvious because strong fairness
implies weak fairness.

4.2.7

Properties of WF and SF

Several assertions were made above about weak and strong fairness. We now
assert the general theorems from which those assertions follow. The first isthat taking weak and strong fairness conditions as the liveness property
produces a machine-closed description of a program. This is true if we takenot just a single weak or strong fairness property or the conjunction of afinite number of them. It is true for a conjunction of a countable set of weak
and/or strong fairness conditions, if each of those conditions asserts fairnessof a subaction of the program’s next-state action.
An action A is defined to be a subaction of an action Next iff |= A ⇒ Next
is true. The subactions of the next-state action Next for which fairness is asserted are usually disjuncts in the definition of Next—for example, Wait(p)is a subaction of the next-state action Next of algorithm OB . Often, we assert fairness of an action P ∧A where A is a disjunct in the definition of Next
and P is a state predicate—for example, the action (pc(p) 6= ncs)∧PNext(p)of OB .7
We now state the theorem asserting that the conjunction of fairness properties produces a machine-closed specification. Its proof is in the Appendix.
Theorem 4.7 Let Init be a state predicate, Next an action, and v a tupleof all variables occurring in Init and Next. If Ai is a subaction of Next for
all i in a countable set I , then the pairh Init ∧ 2[Next]v , ∀ i ∈ I : XFiv (Ai ) i
is machine closed, where each XFiv may be either WFv or SFv .
7

All the results that will be stated are satisfied if we allow a subaction A to be one
satisfying |= Inv ∧ A ⇒ Next, where Inv is an invariant of the program. However, thisgeneralization does not seem to be needed in practice.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

107

Writing an infinite conjunction of fairness properties may not seem to besomething we would do in practice. However, the next-state action of an
abstract program sometimes does contain an infinite disjunction—that is,existential quantification over an infinite set of subactions—and we mightwant a fairness condition for each of those subactions. For example, a program that dynamically creates processes may be described as having an
infinite number of processes, only a finite number of which have their nextstate action enabled at any time. We might want a fairness condition foreach of those processes.
It was stated above that, for program LM , weak or strong fairness of(pc(p) 6= ncs) ∧ PNext(p) is equivalent to weak or strong fairness of its
three subactions Wait(p), Cs(p), and Exit(p). That’s true because when
any one of these subactions is enabled, a step of neither of the other two
subactions can occur until a step of that subaction occurs. Let Q equal(pc(p) 6= ncs) ∧ PNext(p) and let’s call its three subactions A1 , A2 , and A3 .
This condition can then be asserted as:(4.25) ∀ i ∈ 1 . . 3 : EhAi iv ⇒ ( EhQ iv ⇒ EhAi i) U hAi iv
where U is the until operator with which we first defined weak fairness
of PNext(p) as (4.8). Similarly to what we did for weak fairness, we canremove the U by observing that F U G implies that if G is never true,
then F must remain true forever. That hAi iv is never true is asserted by¬3hAi iv , which is equivalent to 2[¬Ai ]v . Therefore (4.25) implies(4.26) ∀ i ∈ 1 . . 3 : EhAi iv ∧ 2[¬Ai ]v ⇒ 2( EhQ iv ⇒ EhAi i)
While (4.25) implies (4.26), the formulas are not equivalent. Formula (4.26)
is strictly weaker than (4.25). However, it’s strong enough to imply thatstrong or weak fairness of all the Ai is equivalent to strong or weak fairness
of Q—assuming that Q is the disjunction of the Ai . Here is the precise
theorem; its proof is in the Appendix.
∆

Theorem 4.8 Let Ai be an action for each i ∈ I , let Q = ∃ i ∈ I : Ai ,and let XF be either WF or SF. Then|= ( ∀ i ∈ I : 2( EhAi iv ∧ 2[¬Ai ]v ⇒2[¬Q]v ∧ 2( EhQ iv ⇒ EhAi iv ) )⇒ ( XFv (Q) ≡ ∀ i ∈ I : XFv (Ai ) )It is perhaps interesting, but of no practical significance, that the theorem
is valid even if the set of actions Ai is uncountably infinite.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

108

The completeness result for safety properties in Theorem 4.2 can beextended as follows to arbitrary properties. A proof is sketched in the Appendix.
Theorem 4.9 Let x be the list x 1 , . . . , x n of variables and let F be aproperty such that F (σ) depends only on the values of the variables x in σ,
for any behavior σ. There exists a formula S equal to Init ∧ 2[Next]hx,y i ∧WFhx,y i (Next), where Init and Next are defined in terms of F , y is a variable
not among the variables x, and the variables of S are x and y, such that|= F ⇒ [[G]] iff |= S ⇒ G, for any property G. If F is a safety property,
then the conjunct WFhx,y i (Next) is not needed.
Like Theorem 4.2, this result is of theoretical interest only.

4.2.8

What is Fairness?

Before TLA, concurrent abstract programs were generally written in something like a coding language. Fairness meant that each process had to execute its next atomic statement when it could. Viewed in terms of TLA, eachatomic statement was described by an action, and fairness meant fairnessof those actions. Usually that meant weak fairness of the action, but when
the statement was a synchronization primitive, it sometimes meant strong
fairness. For rigorous reasoning, those fairness requirements were expressed
as requirements on when control in the process had to move from one control
point to another [45].
With TLA, fairness was generalized to weak and strong fairness of arbitrary actions. We have considered a fairness property for a safety property
S to be a formula L that is the conjunction of weak and strong fairness conditions on actions such that hS , Li is machine closed. However, weak andstrong fairness of an action are defined in terms of how the action is written,
not in terms of its semantics. While we have given semantic definitions ofsafety, liveness, and machine closure; we have not done it for fairness.
I only recently learned that a semantic definition of fairness was published in 2012 by Völzer and Varacca [49]. Their definition of what it means
for a property L to be a fairness property for a safety property S can bestated in terms of the following infinite two-player game. Starting with seq
equal to the empty sequence, the two players forever alternately take steps
that append a finite number of states to seq. The only requirement on thesteps is that after each one, seq must satisfy S . The second player wins
the game if she makes seq an infinite sequence that satisfies L. (Since S
is a safety property, seq must satisfy S .) They defined L to be a fairness

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

109

property for S iff the second player can always win, regardless of what thefirst player does (as long as he follows the rules).
It is mathematically meaningless to say that a definition is correct. However, this seems to be the only reasonable definition that includes weak andstrong fairness such that fairness implies machine closure and the conjunction of countably many fairness properties is a fairness property. This definition also encompasses other fairness properties that have been proposed,
including one called hyperfairness [33].
I believe that weak and strong fairness of actions are the only fairness
properties that are relevant to abstract programs. However, this generaldefinition is interesting because it provides another way to think about fairness. More importantly, it’s interesting because concepts we are led to bymathematics often turn out to be useful.

4.3

Possibility and Accuracy

4.3.1

Possibility Conditions

Informally, a safety property states what an abstract program is allowed to
do and a liveness property states what it must do. If a behavior violates asafety property, then it does so at a particular step in the behavior. Therefore, we can also view a safety property as stating what a program must not
do—that is, it must not take a step that violates the property. So, livenesssays what must happen and safety says what must not happen. That a
program eventually sets x to 0 is a liveness property, that it never sets x to
0 is a safety property.
Possibility says what might happen. That a program might set x to 0 is
a possibility condition. It is not a property, because it is not a predicate on
behaviors. It is satisfied by an abstract program iff there is some behaviorof the program in which x is set to 0. We can tell that the program satisfies
it if we see such a behavior. But seeing one behavior that doesn’t satisfy it
doesn’t tell us whether or not some other behavior might satisfy it. However,
we will see that possibility conditions can be expressed as properties that
explicitly mention the program’s actions.
Knowing that something might be true of a system, but knowing nothing about the probability of its being true, is of almost8 no practical use.
The only way I know of calculating such probabilities is to view the abstract
8
Section 7.1 explains one way in which a possibility condition can be used to verify aproperty of a system and could therefore be of practical use.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

110

program as a state-transition system, attach probabilities to the varioustransitions, and mathematically analyze that system—for example, using
Markov analysis. Usually, the state-transition system would be a more abstract program implemented by the program of interest.
While possibility conditions of systems are of little interest, we don’t
reason about systems; we reason about abstract programs that describe systems. Verifying that a program satisfies a possibility condition can be a wayof checking what we will call here the accuracy of an abstract program—that
it accurately describes the system it is supposed to describe. For example,
if the system doesn’t control when users send it input, a program that accurately describes the system and its users should satisfy the condition thatit’s always possible for users to enter input.

4.3.2

Expressing Possibility in TLA

There exist logics for expressing possibility properties and tools for checking
them. Such tools could be built to check those properties for abstract TLA
programs, and it might be worthwhile to do so. But we will see how thatcan be avoided.
Even though a possibility condition is not a property, that an abstract
program satisfies a possibility condition can be expressed by a TLA formulathat depends on the program and the possibility condition. For example,
suppose S is a TLA description of an abstract program and the action Input
is a subaction of its next-state action that describes users entering input.
That it is always possible for users to enter input could be considered to meanthat the Input action is enabled in every reachable state of the program,which is asserted by|= S ⇒ 2 E(Input)
However, “always possible” might instead mean that from any reachable
state, there is a sequence of possible steps that reach a state with E(Input)
true—a condition we will call “always eventually possible”. To express thisand other possibility conditions in TLA, we can use the action composition
operator defined in Section 3.4.1.4. Recall that for any action A, the action
A+ is true of a step s → t iff t is reachable from s by a sequence of one ormore A steps.
Now consider an abstract program Init ∧ 2[Next]v where Init is a statepredicate, Next is an action, and v is the tuple of all variables that appear
in Init or Next. Let’s abbreviate ([Next]v )+ as [N ext]+
v . If s is a reachable
state of the program, then s → t is a [N ext]+
step
iff
it is possible for anv

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

111

execution of the program to go from state s to state t. (Since [Next]v allows+
stuttering steps, t can equal s. In fact, [N ext]+
v is equivalent to [Next ]v .)A state t is a reachable state of the program iff there is a state s satisfying
Init such that s → t is a [N ext]+
v step. In other words, t is a reachable stateof the program iff there is a state s such that s → t is an Init ∧ [N ext]+v
step.
We can now express the condition that it is always eventually possible forthe user to enter input, meaning that from any reachable state, it is possible
to reach a state in which E(Input) is true. We generalize this condition byreplacing E(Input) with an arbitrary state predicate P . For the abstract
program Init ∧ 2[Next]v , that P is always eventually possible is expressedas:0(4.27) |= Init ∧ 2[Next]v ⇒ 2 E([N ext]+v ∧P )

This example indicates that it should be possible to express possibility
conditions in TLA using Next + and the E operator. However, like (4.27),
the resulting TLA formulas are quite different from the ones that arise inchecking that an abstract program satisfies a property. Different tools would
be needed to verify that a program satisfies a possibility condition expressedin this way. It would be nice to be able to verify possibility conditions byverifying the same kind of properties that arise in verifying that an abstract
program satisfies a liveness property. Here is how it can be done for thecondition that it is always possible to reach a state satisfying P .
This condition obviously holds if the program satisfies the property thatin any reachable state, a state satisfying P must eventually occur—that is,if the program satisfies the property 23P . Let S equal Init ∧ 2[Next]v .
The safety property S will not imply the liveness property 23P unless P
is true in all reachable states of F —that is, unless S implies 2P . However,
if F is a fairness property for S , so hS , F i is machine closed, then S ∧ F
has the same set of reachable states as S . So, any state satisfying P canbe reached from a reachable state of S iff it can be reached from a statesatisfying S ∧ F . Therefore, it suffices to verify that a state satisfying P
can be reached from every reachable state of S ∧ F , which is true if S ∧ F
implies 23P . Therefore, we can verify that P is always eventually possible
by verifying|= Init ∧ 2[Next]v ∧ F ⇒ 23P
for a fairness property F of Init ∧ 2[Next]v . By Theorem 4.7, we can ensurethat F is a fairness property for S by writing it as the conjunction of strong

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

112

fairness properties. (Since strong fairness implies weak fairness, there is noneed to use weak fairness properties.) There is a completeness result thatessentially says that such a fairness property always exists for any statepredicate P if S has the standard form Init ∧ 2[Next]v [32].
I suspect that TLA can in a similar way express possibility for a moregeneral class of possibility conditions than the two possible interpretationsof “always possible”. However, the only other possibility condition I havefound to be useful for checking the accuracy of an abstract program is avery simple one, discussed in the following section.

4.3.3

Checking Accuracy

Using TLA to check that a state predicate P is always eventually possible
may not be easy, since it requires finding a fairness condition that implies P
is true infinitely often. There’s a simpler condition that is easier to check:it’s possible for P to be true (at least once). It would be more useful tocheck the stronger condition of always eventually possible. However, I havefound that most people, including me, don’t spend enough time checking
the accuracy of their abstract programs. The weaker check is likely to be
more helpful in practice because it’s more likely to be done than one that
requires more effort.
It’s possible for P to be true means that it is true in some reachable
state. This is equivalent to the assertion that ¬P is not true in all reachable
states—in other words, that ¬P is not an invariant of the program. We
can check this by asking a tool for checking invariance to check if ¬P is
an invariant. If the tool reports that it isn’t, then it’s possible for P to betrue. For example, if a model checker reports that your mutual exclusion
algorithm satisfies mutual exclusion, you should check that it’s possible for aprocess to enter its critical section. This is especially true if you did not haveto make many corrections to reach that point. Remember that a programthat takes no non-stuttering steps satisfies most safety properties.
Tools can provide other ways of checking the accuracy of a program. For
example, if Input is a subaction of the program’s next-state action, a TLA+
model checker called TLC reports how many different steps satisfying Input
occur in behaviors of the program. If it finds no such steps, then it is notalways possible for an Input step to occur with either definition of “always
possible”. Finding too few such steps can also be an indication that the
program is not accurate.
Accuracy of an abstract program cannot be formally defined. It meansthat a program really is correct if it implements the abstract program. In

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

113

other words, an abstract program is accurate iff it means what we want it
to mean, and our desires can’t be formally defined. That accuracy can’t
be formally defined does not mean it’s unimportant. There are quite a few
important aspects of programs that lie outside the scope of our science ofcorrectness.

4.4

Real-Time Programs

Real-time abstract programs are ones in which timing constraints ensurethat safety properties hold. Real time is most often used in concrete programs to ensure not safety but liveness. It appears in timeouts that guarantee something eventually happens. For example, to guarantee that a message
is eventually delivered despite possible message loss, a timeout occurs if an
acknowledgement of the message is not received soon enough after it is sent,
and the message is then resent. A program that uses timeouts only in thisway is not a real-time program. The actual time at which a timeout occurs
affects only performance, not correctness. Therefore, timeout can be modeled in an abstract program as an event that must eventually occur but canoccur at any time. The program can use liveness to abstract away time.
We need to write a real-time abstract program only if timing constraints areused to ensure safety properties.
Scientists have been dealing mathematically with real-time systems for
centuries by simply representing time as the value of a variable. It has
been known for decades that this works for real-time programs too [6]. I
will illustrate how it is done with a mutual exclusion algorithm of Michael
Fischer.9
I believe that most work on the correctness of real-time programs has
considered only safety properties. Instead of requiring that something eventually happens, it requires the stronger property that it happens withinsome fixed amount of time, which is a safety property. Fischer’s Algorithm
is more general because in addition to using real-time to ensure mutual exclusion, a safety property, it uses fairness to ensure deadlock freedom, aliveness property.
In the past 40 years, I have had essentially no contact with engineers whobuild real-time systems. I know of only one case in which TLA was used to
9

Fischer sent this algorithm in an email to me [12]. I believe Martı́n Abadi and I were
the first to describe it in print [1].

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

114

check that a commercial system satisfied a real-time property [5].10 Fromthe point of view of our science, there is nothing special about real-time
programs. However, how well tools work can depend on the application
domain. The TLA+ tools were not developed with real-time programs in
mind, and it’s unclear how useful they are in that domain.

Math VI
Definitions Within an Expression The scope of an ordinary definition
includes everything that comes logically after it in the current discussion,
which in this book might end at the end of the current section. It’s sometimes convenient to make a definition whose scope is limited to a single
expression exp. The usual reason is “common subexpression elimination”,
where exp contains multiple occurrences of the same subexpression subexp,
and we want to give that subexpression a name nm and rewrite exp as theexpression nmexp in which each occurrence of subexp has been replaced by
nm. We do that by rewriting exp as:∆

let nm = subexp in nmexp
Note that if exp occurs in the scope of bound variables and we wanted to do
this with an ordinary definition, we would have to define nm as an operator
with one argument for each of those bound variables. The general form of
the let/in construct is
let defs in exp
where exp is an expression and defs consists of one or more definitions.
The scope of those definitions is the expression exp, and the definitions can
include definitions of mappings that take arguments.
The Mapping Set Constructor ZF contains a set constructor that I
call the mapping constructor. Its general form is {exp : v ∈ S }, where v isa bound variable whose scope is the expression exp. It equals the set of allvalues obtained by substituting an element of the set S for v in exp. For
example, {2 ∗ n : n ∈ N} is the set of all even natural numbers. As anotherexample, if S is a set of n-tuples, then it is a subset of S 1 × . . . × S n , whereS i is the set {v (i ) : v ∈ S }.
10

The TLA+ design of the real-time operating system mentioned in Section 1.6 was not
used to check its real-time properties.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

115

variables x = none ;process p ∈ Procs
variables pc = ncs ;while true doncs: skip ;noncritical section
wait: await x = none ;w 1: x : = p ;w 2: if x 6= p then goto wait end if ;cs: skip ;critical section
exit: x : = noneend while
end process
Figure 4.7: Fischer’s Algorithm.
Don’t confuse the mapping constructor with the subsetting constructor,
whose form is {v ∈ S : exp}. The set of all even natural numbers can be
written with the subsetting constructor as {n ∈ N : n % 2 = 0}.11

4.4.1

Fischer’s Algorithm

The algorithm without its timing constraints is described by the pseudocode
in Figure 4.7. The constant Procs is the set of processes, and none is someconstant that is not in Procs. The global variable x is read and written by
all the processes and, as usual, the value of pc(p) is the label of the next
statement to be executed by process p. As explained in Section 4.2.2.1, thestatement await P is a synchronization primitive that allows the program tocontinue only when the state predicate P is true. Thus, the wait statementof process p is described by the action:∧ pc(p) = wait
∧ x = none
∧ pc 0 = (pc except p 7→ w 1)
∧ x0 = x
With no time constraints, mutual exclusion is easily violated. Two processes
can execute the wait statement when x equals none, then statements w 1 andw 2 can both be executed by the first process and then by the second one,11

The expression {v ∈ S : v ∈ T } is ambiguous; it could be either a subsetting or amapping constructor. We will never write such an expression, so we won’t worry about
which it is.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

116

putting both processes in the critical section. Mutual exclusion is ensured
by timing constraints.
We assume that each step is executed instantaneously at a certain time,
and that each process executes w 1 at most δ seconds after it executes wait
and executes w 2 at least  seconds after it executes w 1, for constants δ and with δ < . (The algorithm doesn’t specify what the time units are; wewill call them seconds for convenience.) It’s a nice exercise to show that thisensures mutual exclusion by assuming that two processes are in their criticalsections and showing that the necessary reads and writes of x that allowed
them both to enter the critical section must have occurred in an order that
violates the timing constraints if δ < . While it may be good enough forsuch a simple algorithm, this kind of behavioral reasoning is unreliable formore complicated programs.
To verify mutual exclusion more rigorously, we describe Fischer’s Algorithm with its timing constraints as an abstract program. This requires
adding a variable whose value represents the current time. Scientists usually call that variable t, but I like to call it now . We also add a variable rt,
where the value of rt(p) records the time at which certain actions of process
p were executed. The program also contains an additional process called
Time that advances time.
The algorithm is written in pseudocode in Figure 4.8. The initial valueof now can be any number in the set R of real numbers, and the initial valueof rt can be any function from the set of processes to R. Let’s now examine
the code of process p. Two assignments to rt(p) have been added. Eachsets rt(p) to the time at which the action in which it appears is executed,
the actions being the ones performed when the program is at control points
wait and w 1. Also added is an await statement at w 2 that allows theaction to be performed only when now − rt(p) ≥ . This await enforces
the requirement that the w 2 action must not be executed until at least 
seconds after execution of the w 1 action.
Let’s now examine the Time process. It repeatedly performs a single
atomic action, so it has just one control point that needs no label. That
action increases the value of now . The :∈ operation is like the assignment
operation : = except with = replaced by ∈. That is, a step of the Timeprocess’s action assigns to now an arbitrary element of the set on the righthand side of the :∈ . The action can assign to now any value t greater thanits current value subject to the condition that t ≤ rt(p) + δ for every process
p at control point w 1. It is this condition that enforces the requirement thata process must execute statement w 1 within δ seconds of when it executes
the wait statement.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

117

variables x = none, now ∈ R, rt ∈ (Procs → R) ;process p ∈ Procs
variables pc = ncs ;while true doncs: skip ;noncritical section
wait: await x = none ;rt(p) : = now ;w 1: x : = p ;rt(p) : = now ;w 2: await now − rt(p) ≥  ;if x 6= p then goto wait end if ;cs: skip ;critical section
exit: x : = noneend while
end processprocess Time
while true do
now :∈ {t ∈ R :∧ t > now∧ ∀ p ∈ Procs : (pc(p) = w 1) ⇒ (t ≤ rt(p) + δ) }end while
end process
Figure 4.8: Fischer’s Algorithm with explicit time.
Fischer’s Algorithm illustrates the basic method of representing realtime constraints in an abstract program. Lower bounds on how long it
must take to do something are described by enabling conditions on thealgorithm’s actions. Upper bounds are described by enabling conditions on
the action that advances time. There are a number of ways of enforcing thesebounds. The use of the variable rt in Fischer’s algorithm shows one way.
Another is to use variables whose values are the number of seconds remaining
before an action must be executed (lower bounds) or can be executed (upperbounds)—variables whose values are decremented by the time-advancing
action.
The idea of an abstract program constraining the advance of time ismind-boggling to most people, since they view a program as a set of instructions. They see it as the program stopping time. You should by now
realize that an abstract program is a description, not a set of instructions.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

118

It describes a universe in which the algorithm is behaving correctly. That
description may constrain the algorithm’s environment, which is the partof the universe that the algorithm doesn’t control—for example, its users.
Time is an important part of that environment if the amount of time it takes
to perform the algorithm’s actions is relevant to its correctness.

4.4.2

Correctness of Fischer’s Algorithm

Having written Fischer’s algorithm as an abstract program, we know how
to verify its correctness. Mutual exclusion is an invariance property, andto understand why the algorithm satisfies it we need to find the inductive
invariant that explains why the algorithm satisfies that property. As usual,the inductive invariant asserts type-correctness of all the variables. Theinteresting part of the invariant makes the following assertions about eachprocess p:• If control is at w 1, then the current time is at most δ seconds after
the time at which p just executed the wait statement.
• If control is at cs or exit, then x = p and in no process is control at
w 1. (This condition implies mutual exclusion.)• If p is at w 2 and x = p, then any process with control at w 1 must
execute statement w 1 before p can execute statement w 2.
These assertions about every process p are expressed mathematically as:∀ p ∈ Procs :∧ (pc(p) = w 1) ⇒ (rt(p) ≤ now ≤ (rt(p) + δ))∧ (pc(p) ∈ {cs, exit}) ⇒ (x = p) ∧ (∀ q ∈ Procs : pc(q) 6= w 1)
∧ (pc(p) = w 2) ∧ (x = p) ⇒∀ j ∈ Procs : (pc(q) = w 1) ⇒ ((rt(q) + δ) < (rt(p) + ))
You should understand why the three conjuncts in this formula are the three
assertions expressed informally above. Adding the type-correctness part andproving that it is an inductive invariant is a good exercise if you want tolearn how to write proofs.
Under suitable fairness assumptions, Fischer’s Algorithm is deadlock
free. Recall that deadlock freedom for a mutual exclusion algorithm means
it’s always true that if some process is trying to enter the critical section,then some process (not necessarily the same process) will eventually do so.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

119

Deadlock freedom of Fischer’s Algorithm follows from the algorithm having
this additional invariant:(4.28) (x 6= none) ⇒ (pc(x ) ∈ {w 2, cs, exit})
Here’s a sketch of a proof by contradiction that the algorithm is deadlock
free. Suppose some process is at wait and no process is ever in its criticalsection. Eventually, some set of processes will be forever in their noncriticalsections, and one or more processes will forever have control at wait, w 1,
or w 2. Eventually the latter processes will all wind up waiting at the waitstatement with x 6= none. But that contradicts the invariant (4.28), which
implies that process x cannot be at wait.

4.4.3

Fairness and Zeno Behaviors

What fairness requirements of the abstract program of Figure 4.8 are assumed in the informal argument that the program is deadlock free? If
procStep(p) is the next-state action of a process p in Procs, then we naturally assume weak fairness of the action procStep(p) ∧ (pc 6= ncs). Whatabout fairness of the Time process? Let’s call that process’s action timeStep.
The obvious choice is to let it be strong fairness of timeStep. However, thatallows the following behavior: While all other processes in Procs remain in
their noncritical sections, a process p executes the wait statement and then,at time t, executes statement w 1 that sets rt(p) to t. Repeated executionsof action timeStep then set now to t + /2, then t + 2 ∗ /3, then t + 3 ∗ /4,and so on. Process p must wait forever at w 2 because now is always lessthan t +  and the w 2 action is enabled only when now ≥ t + . Such abehavior, in which time remains bounded, is called a Zeno behavior.
The most natural way to avoid the problem of Zeno behaviors is tomake the abstract program describing Fischer’s Algorithm disallow them.
The obvious way to do that is to conjoin this liveness property:(4.29) ∀ t ∈ R : 3(now > t)which asserts that the value of time is unbounded. However, this isn’t necessarily a fairness property. It’s easy to write an abstract program that allows
only Zeno behaviors, so conjoining the liveness property (4.29) produces a
program that allows no behaviors. For example, we can add timing constraints to the program of Figure 4.7 that require a process both to executestatement w 1 within δ seconds after executing statement wait and to wait
at least  seconds after executing wait before executing w 1, with δ < . If a
process executes wait at time t, then now ≤ t + δ must remain true forever.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

120

If we added fairness properties that required processes eventually to reach
the wait statement and execute it if it’s enabled, then the program would
allow only Zeno behaviors.
We can ensure that Fischer’s Algorithm satisfies (4.29) by having it require an appropriate fairness condition on the advancing of time. The condition we need is strong fairness of the action timeStep ∧ (now 0 = exp), where
exp is the largest value of now 0 permitted by the values of rt(p) for processes
p with control at w 1, or now + 1 if there is no such process. More precisely:∆∆

exp = let T = {rt(p) + δ : p ∈ {q ∈ Procs : pc(q) = w 1}}
in if T = {} then now + 1 else Min(T )where Min(T ) is the minimum of the nonempty set T of real numbers.
With this fairness condition on advancing time and the conjunction of thefairness conditions for the processes in Procs, Fischer’s Algorithm satisfies(4.29) and the proof sketch that the algorithm is deadlock free can be maderigorous.
If we are interested only in safety properties, there is no need for an
abstract program to rule out Zeno behaviors. A program satisfies a safety
property iff all finite behaviors allowed by the program satisfy it, and a Zeno
behavior is an infinite behavior. In many real-time programs, liveness properties are of no interest. Correctness means not that something eventually
happens but that it happens within a certain length of time, which is asafety property. Zeno behaviors then make no difference, and there is no
reason to disallow them.
Even if Zeno behaviors don’t matter, the absence of non-Zeno behaviors
can be a problem. Since real time really does increase without a bound,an abstract program in which it is not always possible for time to become
arbitrarily large is unlikely to be accurate. Therefore, we almost always
want to ensure that a real-time program satisfies the condition that for anyt ∈ R, it is always possible for now > t to be true. This is true iff, for
any t ∈ R, from any reachable state of the program it is always possible
for now > t to be true. This is the kind of possibility condition consideredin Section 4.3. We saw there that if the program Safe is a safety property
that satisfies this condition, then we can verify that it does so by finding a
conjunction F of fairness properties for Safe and verifying:(4.30) |= Safe ∧ F ⇒ 23(now > t)for all t ∈ R. (Since a real-time program never allows now to decrease, itsuffices to verify that Safe ∧ F implies (4.29).)

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

4.4.4

121

Discrete Time

Verifying properties of real-time programs is easier if we assume time is discrete and now always equals a multiple of some time unit. It may seem
obvious that, since concrete programs run on real computers reading thecurrent time from a clock that advances in discrete steps, we can always
assume discrete time. However, different processes can be executed on different computers whose clocks can run at slightly different rates. Still, it
seems likely that an abstract program will be sufficiently accurate if it assumes time changes only in one yoctosecond (10−24 second) increments. So,
in practice we should be able to assume that the values of now and any time
constants are integers, leaving unspecified how long one time unit is.
When writing proofs, there doesn’t seem to be much reason to use discrete time. The main advantage of discrete time is that tools for automatically verifying properties of ordinary abstract programs can, in principle,
handle discrete real-time programs. For example, I didn’t prove that what I
claimed in Section 4.4.2 to be an inductive invariant of Fischer’s Algorithm
actually is one. Instead, I used a model checker to check that it is, whichgave me enough confidence to make the claim.
Many model checkers are based on enumerating reachable states, usuallyon a small instance of the program—for example, with a small number ofprocesses. This is impossible with continuous time, in which a single state
can have possible next states with uncountably many values of now . There
are still infinitely many reachable states with discrete time because the valuesof now are unbounded, but counterexamples to incorrect safety properties
and to (4.29) for a particular time t can be found by examining all reachable
states with now less than some value.
The number of reachable states that must be examined can be reduced
for real-time programs that satisfy a condition called symmetry under timetranslation. This condition asserts that for every d ∈ R there is a timetranslation mapping T d from states to states such that: For every state s,
the value of now in state T d (s) equals d plus its value in s, and any steps → t satisfies the program’s next-state action iff T d (s) → T d (t) does. For
example, Fischer’s Algorithm is symmetric under the time translations T ddefined by letting the values of now and rt(p) in T d (s) equal d plus theirvalues in s, and letting the values of x and pc be the same in s and T d (s).
Suppose S is a program symmetric under the time-translation functions
T d , and for simplicity assume that the program’s initial predicate asserts
now = 0. Let’s call states s and t translation equivalent iff t = T d (s) forsome d . If P is a safety property containing only variables whose values

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

122

are left unchanged by the functions T d , then to verify that P is satisfied by
S we can verify that it is satisfied by the program Sb obtained from S byconsidering two translation equivalent states to be the same state. Often,
there will be some time λ such that every reachable state of S is translationequivalent to a state in which now ≤ λ, in which case now ≤ λ in every
state of Sb . This implies we can verify that S satisfies (4.29) by checking
that it satisfies 3(now ≥ λ + 1), which requires examining only reachable
states with now ≤ λ + 1. The details can be found elsewhere [35].
Being able to reduce verification of a discrete-time program to examining
reachable states with now less than some value would still leave an enormous
number of states to consider if now advanced in yoctosecond steps. Henzinger, Manna, and Pnueli [17] proved that for a class of programs called
timed transition systems, certain properties can be verified with discrete
time in which now advances only in reasonably sized steps. Timed transition systems are essentially programs in which, like Fischer’s Algorithm,
time is used only to require minimum and maximum delays between whena program action becomes enabled and when it either must be executed(maximum delay) or may be executed (minimum delay). If those delays areconstants that are all multiples of some time unit ∆, then a certain class ofproperties can be verified by letting time always be a multiple of ∆. Thatclass of properties are ones in which replacing each state in a behavior bytime-translating it by d with −∆ < d ≤ 0 does not change whether the
behavior satisfies the property. It includes properties that depend only on
variables whose values are unchanged by time translation. It also includes
the property (4.29).
One reason that has been given for preferring continuous time is that
it is necessary for composing programs. It would be difficult to compose a
program in which a clock tick represents a nanosecond with one in which aclock tick represents a millisecond. However, we can easily describe a program in terms of a clock that ticks at an unspecified rate and an unspecified
constant that equals the number of clock ticks in a second.
Program composition is discussed in Section 7.2, where it is shown how
the composition of two abstract programs can be represented as the conjunction of the TLA formulas that describe them. Moreover, a real-time
abstract program can be written as the conjunction of two formulas, one
describing an ordinary, untimed program, the other specifying the required
timing constraints [1]. However, this kind of abstract program composition
is not yet usable in practice.

CHAPTER 4. SAFETY, LIVENESS, AND FAIRNESS

4.4.5

123

Hybrid Systems

A hybrid computer system is one that controls physical processes—for example, one that flies an airplane or runs a chemical plant. An abstract programthat describes such a system is a real-time program that describes not only
the passage of time but also other physical quantities like altitude or pressure. There is no fundamental difference between programs that describe
hybrid systems and other real-time programs. The current altitude or pressure is represented by a variable like any other variable. Abstract programs
describing hybrid systems differ from other real-time abstract programs onlyin the math used to describe them. If the variable prs describes the current
pressure, then the time-advancing subaction of the next-state action might
contain a subformula like:
0(4.31) prs = prs +Z now0exp dtnow

for some expression exp containing the bound variable t and other variables [30].
It may seem that a representation of the behavior of a continuous process
by a sequence of discrete states would not be sufficiently accurate. For
example, if it is required that the pressure not be too high, violation of that
requirement would not be found if it occurred during the time between two
successive states of the behavior. This is not a problem because correctnessmeans that a property is true of all possible behaviors, and the possibility ofthe pressure being too high at some time is revealed by a behavior containing
a state in which now equals that time.
Other than the differences implied by the use of continuous math, suchas the calculus in (4.31), rather than discrete math, proving properties ofhybrid programs is the same as proving properties of other real-time abstract programs. Automatic tools like model checkers for ordinary abstract
programs seem to be unsuitable for checking abstract programs in which
variables represent continuously varying quantities. Methods have been developed for checking such programs [11].

Chapter 5

Refinement
We have discussed one abstract program implementing another. We now
consider more carefully what that means. We write abstract programs with
TLA formulas, and it is rather weird to talk about one formula implementing
another. Computer scientists who view programs mathematically generally
use the term refinement rather than implementation. Henceforth, we will
use the two terms interchangeably. There are two aspects to refinement:
Step Refinement The refining program has a finer grain of atomicity.
This means that a non-stuttering step of the high-level program cancorrespond to multiple steps of the refining program, all but one ofthem implementing stuttering steps of the high-level program. In theexample of Section 3.5.1, the hour-minute-second clock HMS refines
the hour-minute clock HM . Every non-stuttering step of HM , which
advances the minute, corresponds to 60 steps of HMS , each changing
the second and one of them changing the minute.
Data Refinement A program refining another program can also refine therepresentation of data used by the higher-level program. This will beillustrated by refining a higher-level program that uses numbers witha program that implements a number by a sequence of digits.
Refinement usually involves both step and data refinement, with step refinement manifest as operations on the lower-level data requiring more nonstuttering steps than the corresponding operations on the higher-level program’s data. As we saw with the example of the hour-minute and hourminute-second clocks in Section 3.5.2, without data refinement, a program
S is refined by a program T means that T implies S . We will see that124

CHAPTER 5. REFINEMENT

125

with data refinement, T refines S means that T implies the formula obtained from S by substituting expressions containing the variables of T forthe variables of S . To describe this precisely, we need some notation for
substitution.
Mathematicians have no standard way of describing substitution, andthe notation I’ve seen used by computer scientists is impractical for theformulas that arise in describing programs. The notation used in this book,illustrated with substitution for three variables, is that
E with v 1 ← exp 1 , v 2 ← exp 2 , v 3 ← exp 3
is the expression obtained from the expression E by simultaneously substituting exp 1 for v 1 , exp 2 for v 2 , and exp 3 for v 3 ; where v 1 , v 2 , and v 3 are
distinct variables and exp 1 , exp 2 , and exp 3 are expressions. For example:( p ∗ (q + r ) with q ← r , r ← q + s ) = p ∗ (r + (q + s))
As in this example, the with expression is usually enclosed in parentheses
when it appears as a subexpression in a larger expression, otherwise parsing
would be difficult.
When a program S is refined by a program T , the variables in formula
T are usually different from the variables in formula S , and the two sets ofvariables have non-overlapping scopes. Showing that T refines S involves
reasoning in the scope of T about formulas containing the variables of S .
To do this, we import an expression E containing variables of S into thescope of the variables of T as the expression
E with v 1 ← exp 1 , . . . , v m ← exp mwhere the v i are the variables of S and the exp i are expressions containing
the variables of T . The same thing applies to the constants of T and S ,so the v i are both the variables and constants of S , and if v i is a constantthen exp i is a constant expression. We adopt the convention that if theexpression exp i is a constant or variable of T with the same name as theconstant or variable v i of S , then we omit the substitution v i ← v i . (This isconvenient because it can be unclear whether the two variables or constants
are the same in both programs or just have the same name.)

5.1

A Sequential Algorithm

In step refinement, the additional steps taken by the lower-level program
correspond to stuttering steps in the higher-level one. We consider an extreme example of this: a program that terminates after taking a single

CHAPTER 5. REFINEMENT

126

non-stuttering step that is refined by a traditional sequential program thatcomputes a value and stops.
This example is used because it’s simple and nicely illustrates data refinement. Its use does not imply that this way of looking at refinement isthe best one to use for traditional programs. There are other methods forreasoning about refinement of traditional programs that are probably better
than our science of more general programs [20]. We consider only safety inthis example; liveness is straightforward.
The high-level abstract program Add begins with variables x and y equal
to arbitrary natural numbers, sets the variable z to their sum, and terminates. Termination is indicated by changing the value of a Boolean-valued
variable end to true. Here is the definition:
InitA
NextA
vA
Add

∆

=
∆
=
∆
=
∆
=

(end = false) ∧ (x ∈ N) ∧ (y ∈ N)
¬end ∧ (z 0 = x + y) ∧ (end 0 = true)hx , y, z , end i
InitA ∧ 2[NextA]vA

Note that Init does not specify the value of z . Its initial value doesn’t matter.
Note also that action NextA does not specify the values of x 0 or y 0 . You
should realize by now that this doesn’t mean those values are unchanged; itmeans that their new values are unspecified. We are assuming that the final
values of x and y don’t matter; we care only about the final value of z .

Math VII
Sequence Operators We now define some operators for sequences. They
are defined for both ordinal and cardinal sequences. For any sequences σand τ such that σ is finite, we define σ ◦ τ to be the sequence obtained byconcatenating σ and τ . For example, h4, 5i ◦ h1, 2i equals h4, 5, 1, 2i, and(4 → 5) ◦ (1 → 2) equals 4 → 5 → 1 → 2.
For any (finite or infinite) nonempty sequence σ, we define Head (σ) to be
the first item of σ and Tail (σ) to be the sequence obtained by removing thefirst element of σ. For example, Head (h1, 2, 3i) and Head (1 → 2 → 3) both
equal 1; Tail (h1, 2, 3i) equals h2, 3i; and Tail (1 → 2 → 3) equals 2 → 3. If
σ is a nonempty ordinal sequence, then it equals hHead (σ)i ◦ Tail (σ).
For any finite sequence σ, we define Len(σ) to be the number of items
in σ. Thus, domain(σ) equals 1 . . Len(σ) if σ is a finite ordinal sequence;and it equals 0 . . (Len(σ) − 1) if σ is a finite cardinal sequence.
We need the following two operators only for ordinal sequences, so we
don’t define them for cardinal sequences. For any ordinal sequence σ andCHAPTER 5. REFINEMENT

127

value v , we define Append (σ, v ) to equal σ ◦ hv i, the sequence obtained byappending the item v to the end of σ. We define Seq(S ) to be the set of
all finite ordinal sequences whose items are in S . Thus, if σ ∈ Seq(S ) thenσ ∈ (1 . . Len(σ) → S ) .
The set difference operator \ is defined by

Set Difference∆

S \ T = {v ∈ S : ¬(v ∈ T )}In other words, S \ T is the set of elements of S that are not elements of T .

5.1.1

A One-Step Program

We refine Add by a program AddS in which a natural number is represented
by a finite ordinal sequence of decimal digits—that is, by an element of theset Seq(0 . . 9). For convenience, we number the digits from right to left, so
the sequence h1, 2, 3i represents the number 321. Thus a sequence seq of
digits represents the number Val (seq) defined as follows, where the empty
sequence is defined to represent 0.
∆

Val (seq) = if seq = h i then 0
else seq(1) + 10 ∗ Val (Tail (seq))Let ⊕ represent addition of numbers represented in this way as sequencesof digits. In other words, ⊕ satisfies
Val (s ⊕ t) = Val (s) + Val (t)for all sequences s and t of digits. We would expect Add to be refined by
the program AddS obtained by replacing + by ⊕ and N by Seq(0 . . 9) inthe definition of Add . To avoid confusing the variables of the two programs,
we’ll also replace x , y, z , and end by u, v , w , and fin, so AddS is defined
by:
InitS
NextS
vS
AddS

∆

=
∆
=
∆
=
∆
=

(fin = false) ∧ (u ∈ Seq(0 . . 9)) ∧ (v ∈ Seq(0 . . 9))¬fin ∧ (w 0 = u ⊕ v ) ∧ (fin 0 = true)hu, v , w , fin i
InitS ∧ 2[NextS ]vS

Exactly what does it mean for AddS to refine Add ? I believe the naturaldefinition is: If we look at any behavior of AddS and interpret the numbers
represented by the sequences u, v , and w of digits to be the values of x ,y, and z and we interpret the value of fin to be the value of end , then weCHAPTER 5. REFINEMENT

128

get a behavior of Add . More precisely, let “←” mean “is represented by”.
That AddS refines Add means that a behavior satisfying AddS represents abehavior satisfying Add with this representation of the variables of Add interms of the variables of AddS :(5.1) x ← Val (u)y ← Val (v )z ← Val (w )end ← finHere’s an example to illustrate this, where the first two-state sequence isa finite behavior satisfying AddS and the second two-state sequence is thefinite behavior it represents. Remember that AddS leaves unspecified thevalue of w in an initial state and the values of u and v in a halting state.
A “?” in the second behavior means the value is unspecified because, as
explained in Section 2.6, Val (seq) is a meaningless expression if seq isn’t asequence of numbers.
u :: h1, 2, 3i
 v :: h3, 2i 

√ 


 w ::2 
f in :: false 0→

x :: 321
 y :: 23  z :: ? end :: false 0

→









u :: h5i
 v :: −27  w :: h4, 4, 3i
f in :: true 1
x :: 5
 y :: ?  z :: 344 
end :: true 1

As you can see, the second finite behavior satisfies Add , since 321+23 equals
344 and end has the values the abstract program Add says it should.
Let’s look closely at this example. What it shows is that when we perform the substitutions (5.1) for the variables of Add in a behavior satisfying
formula AddS , we get a behavior that satisfies formula Add . In other words,
in any behavior: if the behavior satisfies AddS , then it satisfies the formula
Add when we perform the substitutions (5.1). This means that the following
formula is true:(5.2) |= AddS ⇒(Add with x ← Val (u), y ← Val (v ), z ← Val (w ), end ← fin)This is what it means for AddS to refine Add under the representation defined by (5.1). That representation is called a refinement mapping. Formula(5.2) asserts that AddS implements Add under this refinement mapping.
I find (5.2) beautiful. We’ve already seen that, viewed in terms of
TLA, step refinement is implication. Now we see that data refinement isCHAPTER 5. REFINEMENT

129

substitution—the ordinary mathematical operation of substituting expressions for variables in a formula. How beautifully simple! In science, beauty
is not an end in itself. It’s a sign that we’re doing something right.

5.1.2

Two Views of Refinement Mappings

There are two ways to view the refinement mapping (5.1) that appearsin (5.2). To understand them, let’s simplify things by ignoring irrelevant
variables and letting state mean program state—an assignment of values
to the program’s variables. Let an S -state be a state of AddS , which isan assignment of values to the variables u, v , w , and fin of AddS ; and letan A-state be an assignment of values to the variables x , y, z , and end of
Add . Let an S -behavior or A-behavior be a sequence of S -states or A-states,
respectively.
The first way to view the refinement mapping is as a mapping f thatmaps S -states to A-states. We can define the mapping fb from S -behaviors to∆
A-behaviors in terms of f by fb(σ)(i ) = f (σ(i )) for any S -behavior σ. That
AddS implements Add under the refinement mapping f means [[AddS ]](σ) ⇒[[Add ]](fb(σ)) for every S -behavior σ.
The second way to view refinement is expressed in (5.2), which states that
AddS implements Add under the refinement mapping means [[AddS ]](σ) ⇒[[Add with . . . ]](σ) for every S -behavior σ.
In the first view, the refinement mapping maps low-level behaviors tohigh-level behaviors—that is, behaviors of AddS to behaviors of Add . In
the second view, it maps the high-level formula Add to the low-level formula(Add with . . . ) . It may not be obvious, but these two views are equivalent.
They’re equivalent because(5.3) [[Add with . . . ]](σ) ≡ [[Add ]](fb(σ))
is true for every S -behavior σ. To understand why (5.3) is true, rememberthat the meaning [[F ]] of a formula F is defined in terms of the meanings of
its subformulas. Consider the subformula z 0 = x + y of Add , which appears
in its next-state action NextA. You should understand why (5.3) is true if
you understand why this is true:(5.4) [[(z 0 = x + y) with . . . ]](σ) ≡ [[z 0 = x + y]](fb(σ))
A proof of (5.4) is given in the Appendix. However, I recommend that you
try figuring out by yourself why it’s true.
The bidirectional nature of refinement mappings—from low-level behaviors to high-level behaviors and from high-level formulas to low-level

CHAPTER 5. REFINEMENT

130

formulas—is an example of a general mathematical principle. To explain it,
we need the concept of function composition. For any functions g and h,their composition g • h is defined to be the function whose domain is the∆domain of h such that (g • h)(d ) = g(h(d )) for any value d in the domainof h.1 (For any d in the domain of h, the expression g • h(d ) is meaningful
only if h(d ) is in the domain of g.)
Let’s suppose that the collections of S -behaviors and A-behaviors are
sets. For example, we can let them be behaviors that satisfy suitable typeinvariants. Formula (5.3) can then be written:(5.5) [[Add with . . . ]] ≡ [[Add ]] • fb
In general, suppose L and H are sets and ψ ∈ (L → H ), so the function
ψ maps elements of L to elements of H . For any set V , the function ψ←←
determines a function ψ in (H → V ) → (L → V ), so ψ maps functions←
from H to V to functions from L to V . The function ψ is defined by←∆
ψ(g) = g • ψ. Pictorially, we have:
L

ψ
−→

H

←

ψ
(L → V ) ←− (H → V )Refinement mappings are the special case in which L is the set of S -behaviors,
H is the set of A-behaviors, V is the set {true, false} of Booleans, and ψ
is fb.

5.1.3

A Step and Data Refinement

Section 3.5.1 illustrated step refinement by showing that an hour-minutesecond clock refines an hour-minute clock. We have just illustrated data
refinement by showing that AddS implements Add under a refinement mapping. We now show an example that involves both step and data refinement.
The example involves an algorithm AddSeq that adds numbers the way
you probably learned to add them as a child. However, we represent thosenumbers as sequences of digits in the reverse order, as they are in program
AddS , with the low-order digit being the first one in the sequence. It sets
sum equal to u ⊕ v , where u and v are numbers represented by strings ofdigits. The algorithm computes sum digit by digit, keeping it equal to theright-most digits of the sum computed so far. Each step removes the first
1
Mathematicians generally use “·” or “◦” to denote function composition, but we havedefined those symbols to mean other things.

CHAPTER 5. REFINEMENT

131

variables u ∈ DigitSeq, v ∈ DigitSeq, sum = h i, carry = 0, pc = a ;while a: (u 6= h i) ∨ (v 6= h i) ∨ (carry 6= 0) do∆

define digit = Fix (u)(1) + Fix (v )(1) + carry;sum : = Append (sum, digit % 10) ;carry : = bdigit / 10c
end define ;u : = Tail (Fix (u)) ;v : = Tail (Fix (v ))end while ;carry : = 0
Figure 5.1: Algorithm AddSeq.
(right-most) digit from u and v and appends the next (left-most) digit tosum, setting carry equal to the value 0 or 1 “carried over” from that sum.
A pseudocode description of the algorithm is in Figure 5.1, but it uses
some notation that requires explanation. Recall that Append (seq, val ) isdefined in Section 2.8.3 to equal seq ◦ hval i, the sequence obtained by appending the value val to the end of the sequence seq of values. The code
assumes that DigitSeq is the set Seq(0 . . 9) \ {h i} of nonempty finite sequences of the digits 0 through 9. If u and v are of unequal length, then
the number of steps taken by the algorithm you learned in school is usuallyequal to or one greater than the length of the longer number. For simplicity,
the number of steps taken by AddSeq always equals one plus the length ofthe longer number. To simplify the description of what happens when thealgorithm runs out of digits in one of the numbers, it uses the operator Fix
defined as follows to replace the empty sequence by h0i:∆

Fix (seq) = if seq = h i then h0i else seq
The algorithm’s define statement defines digit to equal the indicated expression within that statement. The value of bn/10c is the greatest integer
less than or equal to n/10. To simplify the invariant, AddSeq specifies theinitial value of carry to equal 0 and ensures that it equals 0 at the end. Since
the low-order digit of a two-digit number n is n % 10 and its high-order digit
is bn/10c, it should be clear that AddSeq describes an algorithm for adding
two decimal numbers. (If it’s not, execute it by hand on an example.)
The usual way to express correctness of a program that computes a value
sum and stops is with an invariant asserting that if the program has stopped

CHAPTER 5. REFINEMENT

132

then sum has the correct value. We can’t do that with AddSeq because thecorrect value of sum is the initial value of u ⊕ v , and those initial values
have disappeared by the time the program stops. To express correctness, we
can add a constant ans that equals the initial value of u ⊕ v . Since stoppingmeans pc equals done for our pseudocode, correctness means:(5.6) |= AddSeq ⇒ 2((pc = done) ⇒ (ans = sum))
The key part of an inductive invariant to prove (5.6) is the assertion thatans equals the final value of sum. A first approximation to the final valueof sum is:sum ◦ (hcarry i ⊕ (u ⊕ v ))We haven’t said what s ⊕ t means if s or t is the empty sequence, but it’s
clear that we should define the empty sequence to represent 0. However, aclose examination of the algorithm indicates that if u and v both equal h iand carry = 0, then this expression equals a sequence with an extra 0 at theend. The correct assertion that is the key to the inductive invariant is(5.7) ans = if (u ◦ v = h i) ∧ (carry = 0)then sum else sum ◦ (hcarry i ⊕ (u ⊕ v ))The remainder of the inductive invariant asserts type correctness and thatpc = done implies that u, v , and carry have their correct final values.
However, the point of this example is not that AddSeq implements aparticular procedure for adding sequences of digits; it’s that it refines theabstract program Add that adds two integers in a single step. This is adramatic example of step refinement, in which a program that can take arbitrarily many non-stuttering steps to finish refines one that always finishes
in one non-stuttering step. And we don’t have to add the constant ans to
do it.
Under the refinement mapping, one step in an execution of AddSeq mustrefine a NextA step of Add ; all the other steps must refine stuttering stepsof Add . The initial values of the variables x and y of Add should equal the
initial values of Val (u) and Val (v ). The initial values of u and v are nolonger deducible from the state after AddSeq takes it first step. This tells usthat the NextA step of Add must be refined by the first non-stuttering stepof AddSeq.
An Add step changes the value of its variable done from false to true.
So, the refinement mapping must assign to done an expression whose value
is changed from false to true by the first non-stuttering step of AddSeq.

CHAPTER 5. REFINEMENT

133

Since further steps of AddSeq refine stuttering steps of Add , the expression
assigned to done must remain true for the rest of the execution of Add . A
suitable expression is sum 6= h i, so we let the refinement mapping include
done ← sum 6= h i.
In the initial state of AddSeq, the refinement mapping should assign to x
and y the values of u and v . Since Add allows x and y to have any values in
its final state, it doesn’t matter what values the refinement mapping assigns
to x and y after the first step of AddSeq. However, since later steps mustrefine stuttering steps of Add , the values of x and y must not change. Zeroseems like a nice value to let x and y equal when their value no longer
matters, so we let the refinement mapping include:x ← if sum 6= h i then 0 else Val (u) ,y ← if sum 6= h i then 0 else Val (v )Finally, we must decide what value the refinement mapping assigns to z .
If we add to AddSeq the constant ans that always equals the result the algorithm finally computes, then we can substitute Val (ans) for z . But wedon’t have to add it because the invariant (5.7) tells us what expression containing only the variables of AddSeq always equals ans. We could therefore
substitute for z the expression obtained by applying Val to the right-handside of equation (5.7). However, there’s a simpler expression that we canuse. Convince yourself that the following substitution works:z ← Val (sum) + 10Len(sum) ∗ (carry + Val (u) + Val (v ))This completes the refinement mapping. That AddSeq implements Add
under the refinement mapping means that this theorem is true:|= AddSeq ⇒ (Add withdone ← sum 6= h i ,x ← if sum 6= h i then 0 else Val (u) ,y ← if sum 6= h i then 0 else Val (v ) ,z ← Val (sum) + 10Len(sum) ∗ (carry + Val (u) + Val (v )))5.2

Invariance Under Refinement

If an abstract program T implements an abstract program S under a refinement mapping, and Inv is an invariant of S , then the refinement mapping
maps Inv to an invariant of T . The precise statement of this is the following
theorem, where “. . . ” is any refinement mapping.

CHAPTER 5. REFINEMENT

134

Theorem 5.1 |= T ⇒ (S with . . .) and |= S ⇒ 2Inv imply|= T ⇒ 2(Inv with . . .) .
The proof is simple:
1. |= S ⇒ 2Inv implies |= (S ⇒ 2Inv ) with . . . .
Proof: Substitution in a true formula produces a true formula
2. |= (S ⇒ 2Inv ) with . . . equals |= (S with . . .) ⇒ 2(Inv with . . .) .
Proof: By definition of what substitution means.
3. Q.E.D.
Proof: The theorem follows from steps 1 and 2 by propositional logic.
Recall the trick used in Section 3.2.3 to obtain an invariant of FGSqrs
from an invariant of the coarser-grained algorithm Sqrs. We replaced thevariable y by the expression yy in the invariant of Sqrs. That trick was
an application of the theorem, because FGSqrs implements Sqrs under therefinement mapping x ← x , y ← yy.

5.3

An Example: The Paxos Algorithm

We’ve seen step and data refinement for a sequential abstract program. Concurrency adds nothing new. Refinement works exactly the same for concurrent programs. This is illustrated with the Paxos consensus algorithm, an
example chosen for the following reasons:• It’s a distributed algorithm. Quite a few researchers used to believethat different techniques are needed to reason about correctness of distributed programs; perhaps some still do. Paxos illustrates that there
is no mathematical difference between distributed and non-distributed
concurrent programs. In fact, Paxos is obtained as a refinement of anon-distributed algorithm.
• It’s a widely used algorithm. If you perform any commercial transaction on the Web, there is a good chance that Paxos or an algorithm
inspired by it is being executed by a program running on the computersthat perform the transaction.
• It illustrates the importance of abstraction. Thinking scientificallymeans thinking abstractly. The abstract programs in this example are
more abstract than ones most computer scientists and engineers would

CHAPTER 5. REFINEMENT

135

think of. Learning to think more abstractly is the key to building
better complex computer systems.
• The complete TLA+ specifications of the abstract programs, as well
as videos of a pair of lectures that explain them, are available on the
Web [26]. Therefore, the abstract programs are only sketched here.
The Paxos algorithm was invented (at least) twice, first by Barbara Liskov
and Brian Oki [42] and then by me.

5.3.1

The Consensus Problem

One reason for building distributed systems is fault tolerance. Systems
implemented by multiple computers are often required to operate normallyeven if one or more of the computers fail. What a system should do can be
described as a single-process abstract program that executes a sequence ofcommands it receives as inputs. Correct execution of the system by multiple
computers requires that all the computers agree on what that sequence of
inputs is. This is achieved by having all the computers agree on what the i th
input is for every i . Ensuring that all the computers agree on a single input
is called consensus. A fault-tolerant system repeatedly executes a consensus
algorithm to choose a sequence of inputs.
I was inspired to invent the Paxos algorithm because colleagues werebuilding a distributed fault-tolerant system. I realized that the system
had to implement consensus, so it should implement a consensus algorithm.
However, my colleagues were writing code; they didn’t have an algorithm. I
never found out how their program implemented consensus. But based on
the state of the art of programming at the time, here is what their program
might have done.
A process called the leader, running on a single computer, receives all
input requests and decides what input should be chosen next. A new leader
will have to be selected if the initial leader fails, but we’ll worry about thatlater. (Failure of a process usually means failure of the computer executing
the process.) For the system to keep running despite the failure of individualcomputers, a set of processes called acceptors, each running on a different
computer, have to know what value was chosen. Moreover, only a subset ofthe acceptors should have to be working (that is, not failed) for an input tobe chosen. If an input v is chosen by a leader and a set of acceptors, andthe leader and those acceptors fail, then a different leader and a different setof acceptors must not choose an input different from v . The obvious way
to ensure that is to require a majority of the acceptors to agree upon theCHAPTER 5. REFINEMENT

136

input v in order for that input to be chosen. Any two majorities have atleast one acceptor in common, and that acceptor will know that it agreed
to the choice of v .
This reasoning leads to the following algorithm: The leader decides what
input v should be chosen. It sends a message to the acceptors saying thatthey should agree to the choice of v . Any working acceptor that receives themessage replies to the leader with a message saying “v is OK”. When theleader receives such an OK message from a majority of acceptors, it sends
a message to all the acceptors telling them that v has been chosen.
This algorithm works fine, and the system keeps choosing a sequence of
inputs, until the leader fails. At that point, a new leader is selected. The
new leader sends a message to all the acceptors asking them what they’ve
done. In particular, the new leader finds out from the acceptors if inputs
were chosen that it was unaware of. It also finds out if the previous leader
had begun trying to choose an input but failed before the input was chosen.
If it had, then the new leader completes the choice of that input. When the
new leader has received this information from a majority of acceptors, it
can complete any uncompleted choices of an input and begin choosing new
inputs. Let’s call this algorithm the naive consensus algorithm.
There’s one problem with the naive algorithm: How is the new leader
chosen? Choosing a single leader is just as hard as choosing a single input.
The naive consensus algorithm thus assumes the existence of a consensus
algorithm. However, because leader failures should be rare, choosing a leader
does not have to be done efficiently. So, programmers would probably haveapproached the problem of choosing a leader the way they approached mostprogramming problems. They would have found a plausible solution andthen debugged it. Debugging usually means thinking of all the things that
could go wrong and adding code to handle them.
Let’s pause and look at the science of consensus. Before Paxos, there
were consensus algorithms that worked no matter what a failed process
could do [46]. However, they were synchronous algorithms, meaning thatthey assumed known bounds on the time required for messages sent by one
process to be received and acted upon by another process. They were notpractical for the loosely coupled computers that had become the norm by the
1980s. Although asynchronous algorithms were required, they had to solve a
simpler problem because sufficiently reliable systems could be based on theassumption that a process failed by stopping and could not perform incorrect
actions. However, the FLP theorem, named after Michael Fischer, Nancy
Lynch, and Michael Paterson who discovered and proved it, states that no
asynchronous algorithm can implement consensus if even a single process canCHAPTER 5. REFINEMENT

137

fail in this benign way [13]. More precisely, any algorithm that ensures thesafety property that two processes never choose different values must allow
behaviors that violate the liveness property that requires a value eventually
to be chosen if enough processes are working and can communicate with one
another. Asynchronous algorithms that ensure liveness must allow behaviors
in which processes disagree about what input is chosen.
The leader-selection code programmers would have written therefore had
to allow either behaviors in which two processes thought they were theleader, probably with serious consequences, or else behaviors in which noleader is selected, causing the system to stop choosing values. With a properly designed algorithm, the probability of never choosing the leader is zero,and a leader will be chosen fairly quickly if enough of the system is working
properly. The system my colleagues built ran for several years with about
60 single-user computers, and I don’t think their consensus code caused any
system error or noticeable stalling. There is no way to know if it had errorsthat would have appeared in today’s systems with thousands of computers
and many thousands of users.

5.3.2

The Paxos Consensus Algorithm

We develop the Paxos consensus algorithm as a series of three abstract
programs: a trivial specification of the problem the algorithm solves, whichis refined by a non-distributed multiprocess algorithm, which is refined by
the Paxos algorithm. I believe that this description—in particular, its viewof Paxos as a refinement of the non-distributed algorithm—mirrors how I
actually found the algorithm.
Only the safety properties of these abstract programs are described. In
most applications, violation of safety in a consensus algorithm can be quite
serious—for example, causing money deposited to a client’s bank accountto disappear. We will see later how the algorithm can be implemented toalmost always achieve liveness while never violating safety. As mentioned
above, the abstract programs are just sketched; complete descriptions areavailable on the Web [26].
5.3.2.1

The Specification of Consensus

Instead of talking about inputs, we define consensus as choosing an elementof some set Value of values. Most correctness proofs of consensus algorithms
prove only that they satisfy the invariance property that two processes neverchoose different values. A consensus algorithm must also not allow a value

CHAPTER 5. REFINEMENT

138

to be unchosen and a different value then chosen. Proving the invarianceproperty is usually sufficient because it’s obvious that the algorithm doesn’tallow a value to be unchosen. But to illustrate refinement, we write a highlevel abstract program that rules out such a possibility.
There are a number of reasonable ways to describe consensus as an abstract program, and it makes little difference which one is used. Perhaps
the most obvious way is with a multiprocess abstract program in which
each process independently learns what value is chosen. The next-state action would allow a process p that has not learned a value to learn one, withthe constraint that if any process has learned that the value v was chosen,
then p must also learn that v was chosen.
We take a different approach and let the abstract program describe only
the choosing of a value, without mentioning processes that learn the chosen
value. This abstract program has a single variable chosen that represents
the set of values that have been chosen. (In any behavior allowed by the
program, that set always has at most one value.) The initial predicate ischosen = {}, and the next-state action is:(chosen = {}) ∧ (∃ v ∈ Value : chosen 0 = {v })As explained above, there is no fairness condition.
5.3.2.2

The Voting Algorithm

In the naive algorithm, leader and acceptor processes communicate by sending messages. It’s natural to think about a consensus algorithm in termsof messages being sent. However, remember that we reason about an abstract program in terms of its state, so we should be thinking about states,
not about sending messages. And the important part of the state is thestate of the acceptors. So, we refine the Consensus program with an abstract program called the Voting algorithm whose state is just the state of
the acceptors. This is not just a nice way to describe the Paxos algorithm.
Viewing Paxos as a refinement of the non-distributed voting algorithm iswhat enabled me to discover Paxos.
In good programming, we begin by abstracting away lower-level details
and getting the high-level design right. There’s a kind of bad programmingthat sounds similar: We begin writing something that handles the normal
behavior, and we then modify it to handle non-normal situations. That’s
the way the naive consensus algorithm was described, and it’s a recipe forcreating incorrect programs—both abstract and concrete ones. We should
start thinking about the general case, not the normal case.

CHAPTER 5. REFINEMENT

139

The general state of acceptors in the naive algorithm is one that isreached after a number of leaders have begun trying to get a value chosen, and some of them may have succeeded. When a leader tries to get aparticular value chosen, we say that the leader has begun a ballot. Whenan acceptor has sent an OK message for a value v in that ballot, we saythat the acceptor has voted for v in that ballot. The algorithm will assign
a unique natural number to each ballot.2 The state of the Voting algorithm
records all the votes that each acceptor has cast. This is described by avariable votes whose value is a function that assigns to each acceptor a a
set votes(a) of pairs hb, v i where b ∈ N and v ∈ Value. The pair hb, v i invotes(a) means that a has voted for v in ballot number b.
Choosing a leader is the weak point in the naive algorithm. The Voting
algorithm abstracts away the leaders. A leader serves two functions. The
first is to ensure that in any ballot, acceptors can cast votes only for thevalue proposed by the leader. The Voting algorithm’s next-state action
takes care of that by not letting an acceptor cast a vote for a value v inballot b if a vote has already been cast in ballot b for a different value. The
second function of the leader is to learn that a value has been chosen, which
it does when it has received enough OK messages. The Voting algorithm
does away with that function by declaring that the value has been chosenwhen the requisite number of OK messages have been sent—that is, when
there are enough votes cast for the value in the ballot. More precisely, wedefine ChosenAt(b, v ) to be true iff a majority of acceptors has voted for v inballot b. The Voting algorithm implements the Consensus abstract program
under the refinement mapping(5.8) chosen ← {v ∈ Value : ∃ b ∈ N : Chosen(b, v )}In addition to votes, the algorithm has one other variable maxBal whose
value is a function that assigns to each acceptor a a number maxBal (a).
The significance of this number is that a will never in the future cast a votein any ballot numbered less than maxBal (a). The value of maxBal (a) is
initially 0 and is never decreased. The algorithm can increase maxBal (a) at
any time.
It may seem strange that the state does not contain any information
about what processes have failed. We are assuming that a failed process doesnothing. Since we are describing only safety, a process is never required to2
Don’t confuse different ballots with the different instances of the consensus algorithm
being executed. Execution of an instance of the consensus algorithm can consist of multiple
ballots.

CHAPTER 5. REFINEMENT

140

do anything, so there is no need to tell it to do nothing. A failed process thathas been repaired can differ from a process that hasn’t failed because it may
have forgotten its prior state when it resumes running. A useful property
of a consensus algorithm is that, even if all processes fail, the algorithm canresume its normal operation when enough processes are repaired. To achievethis, we require that a process maintains its state in stable storage, so it isrestored when a failed process restarts. A process failing and restarting isthen no different from a process simply pausing.
The heart of the Voting algorithm is a state expression SafeAt(b, v ) thatis true iff ChosenAt(c, w ) is false and will remain false forever for any c < band w 6= v . That it will remain false forever can be deduced from the current
state, because the next-state action implies both that a process a will not
cast a vote in ballot c when c < maxBal (a) and that maxBal (a) can neverdecrease. The key invariant maintained by the algorithm is(5.9) ∀ a ∈ Acceptor , b ∈ N, v ∈ Value :(hb, v i ∈ votes(a)) ⇒ SafeAt(b, v )where Acceptor is the set of acceptors. The next-state action allows a process
a to perform either of two actions:• Increase maxBal (a). This action is always enabled.
• Vote for a value v in a ballot numbered b. As already explained, thisaction is enabled only if no process has voted for a value other thanv in ballot b and b ≥ maxBal (a). An additional enabling condition isrequired to maintain the invariance of (5.9).
I have given you all the information you need to figure out the definitionof SafeAt(b, v ) and the enabling condition on acceptors needed to maintainthe invariance of (5.9). Can you do it? Few people can. I was able to
only because I had simplified the problem to finding an abstract program
whose only processes are the acceptors and whose state consists only of theset of votes cast and the value of maxBal . I had abstracted away leaders,messages, and failures.
The Voting algorithm requires an acceptor to know the current state ofother acceptors to decide what vote it can cast. How can this lead to a
distributed consensus algorithm? I abstracted away leaders and messages; I
didn’t ignore them. I knew that an acceptor didn’t have to directly observe
the state of other acceptors to know that they hadn’t voted for some value
other than v in a ballot. The acceptor could know that because of a message
it received from a leader. I also knew that it could deduce that the otherCHAPTER 5. REFINEMENT

141

enabling conditions were satisfied from messages it received. Abstracting
away leaders and messages enabled me to concentrate on the core problemof achieving consensus. The solution to that problem told me what theleaders should do and what messages needed to be sent.
5.3.2.3

The Paxos Abstract Program

The Voting algorithm told me what messages needed to be sent. But I had todecide how to represent message passing in an abstract program. Languages
expressly designed for describing distributed algorithms usually don’t require us to make that decision because they provide built-in message-passing
primitives. However, different distributed algorithms and distributed systems have different requirements for message passing. They may or may not
tolerate lost messages; they may or may not require messages to be delivered in the order they are sent; they may or may not require that the samemessage not be received twice; and so on. Our abstract programs requirethat we choose how to represent message passing, but they make it easy torepresent any form of message passing we want.
I have found that most computer scientists and engineers are constrainedby thinking in terms of how messages are transmitted in actual systems.
They think of messages being sent on communication channels between processes. Few of them would come up with the simple representation of message passing I used in the Paxos abstract program—a representation that is
obvious if one thinks mathematically.
Paxos doesn’t require that messages be delivered in the order in which
they are sent, so there is no need for message channels. The receiver ofa message can be inferred from the message, so we can just have a set of
messages. Paxos tolerates the same message being received multiple times
by a process, so there is no need to remove a message when it is received.
This means that if the same message is sent to multiple recipients, there
is no need for multiple copies of the message. There is also no need for aseparate action of receiving a message. An action that should be taken uponreceipt of a message simply has the existence of that message in the set ofsent messages as an enabling condition. Paxos tolerates message loss. But
since we are describing safety, there’s no difference between a lost message
and a message that is sent but never received. So, there is no need ever toremove messages that have been sent.
We can therefore represent message passing with a variable msgs whose
value is the set of all messages that have been sent. A message is sent byadding it to the set msgs. The presence of a message in msgs enables anCHAPTER 5. REFINEMENT

142

action that should be triggered by the receipt of the message. The algorithm
has a variable maxBal that implements the variable of the same name inthe Voting algorithm. It also has two other variables MaxVBal and MaxVal
whose values are functions with domain the set of acceptors. They are
explained below.
The Paxos consensus algorithm can be viewed as a multiprocess algorithm containing two sets of processes: the acceptors that implement theacceptors of the Voting algorithm, and an infinite set of processes, one foreach natural number, where process number b is the leader of ballot number b. More precisely, the ballot b leader orchestrates the voting by theacceptors in ballot b of the Voting algorithm.
The next-state action of the algorithm could be (but isn’t literally) written in the form ∃ b ∈ N : BA(b) where BA(b) describes how ballot b is performed. The ballot consists of two phases. In phase 1, the ballot b leader
sends a message to the acceptors containing only the ballot number b. An
acceptor a ignores the message unless b > maxBal (a), in which case it sets
maxBal (a) to b and replies with a message containing a, b, MaxVBal (a),and MaxBal (a). When the ballot b leader receives those messages from amajority of the acceptors, it can pick a value v to be chosen, where v is either a value picked by the leader of a lower-numbered ballot or an arbitraryvalue. The complete algorithm describes how it picks v . Phase 2 begins
with the leader sending a message to the acceptors asking them to vote forv in ballot b. An acceptor a ignores the message unless b ≥ maxBal (a), in
which case a sets maxBal (a) to b and replies with a message saying that it
has voted for v in ballot b.
The Paxos algorithm implements the Voting algorithm under a refinement mapping in which the variable votes of Voting is implemented by theexpression defined in the obvious way from the set of votes reported byacceptors’ phase 2 messages in msgs, and in which the variable maxBalof Voting is implemented by the variable of the same name in the Paxos
abstract program.
The values of maxVBal and maxVal can be described as functions of
the value of votes. For any acceptor a, the pair hmaxVBal (a), maxVal (a)iequals the pair hb, v i in the set votes(a) with the largest value of b. (Initially, when votes(a) is the empty set, it equals h−1, None i for some special
value None.) Making maxVBal and maxVal variables rather than state
expressions makes it clear that they are the only information about whatmessages have been sent that needs to be part of the acceptors’ states.

CHAPTER 5. REFINEMENT

5.3.3

143

Implementing Paxos

An implementation of the Paxos consensus algorithm would add a third
phase to each ballot in which the leader sends a message announcing that avalue v had been chosen after it receives phase 2 messages telling it that amajority of acceptors had voted for v in the ballot. With that addition, aballot of the Paxos algorithm looks like what the naive algorithm does whena new leader has been selected. Phase 1 of a Paxos ballot corresponds tothe new leader finding out if it needs to complete the choosing of a value
proposed by the failed leader. Phase 2 corresponds to the leader completingthe choosing of a previously proposed value or choosing a new value.
In Paxos, a leader performs phase 1 in every instance of the consensus algorithm, while in the naive algorithm it performs the corresponding actions
only once when it is selected. This makes Paxos seem much less efficient,since leaders are infrequently replaced. However, the value to be chosen isn’t
selected until phase 2. This means that phase 1 can be executed simultaneously for a ballot numbered b in all instances of the consensus algorithm
the first time ballot b is executed for any instance. A single message canserve as the leader’s phase 1 message for all instances. A single message
can also contain the phase 1 responses of a particular acceptor for all the
instances, since there is only information to be transmitted for consensus
instances that have begun but not yet chosen a value. Thus Paxos uses thesame number of messages to choose a value as the naive algorithm.
The Paxos consensus algorithm is an efficient algorithm that has been
proved to satisfy the safety requirement of consensus. We still have to see
how to get it to satisfy the liveness requirement of actually choosing a value.
To solve a problem, we need to understand it, and it’s easy to understandwhat prevents Paxos from choosing a value. An acceptor a participating inballot number b sets maxBal (a) to b, preventing it from responding to any
message from the leader of any ballot numbered less than b. Even in theabsence of failures or message loss, no value will ever be chosen if higher andhigher numbered ballots are begun before any ballot chooses a value.
Conversely, if ballot number b is started and no higher-numbered ballot
is begun, and if the ballot b leader and a majority of acceptors are working, then liveness assumptions that require working processes eventually toperform enabled actions (which implicitly assume that messages sent are
eventually delivered) imply that a value is eventually chosen. This observation can be stated mathematically as a temporal logic formula and proved.
However, it is so obviously true that, to my knowledge, no one has everbothered doing it.

CHAPTER 5. REFINEMENT

144

How do we assure that a ballot numbered b is started and no highernumbered ballots are? Paxos uses an infinite number of leader processes—
one for each ballot number. Those infinitely many processes are executedby a finite number of computers, with each ballot number pre-assigned toa single computer that executes the leader of the corresponding ballot. A
single computer, called the coordinator, is selected to be the only one that
executes leader processes, and it is easy to add messages that allow it tofind a ballot number higher than the values of mbal (a) for a majority ofacceptors a.
Like the naive algorithm, Paxos depends on selecting a single coordinator. However, the naive algorithm can fail to maintain its safety requirement
if two different computers believe they are the coordinator. If that happens
with Paxos, safety is preserved; the algorithm just fails to make progress.
An algorithm for choosing a coordinator in Paxos needs to work only most of
the time, a much easier problem to solve. One solution uses a synchronousalgorithm that implements consensus assuming known bounds on the times
needed to transmit and process messages. That algorithm chooses the coordinator assuming values for those bounds that will be satisfied most of the
time.

5.4

Proving Refinement

This section sketches how to prove that one abstract program refines another. We use as an example the proof that the One-Bit mutual exclusion
algorithm OB of Section 4.2.5.2 refines program LM of Figure 4.6, assuming
a weakly fair semaphore.
The proof uses identifiers from the definition of OB and ones from thedefinition of LM . To avoid confusion, we indicate to which program an
identifier belongs with a subscript. We defined OB to equal:
Init ∧ 2[Next]v ∧ Fair∆

where Next = ∃ p ∈ {0, 1} : PNext(p)∆Fair = ∀ p ∈ {0, 1} : WFv (PNext(p))
We now add subscripts to that definition, so OB equals:
InitOB ∧ 2[NextOB ]vOB ∧ FairOB
We assume LM has the same definition, except with the subscripts LM .
We sometimes use subscripts even when they aren’t necessary—for example
writing xOB even though LM has no variable named x .

CHAPTER 5. REFINEMENT145

We define OBSafe and OBFair as before, so OB equals OBSafe∧OBFair .
We define LMSafe and LMFair similarly. As expected, safety and livenessare proved separately. We first show that OBSafe refines LMSafe. (Bymachine closure of hOBSafe, OBFair i and Theorems 4.3 and 4.5, OBFair
isn’t needed to prove that OB refines LMSafe.) We then show that OB
implies LMFair . However, first we must define the refinement mapping
under which OB implements LM .

Math VIII
Hierarchical Proofs Thus far, our structured proofs have consisted of asingle list of steps. That doesn’t work for the long proofs needed to prove
complex results, such as correctness of the abstract programs that engineers
write. The method of handling complexity that’s obvious to an engineer ishierarchical structuring. With structured proofs, a proof consists of either aparagraph proof or a sequence of steps, each step having a proof. The last
step in a proof consisting of a sequence of steps is a Q.E.D. step.
The steps of a top-level proof are numbered 1, 2, etc. The steps of a
proof of step number 2 are numbered 2.1, 2.2, . . . . The steps of a proof ofstep number 3.4 are 3.4.1, 3.4.2, . . . and so on. The lowest-level proofs areparagraph proofs. A step can be used only in the proof of later steps of thesame proof. For example, the assertion proved as step 3.4.2 can be used in
the proofs of steps 3.4.4 and 3.4.5.1, but not in the proof of step 3.5. This
ensures that a step is used only where the assumptions under which the step
was proved still hold.
This numbering scheme works for three or four levels. For deeper proofs,
we can abbreviate step number 2.7.4 as h3i4 because it’s step number 4 ofa depth-3 proof. Although many step numbers can have the same abbreviation, at most one of those steps can be used at any point in the proof [37].
For reliable proofs, the paragraph proofs should be short enough sothey’re easy to understand and obviously correct. If a paragraph proof isn’t
obviously correct, it should be decomposed into a sequence of steps. Somesteps need deeper proofs than others. The proofs of Q.E.D. steps should
usually be paragraphs. My rule of thumb is to decompose a proof until I’msure that every paragraph proof is correct, then decompose the paragraphproofs one level further. The proofs in this book haven’t been carried down
to that level. This was to keep the book from being too long, and because no
program will crash if there’s a small mistake in one of the book’s theorems.
For machine-checked proofs, paragraph proofs are replaced by instructions to the prover. The proof must be decomposed into steps that are simple

CHAPTER 5. REFINEMENT

146

enough for the prover to check, which may sometimes be infuriatingly simple. This should eventually change as machine learning is applied to proof
checking. Some proof checkers don’t support hierarchical structuring. They
require you to do the structuring by hand. If you don’t structure the proof,
you will wind up with an unmanageable unstructured mass of lemmas whentrying to prove the correctness of a complex abstract program.
Suffices Proof Steps A mathematical proof of a formula G often begins
by showing that, to prove G, it suffices to prove F . That step in a proof isrepresented in our structured proof style by a Suffices step.
At any step in a proof, there is a current goal. The current goal at thefirst step is the assertion to be proved. The statement Suffices: F changes
the current goal to F . If G is the current goal at this Suffices statement,
then the statement’s proof must prove Assume: F Prove: G . That is, theproof must prove G assuming that F is true.
The Suffices statement can be used with an Assume/Prove to assertthat to prove the current goal, it suffices to assume E is true and prove F
is true. The statement
Suffices: Assume: E
Prove: Fchanges the current goal to F , and it adds E to the set of formulas that canbe assumed true by the following steps of the current proof. The proof ofthis statement is the same as the proof of Suffices: E ⇒ F .

5.4.1

The Refinement Mapping

To define the refinement mapping, it’s helpful to think of a single behavior
in which the variables xOB and pcOB describe a behavior of program OB andthe variables semLM and pcLM describe the corresponding behavior of LM
that is implemented by OB under the refinement mapping. To determine
what the refinement mapping should be, for each possible step in such abehavior that changes the values of the variables of LM , we decide how thatstep should change the values of OB .
For example, if a step of the behavior describes the execution of statement cs by a process p of LM , then it should describe the execution of cs byprocess p of OB . Thus, when the value of pcLM (p) changes from cs to exit,
the value of pcOB (p) should also change from cs to exit. Reasoning in thisway, we see that the values of pcLM (p) and pcOB (p) should be equal exceptthat when pcLM (p) equals wait, the value of pcOB (p) can be wait, w 2, w 3,

CHAPTER 5. REFINEMENT

147

or w 4. This tells us that the refinement mapping must substitute for pcLM
the value pcBarOB defined by:∆

pcBarOB = p ∈ {0, 1} 7→ if pcOB (p) ∈ {w 2, w 3, w 4} then wait
else pcOB (p)In a behavior satisfying LM , the value of semLM can be deduced from thevalue of pcLM . In particular, semLM equals 0 iff pcLM (p) equals cs or exit for
one of the processes p. From the definition of pcBarOB , this means that therefinement mapping must substitute for semLM the value semBarOB definedby:∆semBarOB = if (∃ p ∈ {0, 1} : pcOB (p) ∈ {cs, exit}) then 0 else 1
That OB refines LM under this refinement mapping means:(5.10) |= OB ⇒ (LM with pcLM ← pcBarOB , semLM ← semBarOB )We’ll be using a lot of formulas that are obtained from formulas FLM bymaking the substitutions defined by the refinement mapping for the variablesof LM . To keep from having lots of withs, we use this abbreviation, forany formula FLM :∆FLM = (FLM with pcLM ← pcBarOB , semLM ← semBarOB )Thus, (5.10) can be written |= OB ⇒ LM . Also, pcLM equals pcBarOB andsemLM equals semBarOB (which explains the suffix Bar in the names pcBarand semBar ).

5.4.2

Refinement of Safety

We now sketch the proof that OBSafe refines LMSafe, which means theproof of(5.11) |= OBSafe ⇒ LMSafe
By the definitions of these formulas, this requires proving:(5.12) (a) |= InitOB ⇒ InitLM(b) |= InitOB ∧ 2[NextOB ]vOB ⇒ 2[NextLM ]vLM
The proof of (a) is simple. To prove (b), we use the invariant InvOB of OB ,which is defined by (4.19), where TypeOK is defined by (4.17). That is, we
assume:(5.13) |= OBSafe ⇒ 2InvOB

CHAPTER 5. REFINEMENT

148

To prove (5.12b), it suffices to prove(5.14) |= InvOB ∧ [NextOB ]vOB ⇒ [NextLM ]vLM
By definition of [. . .]v , we can prove (5.14) by proving:(5.15) (a) |= InvOB ∧ NextOB ⇒ NextLM ∨ (vLM 0 = vLM )(b) |= (vOB 0 = vOB ) ⇒ (vLM 0 = vLM )Part (b) is trivial, since vLM is defined in terms of the variables of vOB . For
part (a), propositional logic tells us that we prove F ∧ (G 1 ∨ . . . ∨ G n ) ⇒ H
by proving F ∧ G i ⇒ H for each i . So, we decompose the proof of part (a)by writing NextOB as the disjunction of subactions.
We use the notation introduced in Section 4.2.6 of naming the action
described by a labeled statement with the capitalized label. For example,
CsOB (p) is the action described by statement cs of process p of program
OB . We decompose the proof of (5.15a) into proving:(5.16) |= InvOB ∧ LblOB (p) ⇒ NextLM ∨ (vLM 0 = vLM )for each label lbl in Figure 4.3 and p in {0, 1}.
Condition (5.16) asserts that a step of OB described by the statement
labeled lbl implements a step of LM under the refinement mapping. We
defined the refinement mapping to make that true, so we should be able
to prove this assertion. We prove it by showing that each action LblOB (p)implements some particular subaction of NextLM . In particular, we prove thefollowing seven assertions R1–R7. Three of them assert that actions of OB
imply actions of the form hALM ivLM . For proving that OB implies LMSafe,
we need only the weaker assertions obtained by replacing such an action by
ALM . However, we will need the stronger assertions later for proving that
OB implies LMLive.
R1. |= InvOB ∧ NcsOB (p) ⇒ NcsLM (p)R2. |= InvOB ∧ WaitOB (p) ⇒ (vLM 0 = vLM )R3. |= InvOB ∧ W 2OB (p) ⇒if p = 0 then hWaitLM (0)ivLMelse if xOB (0) then vLM 0 = vLM
else hWaitLM (1)ivLM
0
R4. |= InvOB ∧ W 3OB (p) ⇒ (vLM = vLM )R5. |= InvOB ∧ W 4OB (p) ⇒ (vLM 0 = vLM )R6. |= InvOB ∧ CsOB (p)⇒ hCsLM (p)ivLM

R7. |= InvOB ∧ ExitOB (p) ⇒ hExitLM (p)ivLM

CHAPTER 5. REFINEMENT

149

WaitLM (0) ≡W 2OB (0) ≡∧ pcLM (0) = wait
∧ pcOB (0) = w 2∧ semLM = 1∧ ¬xOB (1)∧ pcOB 0 = (pcOB except 0 7→ cs) ∧ pcLM 0 = (pcLM except 0 7→ cs)∧ semLM 0 = 0∧ xOB 0 = xOB∆

InvOB = ∧ TypeOKOB∧ ∀ p ∈ {0, 1} : ∧ (pcOB (p) ∈ {w 2, cs}) ⇒ xOB (p)∧ (pcOB (p) = cs) ⇒ (pcOB (1 − p) 6= cs)∆

TypeOKOB = ∧ xOB ∈ ({0, 1} → {true, false})∧ pcOB ∈ ({0, 1} → {ncs, wait, w 2, w 3, w 4, cs, exit})∧ pcOB (0) ∈/ {w 3, w 4}∆

pcBarOB = p ∈ {0, 1} 7→ if pcOB (p) ∈ {w 2, w 3, w 4} then wait
else pcOB (p)∆semBarOB = if ∃ p ∈ {0, 1} : pcOB (p) ∈ {cs, exit} then 0 else 1
pcLM = pcBarOB

semLM = semBarOB

Figure 5.2: Definitions used in the proofs.
Assertion R3 is equivalent to these three assertions:
R3a. |= InvOB ∧ W 2OB (0) ⇒ hWaitLM (0)ivLM
R3b. |= InvOB ∧ W 2OB (1) ∧ xOB (0) ⇒ (vLM 0 = vLM )R3c. |= InvOB ∧ W 2OB (1) ∧ ¬xOB (0) ⇒ hWaitLM (1)ivLM
All these assertions are proved by expanding the definitions of the actions
and of the refinement mapping. To see how this works, we consider R3a.
We haven’t written the definitions of the actions corresponding to the pseudocode statements of algorithms OB and LM . The definitions of W 2OB (0)and WaitLM (0) as well as the other relevant definitions are in Figure 5.2.
Here is the proof of R3a.
1. Suffices: Assume: InvOB ∧ W 2OB (0)Prove: hWaitLM (0)ivLM
Proof: Obvious.
2. (pcLM (0) = wait) ∧ (pcLM 0 = (pcLM except 0 7→ cs))

CHAPTER 5. REFINEMENT

150

Proof: By the step 1 assumption and the definitions of W 2OB (0) andpcBarOB (0), since pcLM equals pcBarOB .
3. (semLM = 1) ∧ (semLM 0 = 0)
Proof: W 2OB (0) implies (pcOB (0) = w 2)∧¬xOB (1), and InvOB and ¬xOB (1)imply pcOB (1) ∈/ {cs, exit}. Hence, semBarOB = 1, so semLM = 1. The
definition of W 2OB (0) and InvOB (which implies pcOB is a function withdomain {0, 1}) imply pcOB 0 (0) = cs. Hence semBarOB 0 = 0, so semLM 0 = 0.
4. Q.E.D.
Proof: Steps 2 and 3 and the definition of WaitLM (0) imply WaitLM (0).
0 6= v , proving the goal
Step 3 implies semLM 0 6= semLM which implies vLMLM
hWaitLM (0)ivLM introduced by step 1.
How we decomposed the proof that OBSafe refines OBLive into proving
R1–R7 was determined by the structure of NextOB as a disjunction of sevensubactions and knowing which disjuncts of NextLM each of those subactions
implements, which followed directly from the definition of the refinement
mapping. The decomposition of R3 into R3a–R3c followed from the structure of R3. As illustrated by the proof of R3a, the proof of each of theresulting nine formulas is reduced to ordinary mathematical reasoning by
expanding the appropriate definitions. The only place where not understanding the algorithms could result in an error is in the definition of the invariant InvOB or of the refinement mapping. Catching such an error requires
only careful reasoning about simple set theory and a tiny bit of arithmetic,
using elementary logic. Someday, computers should be very good at suchreasoning.

5.4.3

Refinement of Fairness

This section shows how to prove that a program refines the fairness propertyof another program by sketching the proof of one example: OB implies
LMFair . Define
OBB = 2(InvOB ∧ InvLM ) ∧ 2[NextOB ]vOB ∧ OBFair∆

where InvOB is the invariant satisfied by OB defined by (4.19) and (4.17),
and InvLM is an invariant of LM . For our example, we just require that
InvLM implies type correctness of LM . Formula OBB is a 2 formula that is
implied by OB . (We have proved that OB implies LMSafe, which implies
that InvLM is an invariant of OB .) We prove |= OBB ⇒ LMFair .

CHAPTER 5. REFINEMENT
ALM

QOB

151
BOB

POB

W aitLM (0)∧ pcOB (0) ∈ {wait, w2} W 2OB (0)∧ pcOB (1) ∈/ {cs, exit}∧ pcOB (0) = w2
∧ ¬ x(1)

W aitLM (1)∧ pcOB (1) ∈W 2OB (1){wait, w2, w3, w4}∧ pcOB (0) ∈/ {cs, exit}∧ pcOB (1) = w2
∧ ¬ x(0)CSLM (p)pcOB (p) = cs

CSOB (p)pcOB (p) = cs

ExitLM (p)pcOB (p) = exit

ExitOB (p) pcOB (p) = exit

Figure 5.3: Formulas BOB , POB , and QOB for the actions ALM , with p ∈ {0, 1}.
We use Theorem 4.8 to write LMFair as the conjunction of weak fairnessof WaitLM (p), CSLM (p), and ExitLM (p), for p ∈ {0, 1}. So, we have to prove|= OBB ⇒ WFvLM (ALM ) for ALM equal to each of those six actions. By(4.12), we can do this by proving:(5.17) |= OBB ⇒ (2 EhALM ivLM ; hALM ivLM )We prove (5.17) by finding an action BOB and state predicates POB and QOBsatisfying the following conditions:A1. 1. |= InvOB ∧ InvLM ∧ EhALM ivLM ⇒ QOB
2. |= OBB ⇒ (2QOB ; 2POB )A2. 1. |= InvOB ∧ InvLM ∧ POB ⇒ EhBOB ivOB
2. |= OBB ⇒ WFvOB (BOB )A3. |= InvOB ∧ InvLM ∧ POB ∧ hBOB ivOB ⇒ hALM ivLM
To show that these conditions imply (5.17), we have to show that they imply
that in any behavior σ satisfying OBB , if 2 EhALM ivLM is true of σ +m , then
σ(n) → σ(n + 1) is an hALM ivLM step for some n ≥ m. Condition A1.1
implies 2QOB is true of σ +m , which by A1.2 implies 2POB is true of σ +q forsome q ≥ m. By the definition of WF, conditions A2 imply σ(n) → σ(n + 1)
is a hBOB ivOB step for some n ≥ q, and A3 implies that hBOB ivOB step isan hALM ivLM step.
The formulas BOB , POB , and QOB used for the six actions ALM are shownin Figure 5.3. Condition A2.1 for the actions ALM follows easily from theCHAPTER 5. REFINEMENT

152

definitions of BOB and POB . To show that A2.2 is satisfied, we apply Theorem 4.8 to write OBFair as the conjunction of weak fairness of the actions
described by each process’s statements other than its ncs statement. That
A3 is satisfied for the four actions ALM in Figure 5.3 follows from conditions
R3a, R3c, R6, and R7 of Section 5.4.2.
This leaves condition A1 for the actions. A1.1 is proved by using
the type correctness invariant implied by InvLM to show that EhALM ivLM
equals E(ALM ) , and then substituting pcBarOB for pcLM and semBarOB
for semLM in E(ALM ) . For our example, this actually shows that InvLM
implies EhALM ivLM ≡ QOB for all the actions ALM . A1.2 is trivially satisfied
for CSLM (p) and ExitLM (p), since QOB and POB are equal. The interesting
conditions are A1.2 for WaitLM (0) and WaitLM (1). They are the kind ofleads-to property we saw how to prove in Section 4.2.5. In fact, we now
obtain a proof of A1.2 for WaitLM (0) by a simple modification of the proof
in Section 4.2.5.3 that OB implies:(5.18) (pc(0) ∈ {wait, w 2}) ; (pc(0) = cs)
Let’s drop the subscript OB , so the variables in any formula whose namehas no subscript are the variables of OB . The proof of (5.18) is describedby the proof lattice of Figures 4.4 and 4.5. A 2 formula in a label on abox in a proof lattice means that the formula is conjoined to each formula
inside the box. Since F ; G implies (2H ∧ F ) ; (2H ∧ G) for any F ,G, and H , we obtain a valid proof lattice (one whose leads-to assertions are
all true) by conjoining 2InvLM ∧ OBFair ∧ 2Q to the labels of the outerboxes in the lattices of Figures 4.4 and 4.5. This makes those labels equal
to OBB ∧ 2Q . Since Q implies pc(0) ∈ {wait, w 2} , we obtain a valid
proof lattice by replacing the source node of the lattice in Figure 4.4 by
2Q. Moreover, since the new label’s conjunct 2Q implies 2(pc(0) 6= cs),
so it’s impossible for pc(0) ever to equal cs, we can remove the sink nodepc(0) = cs and the edges to and from it from the lattice of Figure 4.5.3
Since the label on the inner box containing 2¬x (1) , which is the new sink
node, implies 2(pc(0) = w 2) , we now have a valid proof lattice that shows:|= OBB ⇒ (2Q ; 2((pc(0) = w 2) ∧ ¬x (1)))
This proves A1.2 for the action WaitLM (0).
To prove A1.2 for action WaitLM (1), it suffices to assume OBB and prove
2Q ; 2P for the formulas P and Q given in Figure 5.3 for the action. Here3
Equivalently, we can remove edge 8 and add an edge from pc(0) = cs to false andan edge from false to 2¬x (1), since false implies anything.

CHAPTER 5. REFINEMENT

153

is the proof sketch, which uses without mention some simple temporal logic,
including transitivity of ;.
1. 2Q ⇒ 2¬x (0)1.1. 2Q ⇒ 2(pc(0) ∈/ {wait, w 2})
Proof: We proved in Section 4.2.5.3 that pc(0) ∈ {wait, w 2} leads topc(0) = cs, and 2Q implies 2(pc(0) 6= cs).
1.2. 2Q ∧ 2(pc(0) ∈/ {wait, w 2}) ⇒ 2(pc(0) = ncs)
Proof: Q implies pc(0) ∈/ {cs, exit}, which by Inv and pc(0) ∈/ {wait, w 2}
implies pc(0) = ncs.
1.3. Q.E.D.
Proof: By steps 1.1 and 1.2, since Inv ∧ Q imply pc(0) = ncs, and Inv
and pc(0) = ncs imply ¬x (0).
2. 2Q ∧ 2¬x (0) ; 2P
2.1. 2Q ∧ 2¬x (0) ; (pc(1) = w 2)
Proof: Q implies pc(1) ∈ {wait, w 2, w 3, w 4}, and a straightforward
proof using fairness of PNext(1) and 2¬x (0) shows(pc(1) ∈ {wait, w 2, w 3, w 4}) ; (pc(1) = w 2)
2.2. 2Q ∧ 2¬x (0) ∧ (pc(1) = w 2) ⇒ 2(pc(1) = w 2)
Proof: 2Q implies 2(pc(1) 6= cs), and (pc(1) = w 2) ∧ 2[Next]v ∧2(pc(1) 6= cs) implies 2(pc(1) = w 2).
2.3. Q.E.D.
Proof: Steps 2.1 and 2.2 imply 2Q ∧ 2¬x (0) ; 2(pc(1) = w 2), and
2P equals 2(pc(1) = w 2) ∧ 2¬x (0).
3. Q.E.D.
Proof: By steps 1 and 2,

5.4.4

A Closer Look at E

5.4.4.1

A Syntactic View

Section 4.2.1 explained E semantically, defining E(A) to be true of a states iff there exists a state t such that action A is true of the step s → t. We
now translate this semantic definition into a syntactic definition of E(A). A
state is an assignment of values to variables, so we can restate that definitionas:CHAPTER 5. REFINEMENT

154

E1. E(A) is true for an assignment of values to the unprimed variables
iff there exists an assignment of values to the primed variables thatmakes A true.
A state predicate is true of a state iff it is true when its variables have thevalues assigned to them by the state. We can restate E1 as:
E2. E(A) is true (of a state) iff there exist values of the primed variables
for which A is true.
We will now translate E2 into a precise syntactic definition of E.
To do this, for any variable x , we now regard x and x 0 as two unrelated
symbols. For an expression exp, we take exp 0 to be the expression obtainedby priming all the variables in exp. If exp contains a defined symbol whose
definition contains variables, then all the variables in that definition areprimed in exp 0 .
We now define awith to be substitution like with, except regarding x 0
as being a different variable from x . For example, if x , y, and z are variables,then:(x 0 = x + 1) with x ← y − z equals (y − z )0 = (y − z ) + 1(x 0 = x + 1) awith x ← y − z equals x 0 = (y − z ) + 1(x 0 = x + 1) awith x 0 ← y − z equals (y − z ) = x + 1
If sym is a defined symbol, then(x 0 = x + sym) awith x 0 ← y − zequals(y − z ) = x + (sym awith x 0 ← y − z )√∆If sym = 2 ∗ x 0 , then this equals(y − z ) = x +q

2 ∗ (y − z )Now let A be an action and let x 1 , . . . , x n be all the variables thatappear in A. We can then write E2 as:(5.19) E(A) = ∃ c 1 , . . . , c n : (A awith x 0 1 ← c 1 , . . . , x 0 n ← c n )∆Thus, we obtain E(A) from A by replacing the primed variables by boundconstants that are existentially quantified. We informally describe this definition by saying that E(A) is obtained from A by existentially quantifying
its primed variables.

CHAPTER 5. REFINEMENT
5.4.4.2

155

Computing E

The syntactic definition (5.19) of E immediately provides rules for writing
E(A) in terms of formulas E(B i ), for B i subactions of A. From the rule|= (∃ c : A ∨ B ) ≡ (∃ c : A) ∨ (∃ c : B )we have
E1. |= E(A ∨ B ) ≡ E(A) ∨ E(B )For example, in program LM defined in Section 4.2.6.1, the next-state action
PNext(p) is the disjunction of actions Ncs(p), Wait(p), Cs(p), and Exit(p).
Therefore, rule E1 implies
E(PNext(p)) ≡ E(Ncs(p)) ∨ E(Wait(p)) ∨ E(Cs(p)) ∨ E(Exit(p))
The generalization of E1 is:E2. |= E(∃ i ∈ S : Ai ) ≡ ∃ i ∈ S : E(Ai )where S is a constant or state expression.
Another rule of existential quantification is that if the constant c does
not occur in A, then ∃ c : (A ∧ B ) is equivalent to A ∧ (∃ c : B ). From thiswe deduce:
E3. If no variable appears primed in both A and B , then |= E(A ∧ B ) ≡E(A) ∧ E(B ).
For example, in program LM we have:∆

Wait(p) = ∧ (sem = 1) ∧ (pc(p) = wait)∧ sem 0 = 0∧ pc 0 = (pc except p 7→ cs)
Therefore, rule E3 implies(5.20) E(Wait(p)) ≡ ∧ E((sem = 1) ∧ (pc(p) = wait))∧ E(sem 0 = 0)
∧ E(pc 0 = (pc except p 7→ cs))
The following two rules also follow easily from (5.19) and properties of existential quantification:
E4. If P is a state predicate, then |= E(P ) ≡ P .

CHAPTER 5. REFINEMENT

156

E5. If x is a variable and exp is a state expression, then |= E(x 0 = exp) ≡true.
From (5.20), E4, and E5, we deduce that E(Wait(p)) equals (sem = 1) ∧(pc(p) = wait). Here is another obvious rule, which can be considered ageneralization of E5, since c = exp is equivalent to c ∈ {exp} :E6 If x is a variable and exp is a state expression, then |= E(x 0 ∈ exp) ≡(exp 6= {}).
Rules E1– E6 are sufficient for computing E(A) for almost all subactions
A that, like PNext(p), appear in the definition of a program’s next-state
action. However, the definition of fairness does not contain such formulas E(A). Instead, it contains formulas of the form EhAiv , which equalsE(A ∧ (v 0 6= v )). None of those rules apply to such a formula. In particular,
E3 does not apply because v is the tuple of all the program’s variables.
Most of the time, a subaction A in the definition of a program’s nextstate action does not allow stuttering steps. Therefore, hAiv equals A, so
EhAiv equals E(A) and we can apply the rules. For example, EhPNext(p)iv
equals E(PNext(p)) because a PNext(p) step changes the value of pc(p), so
it can’t be a stuttering step. We are using the substitutivity rule (3.34) ofordinary math to deduce|= (A ≡ B ) ⇒ ( E(A) ≡ E(B ))(Even though substitutivity is not valid for TLA or the Logic of Actions, we
can apply it to the syntactic definition (5.19) of E, which treats x and x 0 as
two different variables of ordinary math—that is, two different constants.)
However, we can’t deduce PNext(p) ≡ hPNext(p)iv from the definitionof PNext(p). For example, if pc(p) = cs, then the definition of PNext(p)asserts
pc 0 = (pc except p 7→ exit)
If p is not in the domain of pc, then pc 0 (p) = pc(p). If pc is not a function,then we have no idea what pc 0 (p) equals, so it could equal pc(p). Fortunately, we care what EhPNext(p)iv equals only in reachable states of LM .
So, we just have to prove that Inv implies EhPNext(p)iv ≡ E(PNext(p))
for an invariant Inv of LM that asserts type correctness. To do this, weobserve that for any action A and state predicate P , rules E3 and E4 imply
P ∧ E(A) ≡ E(P ∧ A). So, to prove that Inv implies EhPNext(p)iv ≡E(PNext(p)), it suffices to prove|= Inv ⇒ (hPNext(p)iv ≡ PNext(p))

CHAPTER 5. REFINEMENT

157

which is straightforward. In general, we reason about liveness under theassumption that the program’s safety property is satisfied, so we can assume
2Inv is true for an invariant Inv of the program.
Since the formula 2[Next]v always allows stuttering steps, there is noneed for a next-state action Next to allow them. Usually, it doesn’t. However, there is no reason for Next not to allow stuttering steps, and sometimes
it’s more convenient to write a subaction A that allows them. In that case,
we have to use the definition (5.19) to compute EhAiv . However, we apply
the definition to E(Inv ∧ hAiv ), which equals EhInv ∧ Aiv , for a program
invariant Inv .
5.4.4.3

The Trouble With E

Refinement is based on substitution. Program OB refines LM means:(5.21) |= OB ⇒ (LM with pc ← pcBar , sem ← semBar )We no longer need the subscripts that were added to help us understandwhich program an identifier refers to. We continue using the abbreviation
that, for any formula F :∆F = (F with pc ← pcBar , sem ← semBar )Almost without thinking, we replaced Init ∧ 2[Next]v with the equivalent
property Init ∧ 2[Next]v . We were actually using these three rules:• F ∧ G ≡ F ∧ G for any formulas F and G.
• 2F ≡ 2F for any formula F .
• [A]v ≡ [A]v for any action A and state expression v .
The first asserts that substitution distributes over ∨; the second assertsthat substitution distributes over 2; and the third asserts that substitution
distributes over the construct [. . .]... .
We expect substitution to distribute in this way over all mathematicaloperators, so we would expect E(A) and E(A) to be equal for any action A.
In fact, they are equal for most actions encountered in practice. But here’s
an action A for which they aren’t for the refinement mapping of (5.21):∆

A = ∧ pc 0 = (p ∈ {0, 1} 7→ wait)∧ sem 0 = 0CHAPTER 5. REFINEMENT

158

Rules E3 and E5 imply that E(A) equals true, so E(A) equals true. By
definition of the refinement mapping:∆A = ∧ pcBar 0 = (p ∈ {0, 1} 7→ wait)∧ semBar 0 = 0
A implies pcBar 0 (p) = wait for p ∈ {0, 1}. By definition of pcBar , this
implies:(1) pc 0 (p) ∈ {w 2, w 3, w 4, wait} for p equal to 0 or 1.
But A also implies semBar 0 = 0, which by the definition of semBar implies:(2) pc 0 (p) ∈ {cs, exit} for p equal to 0 or 1.
Both (1) and (2) can’t be true, so A must equal false and thus E(A)equals false. Therefore, E(A) does not equal E(A), so substitution does
not always distribute over E.
The reason substitution doesn’t distribute over E is that E(A) performs
the substitutions pc ← pcBar and sem ← semBar for the primed variables
pc 0 and sem 0 . However, as we see from (5.19), those primed variables do notoccur in E(A); they are replaced by bound constants. The substitutions
should be performed only on the unprimed variables. Therefore:
E(A) with pc ← . . . , sem ← . . .
does not equalE(A with pc ← . . . , sem ← . . .)Instead, it equalsE(A awith pc ← . . . , sem ← . . .)which substitutes only for unprimed variables.
Since WF and SF are defined in terms of E, substitution does not distribute over them either. We proved that OB refines LM by proving that OB
implies WFv (A) for six actions A. To evaluate WFv (A), we expanded thedefinition of WF. Since substitution distributes over all the operators otherthan E in the definition of WFv (PN ), including in the definition PN (p),we could perform the substitutions everywhere in the resulting formula except in EhAiv ). We could then have used (5.19) to expand the definitionof E and perform the substitution on the resulting formula, which contains
no primed variables. (This is equivalent to performing the substitution in
EhAiv , except using awith instead of with.)

CHAPTER 5. REFINEMENT

159

While expanding the definition of E in this way would have allowed
EhAiv to be evaluated, it would have required applying E to an actionthat was more complicated than hAiv . That’s not what we did in the proof
sketch in Section 5.4.3. Instead we showed that hAiv equals A and performed
the substitution on E(A). Showing hAiv ≡ A required an invariant Inv ofLM , but because OB refines LMSafe, the formula Inv is an invariant of OB ,allowing us to deduce that EhAiv equals A.
Substitution not distributing over E makes E mathematically weird.
You should be suspicious of such weird things. The operators 2 and 0(prime) that TLA adds to ordinary math are weird because they are notsubstitutive. But substitution does distribute over them. Moreover, temporal logic is a well-studied field of math. I find E weirder than the temporal
logic operators.
However, fairness is an important concept in concurrent programs. The
WF and SF operators are the mathematical expressions of what fairness has
meant since Dijkstra introduced the assumption of weak fairness in 1965 [9].
There seems to be no good way to express it mathematically without theoperator E.
A similarly weird operator has been at the heart of traditional programs
since the earliest coding languages—namely, the action composition operator“·” introduced in Section 3.4.1.4. If x 1 , . . . , x n are all the variables thatappear in actions A and B , then A · B can be defined syntactically by:∆

A · B = ∃ c 1 , . . . , c n : ∧ (A awith x 0 1 ← c 1 , . . . , x 0 n ← c n )∧ (B awith x 1 ← c 1 , . . . , x n ← c n )The primed variables of A and the unprimed variables of B are replaced bybound constants, and substitution does not distribute over “·” for the same
reason it doesn’t distribute over E.
The common methods for reasoning about traditional programs written
in an imperative language can be viewed as a form of Hoare logic. As explained in Appendix Section A.5, such a logic can be viewed mathematicallyas defining the meaning of a statement S to be an action AS . If the meanings of statements S and T are the actions AS and AT , then the meaningof S ; T is the action AS · AT .
With this way of reasoning, the semicolon of imperative coding languages
therefore has the same weirdness as the E operator. I suspect this was neverdiscovered because people thought of programs in terms of conventionalcode, and it makes no sense to implement a variable x by an expression
when x can appear in an assignment statement x : = . . . .

CHAPTER 5. REFINEMENT

5.5

160

A Warning

We have defined correctness of a program S to mean |= S ⇒ P for someproperty P . We have to be careful to make sure that we have chosen P sothat this implies what we really want correctness of the program to mean.
As discussed in Section 4.3, we have to be concerned with the accuracy of P .
When correctness asserts that S refines a program T , the property P
is (T with . . . ) for a refinement mapping “. . .”. That refinement mapping
is as important a part of the property as the program T , and it must be
examined just as carefully to be sure that proving refinement means what
you want it to. As an extreme example, OB also implements LM under thisrefinement mapping:
pcLM ← (p ∈ {0, 1} 7→ ncs), semLM ← 1
Implementation under this refinement mapping tells us nothing about OB ,because under it, every behavior of OB implements a behavior in which allprocesses remain forever in their noncritical sections. The program obtainedby replacing the next-state action of OB by false also implements LM
under this refinement mapping.
Such an egregiously useless refinement mapping can often be detected
because, under a refinement mapping that implements behaviors of a program T by behaviors of program S that do nothing, S won’t implement
the fairness properties of T . However, programs often don’t require that
actions representing the initiation of an operation by the environment everoccur. In such a case, it’s a good idea to make sure that S refines T whenfairness requirements are added to those actions in both programs. This is
an application of the general idea of adding fairness to verify possibility thatwas introduced in Section 4.3.2.

Chapter 6

Auxiliary Variables
An auxiliary variable is a variable that is added to an abstract program
without altering the values assumed by the program’s regular variables. It’s
sometimes necessary to add auxiliary variables to a program in order to provethat it refines another program. Sections 6.2, 6.3, and 6.4 define the threekinds of auxiliary variables that may be needed, illustrating them with silly
little examples. Section 6.5 describes a realistic example that makes use of
all three kinds of auxiliary variables. We begin with a section that explainsvariable hiding, which is the basis for auxiliary variables and is also used in
Chapter 7.

6.1

Variable Hiding

Math IX
Reasoning About ∃ Variable hiding in abstract programs is performed
with an existential quantifier of temporal logic. That quantifier obeys thesame rules as the unbounded quantifier ∃ of ordinary math, so we now
describe those rules. We are concerned with two rules: the ∃ Introduction
rule used for proving a formula ∃ v : F , and the ∃ Elimination rule used
for proving that ∃ v : F implies a formula G. Rules for reasoning about thebounded quantifier ∃ v ∈ S can be obtained from these rules by replacing F
with (v ∈ S ) ∧ F and then replacing ∃ v : (v ∈ S ) ∧ F with ∃ v ∈ S : F .
∃ Introduction To prove ∃ v : F , we have to show that there is a value ofv that makes F true. We do that by explicitly describing that value. This

161

CHAPTER 6. AUXILIARY VARIABLES

162

is asserted by the following rule, where exp is a arbitrary expression:|= (F with v ← exp) ⇒ (∃ v : F )∃ Elimination Suppose ∃ v : F is true and F ⇒ G is true when v has any
value. This implies that G is true for the particular value of v that makes
F true, so ∃ v : G is true. Stated precisely, this rule is:|= F ⇒ G

implies|= (∃ v : F ) ⇒ (∃ v : G)This doesn’t look like an ∃ elimination rule because we use ∃ v : F to proveanother existentially quantified formula ∃ v : G, so we haven’t eliminatedthe ∃ . It becomes an elimination rule if v is not a free variable of G,
because then ∃ v : G is equivalent to G. The rule is usually stated with
∃ v : G replaced by G and the side condition that v is not a free variableof G. This syntactic side condition can be replaced by the more generalmathematical condition that substituting 0 (or any other fixed value) for v
leaves G unchanged. (This condition is satisfied by the formula v = v , inwhich v occurs.) In practice, the syntactic condition is good enough. But
the mathematical condition makes it clear that v not occurring free in G
means that v does not occur in G after the definitions of all defined symbols
that appear in G have been expanded. With this understanding of what itmeans, the rule used to eliminate the quantifier from ∃ x : G is:(6.1) |= (∃ v : G) ≡ G

if v does not occur free in G

Of course, the same rule holds for the quantifier ∀ as well.

6.1.1

Introduction

Recall the behavior predicate F12 , discussed in Section 4.1.2, that is true ofa behavior iff the value of x can equal 2 in a state only if x equaled 1 in aprevious state. We gave a semantic definition of F12 ; it can’t be expressedin RTLA or TLA as those languages have been defined so far. We observedthat F12 can be expressed as the abstract program S 12 , defined in (4.2), byintroducing an additional variable y.
The variable x that we’re interested in is called an interface variable.
The variable y that’s used only to describe how the values of x can change
is called an internal variable. There’s a problem with using the internalvariable y to describe F12 . Consider the abstract program S x that starts
with x = 0 and can keep incrementing x by one:S x = (x = 0) ∧ 2[x 0 = x + 1]x∆

CHAPTER 6. AUXILIARY VARIABLES

163

Since S x allows x to equal 2 only after it has equaled 1, it satisfies property
F12 . However, S x doesn’t imply S 12 because S 12 describes how the values ofx and y change, while S x allows behaviors in which y can have any values.
We want to express F12 by a formula that asserts of a behavior σ that
there is some way to assign values to y that makes S 12 true, but says nothing
about the actual values of y. As mentioned in Section 4.1.2, that formula iswritten ∃ y : S 12 . The operator ∃ is explained here.
In ordinary math, the formula ∃ y : x ∗ y 2 = 36 asserts that there is somevalue y for which x ∗y 2 equals 36, but says nothing about the actual value ofy. The variables of ordinary math correspond to the constants of temporal
logic. The y in ∃ y : S 12 is a constant, so that formula asserts that there is aconstant value y that satisfies S 12 ; and that value equals true if the initialvalue of x is 1, otherwise it equals false. Formula ∃ y : S 12 asserts that x
can never equal 2 unless the initial value of x is 1, which is not what F12
asserts.
The formula ∃ y : S 12 is true of a behavior iff the values of x in thatbehavior are the same as its values in a behavior satisfying S 12 , where yis a variable rather than a constant; but it says nothing about the actual
values assumed by y. Thus, y is a bound variable, not a free variable, of∃ y : S 12 . The precise definition of ∃ is subtle and is given below. For now,
we just need to know that [[∃ y : S 12 ]] equals F12 . I like to say that ∃ y : S 12
is formula S 12 with y hidden, because ∃ does what hiding is supposed to
do in coding languages.
We now generalize abstract programs to allow quantification over variables. As with the operator ∃ , we let ∃ y 1 , . . . , y n : F be an abbreviationfor ∃ y 1 : . . . ∃ y n : F . The general form of an abstract program with hidden
variables is:(6.2) ∃ y 1 , . . . , y k : Init ∧ 2[Next]v ∧ Lwith internal (bound) variables y 1 , . . . , y k . (The interface variables are thefree variables of the formula.) Theorem 4.9 shows that any property thatcan be described mathematically can be written in this form, with a single
bound variable. However, ∃ is of little use in practice. The only role itplays is telling us that, when implementing the program, it doesn’t matter
how the internal variables are refined. That can be stated just as well in acomment; we don’t need to introduce a new operator just for that. In fact,
although ∃ is an operator of TLA+ and is recognized by the parser, none of
the current tools handle it. Model checking formulas containing ∃ seems to
be computationally infeasible. I don’t know of any engineer wanting to useit.

CHAPTER 6. AUXILIARY VARIABLES

164

The reason to understand the temporal existential quantification operator ∃ is that it is the logical underpinning of important concepts such as
the auxiliary variables discussed in this chapter.

6.1.2

Reasoning About ∃Allowing an abstract program to be described with a formula of the form
(6.2) raises the question of how to reason about such formulas. The answer
is that the operator ∃ obeys the same introduction and elimination rules as
the quantifier ∃ of ordinary math, except with program variables (now called
variables) replacing the mathematical variables (now called constants). In
principle, ∃ has the same problem of variable capture as ∃ , but in practice,∃ is used in such a restricted way that variable capture is not an issue.
We want to reason about a formula of the form ∃ y 1 , . . . , y k : F . Applying the ∃ introduction rule k times to ∃ , we get the following rule, where
the exp i may be any expressions:|= G ⇒ (F with y 1 ← exp 1 , . . . , y k ← exp k )implies |= G ⇒ ∃ y 1 , . . . , y k : F
Applying the E elimination rule k times to ∃ , we get the rule:|= F ⇒ G implies |= (∃ y 1 , . . . , y k : F ) ⇒ G
if no variable y i occurs free in G.
Of course, we can always ensure that no y i occurs free in G by renaming
the internal variables y i of F .
Combining these two rules, we see that we can prove that one programof the form (6.2) implements another program of that form by proving anassertion of the form
(6.3) T ⇒ (S with y 1 ← exp 1 , . . . , y k ← exp k )where S and T have the standard form Init ∧ 2[Next]v ∧ L of an abstract
program, and none of the internal variables of T are interface variables of
S , which in practice will always be the case. For every interface variable x
of S , which in practice must also be an interface variable of T , the withclause includes an implicit substitution x ← x that substitutes the variable
x of T for the variable x of S . Thus, the with clause describes a refinement
mapping under which T refines S .
This raises a question: If |= T ⇒ ∃ y 1 , . . . , y k : S is true, do there always exist expressions exp i for which (6.3) is true? The answer is no, if

CHAPTER 6. AUXILIARY VARIABLES

165

we can use only the variables that appear in T to define the refinement
mapping. If S has the form Init ∧ 2[Next]v ∧ L, then the answer is yes if
we’re allowed to add auxiliary variables to T . Adding an auxiliary variablea (which does not occur in T ) to T means writing a formula T a such that
∃ a : T a is equivalent to T . By this equivalence, we can verify |= T ⇒ S byverifying |= (∃ a : T a ) ⇒ S . By the ∃ Elimination rule, we do this by verifying |= T a ⇒ S . And to verify this, we can use a as well as the variables of
T to define the refinement mapping. Auxiliary variables are the main topic
of this chapter and are discussed below.

6.1.3

The Definition

The standard way temporal existential quantification is defined in most temporal logics is not suitable for TLA because it does not preserve stuttering
insensitivity (SI), defined in Section 3.5.3. It’s the natural way to define it
for RTLA, so we will call the operator defined in that way ∃ rtla .
To define ∃ rtla , we first define s =y t to be true for states s and t iff thevalues of all variables except y are the same in states s and t. Rememberingthat σ(i ) is state number i of a behavior σ, we define the relation ' y on
behaviors by:∆

σ 'y τ = ∀ i ∈ N : σ(i ) =y τ (i )Therefore, σ ' y τ asserts that behaviors σ and τ are the same except for
the values assigned to y by their states. We then define ∃ rtla y : F to besatisfied by a behavior σ iff it is satisfied by some behavior τ with σ 'y τ .
The operator ∃ rtla is not a suitable hiding operator for properties, andhence not suitable for TLA, because the formula ∃ rtla y : F need not be aproperty even if F is. For example, let F be the following formula, where
br c is the largest integer less than or equal to r :(6.4) (x = y = 0) ∧ 2[(y 0 = y + 1) ∧ (x 0 = by 0 /2c)]hx ,y i
Ignoring the values of other variables, the property F is satisfied by thisnon-halting behavior with no stuttering steps:"#

x :: 0y :: 0"0#x :: 0→y :: 1"1#

x :: 1→y :: 22"#

x :: 1→y :: 3"

3#

x :: 2→y :: 4→ ···4The non-halting behaviors of ∃ rtla y : F consist of this behavior:
(6.5)

h

i

x :: 0h0i→ x :: 01hi→ x :: 1h2i→ x :: 13hi→ x :: 2

4→ ···CHAPTER 6. AUXILIARY VARIABLES

166

and behaviors obtained from it by adding stuttering steps. An SI formulacontaining the one free variable x that allows behavior (6.5) should also
allow this behavior:
(6.6)

h

i

x :: 0h0i→ x :: 11hi→ x :: 2h2i→ x :: 33hi→ x :: 44→ ···which ∃ rtla y : F does not allow, so it is not a property.
To obtain the proper quantifier ∃ for TLA, we modify the definition of∃ rtla so ∃ y : F is satisfied by (6.6). The definition of ∃ is the same as thatof ∃ rtla except with the relation ' y on behaviors replaced by a relation∼ y . This relation is defined so σ ∼ y τ means approximately that σ can beobtained from τ by adding and removing stuttering steps and then changing
the values of y. The precise definition of ∼ y is a bit subtle. (In fact, its
definition in [34] is wrong.)
To define ∼y , we first define the operator \y on behaviors. This operator
is the same as the operator \ defined in Section 3.5.3, except it removes“almost stuttering” steps instead of just stuttering steps, where a step s → t
is almost stuttering if s =y t. The precise definition is that \y (σ)(n) equals
σ(f y,σ )(n), where the definition of f y,σ is obtained from the definition of f σ
in Section 3.5.3 by replacing = and 6= by = y and 6= y in “ σ(i ) = ” and“ σ(i ) 6= ”.
We now define σ ∼ y τ to equal \y (σ) 'y \y (τ ) and define ∃ y : F to besatisfied by a behavior F iff there is a behavior τ satisfying F such thatσ ∼y τ . Observe that σ 'y τ implies σ ∼y τ , so ∃ rtla y : F implies ∃ y : F
for any behavior predicate F .
One reason not to use ∃ is that if S is a safety property, then ∃ y : S
need not be a safety property. Temporal quantification destroys the niceseparation of safety and liveness provided by our way of describing abstract
programs. For example, let F be this safety property for an abstract program:(6.7) ∧ (x = 0) ∧ (y ∈ N)
∧ 2 [(y > 0) ∧ (x 0 = x + 1) ∧ (y 0 = y − 1)]hx ,y i
In a behavior satisfying this formula, x cannot be incremented forever because eventually y would equal 0, making any further non-stuttering steps
impossible. Therefore, formula ∃ y : F is equivalent to(6.8) (x = 0) ∧ 2[x 0 = x + 1]x ∧ 32[x 0 = x ]xTo see that this is not a safety property, remember that a behavior σ satisfies
a safety property iff every finite prefix of σ satisfies that property. Consider

CHAPTER 6. AUXILIARY VARIABLES

167

a behavior σ in which x does keep being incremented forever. Every finite
prefix of σ satisfies (6.8), since completing the prefix with stuttering steps
makes the behavior satisfy the liveness property 32[x 0 = x ]x . However, σdoesn’t satisfy (6.8) because it doesn’t satisfy this liveness property. Therefore, even though formula F , defined to equal (6.7), is a safety property,
formula ∃ y : F , which is equivalent to (6.8), is not a safety property.

6.2

History Variables

The simplest kind of auxiliary variable is a history variable. As the nameimplies, a history variable is used to remember things that happened in thepast and can’t be deduced from the current state. We may need to add ahistory variable to T to prove |= T ⇒ S when the internal state of S records
information about past events that isn’t needed to describe the behavior of
its interface variables.

6.2.1

How to Add a History Variable

Except in one unusual case described in Section 6.3.5, we add an auxiliary
variable to an abstract program by adding it to the safety part of the program. Thus, if T equals Init ∧ 2[Next]v ∧ L for a liveness property L, thenthe formula T h obtained by adding a history variable h will equal
Init h ∧ 2[Next h ]vh ∧ L
where Init h and Next h are obtained by augmenting Init and Next to describe, respectively, the initial value of h and how h can change; and vh isthe tuple v ◦ hh i of the variables of v and the variable h. Since h does notappear in L, the formula ∃ h : T h equals(∃ h : Init h ∧ 2[Next h ]vh ) ∧ L
We can therefore ignore L for now, so we assume T equals Init ∧ 2[Next]v
and show how to define Init h and Next h .
We use a tiny example to illustrate history variables. There is an abstract
program in which a user inputs a sequence of real numbers and the system
displays the average of the numbers entered thus far. The interface variables
are inp and avg. Initially, inp equals a value rdy that is not a number andavg = 0. The user’s input action sets inp to a real number and leaves avg
unchanged. The system’s output action sets avg to the new average of the
inputs and resets inp to rdy.

CHAPTER 6. AUXILIARY VARIABLES

168∆

InitS = (inp = rdy) ∧ (avg = 0) ∧ seq = h i∆

User = ∧ inp = rdy∧ inp 0 ∈ R∧ (avg 0 = avg) ∧ (seq 0 = seq)∆

Syst = ∧∧∧∧inp ∈ Rseq 0 = Append (seq, inp)
avg 0 = SeqSum(seq 0 ) / Len(seq 0 )inp 0 = rdy∆

NextS = User ∨ Syst
IS = InitS ∧ 2[NextS ]hinp,avg,seq i∆∆
S = ∃ seq : IS

Figure 6.1: The abstract averaging program S.
This abstract program is described by formula S of Figure 6.1. It uses
an internal variable seq whose value is the ordinal sequence of numbers
input so far. Recall that R is the set of real numbers, and Section 2.8.3
defines these operators on sequences seq: Append (seq, inp) is the sequenceobtained by appending inp to the end of seq; Len(seq) is the length of seq;
and Tail (seq) is the sequence obtained by removing the first element of
seq if seq is nonempty. The operator SeqSum is defined as follows so that
SeqSum(sq) is the sum of the elements of a finite sequence sq of numbers:∆

SeqSum(sq) = if sq = h i then 0 else sq(1) + SeqSum(Tail (sq))
Using the internal variable seq to write the behavior predicate S is arguably
the clearest way to describe the values assumed by the interface variables inp
and avg. It’s a natural way to explain that the value of avg is the average ofthe values that have been input. However, it’s not a good way to describe
how to implement the system. There’s no need for an implementation to remember the entire sequence of past inputs; it can just remember the numberof inputs and their sum. In fact, it doesn’t even need an internal variable toremember the sum. We can implement it with an abstract program T that
implements S using only a single internal variable num whose value is thenumber of inputs that the user has entered.
We first describe T in pseudocode and construct T h by adding a history
variable h to the code. The TLA translations of the pseudocode show how
to add a history variable to an abstract program described in TLA.

CHAPTER 6. AUXILIARY VARIABLES

169

variables inp = rdy, avg = 0, num = 0 ;while true do
usr : inp :∈ R ;sys: avg : = (avg ∗ num + inp) / (num + 1) ;num : = num + 1 ;inp : = rdy
end while
Figure 6.2: Abstract program T in pseudocode.
variables inp = rdy, avg = 0, num = 0, h = h i ;while true do
usr : inp :∈ R ;sys: avg : = (avg ∗ num + inp) / (num + 1) ;num : = num + 1 ;h : = Append (h, inp) ;inp : = rdy
end while
Figure 6.3: Abstract program T h in pseudocode.
It’s natural to think of the user and the system in this example as two
separate processes. However, the abstract programs S and T are predicateson behaviors, which are mathematical objects. Process is not a mathematical concept; it’s a way in which we interpret predicates on behaviors. For
simplicity, we write T as a single-process program.
The pseudocode for program T is in Figure 6.2. It uses the operator :∈introduced in Figure 4.8, so statement usr sets inp to an arbitrary elementof R. Since we’re not concerned with implementing T , there’s no reason tohide its internal variable num.
Because the sum of n numbers whose average is a is n ∗ a, it should beclear that program T implements program S . But showing that T implements S requires defining a refinement mapping under which T implements
IS (program S without variable seq hidden). And that requires adding an
auxiliary variable that records the sequence of input values. Adding therequired auxiliary variable h is simple and obvious. We just add the twopieces of code shown in black in Figure 6.3.
It is a straightforward exercise to prove|= T h ⇒ (IS with inp ← inp, avg ← avg, seq ← h)

CHAPTER 6. AUXILIARY VARIABLES

170

using that fact thatavg ≡ if h = h i then 0 else SeqSum(h) / Len(h)is an invariant of T h . To show that this proves |= T ⇒ S , we have to showthat T h actually is obtained by adding the auxiliary variable h to T —that
is, we have to show that T is equivalent to ∃ h : T h . This requires showing(i) |= (∃ h : T h ) ⇒ T and (ii) |= T ⇒ (∃ h : T h ).
To show (i) we have to show |= T h ⇒ T , which is obvious because it’seasy to see that the initial predicate and next-state action of T h imply the
initial predicate and next-state action of T . To show (ii), we have to showthat for any behavior σ satisfying T there is a behavior τ satisfying T h withτ ∼ h σ. From the code for T h , it’s easy to obtain a recursive definition of
the value of h in each state τ (i ) of τ . The declaration of h provides thevalue of h in state τ (0), and the rest of the code defines the value of h instate τ (i + 1) as a function of its value and the value of pc in state τ (i ).
It’s pretty obvious how to generalize from this example to adding ahistory variable h to any abstract program T described by pseudocode. We
let the initial value of h be any expression that can contain the variables ofT . We modify the pseudocode by adding at most one statement assigning avalue to h to any action of the code. The right-hand side of the assignment
can contain h as well as the variables of T . Making this precise would
require making pseudocode precise, which we don’t want to do. When wewant to be precise, we use math.
So, let’s now see how we add a history variable when the abstract program T is written in TLA. The translation of the code in Figure 6.2 to TLA
defines
T = Init ∧ 2[Next]hinp,avg,num i∆∆

where Next = Usr ∨ Sys

Actions Usr and Sys are the actions executed from control points usr andsys, respectively. The TLA translation of the code in Figure 6.3 is(6.9) T h = Init h ∧ 2[Next h ]hinp,avg,num,h i∆∆where Init h = Init ∧ (h = h i)∆
Next h = Usr h ∨ Sys h∆
Usr h = Usr ∧ (h 0 = h)∆
Sys h = Sys ∧ (h 0 = Append (h, inp))
Here is the general result that describes how to add a history variable to a
program. Its proof is a simple generalization of the proof for our example.

CHAPTER 6. AUXILIARY VARIABLES

171

Theorem 6.1 (History Variable) Let T equal Init ∧ 2[Next]v , where
Next equals ∃ i ∈ I : Ai and v is the tuple of variables in T , and assume his not one of those variables. If T h equals Init h ∧ 2[Next h ]vh , where∆• Init h = Init ∧ (h = exp)∆

• Next h = ∃ i ∈ I : Ai ∧ (h 0 = exp i )∆• vh = v ◦ hh i
• exp is a state expression that does not contain the variable h, and theexp i are step expressions that do not contain h 0 ,then |= T ≡ ∃ h : T h .

6.2.2

History Variables and Fairness

We add a history variable h to a safety property T of the form Init ∧2[Next]v
to obtain a formula T h such that ∃ h : T h is equivalent to T . If a program
also contains a liveness condition L, this gives us the program T h ∧ L. Since
the variable h does not occur in L, the formula ∃ h : T h ∧ L is equivalent to(∃ h : T h ) ∧ L which equals T ∧ L. Therefore the history variable h is an
auxiliary variable for T h ∧ L.
As explained in Section 4.2.7, the standard form for the liveness conditionof a program is the conjunction of weak and/or strong fairness conditionsof subactions of its next-state action. Even if T ∧ L has this form, T h ∧ Lwill not because a subaction of Next will not be a subaction of Next h . (Anaction that does not mention h cannot imply Next h .) This means that we
can’t apply Theorem 4.7 to show that hT h , Li is machine closed. However,
we can show as follows that if hT , Li is machine closed, then hT h , Li is also
machine closed. By definition of machine closure, this means showing thatany finite behavior ρ satisfying T h can be extended to an infinite behavior
satisfying T h ∧ L. Since T h implies T , machine closure of hT , Li implies ρ
can be extended to a behavior ρ ◦ σ satisfying T ∧ L. By definition of T h ,we can modify the values of h in the states of σ to obtain a behavior τ suchthat ρ ◦ τ satisfies T h . Since the truth of L does not depend on the valuesof h, the behavior ρ ◦ τ also satisfies L, as required.
When using TLA, the fact that L will contain fairness conditions onactions that are not subactions of Next h makes no difference. However, noteveryone uses TLA. In some approaches, abstract programs are describedin something like a coding language, and they define fairness only in termsof weak and strong fairness of subactions of the next-state action. So, it isCHAPTER 6. AUXILIARY VARIABLES

172

interesting to know if we can replace a fairness condition on a subaction B iof T with the same fairness condition on a corresponding subaction B hi of
T h . We can, under the following condition, which is likely to be satisfied
by programs written in those other languages: The next-state action of T
must be the disjunction of actions Ai , and each B i must be a subaction of
Ai such that a B i step is not an Aj step for j 6= i . The precise result isthe following, whose proof is in the Appendix. In this theorem, letting B iequal false is equivalent to omitting that fairness condition because weak
and strong fairness of false are trivially true. (The action false is neverenabled, so (4.23) implies SFv (false) equals 23false ⇒ 23false, whichequals true.)
Theorem 6.2 With the assumptions of Theorem 6.1, for all i ∈ I let B i
be a subaction of Ai such that T ∧ (i 6= j ) ⇒ 2[¬(B i ∧ Aj )]v for all j in∆
I ; and let B hi = hB i iv ∧ (h 0 = exp i ). ThenT ∧ (∀ i ∈ I : XFiv (Bi )) ≡ ∃ h : T h ∧ (∀ i ∈ I : XFivh (Bih ))where each XFi is either WF or SF.

6.2.3

A Completeness Result for History Variables

A popular approach to proving safety properties of concurrent programs,
derived from work by Owicki and Gries [43], can prove only invarianceproperties. We can, in theory, reduce proving safety properties to proving invariance. We do this by adding a history variable h to a program T to
obtain a program T h . For any safety property F , we can then define a statepredicate I F that is an invariant of T h iff (every behavior of) T satisfies F .
The idea is simple: We define the value of h to be the sequence of system
states in the current behavior up to and including the current state. We
then define I F to be true iff the value of h satisfies F . The result is statedin the following theorem, whose proof is sketched in the Appendix.
Theorem 6.3 Let T equal Init ∧ 2[Next]hxi where x is the list of all variables of S ; let F be a safety property such that F (σ) depends only on thevalues of the variables x in σ, for any behavior σ; and let h be a variable notone of the variables x. We can add h as a history variable to T to obtainT h and define a state predicate I F in terms of F such that |= [[T ]] ⇒ F istrue iff I F is an invariant of T h .
A simple example of the theorem is when F is the safety property F 12
defined semantically by (4.1) of Section 4.1.2. That property asserts x must

CHAPTER 6. AUXILIARY VARIABLES

173

equal 1 before it can equal 2. A program Init ∧ 2[Next]v satisfies F 12 iff theformula (x = 2) ⇒ h is an invariant of the program obtained by adding thehistory variable h to that program as follows:(Init ∧ (h = false)) ∧ 2[Next ∧ (h 0 = h ∨ (x = 1))]v ◦hh i
Theorem 6.3 assumes only that F is a safety property. This might suggest
we can show that one program satisfies the safety part of another program byverifying an invariance property. However, I have never seen this done, andin practice it seems unlikely to be possible to describe any but the simplest
abstract programs with an invariant.

6.3

Stuttering Variables

Typically, when a lower-level abstract program T implements a higher-level
abstract program S , program T takes more steps than S does to perform an
operation. Under the refinement mapping, the extra steps of T implement
stuttering steps of S . It’s also possible for S to take more steps than T . In
that case, defining a refinement mapping requires adding steps to behaviors
of T that implement those extra steps of S . This is done by adding a
stuttering variable s to T . The extra steps are ones that change only s, sowhen s is hidden, those steps become stuttering steps of T .
There are two kinds of stuttering variables used in practice: ones that
add stuttering steps immediately after steps of an action, and ones that add
stuttering steps immediately before steps of an action. They are describedin Sections 6.3.2 and 6.3.3. Multiple such variables can be combined into asingle stuttering variable. Section 6.3.5 explains another kind of stuttering
variable that is never needed in practice but could, in theory, be required.
This section talks about adding stuttering steps, which literally makes nosense because it’s impossible to require or forbid stuttering steps in a TLA
formula. Here, adding stuttering steps to an abstract program T means
writing a formula T s containing s and the variables of T by adding steps
that change s and leave the variables of T unchanged, so that ∃ s : T s isequivalent to T . In this section, a stuttering step usually means one of thoseadditional steps that leave the variables of T unchanged and change s.

Math X
Case Proof Steps A common proof method is case splitting—for example, splitting the proof of a formula containing a number x into proving it

CHAPTER 6. AUXILIARY VARIABLES

174

first if x ≥ 0 and then if x < 0. This is done with Case statements, where
if G is the current goal, then Case: F is an abbreviation of F ⇒ G . A
proof by case splitting usually ends with a sequence of Case steps followed
by a Q.E.D. step showing that those steps cover all possible cases.
Well-Founded Relations A relation  is said to be well-founded on a
set S iff there is no infinite sequence s 1  s 2  . . . with s i ∈ S for all i . If
we think of s  t meaning that t is smaller than s, then well-founded on
S means that if you keep taking smaller and smaller elements of S , thenyou’ll eventually reach a minimal element. (There may be many minimal
elements.) The prototypical example of a well-found relation on a set is therelation > on the set N of natural numbers.

6.3.1

The Example

Stuttering variables are explained with the silly example of a tiny censoring
system. An artist paints pictures and submits them to a censor, who decides
either to display or reject each picture. This system is described by theabstract program Cen1 defined as follows.
There are two interface variables inp and disp. The artist submits apicture w , which is an element of the set Art of all possible pictures, bysetting the value of the variable inp to w . The censor then either displays w
by setting the value of the variable disp to hw , i i, where i is set alternately
to 0 and 1, or else rejects w . (The second component of disp is needed
so displaying the same picture twice isn’t a stuttering step, which would
needlessly complicate the example.) The censor then acknowledges receiptof the picture by setting the value of inp to a special value NotArt that is
not an element of Art.
There is also an internal variable aw that is hidden. The value of aw isinitially the empty sequence h i. It is set to hw i when the artist submits apicture w , and it is reset to h i when w is either displayed or rejected. The
value of aw records whether or not the display/reject decision has been made.
That information is encoded in aw this way so the example is more easily
modified to obtain an example in Section 6.4. The complete description of
the abstract program is formula Cen1 in Figure 6.4, where ICen1 is the
program without aw hidden. (Initially, any painting may be displayed.)
There is another way to describe the artist/censor system as an abstract program. In ICen1, submission of a picture w by the artist is described by an input action that sets inp to w and aw to hw i. A separate
action DispOrNot either displays or rejects w . We define Cen2 to equal

CHAPTER 6. AUXILIARY VARIABLES

175∆
Cen1 = ∃ aw : ICen1

ICen1 = Init ∧ 2[Next1]v∆∆

v = hinp, disp, aw i∆

Init = ∧ inp = NotArt∧ aw = h i∧ disp ∈ Art × {0, 1}∆

Next1 = Input ∨ DispOrNot ∨ Ack∆

Input = ∧ (inp = NotArt) ∧ (aw = h i)
∧ inp 0 ∈ Art∧ aw 0 = hinp 0 i∧ disp 0 = disp∆

DispOrNot = ∧ aw 6= h i∧ ∨ disp 0 = haw (1), 1 − disp(2)i∨ disp 0 = disp
∧ aw 0 = h i∧ inp 0 = inp∆
Ack = ∧ (inp ∈ Art) ∧ (aw = h i)
∧ inp 0 = NotArt∧ (aw 0 = aw ) ∧ (disp 0 = disp)
Figure 6.4: The program Cen1.
∃ aw : ICen2 where ICen2 describes a program in which it is the input action that decides whether to display or reject w , setting aw to hw i iff it
decides to display w . The displaying action always displays w if aw equals
hw i. The program Cen2 is defined in Figure 6.5, where v , Init, and Ack
are the same as in Cen1 and are defined in Figure 6.4.
If we ignore the values of aw , the only difference between behaviors
of ICen1 and ICen2 is that, when a picture is rejected, the behavior of
ICen1 takes one more step than the corresponding behavior of ICen2—astep that leaves inp and disp unchanged. Since inp and disp are the only
free variables in the two definitions of Cen, stuttering insensitivity implies
that the formulas Cen1 and Cen2 are equivalent, so they describe the same
abstract program.
To show that the two definitions are equivalent, we have to show that
ICen1 and ICen2 each implement the other under a suitable refinement map-

CHAPTER 6. AUXILIARY VARIABLES

176∆
Cen2 = ∃ aw : ICen2

ICen2 = Init ∧ 2[Next2]v∆∆

Next2 = InpOrNot ∨ Display ∨ Ack∆

InpOrNot = ∧ (inp = NotArt) ∧ (aw = h i)
∧ inp 0 ∈ Art∧ ∨ aw 0 = hinp 0 i∨ aw 0 = aw
∧ disp 0 = disp∆

Display = ∧ aw 6= h i∧ disp 0 = haw (1), 1 − disp(2)i∧ aw 0 = h i∧ inp 0 = inp
Figure 6.5: The program Cen2.
ping. We will see here how to define the refinement mapping under which
ICen2 implements ICen1. Section 6.4 shows how to define the refinement
mapping under which ICen1 implements ICen2.

6.3.2

Adding Stuttering Steps After an Action

To define the refinement mapping that shows ICen2 implements ICen1, we
have to add a stuttering step to an execution of ICen2 for each operation ofreceiving an input and rejecting it. We do that by adding a stuttering variable that adds a stuttering step after each InpOrNot step of the executionthat rejects the input—that is, after InpOrNot steps that set aw to h i.
The simplest stuttering variable s is one whose value is a natural numberthat equals 0 except when it is adding stuttering steps (steps that change
only s), in which case s equals the number of such steps it has yet to take.
Here’s how we add such a variable that adds stuttering steps after a subaction A of the next-state action.
Let T equal Init ∧ 2[Next]v , where Next equals A ∨ (∃ j ∈ J : B j ) foractions A and B j . We define T s to equal Init s ∧ 2[Next s ]vs , where Next s
equals As ∨ (∃ j ∈ J : B sj ) and Init s , As , B sj , and vs are defined as follows:
S1. vs is the tuple of variables obtained by appending s to the tuple v of
variables.
∆

S2. Init s = Init ∧ (s = 0).

CHAPTER 6. AUXILIARY VARIABLES

177∆

S3. As = ∨ (s = 0) ∧ A ∧ (s 0 = exp)
∨ (s > 0) ∧ (v 0 = v ) ∧ (s 0 = s − 1)
where exp is an expression whose value is a natural number; it cancontain the original variables primed or unprimed.
∆

S4. Bjs = (s = 0) ∧ B j ∧ (s 0 = 0), for j ∈ J .
Ignoring the value of s, the behaviors satisfying T s are the same as behaviors
satisfying T , except each A step in a behavior of T is followed in T s by afinite number (possibly 0) of steps that leave the variables of T unchanged.
Therefore, by stuttering insensitivity, T and ∃ s : T s are satisfied by thesame sets of behaviors, so they are equivalent.
To show that ICen2 implements ICen1, we define ICen2s in this way,where A equals InpOrNot and the B i are Ack and Display. In the definitionof InpOrNot s , we let:∆

exp = if aw 0 = h i then 1 else 0This adds a stuttering step to a behavior of ICen2s after an InpOrNot stepthat rejects the input.
Programs ICen1 and ICen2s take the same number of steps to process
an input. A stuttering step of ICen2s corresponds to a DispOrNot step of
ICen1 that rejects the input. If we compare behaviors of these two programs,
we find that corresponding states have the same values of the variables inp,
disp, and aw except when ICen2s is about to take a stuttering step. In thatstate, s = 1 in ICen2s , and the value of aw for an input w is h i in ICen2s
and hw i in ICen1. This means that the value of aw in a behavior of ICen1
always equals the value of the following state function in the corresponding
behavior of ICen2s :∆(6.10) awBar = if s = 0 then aw else hinp i
Therefore, ICen2s implements ICen1 under the refinement mapping that
substitutes awBar for aw . In other words:(6.11) |= ICen2s ⇒ (ICen1 with aw ← awBar )The proof of (6.11) is similar to, but simpler than, the refinement proof
sketched in Section 5.4.2. Here, we give only the briefest outline of a proof
to present results that will be used below when discussing liveness.
Let’s abbreviate (F with aw ← awBar ) by F for any formula F , so wemust prove |= ICen2s ⇒ ICen1. The proof of |= Init s ⇒ Init is trivial, sinceCHAPTER 6. AUXILIARY VARIABLES

178

s = 0 implies v = v by definition of awBar , so Init s implies Init = Init.
The main part of the proof is proving:(6.12) |= ICen2s ⇒ 2[Next1]v
This is proved by proving assertions C1–C4 below, which are the analogs ofassertions R1–R7 of the proof in Section 5.4.2. Again, assertions containing
actions of the form hAiv are proved for use in reasoning about liveness when aweaker assertion containing A suffices to prove (6.12). Two of the assertions
require an invariant Inv 2s of ICen2s . That invariant needs to assert typecorrectness of disp (for C3) and that s = 1 implies aw = h i (for C2).
C1. |= (s = 0) ∧ InpOrNot s ⇒ Input
C2. |= Inv 2s ∧ (s = 1) ∧ InpOrNot s ⇒ hDispOrNot iv
C3. |= Inv 2s ∧ Display s ⇒ hDispOrNot iv
C4. |= Ack s ⇒ hAck iv
Proving these assertions is a good way to start learning to write proofs.
Often, when showing that one program implements another, after adding
a simple stuttering variable it’s necessary to add a history variable to be able
to define the refinement mapping. For example, suppose we split the input
actions of the censor programs into two actions, where the first chooses thevalue of inp and the second sets the values of aw and disp and sets inp toa special value Busy. The Ack action must also be modified by replacing
inp ∈ Art with inp = Busy. We could then not define awBar to make (6.11)
true because the input value would be forgotten when s equals 1. To definea state function awBar to make (6.11) true, we would have to add a history
variable that remembers what value was input.
We can avoid having to add a history variable by letting the stuttering
variable carry additional information. This is done by generalizing the way
stuttering steps are counted. In the censor example, instead of setting s
to 1 when adding a stuttering step and to 0 otherwise, we can set it to hinp iwhen adding the step and to h i when not adding the step. The number ofstuttering steps to be taken at any point in the execution is then the lengthLen(s) of the sequence s. We would define awBar to equal:
if s = h i then aw else s
In general, we can let s assume values in any set with a well-founded relation.
We just require that every added stuttering step decreases the value of s.
One use of this generality is for adding stuttering steps after multiple
actions. To do this, we let the value of s be a pair hm, i i, where m is theCHAPTER 6. AUXILIARY VARIABLES

179

number of remaining stuttering steps and i identifies the action. We define
the well-founded ordering  on this set of pairs by letting hm, i i  hn, j i
iff m > n. We can use this same trick to let the value of s be a tuple
with additional components. Information in those other components canbe used in defining the refinement mapping so it makes the stuttering steps
implement the appropriate steps of the higher-level program. For simplicity,
we state our theorem just for this particular use of a well-founded order.
However, the conjunct s(2) = i in the definition of Asi is added to ensurethat only Asi performs stuttering steps added after Ai , although that mattersonly if s contains additional components that depend on i .
Theorem 6.4 (Post-Action Stuttering Variable)
Let T equal Init ∧ 2[Next]v , where Next equals (∃ i ∈ I : Ai ) ∨ B for aconstant set I , and v is a tuple of all the variables of T . If T s equals
Init s ∧ 2[Next s ]vs where∆• s is not a variable of T and vs = v ◦ hs i.
∆• Init s = Init ∧ (s = h0, i 0 i) for some i 0 in I .
∆• Next s = (∃ i ∈ I : Asi ) ∨ B s∆• Asi = ∨ (s(1) = 0) ∧ (s(2) = i ) ∧ Ai ∧ (s 0 = hexp i , i i)
∨ (s(1) > 0) ∧ (v 0 = v ) ∧ (s 0 = hs(1) − 1, s(2)i)
where |= T ⇒ 2[exp i ∈ N]v and exp i is a step expression not containing s.
∆• B s = (s(0) = 0) ∧ B ∧ (s 0 = s)then ∃ s : T s equals T .
The theorem does not assume that the actions Ai and B are mutually disjoint. A step could be both an Ai and an Aj step for i 6= j , or both an Ai
and a B step. That should rarely be the case when applying the theorem,
since it allows a nondeterministic choice of how many stuttering steps (ifany) are added in some states. The action B will usually be the disjunction of actions B j . In that case, B s equals the disjunction of the actions(s(0) = 0) ∧ B j ∧ (s 0 = s).

CHAPTER 6. AUXILIARY VARIABLES

6.3.3

180

Adding Stuttering Steps Before an Action

Suppose that instead of adding stuttering steps after InpOrNot steps ofICen2, we want to add them before Ack steps. That’s a silly thing to do,but it’s a silly example anyway. One thing that makes it silly is that whenthe Ack action is enabled, nothing in the state tells us whether a stuttering
step is necessary. The value of aw is h i regardless of whether or not a
Display step has occurred. So we’ll have to add the stuttering step whether
or not it’s needed. But that’s not a problem, since an unnecessary stuttering
step can simply implement a stuttering step of ICen1.
For a simple stuttering variable that counts down to 0, we add stuttering
steps before an action A the way we added them after A, except instead of
As executing A in the first step when s equals 0, it executes A in the laststep, when s equals 1 (unless it adds 0 stuttering steps). However, to ensurethat an As step can be taken after those k stuttering steps, the stuttering
steps can begin only when A is enabled. (Once A is enabled, stuttering steps
leave it enabled.) To add exp stuttering steps before an A step, we define:∆

As = ∧ ∨ E(A) ∧ (s = 0) ∧ (s 0 = exp)
∨ (s > 0) ∧ (s 0 = s − 1)
∧ if s 0 = 0 then A else v 0 = v
Since A is enabled when s 0 = 0 is true, any enabling condition (conjunctwith no primed variable) can be removed from A in the last line of thedefinition.
We could define Ack s this way in ICen2s with exp = 1 to add a stuttering step before every Ack step. However, there’s nothing in the state toindicate whether that stuttering step should implement a Display step ora stuttering step of ICen1. To define the refinement mapping that shows
ICen2s implements ICen1, we would have to add a history variable thatrecords whether or not the InputOrNot s step decided to display the input.
Alternatively, we could add the history variable before adding the stuttering variable. We could then define Ack s so it adds a stuttering step iff the
InpOrNot step chose not to display the input.
To obtain the general result for adding stuttering steps before actions
Ai , we modify Theorem 6.4 by changing the definition of Asi to:∆

Asi = ∧ ∨ E(Ai ) ∧ (s(1) = 0) ∧ (s 0 = hexp i , i i)
∨ (s > 0) ∧ (s(2) = i ) ∧ (s 0 = hs(1) − 1, s(2)i)∧ if s 0 (1) = 0 then Ai else (v 0 = v )CHAPTER 6. AUXILIARY VARIABLES

181

where exp i is a state expression. (Although allowed, there is usually no point
having primed variables in exp i , because they equal the unprimed variables
unless exp i equals 0.)
We can also add stuttering steps both before and after Ai steps. We add
a third component to s to indicate whether the next stuttering steps to be
added for Ai are ones that precede or follow the Ai step. Writing a precise
definition is left as an exercise for motivated readers.

6.3.4

Fairness and Stuttering Variables

As with other auxiliary variables, we add a stuttering variable to a safety
property T of the form Init ∧ 2[Next]v . If a program is described by theproperty T ∧ L for a liveness property L, then the program with the added
stuttering variable s is T s ∧ L .
To see how stuttering variables work with liveness conditions, we add
fairness requirements L1 and L2 to our two censor programs to define:∆IC 1 = ICen1 ∧ L1∆

IC 2 = ICen2 ∧ L2

We’ve shown that ICen2s implements ICen1 under a refinement mapping.
We show here that IC 2s implements IC 1 under that same refinement mapping. That is, we show:(6.13) |= IC 2s ⇒ (IC 1 with aw ← awBar )The fairness requirements are:∆

L1 = WFv (DispOrNot) ∧ WFv (Ack )∆L2 = WFv (Display) ∧ WFv (Ack )(Theorem 4.8 implies that L1 and L2 are equivalent to weak fairness of
DispOrNot ∨ Ack and Display ∨ Ack respectively, but it’s more convenient
to write them this way.) It’s clear that L1 and L2 are the appropriate
fairness requirements for IC 1 and IC 2, ensuring that an Ack step occurs
after each input step. In particular, an input step of IC 2 is a DispOrNot
step, after which eventually Ack is enabled—either immediately if the input
is rejected or after a Display step that WFv (Display) implies must occur.
When Ack is enabled, WFv (Ack ) implies that an Ack step must occur.
For IC 2s to implement IC 1 under a refinement mapping, it should ensurethat an input step is eventually followed by an Ack s step. In IC 2s , an input
is entered by an (s = 0) ∧ InpOrNot s step. We must show that such a stepis eventually followed by an Ack s step. This appears problematic because if

CHAPTER 6. AUXILIARY VARIABLES

182

the step rejects the input, then it sets s to 1, in which case the only enabled
action of Next2s is (s = 1) ∧ InpOrNot s ; and L2 asserts no fairness condition
for that action. To show that the (s = 0) ∧ InpOrNot s step must be followedby an Ack s step, we first show as follows that ∃ s : IC 2s is equivalent to IC 2:∃ s : IC 2s ≡ ∃ s : ICen2 ∧ L2
≡ (∃ s : ICen2s ) ∧ L2
≡ ICen2 ∧ L2
≡ IC 2

By definition of IC 2s .
Because s does not occur in L2.
By Theorem 6.4.
By definition of IC 2s .

Any behavior that satisfies IC 2s satisfies ∃ s : IC 2s , so it satisfies IC 2. An(s = 0) ∧ InpOrNot s step is an InpOrNot step, which by IC 2 must eventually be followed by an Ack step, which by definition of ICen2s must be an
Ack s step. Thus, IC 2s implies that any input step is eventually followed byan Ack s step.
In the case of the input being rejected, the necessary (s = 1)∧InpOrNot s
step must occur to satisfy the fairness requirement WFv (Ack ) on the action
Ack in IC 2. If you think of the abstract program IC 2s as instructions
to a computer for generating behaviors, then this makes no sense. How
can a fairness condition on Ack tell the computer to take an InpOrNot s
step? But by now, you should understand that an abstract program isa predicate on behaviors, not instructions for generating them. Formula
ICen2s ∧ WFv (Ack ) implies that if a state with s = 1 has been reached,then there must be another InpOrNot s step and then an Ack s step in the
behavior.
This may seem weird. The source of the apparent weirdness is thatICS 2 contains a fairness condition on the action Ack , which is not a subaction of the next-state action Next2s . Fairness conditions on actions not a
subaction of the next-state action can lead to weirdness, including program
descriptions that are not machine closed. However, in this case, we still geta machine-closed program description. In fact, this is true in general. If
hT , Li is machine closed and T s is obtained from T by adding a stuttering
variable, then hT s , Li is also machine closed. The proof is the same as theone for history variables sketched in Section 6.2.2, except in defining the
behavior τ , we may have to add stuttering steps to σ as well as changing
the values of the variable s. Stuttering insensitivity of L implies that ρ ◦ τstill satisfies L.
We now explain the proof of (6.13). As before, define F to equal(F with aw ← awBar ) for any formula F , so (6.13) asserts |= IC 2s ⇒ IC 1.

CHAPTER 6. AUXILIARY VARIABLES

183

The proof of |= ICen2s ⇒ ICen1 is discussed in Section 6.3.2, so we consider
only the proof of |= IC 2s ⇒ L1 , which requires proving:(6.14) (a) |= IC 2s ⇒ WFv (DispOrNot)(b) |= IC 2s ⇒ WFv (Ack )We now sketch a proof of (6.14a). As usual when proving temporal properties, instead of assuming IC 2s , which is true only for a behavior starting ina state satisfying Init2s , we assume this 2 formula implied by IC 2s
IIC 2s = 2Inv 2 ∧ 2[Next2s ]vs ∧ L2∆

where Inv 2 is an invariant of ICen22 that asserts some obvious invariants
such as type correctness. Here is the proof sketch.
1. Suffices: Assume: IIC 2s ∧ 2 EhDispOrNotiv ∧ 2[¬DispOrNot]v
Prove: 3hDispOrNotiv
Proof: By (4.15).
2. 2((aw 6= h i) ∨ (s 6= 0))
Proof: The definition of DispOrNot implies that EhDispOrNotiv equals
aw 6= h i, so the step 1 assumption 2 EhDispOrNotiv implies 2aw 6= h i;and the definition of awBar implies aw 6= h i equals (aw 6= h i) ∨ (s 6= 0).
3. 32(aw 6= h i) ∨ 32(s 6= 0)
3.1. 2 ( (aw 6= h i) ⇒ 2(aw 6= h i) )Proof: The assumption IIC 2s implies that aw 6= h i can be madefalse only by a Display s step, which by C3 is a hDispOrNotiv step.
The assumption 2[¬DispOrNot]v implies that such a step can’t occur.
Therefore, if aw 6= h i ever becomes true, then it must remain true
forever.
3.2. Q.E.D.
Proof: By steps 2 and 3.1 and the temporal logic tautology:|= 2(F ∨ G) ∧ 2(F ⇒ 2F ) ⇒ (32F ∨ 32G)
4. Case: 32(aw 6= h i)
Proof: Since aw 6= h i equals EhDisplayiv , the case assumption andWFv (Display) imply that, when 2(aw 6= h i) becomes true, a hDisplay iv
step eventually occurs, and IIS s implies that this step must be a Display s
step. By C3, this Display s step is a hDispOrNotiv step, which implies thegoal introduced by step 1.

CHAPTER 6. AUXILIARY VARIABLES

184

5. Case: 2(s 6= 0)
Proof: The case assumption and the assumption 2Inv 2 imply 2(s = 1).
As shown above in the explanation of why a behavior of IC 2s can’t halt
in a state with s = 1, the property WFv (Ack ) implies that, in such astate, an (s = 1) ∧ InpOrNot s step must eventually occur. By C2, that is
the hDispOrNotiv step that proves the step 1 goal.
6. Q.E.D.
Proof: Step 3 implies that the step 4 and 5 cases are exhaustive.
The proof of (6.14b) is similar but simpler, since it doesn’t have thecomplication of deducing from fairness of one action (Ack s ) that a step ofanother action (DispOrNot s ) of the same program must occur.
Theorem 6.2 shows how, after adding a history variable to a program,we can rewrite the program’s fairness properties as fairness conditions of
subactions of the modified program’s next-state action. I don’t know if
there is a similar result for stuttering variables. Theorem 6.2 is relevant
to methods other than TLA for describing abstract programs. Those othermethods that I’m aware of do not assume stuttering insensitivity, so a similar
result for stuttering variables seems to be of no interest.

6.3.5

Infinite-Stuttering Variables

Suppose a terminating program is described by a formula ∃ y : IS , where
IS implies that the value of y keeps changing forever. (IS implies that atsome point, the values of all its other variables stop changing.) Suppose
also that program ∃ y : IS is refined by a terminating program T with nointernal variables, so all its variables eventually stop changing. The methodsof adding stuttering steps to a program described so far add a finite numberof stuttering steps to non-stuttering steps of the program. They can’t definea state function that keeps changing forever, so they can’t be used to definea refinement mapping to show that T implements ∃ y : IS .
It’s easy to construct an example of such programs IS and T , but I can’t
imagine one occurring in practice. We consider them only for completeness—and in particular, to prove the completeness theorem in Section 6.4.4 statingthat if |= T ⇒ ∃ y : IS is true for some tuple y of variables, then we can add
auxiliary variables to T to obtain a program T a that implements IS undera refinement mapping. For that theorem to be true, we need to define an
infinite-stuttering variable whose value keeps changing forever to handle thissituation that never occurs in practice.

CHAPTER 6. AUXILIARY VARIABLES

185

There are lots of ways to define an infinite-stuttering variable. Here is
the definition used in the proof of Theorem 6.6. Let T equal Init ∧2[Next]v ,where v is the tuple of all variables that appear in T , and let s not be oneof those variables. We then define T s to equal:
Init ∧ 2[(Next ∧ (v 0 6= v )) ∨ ((s 0 6= s) ∧ (v 0 = v )]v ◦hs i ∧ 23hs 0 6= s is

6.4

Prophecy Variables

Math XI
General Recursive Definitions We have recursively defined a function
f with domain N by defining f (0) and defining f (n) in terms of f (n − 1)for n > 0. That is, we can define f by:f∆= n ∈ N 7→ if n = 0 then exp 0 else exp 1
where the value of exp 0 cannot depend on f and the valueof exp 1 can depend only on the value of f (n − 1).

We can generalize this by allowing the value of exp 1 to depend on f (i ) for
any i ∈ {j ∈ N : j < n}. Moreover, the condition that exp 0 not depend on
f can be expressed as the condition that it can depend only on f (i ) withi ∈ {j ∈ N : j < 0}, since that allows exp 0 to depend on f (i ) only if i isin the empty set. We can therefore express this more general form of arecursive definition as:
RC1. f∆= n ∈ N 7→ exp
where the value of exp can depend on the value of f (i ) only ifi ∈ {j ∈ N : n > j }.

RC1 ensures a meaningful definition of f because it implies that the valueof f (n) can be computed from the definition in a finite number of steps, for
any n ∈ N. The reason the computation terminates is that the relation > iswell-founded on the set N of natural numbers. We can generalize RC1 fromN to any set S with a well-founded relation  to obtain this most generalform of a recursive function definition:
RC2. f∆= n ∈ S 7→ exp
where f occurs in exp only in an expression f (i ) withi ∈ {j ∈ S : n  j } and  a well-founded relation on S .

CHAPTER 6. AUXILIARY VARIABLES

186

As an example, we can define the sum SSum(σ) of the items of a finite
sequence σ of real numbers to equal 0 if σ is the empty sequence h i and otherwise to equal the first element of σ plus the sum of its remaining elements.
The definition is:∆

SSum =σ ∈ Seq( R) 7→ if σ = h i then 0
else Head (σ) + SSum(Tail (σ))
This definition is justified by the well-founded ordering  on Seq( R) defined∆by σ  τ = Len(σ) > Len(τ ) .
Two Set Operators If you’ve ever learned about sets, you should knowthat S ∪ T is the set of values that are in the set S or the set T (or both),and S ∩ T is the set of values that are in both S and T . We can define ∩with the subsetting constructor, since S ∩ T equals {v ∈ S : (v ∈ T )}.1 It isan axiom of ZF that S ∪ T is a set if S and T are sets.

6.4.1

Simple Prophecy Variables

We observed in Section 6.3.1 that the descriptions Cen1 and Cen2 of thecensor system were equivalent. We showed that Cen2 implies Cen1, which
required adding a stuttering variable to ICen2. We now complete the demonstration of equivalence by showing that Cen1 implies Cen2. This requires
defining a state function awBar such that ICen1 implies:(ICen2 with aw ← awBar )However, this is impossible for the following reason. Because the refinement
mapping substitutes the variables inp and disp of ICen1 for the corresponding variables of ICen2, an Input step of ICen1 must implement an InpOrNot
step of ICen2. Besides choosing the input, the InpOrNot action of ICen2
also decides whether or not that input is to be displayed, recording its decision in the value of aw . However, that decision is made by ICen1 later,when executing the DispOrNot action. Immediately after the Input action,
there’s no information in the state of ICen1 to determine what the value ofvariable aw of ICen2 should be.
The solution to this problem is to have the Input action guess what
DispOrNot will do, indicating its guess by setting a prophecy variable p to
1

The parentheses disambiguate this expression, telling us that v ∈ T is a formula whilev ∈ S is syntax.

CHAPTER 6. AUXILIARY VARIABLES

187

a value that predicts whether the input will be displayed or rejected by the
DispOrNot step.
To make the generalization from this example more obvious, let’s write
action DispOrNot of ICen1 as the disjunction of two actions: DorN Yes that
displays the input and DorN No that doesn’t. Remember that:∆

DispOrNot = ∧ . . .
∧ ∨ disp 0 = haw (1), 1 − disp(2)i∨ disp 0 = disp..
.
We can define DorN i , for i = Yes and i = No, by modifying the definitionof DispOrNot to get:∆

DorN i = ∧ . . .
∧ ∨ (i = Yes) ∧ (disp 0 = haw (1), 1 − disp(2)i)∨ (i = No) ∧ (disp 0 = disp)..
.
We then replace DispOrNot in ICen1 by ∃ i ∈ Π : DorN i , where Π equals{Yes, No}. We can then add to ICen2 an auxiliary variable p called aprophecy variable to obtain a formula ICen2p in which the Input action is
replaced by
Input p = Input ∧ (p 0 ∈ Π)∆and the DispOrNot action is replaced by:∆

DispOrNot p = DorN p
Thus the Input p action predicts what the DispOrNot action will do, and
DispOrNot p is modified to ensure that the prediction comes true. To complete the definition of ICen1p , we can let Init p equal Init and Ack p equal
Ack , since the value of p matters only after an Input p step and before thefollowing DispOrNot p step.
In ICen2, the value of aw is h i except after an InpOrNot step that choseto display the input. This implies(6.15) |= ICen1p ⇒ (ICen2 with aw ← awBar )where awBar is defined by:∆

awBar = if aw 6= h i ∧ (p = Yes) then aw else h i

CHAPTER 6. AUXILIARY VARIABLES

188

To show that (6.15) implies |= ICen1 ⇒ ICen2, we have to show that p is an
auxiliary variable—that is, we have to show that ∃ p : ICen1p is equivalent
to ICen1. To do that, we prove two things:
1. Every behavior satisfying ICen1p satisfies ICen1
Proof: It’s clear that Init p equals Init, Act p equals Act, and Input p implies Input. To complete the proof, we must show that every DispOrNot p
step is a DispOrNot step. It’s easy to see that
E(DispOrNot p ) ⇒ (p ∈ {Yes, No})is an invariant of ICen1p , and to check that DispOrNot p implies DispOrNot
for each of those two values of p.
2. For any behavior σ satisfying ICen1 there is a behavior τ satisfying
ICen1p such that σ 'p τ .
Proof: We let σ be a behavior satisfying ICen1 and construct the statesof τ from the states of σ by specifying the value of p in each of thosestates, so obviously σ ' p τ . The behavior τ will satisfy ICen1p if thevalues chosen for p satisfy these three conditions:
1. The value of p in the second state of a stuttering step of σ (oneleaving the variables of ICen1 unchanged) is the same as its value inthe first state of the step.
2. After an Input p step, the value of p is either Yes or No.
3. In the first state of a DispOrNot step of σ, the value of p must makethat step a DispOrNot p step of τ .
We define the values of p in all states of τ as follows. We let p have any
value in the initial state. In any other state of τ , we let the value of p be
the same as its value in the previous state except if the state is the second
state of an Input step of σ. In that case, we let the value of p equal Yes
if the next DispOrNot step of σ changes disp; otherwise we let it equalNo. (If there is no next DispOrNot step, so there remain only stuttering
steps, we can let p have either value.) It’s easy to check that this way ofdefining p makes it satisfy the three conditions. End Proof
Let’s now generalize from this example. We want an action B to predictthe result of the next execution of an action A. We do this by writing A as
∃ i ∈ Π : Ai for a constant set Π of possible predictions and having B predict
for which value of i the next A step will be an Ai step. Action B makes theprediction by setting the variable p to equal its prediction, so we define B p

CHAPTER 6. AUXILIARY VARIABLES

189

to equal B ∧ (p 0 ∈ Π). The prediction is made to come true by defining Ap
to equal Ap .
One way our example was special is that the prediction made by an
Input p step is used by DispOrNot p in the first non-stuttering step after it
is made. This allowed ICen1p to leave the new value of p unspecified byother actions. Usually, there can be steps of other actions between when theprediction is made and when it is fulfilled. Those other actions should leave
the value of p unchanged. For any subaction B of the next-state action otherthan A, we let B p equal either B ∧ (p 0 = p) if it doesn’t make a prediction
or B ∧ (p 0 ∈ Π) if it makes one. It doesn’t matter if multiple predictions are
made for the same A step; only the most recent one counts.
There is no reason not to let p always equal an element of Π, so we will
do that. This means we let Init p equal Init ∧ (p ∈ Π). This can represent
an initial prediction, or it can be overridden by a subsequent prediction. In
either case, it means that we have the type invariant 2(p ∈ Π).
It doesn’t matter if a prediction is never used—either because it is overridden by another prediction or an A step never occurs. What does matter isthat a prediction must be used at most once. Our ability to choose the right
prediction in the proof that ∃ p : ICen1p is equivalent to ICen1 depended
on this. To make sure that this is true, we require that Ap makes a prediction, so we define Ap to equal Ap ∧ (p 0 ∈ Π). That prediction can always
be overridden by a subsequent prediction made by a different action. The
argument above that the variable p in our example was a prophecy variable
then generalizes to prove:
Theorem 6.5 (Simple Prophecy Variable) Let T = Init ∧ 2[Next]v
where v is the tuple of variables in T , let∆∆

Next = (∃ i ∈ Π : Ai ) ∨ (∃ j ∈ J : B j )and let Π be a constant set. If p is not a variable of T ,T p = Init p ∧ 2[Next p ]vp ,∆∆vp = v ◦ hp i ,∆Init p = Init ∧ (p ∈ Π) ,∆Next p = (Ap ∧ (p 0 ∈ Π)) ∨ (∃ j ∈ J : B j ∧ C j ) ,and each C j equals p 0 = p or p 0 ∈ Π, then |= (∃ p : T p ) ≡ T .
The theorem makes no disjointness assumption about the actions Ai and
B j , but in most applications of the theorem they will be mutually disjoint.

CHAPTER 6. AUXILIARY VARIABLES

190

It is inelegant and possibly confusing to have a program make predications that are never used—for example, by having the DispOrNot p action of
ICens1p make a prediction that is always replaced by the prediction madeby the Input p action. If the prediction will never be used, we can replacep 0 ∈ Π by p 0 = None (or p ∈ Π by p = None for an initial prediction),where None is a value not in Π. The assertion that the prediction is neverused means that the following state predicate is an invariant of T p :(p = None) ⇒ ¬ E(∃ i ∈ Π : Ai )We could also modify Next p to allow a special value of p indicate that no
prediction is being made, but there is no reason to do that.

6.4.2

Predicting the Impossible and Liveness

What if a prophecy variable makes a prediction that can’t be fulfilled? Aprophecy variable predicts, for an action A equal to ∃ i ∈ Π : Ai , the valueof i for which the next A step is an Ai step. The prediction that the next A
step will be an Ap step can’t be fulfilled if action Ap can’t be enabled until
an Aj step occurs for some j 6= p.
Let’s look at the worst case: a prediction that predicts that the next A
step will be an Ai step, where Ai equals false. We can write any next-state
action Next as∃ i ∈ {0, 1} : ((i = 1) ∧ Next) ∨ ((i = 0) ∧ false)(If i = 0, then a [Next]v step leaves the variables of v unchanged.) The
observation that ∃ i ∈ {0, 1} : F i equals F 0 ∨ F 1 and a bit of propositional
logic show that|= ∃ i ∈ {0, 1} : (p = i ) ∧ (((i = 1) ∧ Next) ∨ ((i = 0) ∧ false))
equals (p = 1) ∧ Next. Theorem 6.5 therefore implies that if T equals
Init ∧ 2[Next]v , then T equals ∃ p : T p where∆T p = ∧ Init ∧ (p ∈ {0, 1})∧ 2 [ (p = 1) ∧ Next ∧ (p 0 ∈ {0, 1}) ]vp
In other words, if p ever becomes equal to 0, then the next-state relation of
T p is never again enabled, so the behavior halts with an infinite sequenceof stuttering steps—ones that leave p and the variables of T unchanged.
But that’s perfectly OK. T is a safety property; it allows behaviors
that terminate at any point. The prophecy variable p is simply predicting
whether the behavior will terminate before the next Next step.

CHAPTER 6. AUXILIARY VARIABLES

191

If we are describing an abstract program in which hNext iv is always
enabled and its execution is never supposed to stop, then we must conjoin
to T some fairness property, such as WFv (Next). If hNext iv is enabledin every reachable state of T , then it is enabled in every reachable stateof T p , since the reachable states of T p are reachable states of T because
T equals ∃ p : T p . In that case, conjoining WFv (Next) to T p adds therequirement that in every behavior, an infinite number of non-stuttering
Next steps must occur. In our worst-case example, p = 0 implies Next p =false, so T p ∧ WFv (Next) is satisfied only by behaviors in which infinitely
many hNext iv steps occur, and hence in which p never equals 0.
Conjoining WFv (Next) to T p rules out finite behaviors allowed by T p —ones in which p equals 0. Hence, the pair hT p , WFv (Next)i is not machineclosed, so WFv (Next) is not a fairness property for T p . This doesn’t contradict Theorem 4.7, because Next, which is a trivial subaction of Next, is
not a subaction of Next p . In general, if predicting that the next A step is
an Ap step is a nontrivial predication, then every possible A step can’t be a
Next p step, so |= A ⇒ Next p can’t be true—which by definition means A is
not a subaction of Next p .
As dramatically illustrated by this example, adding a prophecy variable
that can make impossible predictions to a description of an abstract programwith a fairness property produces a hsafety, livenessi pair that is not machineclosed. Although this is not a typical example, in practice prophecy variables
often do make impossible predictions. This is usually because it’s easier not
to eliminate them. That’s the case for the example in Section 6.5.
Programs that are not machine closed are weird, and unintentional weirdness usually indicates an error. An abstract program that describes how aconcrete program works should be machine closed, because coding languages
have no way of expressing liveness properties that are not fairness properties. Abstract programs that are not machine closed should almost always
be avoided because they’re hard to understand. However, there are exceptions [25, Section 3.2]. On the other hand, prophecy variables are added
to a program only for verifying that it implements another program. Thereis no reason adding a prophecy variable should produce a machine closed
program.

6.4.3

General Prophecy Variables

A simple prophecy variable makes a single prediction. General prophecy
variables can make multiple predictions. Those multiple predictions can be
successive predictions about a single action or separate predictions about

CHAPTER 6. AUXILIARY VARIABLES

192

different actions. These two possibilities are illustrated with variants ofthe censor system. There can also be multiple predictions about multiple
actions, but we won’t try to be that general. The two examples illustrate
the concepts. A very general definition has been described elsewhere forexpert TLA+ users [38].
6.4.3.1

A Sequence of Prophecies

Let’s now modify the censor programs to allow the artist to submit a new
picture before the censor has either displayed or rejected the previous submission. At any time, there may be a queue of submissions being processedby the censor. In the modified version of ICen1, called ICenSeq1, the censor
has not yet decided whether to display or reject any of the submissions inthat queue. In ICenSeq2, the modified version of ICen2, the censor decides
immediately whether to accept or reject a submission and maintains only aqueue of submissions to be displayed.
Formula CenSeq1 is defined in Figure 6.6, where everything is in grayexcept for parts that differ from the corresponding parts of the definitionof Cen1 in Figure 6.4 other than by adding “Seq” to names. Because of
the way we defined Cen1, with aw equal to a sequence of 0 or 1 pictures,the changes are minimal. (Recall the definitions of Tail and Append from
Section 2.8.3.)
Similarly, Figure 6.7 shows the definition of CenSeq2, using formulas
defined in Figure 6.6. Shown in black are the parts that differ from thecorresponding parts in the definition of Cen2 in Figure 6.5 by more than aname change.
In both ICenSeq1 and ICenSeq2, the value of the variable aw is thequeue being maintained by the censor. As with ICen1 and ICen2, when aw
is hidden by ∃ , the two formulas are equivalent. As in the previous example,
ICenSeq2 decides whether to display or reject an input before ICenSeq1 does.
To define a refinement mapping to show ICenSeq1 implements ICenSeq2, weneed to add a prophecy variable p to ICenSeq1 that is set by the Input action
and predicts the decisions that will be made by the DispOrNotSeq action.
However, this time there are multiple predictions to be remembered—one
for every picture in aw .
You have probably figured out that this will be done by letting thevalue of p be a sequence of Yes or No values, each element of p predicting
whether the corresponding input in the sequence aw will be displayed or
rejected by the DispOrNot action. Here’s how we define ICenSeq1p , theformula obtained by adding the prophecy sequence variable p to ICenSeq1.

CHAPTER 6. AUXILIARY VARIABLES∆
CenSeq1 = ∃ aw : ICenSeq1

ICenSeq1 = Init ∧ 2[NextSeq1]v∆∆

v = hinp, disp, aw i∆

InitSeq = ∧ inp = NotArt∧ aw = h i∧ disp ∈ Art × {0, 1}∆

NextSeq1 = InputSeq ∨ DispOrNotSeq ∨ AckSeq∆

InputSeq = ∧ inp = NotArt∧ inp 0 ∈ Art∧ aw 0 = Append (aw , inp 0 )∧ disp 0 = disp∆

DispOrNotSeq = ∧ aw 6= h i∧ ∨ disp 0 = haw [1], 1 − disp(2)i∨ disp 0 = disp
∧ aw 0 = Tail (aw )∧ inp 0 = inp∆
AckSeq = ∧ inp ∈ Art∧ inp 0 = NotArt∧ (aw 0 = aw ) ∧ (disp 0 = disp)
Figure 6.6: The program CenSeq1.
∆
CenSeq2 = ∃ aw : ICenSeq2

ICenSeq2 = InitSeq ∧ 2[NextSeq2]v∆∆

NextSeq2 = InpOrNotSeq ∨ DisplaySeq ∨ AckSeq∆

InpOrNotSeq = ∧ inp = NotArt∧ inp 0 ∈ Art∧ ∨ aw 0 = Append (aw , inp 0 )∨ aw 0 = aw
∧ disp 0 = disp∆

DisplaySeq = ∧ aw 6= h i∧ disp 0 = haw [1], 1 − disp(2)i∧ aw 0 = Tail (aw )∧ inp 0 = inp
Figure 6.7: The program CenSeq2.

193

CHAPTER 6. AUXILIARY VARIABLES

194

Let Π be the set {Yes, No} of predictions. The value of p should always
be a sequence of elements of Π having the same length as the value of thevariable aw of ICenSeq1. The initial predicate of ICenSeq1p is:∆

Init p = InitSeq ∧ (p = h i)
In addition to appending the input to aw , the action InputSeq p must append
to p the prediction of whether or not that input will be displayed:
InputSeq p = InputSeq ∧ (∃ i ∈ Π : p 0 = Append (p, i ))∆As in ICen1p , to make DispOrNotSeq p display the input iff p predicts that
it will, we define DorNSeq i so that∆

DispOrNotSeq = ∃ i ∈ Π : DorNSeq i
where DorNSeq Yes displays the input and DorNSeq No rejects it. The definition of DorNSeq i is obtained by modifying DispOrNotSeq the same way
we modified DispOrNot to obtain DorN i for ICen1. We can then define:
DispOrNotSeq p = DorNSeq p(1) ∧ (p 0 = Tail (p))∆

Note that having DispOrNotSeq p set p 0 to Tail (p) ensures that every prediction is used only once. Since AckSeq p neither makes nor satisfies a prediction, we define:
AckSeq p = AckSeq ∧ (p 0 = p)∆

Putting this all together we get:ICenSeq1p = InitSeq p ∧ 2[NextSeq1p ]vp
∆

where
∆

NextSeq1p = InputSeq p ∨ DispOrNotSeq p ∨ AckSeq p
and vp equals hinp, disp, aw , p i.
We can now show that CenSeq1 implements CenSeq2 by showing(6.16) |= ICenSeq1 ⇒ (ICenSeq2 with aw ← awBar )where awBar is the subsequence of aw containing only the pictures that p
predicts will be displayed.

CHAPTER 6. AUXILIARY VARIABLES

195

To define awBar , we first define OnlyYes(wsq, ysq) to be the subsequenceof the sequence wsq consisting of all elements for which the corresponding elements of the sequence ysq equals Yes. We define OnlyYes to be afunction of two arguments with domain the set of pairs hwsq, ysq i where
wsq is a sequence of elements of Art, ysq is a sequence of Yes or No values, and Len(wsq) = Len(ysq). (Remember that a function of two arguments is really a function of one argument whose domain is a set of pairs.)
The definition is a recursive one, justified by the well-founded relation 
where hwsq 1 , ysq 1 i  hwsq 2 , ysq 2 i iff the length of sequences wsq 1 and ysq 1
is greater than the length of wsq 2 and ysq 2 . Since we haven’t bothered todefine a convenient syntax for writing recursive definitions of functions of
two arguments, the definition is written somewhat informally as:∆

OnlyYes(wsq, ysq) =if wsq = h i then h ielse ( if Head (ysq) = Yes then hHead (wsq)i
else h i )◦ OnlyYes(Tail (wsq), Tail (ysq))
Defining awBar to equal OnlyYes(aw , p) makes (6.16) true.
It’s straightforward to modify Theorem 6.5 to describe an arbitrary
prophecy variable p that makes a sequence of predictions. We replace thedefinition of Next p in the hypothesis of the theorem by:∆

Next p = (Ap(1) ∧ D) ∨ (∃ j ∈ J : B j ∧ C j ) , where
D equals p 0 = Tail (p) or ∃ i ∈ Π : p 0 = Append (Tail (p), i )C j equals p 0 = p or ∃ i ∈ Π : p 0 = Append (p, i )However, there’s one problem: The empty sequence h i is the value of p
indicating that no prediction is being made. When p = h i, the value of thesubscript p(1) = i in this definition is undefined. That doesn’t matter inour example because p and aw are sequences of the same length, so p = h i
implies aw = h i, which implies that DorNSeq i equals false for i ∈ Π.
Therefore, the value of the undefined subformula makes no difference. In
general, to make the modified theorem valid, we need to add to its hypothesis
the requirement that the following is an invariant of T p :(p = h i) ⇒ ¬ E (∃ i ∈ Π : Ai )6.4.3.2

A Set of Prophecies

To illustrate a prophecy variable that makes a set of concurrent predictions,
we now modify the censor programs CenSeq1 and CenSeq2 so that instead

CHAPTER 6. AUXILIARY VARIABLES

196

of displaying pictures in the order in which they were submitted, the censor
can display them in any order. This is represented by letting aw be a set
rather than a sequence of pictures. It is done in the two programs ICenSet1
and ICenSet2, where the first lets aw be the set of all unprocessed inputs
and the second lets aw contain just the ones that will be displayed. Letting
CenSet1 and CenSet2 be the programs obtained from these two programsby hiding aw , we want to show that CenSet1 implements CenSet2. As you
probably realize, defining a refinement mapping to show that this is true
requires adding a prophecy variable p to ICenSet1 that predicts which of
the inputs in aw will be displayed.
Writing these two censor programs poses a problem. What if the artist
submits the same picture twice? If we want the picture to be displayed twice,
we would need to have two copies of it in aw , which means aw couldn’t
simply be a set. In the example of Section 6.5, you’ll see one way of keeping
multiple copies of a value in a set. But for simplicity, we’ll modify the censor
programs not to allow the artist to submit the same picture twice. This will
be done by adding an interface variable old whose value is the set of all
previously submitted pictures.
The definition of CenSet1 is in Figure 6.8, with the changes from thedefinition of CenSeq1 (Figure 6.6) in black. You should be able to write thedefinition of CenSeq2 yourself.
To define a refinement mapping under which ICenSet1 implements
ICenSet2, we need to add a prophecy variable p to ICenSet1 that predicts,
for each picture in aw , whether or not that picture will be displayed. The
obvious way to do that is to let the value of p be a function in aw → Π , theset of functions from aw to Π. As before, we let Π equal the set {Yes, No}.
Since aw initially equals the empty set, the initial value of p should be
the function whose domain is the empty set. There is just a single suchfunction, and the easiest way to write it is as the empty sequence h i, which
is a (and hence the) function whose domain is the empty set. So, we define:∆

InitSet p = InitSet ∧ (p = h i)
The InputSet p action must add a prediction of whether or not the picture
inp 0 that it adds to aw will be displayed. Thus, it must assert that p 0 is
the function obtained from p by adding inp 0 to its domain and letting thevalue of p 0 (inp 0 ) be either element in Π. To write that action, let’s define
FcnPlus(f , w , d ) to be the function obtained from a function f by adding anelement w to its domain and letting that function map w to d . The domain

CHAPTER 6. AUXILIARY VARIABLES

197∆
CenSet1 = ∃ aw : ICenSet1

ICenSet1 = Init ∧ 2[NextSet1]v∆∆

v = hinp, disp, aw , old i∆

InitSet = ∧ inp = NotArt∧ aw = { }∧ disp ∈ Art × {0, 1}∧ old = { }∆NextSet1 = InputSet ∨ DispOrNotSet ∨ AckSet∆

InputSet = ∧ inp = NotArt∧ inp 0 ∈ Art \ old∧ aw 0 = aw ∪ {inp 0 }∧ (disp 0 = disp) ∧ (old 0 = old ∪ {inp 0 })∆DispOrNotSet = ∃ w ∈ aw :∧ ∨ disp 0 = hw , 1 − disp(2)i∨ disp 0 = disp
∧ aw 0 = aw \ {w }∧ (inp 0 = inp) ∧ (old 0 = old )∆AckSet = ∧ inp ∈ Art∧ inp 0 = NotArt∧ (aw 0 = aw ) ∧ (disp 0 = disp) ∧ (old 0 = old )Figure 6.8: The program CenSet1.
of f is written domain(f ), so the definition is:∆

FcnPlus(f , w , d ) =x ∈ {w } ∪ domain(f ) 7→ if x = w then d else f (x )We can then define
InputSet p = InputSet ∧ (∃ i ∈ Π : p 0 = FcnPlus(p, inp 0 , i ))∆To define DispOrNotSet p , we define DorNSet i (w ) as follows so DispOrNotSet
equals ∃ w ∈ aw , i ∈ Π : DorNSet i (w ) .
∆DorNSet i (w ) = ∧ ∨ (i = Yes) ∧ (disp 0 = hw , 1 − disp(2)i)∨ (i = No) ∧ (disp 0 = disp)∧ aw 0 = aw \ {w }∧ (inp 0 = inp) ∧ (old 0 = old )CHAPTER 6. AUXILIARY VARIABLES

198

The DispOrNotSet p action will have to erase the prediction by removingfrom the domain of p the picture being displayed or rejected. So let’s define FcnMinus(f , w ) to equal the restriction of f to its domain minus theelement w :∆FcnMinus(f , w ) = x ∈ (domain(f ) \ {w }) 7→ f (x )We can now define:∆

DispOrNotSet p =∃ w ∈ aw : DorNSet p(w ) (w ) ∧ (p 0 = FcnMinus(p, w ))Since AckSet p neither makes nor satisfies a prediction, its definition is simply:
AckSet p = AckSet ∧ (p 0 = p)∆

The rest of the definition of ICenSet1p should be clear.
We can then show that CenSet1 implements CenSet2 by showing|= ICenSet1p ⇒ (ICenSet2 with aw ← awBar )where awBar equals {w ∈ aw : p(w ) = Yes}, the set of elements in aw
that p predicts will be displayed.
We won’t bother writing the generalization of Theorem 6.5 for a prophecy
variable p that makes a set of predictions.
6.4.3.3

Further Generalizations

We now extract from our examples a more general formulation of prophecy
variables. To construct a prophecy variable, we start with certain sets of actions we’ll call action sets. For CenSeq1 there is one action set consisting of
two actions: DispOrNotSeq Yes , a DispOrNotSeq action that displays the picture, and DispOrNotSeq No , a DispOrNotSeq action that doesn’t display it.
For CenSet1, for every w ∈ Art, there is an action set consisting of two actions: DispOrNotSet w ,Yes and DispOrNotSet w ,No , which are DispOrNotSet
actions that either display or don’t display the input w . Thus, there is a setof action sets, one action set defined for each w in Art.
In general, for a program T , we have a set of action sets, each of which
can be written as {Ai : i ∈ Π}. (The set Π can be different for different
action sets.) That set of action sets is a constant; it doesn’t change during
a behavior of T .

CHAPTER 6. AUXILIARY VARIABLES

199

A prophecy is a prediction about one of the program’s action sets. Thatis, it is an element of the set Π defining the action set {Ai : i ∈ Π}. It predicts
the value of i for which the next Ai step occurs. In any state, the value ofa prophecy variable describes a set of predictions, some of which are active.
For CenSeq1, the prophecy variable p equals a sequence of predictions, allfor the same action set, only the first element of the sequence being active.
For CenSet1, the prophecy variable p equals a set of prophecies, one for eachaction set defined by an element of aw , all of its prophecies being active.
In general, the program T p is defined by adding the variable p in sucha way that every behavior satisfying T p satisfies T . Moreover, it ensuresthat no active prediction of p is ever violated. When an action predictedby an active prediction of p occurs, we say that the prediction is fulfilled.
The initial value of p can contain prophecies. Prophecies can be added toor removed from p and/or made active or inactive by any action of T p , solong as the following conditions are satisfied:• No two active prophecies can be predictions for the same action set.
• For any action of T p that adds a prophecy to p, it must be possible
for the action to add a prophecy for any element of the set Π for that
action set.
• An action of T p that fulfills a prediction must remove that prediction
from p. (It may also add one or more new predictions.)
The prophecy variables of CenSeq1 and CenSet1 made only predictions thatwere likely to be fulfilled. We could instead have used prophecy variables
that a mathematician might consider simpler that make a lot more predictions. For CenSeq1, instead of having each InputSeq step add a prediction
to p, we could have let the initial value of p be an infinite sequence of predictions. The first element of the sequence would be the active one, and each
DispOrNotSeq action would remove that element from p. For CenSet1, we
could have let the initial value of p be any element of Art → {Yes, No} ,predicting for each picture w whether or not it will be displayed if it is input. Since the same picture can’t be input twice, the value of p(inp) could
be set by a DispOrNotSet action to a value indicating that its prediction isinactive.
We could have used an even more extravagant prophecy variable for
CenSet1—one that predicts not only whether each picture will be displayedor rejected, but in which order they will be input. The initial value ofp would be an infinite sequence of predictions hw , d i, for w ∈ Art andCHAPTER 6. AUXILIARY VARIABLES200

d ∈ {Yes, No}, predicting not just if the next DispOrNotSet step will display
or reject the input, but that it must occur with inp equal to w . Almost allof those predictions will be impossible to fulfill because inp will not equal
w . But as we’ve seen, impossible predictions don’t matter because they
just require the behavior to halt, which is either allowed or is ruled out by
a liveness hypothesis. This may seem silly, but a prophecy variable thatmakes predictions that are almost all impossible is used in the example ofSection 6.5 because it seems to provide the simplest way to define the neededrefinement mapping.

6.4.4

The Existence of Refinement Mappings

We now state a completeness result for the auxiliary variables that we’ve
described. Completeness means that if |= T ⇒ ∃ y : IS is true, where y is
a list of variables, then we can successively add a list a of these auxiliary
variables to T to obtain a formula T a that implies IS under a refinement
mapping that substitutes state expressions of T a for the variables y.
Like most such completeness results, it assumes that there is a mathematical proof of the result based on the semantics of the formulas. Thatis, we assume not only the truth of |= T ⇒ ∃ y : IS , but that there exists
a mathematical proof of its truth. Such a proof consists of an operator Φsuch that for every behavior σ satisfying T , there is a behavior Φ(σ) satisfying IS that shows σ satisfies ∃ y : IS . This means approximately that
we can obtain Φ(σ) from σ by adding and/or removing stuttering steps andchanging the values of the variables of y. The precise statement of thiscondition is Φ(σ) ∼y σ, where the definition of ∼ y is the same as that of∼ y in Section 6.1.3 with = y replaced by = y , and s = y t defined to meanthat states s and t are equal except perhaps for the values they assign tothe variables of y. The assumption that there exists a mathematical proofof |= T ⇒ ∃ y : IS is embodied in the use of Φ to construct the refinement
mapping. Here is the precise statement of the theorem. It uses the notationthat if y is the list y 1 , . . . , y n of variables and exp is the list exp 1 , . . . , exp n of
expressions, then y ← exp is an abbreviation for y 1 ← exp 1 , . . . , y n ← exp n .
Theorem 6.6 Let x, y, and z be lists of variables, all distinct from one
another; let the variables of T be x and z and the variables of IS be x andy; and let T equal Init ∧ 2[Next]hx,zi ∧ L. Let the operator Φ map behaviors
satisfying T to behaviors satisfying IS such that Φ(σ) ∼y σ. By adding
history, stuttering, and prophecy variables to T , we can define a formulaCHAPTER 6. AUXILIARY VARIABLES

201

T a such that ∃ a : T a is equivalent to T and a list exp of expressions definedin terms of Φ and the variables of T a such that|= T a ⇒ (IS with y ← exp)
The theorem makes no assumption about L other than that it contains
no variables besides those of x and z. It doesn’t even have to be a livenessproperty.
Here is the idea behind the theorem’s proof. We first add an infinitestuttering variable t to avoid having to worry about terminating behaviors.
We then add a history variable h that remembers the entire sequence ofvalues of all the tuples hx, z, t i in all the states reached thus far, including
the current one. We then add a prophecy sequence variable p that predicts
the infinite sequence of all future values of hx, z, t i. This means that in allstates of the behavior, the value of h ◦ p is the entire sequence of valuesof hx, z, t i in the complete (infinite) behavior. Moreover, the length of hindicates the position of the current state in that behavior. The values of hand p and the mapping Φ provide all the information needed to determine
the values to substitute for y to obtain a refinement mapping under which
IS is simulated. The proof in the Appendix sketches the details.
The theorem shows that these auxiliary variables are, in principle, all
we need to define a refinement mapping. It and its proof do not tell us how
refinement mappings are defined in practice.

6.5

The FIFO Queue

This section presents a more realistic example of the use of auxiliary variables to show that one abstract program implements another. That makes
it rather long, but it’s included for two reasons. The first is that it describes
serializability, which is an important concept for designing concurrent programs. The second is that stuttering and prophecy variables are not as
intuitive as history variables, and a more realistic example may provide
some insight into how they can be used in practice.

6.5.1

Fifo – A Linearizable Specification

Popular coding languages provide a small number of built-in data types
such as finite-precision integers. Other data types must be implemented as
objects. An object has a state and methods with which the program canread and modify parts of the state. We will ignore how objects are created
and destroyed.

CHAPTER 6. AUXILIARY VARIABLES

202

A simple example of such an object is a first in, first out queue, calleda fifo. We can think of the state of a fifo as an ordinal sequence queueof elements from some set Data. A fifo provides two methods, usuallydescribed as follows.
enqueue Takes an element of Data as an argument, and appends it to theend of queue. It returns no value.2
dequeue If queue is nonempty, it removes the first element of queue andreturns it as the result. If queue is the empty sequence, it returns somespecial value.
An object is accessed only by executing its methods. For the purpose ofcorrectness, the programmer needs to know nothing about how these two
methods are implemented.
This kind of description is adequate for a method in a traditional program. It is inadequate for concurrent programs because it says nothing
about what happens if two processes concurrently access the object. The
call of a method and the return are usually described as single steps, but
execution of the operation may consist of steps that occur between those
two steps.
Often, it is considered an error if two processes concurrently access thesame object. The object must either be accessed by only one process, orelse accesses by different processes must be inside the critical section of amutual exclusion algorithm. We’re interested in objects that are meant to beaccessed concurrently by multiple processes—for example, a critical section
object for implementing mutual exclusion with enter and exit methods.
Maurice Herlihy and Jeannette Wing defined an object to be linearizable
iff if acts as if the execution of a method consists of three steps: the call,the return, and between them a single step that performs the actual reading
and/or modifying of the object’s state [18]. The state of a linearizable object
is described by internal variables. Only the call and return steps changeinterface variables. Linearizability has become a standard requirement forshared objects in concurrent systems.
We describe a linearizable fifo as an abstract program. We require that
execution of a dequeue operation when queue is empty waits for an element
to be enqueued rather than returning a special value. This makes the fifo
more interesting because it involves process synchronization—making one
process wait for another process to do something. Since the purpose of the2
Sometimes the queue can hold only some maximum number of elements, but for
simplicity we assume that there is no such limit.

CHAPTER 6. AUXILIARY VARIABLES

203

example is to illustrate the use of auxiliary variables, which are added only
to the safety property of a program, we consider only the safety property ofa fifo.
We assume there is a set EnQers of processes that perform enqueue
operations. Execution of an enqueue operation by process e consists ofthree steps: a BeginEnq(e) step that describes the call of the method, a
DoEnq(e) step that modifies the variable queue, and an EndEnq(e) step that
describes the return. The enqueuers communicate with the object throughthe interface variable enq, whose value is a function with domain EnQers.
The value of enq(e) equals Done when enqueuer e is not performing an
enqueue operation, and it equals the data value it is appending to queue
when e is performing the operation, where Done is some constant not in
Data. There is also an internal variable enqInner , where enqInner (e) is set
to Busy by the BeginEnq(e) action and is set to Done by the DoEnq(e)action.
Similarly, there is a set DeQers of dequeuer processes, each d ∈ DeQers
performing BeginDeq(d ), DoDeq(d ), and EndDeq(d ) steps. Dequeuers communicate with the object through the interface variable deq, where deq(d ) is
set to Busy by the BeginDeq(d ) action and to the value that was dequeued
by the EndDeq(d ) action. There is an internal variable deqInner , where
deqInner (d ) is set to Busy by the BeginDeq(d ) action and set by DoDeq(d )to the value dequeued by the dequeue operation. The complete definition of
the abstract program is formula Fifo in Figure 6.9. It uses the unchanged
operator, where unchanged exp equals exp 0 = exp. Thus, if v is a tuple
hv 1 , . . . , v n i of variables, unchanged v asserts that v 0i = v i for all i in
1 . . n.

6.5.2

POFifo – A More General Specification

6.5.2.1

The Background

Many people, myself included, used to believe that any implementation ofa fifo had to be a more concrete version of program IFifo, with the valueof the variable queue encoded in the program’s state. This implied that
any implementation of a fifo should implement IFifo under a refinement
mapping, without having to add auxiliary variables.
We were wrong. Suppose two processes concurrently execute enqueue
operations. When the two operations’ EndEnq steps have occurred, program
IFifo has appended both values to queue in some order, determining theorder in which they will be dequeued. However, in a behavior of programCHAPTER 6. AUXILIARY VARIABLES

204∆
Fifo = ∃ queue, enqInner , deqInner : IFifo

IFifo = Init ∧ 2[Next]v∆∆

v = henq, deq, queue, enqInner , deqInner i∆

Init = ∧ enq = (e ∈ EnQers 7→ Done)∧ deq ∈ (DeQers → Data)∧ queue = h i∧ enqInner = (e ∈ EnQers 7→ Done)∧ deqInner = deq∆

Next = ∨ ∃ e ∈ EnQers : BeginEnq(e) ∨ DoEnq(e) ∨ EndEnq(e)∨ ∃ d ∈ DeQers : BeginDeq(d ) ∨ DoDeq(d ) ∨ EndDeq(d )∆BeginEnq(e) = ∧ enq(e) = Done
∧ ∃ D ∈ Data : enq 0 = (enq except e 7→ D)∧ enqInner 0 = (enqInner except e 7→ Busy)∧ unchanged hdeq, queue, deqInner i∆

DoEnq(e) = ∧ enqInner (e) = Busy
∧ queue 0 = Append (queue, enq(e))∧ enqInner 0 = (enqInner except e 7→ Done)∧ unchanged hdeq, enq, deqInner i∆

EndEnq(e) = ∧ enq(e) 6= Done
∧ enqInner (e) = Done
∧ enq 0 = (enq except e 7→ Done)∧ unchanged hdeq, queue, enqInner , deqInner i∆

BeginDeq(d ) = ∧ deq(d ) 6= Busy
∧ deq 0 = (deq except d 7→ Busy)∧ deqInner 0 = (deqInner except d 7→ NoData)∧ unchanged henq, queue, enqInner i∆

DoDeq(d ) = ∧ deq(d ) = Busy
∧ deqInner (d ) = NoData∧ queue 6= h i∧ deqInner 0 = (deqInner except d 7→ Head (queue))∧ queue 0 = Tail (queue)∧ unchanged henq, deq, enqInner i∆

EndDeq(d ) = ∧ deq(d ) = Busy
∧ deqInner (d ) 6= NoData∧ deq 0 = (deq except d 7→ deqInner (d ))∧ unchanged henq, queue, enqInner , deqInner i
Figure 6.9: The program Fifo.

CHAPTER 6. AUXILIARY VARIABLES

205

Fifo, where queue is hidden, there is no way to know in which order the twovalues appear in queue until that order is revealed by dequeue operations. In
their paper defining linearizability, Herlihy and Wing gave an algorithm that
implements a fifo in which, from a state immediately after both enqueue
operations have completed, it is possible for the two values to be dequeued ineither order by two successive non-concurrent dequeue operations. There isno queue encoded in the algorithm. While their algorithm implements Fifo,
there is no refinement mapping under which it implements IFifo without theaddition of auxiliary variables. In particular, showing that their algorithm
implements Fifo requires adding a prophecy variable that predicts the orderin which data items enqueued by concurrent enqueue operations will bedequeued.
What is encoded in the state of their algorithm is not a linearly ordered
queue of enqueued data values, but rather a partial order on the set ofenqueued values that indicates the possible orders in which the values canbe returned by dequeue operations. A partial order on a set S is a relation ≺on S that is transitive and has no cycles (which implies a 6≺ a for any a ∈ S ).
For the partial ordering ≺ on the set of enqueued values, the relation u ≺ wmeans that value u must be dequeued before value w . Program IFifo is the
special case in which that partial order is a total order, meaning that eitheru ≺ w or w ≺ u for any two distinct enqueued values u and w .
Presented here is a program POFifo that is equivalent to Fifo, but which
is obtained by hiding internal variables in a program IPOFifo that maintains a partially ordered set of enqueued values rather than a queue. The
Herlihy-Wing algorithm can be shown to implement IPOFifo under a refinement mapping defined in terms of its variables, without adding a prophecy
variable.
6.5.2.2

Program POFifo

Execution of an operation is described by a sequence of steps. In a linearizable description, there are three steps: a step of the Begin action, a stepof the Do action, and a step of the End action. One operation execution
is defined to precede another if its End step precedes the other execution’s
Begin step. If neither of two operation executions precedes the other, thenthe executions are said to be concurrent.
Since Begin and End steps change interface variables, they appear in a
behavior of Fifo. However, a Do step changes only internal variables, so
it is not visible in a behavior of Fifo. If the executions of two enqueues
are concurrent, then a behavior of Fifo does not show in which order their

CHAPTER 6. AUXILIARY VARIABLES

206

Do steps occurred in IFifo. Only if one enqueue execution precedes theother do we know from a behavior of Fifo the order in which the enqueued
values appear in queue. Therefore, a behavior satisfies Fifo iff it satisfies thefollowing two safety properties. They are stated informally, where a value
is taken to mean a particular enqueueing of a data value.
F1. Each dequeued value has been enqueued, and an enqueued value isdequeued at most once.
F2. If an enqueue of a value v precedes an enqueue of a value w , then thedequeue of value w cannot precede the dequeue of value v .
The values enqueued by two concurrent enqueue executions may be dequeued in either order.
Program IPOFifo must maintain a set of enqueued items and some ordering relation among them. The first thing to observe is that the samedata item might be enqueued twice before any item is dequeued. Since thisis not a silly example, that possibility should be handled. An easy way to
do that is to maintain a set of pairs hd , i i where d is the enqueued data
value and i is an element of a set Ids of identifiers that serve to distinguishbetween different “copies” of an enqueued value. Let’s call such a hdata
value, identifier pairi a datum. (We will use datums as the plural of datum
because data suggests elements of Data rather than of Data × Id . We willcontinue to call an element of Data a data value.)
IPOFifo will use an internal variable elts whose value is the set of currently enqueued datums. It will also have an internal variable whose value
is an ordering relation ≺ on the set elts where, u ≺ w means that datum u
must be dequeued before datum w is. For IPOFifo to describe a linearizable
object, execution of an enqueue operation must consist of a BeginPOEnq
step, followed by a DoPOEnq step that puts the datum in elts, followed by
an EndPOEnq step. Condition F2 is satisfied if the DoPOEnq step thatputs a datum w in elts adds a relation u ≺ w for every datum u put in elts
by an enqueue operation that has completed. Of course, F1 is satisfied if
every DoPODeq step obtains its data item from a datum that it removes
from elts.
Given any behavior σ satisfying IPOFifo, we can obtain a behavior τsatisfying IPOFifo by moving every DoPOEnq step earlier in the behavior
so it occurs immediately after its operation’s BeginPOEnq step, and moving
every DoPODeq step later in the behavior so it occurs immediately before its
operation’s EndPODeq step. Moreover, since the Do . . . steps change onlyinternal variables, the values of the interface variables are the same in eachCHAPTER 6. AUXILIARY VARIABLES

207

state of τ as in σ. Therefore, without eliminating any possible behaviors of
POFifo (which are obtained by hiding the internal variables of IPOFifo),
we can require that a BeginPOEnq step be immediately followed by theoperation’s DoPOEnq step, and that an EndPODeq step be immediately
preceded by the operation’s DoPODeq step. This means that there’s noneed for the Do . . . actions; the BeginPOEnq and DoPOEnq actions can be
combined into a single action, as can the DoPODeq and EndPODeq actions.
We will therefore simplify IPOFifo be eliminating the Do . . . actions andhaving only Begin . . . and End . . . actions.
We can now write the program IPOFifo. It will have the same constants
as IFifo plus the set Ids of identifiers; and it will have the same interface
variables enq and deq. It will have the internal variable elts whose value isthe set of currently enqueued datums.
IPOFifo will need an internal variable to describe the partial order ≺ on
the set elts. Mathematicians describe a relation ≺ on a set S as a subset
of S × S , where u ≺ v is an abbreviation for hu, v i ∈ ≺. We’ll do the samething, except it would be confusing to use the symbol ≺ as a variable. We
will therefore let before be the variable whose value is a subset of elts × elts
such that u ≺ v means hu, v i ∈ before.
Finally, when enqueueing a datum w , the BeginPOEnq step must add
to ≺ the relation u ≺ w for a datum u in elts iff the enqueue operation that
added u has completed. That information is not contained in the interface
variable enq because enq(e) contains only the data value that an uncompleted enqueue operation is enqueueing, not which datum the operation put
in elts. Therefore, we add to IPOFifo an internal variable adding such that
adding(e) equals the datum in elts that enqueuer e put in elts, and equals avalue NonElt that is not a datum if e is not currently performing an enqueue
operation.
We use adding to define the following state expression, whose value isthe set of datums enqueued by operations whose executions have not yet
completed:∆beingAdded = {adding(e) : e ∈ EnQers} \ {NonElt}
The set beingAdded need not be a subset of elts because it can containdatums that were removed from elts by dequeue operations before the operations that enqueued them have completed.
The program POFifo is defined in Figure 6.10. Here are explanations of
the four disjuncts of the next-state action PONext.
BeginPOEnq(e) Enabled when enq(e) = Done, it:CHAPTER 6. AUXILIARY VARIABLES

208∆
POFifo = ∃ elts, before, adding : IPOFifo

IPOFifo = POInit ∧ 2[PONext]POv∆∆

POv = henq, deq, elts, before, adding i∆

POInit = ∧ enq = (e ∈ EnQers 7→ Done)∧ deq ∈ (DeQers → Data)∧ elts = {}∧ before = {}∧ adding = (e ∈ EnQers 7→ NonElt)∆

PONext = ∨ ∃ e ∈ EnQers : BeginPOEnq(e) ∨ EndPOEnq(e)∨ ∃ d ∈ DeQers : BeginPODeq(d ) ∨ EndPODeq(d )∆BeginPOEnq(e) =∧ enq(e) = Done
∧ ∃ D ∈ Data : ∃ id ∈ {i ∈ Ids : hD, i i ∈/ (elts ∪ beingAdded )} :∧ enq 0 = (enq except e 7→ D)∧ elts 0 = elts ∪ {hD, id i}∧ before 0 = before ∪ {hel , hD, id ii : el ∈ (elts \ beingAdded )}∧ adding 0 = (adding except e 7→ hD, id i)∧ deq 0 = deq∆

EndPOEnq(e) = ∧ enq(e) 6= Done
∧ enq 0 = (enq except e 7→ Done)∧ adding 0 = (adding except e 7→ NonElt)∧ unchanged hdeq, elts, before i∆

BeginPODeq(d ) = ∧ deq(d ) 6= Busy
∧ deq 0 = (deq except d 7→ Busy)∧ unchanged henq, elts, before, adding i∆

EndPODeq(d ) = ∧ deq(d ) = Busy
∧ ∃ el ∈ elts :∧ ∀ el 2 ∈ elts : ¬(el 2 ≺ el )∧ elts 0 = elts \ {el }∧ deq 0 = (deq except d 7→ el (1))∧ before 0 = before ∩ (elts 0 × elts 0 )∧ unchanged henq, adding i
Figure 6.10: The program POFifo.

CHAPTER 6. AUXILIARY VARIABLES

209• Sets enq(e) to the data value D that e is enqueuing.
• Adds a datum hD, id i to elts for some id ∈ Ids for which hD, id i
is not already in elts or beingAdded .
• Modifies before to add the relations el ≺ hD, id i for every el in
elts that is not in beingAdded .
• Sets adding(e) to hD, id i, thereby adding hD, id i to beingAdded .
EndPOEnq(e) Enabled when enq(e) is a data value, it sets enq(e) to Doneand sets adding(e) to NonElt, thereby removing from beingAdded thedatum that e had enqueued.
BeginPODeq(d ) Enabled when deq(d ) is a data value, it sets deq(d ) toBusy.
EndPODeq(d ) Enabled when deq(d ) equals Busy and elts is not empty,
which implies that elts contains at least one minimal datum (a datum
not preceded in the ≺ relation by any other datum in elts), since thedatum most recently added to elts must be a minimal datum. The
action chooses an arbitrary minimal datum el of elts, removes it from
elts, sets deq(d ) to its data value component, and modifies before to
remove all relations el ≺ el 2 for elements el 2 of elts.

6.5.3

Showing IPOFifo Implements Fifo

Formulas POFifo and Fifo are equivalent. However, more important andmore interesting than showing that Fifo refines POFifo is showing that
POFifo refines Fifo. It’s more important because Fifo is the generally accepted description of a fifo. By showing that POFifo implements Fifo, we
can show that an algorithm that doesn’t maintain a totally ordered queue
implements Fifo by showing that it implements POFifo. It’s more interesting because showing that POFifo implements Fifo requires all three kindsof auxiliary variables. So, the problem of showing that Fifo refines POFifo
is not discussed.
To show that POFifo refines Fifo, we have to define a refinement mapping under which IPOFifo implements IFifo. This requires adding to
IPOFifo first a prophecy variable, then a history variable, then a stuttering variable. They are added in the three following subsections. Adding theprophecy variable is straightforward and the necessary details are presented.
How to add the other two variables and define the refinement mapping arethen sketched. Rigorously defining those two programs and the refinement

CHAPTER 6. AUXILIARY VARIABLES

210

mapping would be a marvelous learning experience. However, the chance of
doing it without making any error is small unless you use a tool to check
what you have done.
6.5.3.1

The Prophecy Variable

The most significant problem in showing that POFifo implements Fifo isthat IFifo decides the order in which concurrently enqueued values will bedequeued before IPOFifo does. This tells us that to define a refinement
mapping under which IFifo is implemented by POFifo, we need to add aprophecy variable p to IPOFifo.
The simplest way I know of making the necessary predictions is witha prophecy sequence variable p that predicts the sequence of datums thatwill be dequeued next. The first item in the sequence predicts the datum
that the next EndPODeq step removes from elts, and that step of course
removes the prediction from p. The natural step to append a prediction
to the sequence p is the BeginPOEnq step that adds a datum to elts. The
length of p therefore always equals the number of datums in elts. The
predictions are completely arbitrary datums, so in almost all behaviors they
will be impossible to fulfill, at some point not allowing any more datums to
be dequeued. But as we’ve seen, unfulfillable predictions are no problem.
Since no predictions are made about enqueue operations, they can keep
being performed even if the datums they enqueue can never be dequeued.
The set Π of possible predictions equals the set Data × Ids of all possible
datums. The BeginPOEnq(e) action should append a prediction to p, andthe EndPOEnq(e) and BeginPODeq(d ) actions should leave p unchanged.
We can therefore define three of the four subactions of the next-state action
PONext p of IPOFifo p by:∆

BeginPOEnq p (e) = ∧ BeginPOEnq(e)∧ ∃ el ∈ Data × Ids : p 0 = Append (p, el )∆EndPOEnq p (e) = EndPOEnq(e) ∧ (p 0 = p)∆

BeginPODeq p (d ) = BeginPODeq(d ) ∧ (p 0 = p)
The prediction made by the first item p(1) of the sequence p is the datum
that the next EndPODeq(d ) step will remove from elts. The datum p(1)is removed by this step iff elts 0 = elts \ {p(1)} is true of the step. Since thestep must remove the prediction, we can define:∆

EndPODeq p (d ) =EndPODeq(d ) ∧ (elts 0 = elts \ {p(1)}) ∧ (p 0 = Tail (p))

CHAPTER 6. AUXILIARY VARIABLES

211

These four action definitions, and the observation that Init p should equal
Init ∧ (p = h i) give us all the pieces of the definition of IPOFifo p . I won’t
bother to put them together.
6.5.3.2

The History Variable qBar

We now must decide how to define queueBar , the state expression that is
substituted for queue in the refinement mapping. It’s easiest to think ofdefining queueBar as the sequence not of the data values to be substituted
for the variable queue of IFifo, but of the sequence of datums being dequeued
from elts by POFifo. We can then define the refinement mapping so it
substitutes for the variable queue of IFifo the sequence of data values in thedatums of queueBar .
Since there are no Do . . . steps in IPOFifo, we will have to add stuttering steps to append datums to queueBar . To do that, we will first add to
IPOFifo p a history variable qBar to produce a program we’ll call IPOFifo pq .
The value of qBar will be the sequence of datums that will appear inqueueBar . However, datums will be appended to qBar by Begin . . . andEnd . . . steps, so stuttering steps will then have to be added to IPOFifo pq
that append the datums in qBar one at a time to queueBar , since IFifo
appends data values to queue one at a time. How those stuttering steps areadded is explained in Section 6.5.3.3.
We will see that a single BeginPOEnq pq step may append multiple datums to qBar , so letting IPOFifo have Do . . . steps wouldn’t have eliminatedthe need to add stuttering steps. The following definition of the history
variable qBar is subtle. To help you understand it, I suggest you check how
the definition works on the first few steps of several different behaviors of
IPOFifo p .
Suppose that program BeginPOEnq p is in a state in which it’s possible
for a dequeue operation to remove a datum from elts. For qBar to describe
the datums that are in queueBar , the datum removed by that dequeue operation must be in qBar . An EndPODeq p step can remove only the datump(1) from elts, and it can remove p(1) iff p(1) is a minimal element for the
relation ≺ of elts. Therefore, p(1) must be the first element of qBar iff p(1)is a minimal element of elts. If p(1) can be dequeued , then p(2) can bedequeued after it iff p(2) is a minimal element of elts \ {p(1)}. And so on.
Define the state predicate pg to be the longest prefix of p all of whose
datums can be dequeued from elts if no further datums are enqueued in elts.
It follows from the definition of IPOFifo p that pg equals the longest prefixof p satisfying the following conditions:CHAPTER 6. AUXILIARY VARIABLES

212

Q1. Every datum in pg is in elts.
Q2. No datum appears twice in pg.
Q3. For each i ∈ 1 . . Len(pg) and each datum u ∈ elts, if u ≺ pg(i ) thenu = pg(j ) for some j ∈ 1 . . (i − 1).
We have shown that pg must be a prefix of qBar . Our strategy for defining
IPOFifo pq by adding the history variable qBar to IPOFifo p is to keep qBar
equal to pg for as long as possible. To see how to do that, let’s see how pg
can change.
The sequence pg can become shorter only when an EndPODeq p step
occurs, in which case p is not the empty sequence and pg is a nonempty
prefix of p. The step removes the first element of p and pg, so p 0 = Tail (p),pg 0 = Tail (pg), and qBar 0 = Tail (qBar ).
The sequence pg can be made longer by a BeginPOEnq p step as follows.
Suppose the step appends the prediction u to p and adds the datum w toelts. The value of pg at the beginning of the step is a proper prefix of p ◦hu i.
If w equals the prediction in p ◦ hu i immediately after pg, then w will beappended to pg iff doing so would not violate Q3. (We’ll see in a moment
when it would violate Q3.) If w can be appended to pg and the prediction
following w in p is already in elts, then it might be possible to append thatdatum to pg as well. And so on. Thus, it’s possible for the BeginPOEnq p
step to append several datums to pg. If our strategy has been successful
thus far and qBar = pg at the beginning of the step, then a BeginPOEnq pq
step implies qBar 0 = pg 0 . This makes qBar a prefix of qBar 0 , as it should
be because stuttering steps to be added after a BeginPOEnq p step shouldchange queueBar only by appending datums to it.
There is one situation in which it is impossible for any further datum tobe appended to pg. One or more datums can be appended to pg only bya BeginPOEnq p that adds a datum w to elts that can be appended to pg.
However if there is a datum u in elts that is neither in the sequence pg nor in
the set beingAdded , then adding w to elts also adds the relation u ≺ w . This
relation means that w can’t be appended to pg because that would violate
condition Q3. Thus, if there is a datum u in elts that is neither in pg nor
beingAdded , then no datums can be added to pg. Moreover, the datum u
can never be removed from elts because it is not in pg and can never be in pg
because no more datums can be added to pg. (The datum u can’t be added
to beingAdded because a BeginPOEnq step can’t add a datum to elts thatis already in elts.) Let’s call a state in which there is a datum in elts thatis not in beingAdded or pg a blocked state. In a blocked state, datums canCHAPTER 6. AUXILIARY VARIABLES

213

be removed from the head of pg by EndPODeq p steps, but no new datums
can be appended to pg. So, if and when enough EndPODeq p steps haveoccurred to remove all the datums from pg, then no more EndPODeq p steps
can occur. That means that any further enqueue operations that are begun
with a BeginPODeq p step must block, never able to complete.
Let’s consider the first step that caused a blocked state—that is, causing
there to be an element u in elts that is neither in pg nor beingAdded . Sinceu was added to elts by a BeginPOEnq p step that put u in beingAdded , itmust be the EndPOEnq p step of the enqueue operation that added u to elts
that caused the blocked state by removing u from beingAdded . Until thatblocked state was reached, qBar equaled pg. However, since u has not beendequeued, it must be in queueBar after that EndPOEnq p step because thatstep must implement the EndEnq step of IFifo. Thus that EndPOEnq p step
must append u to qBar . Therefore, the first blocked state is the first statein which qBar 6= pg. In that state, qBar equals pg ◦ hu i.
From that first blocked state on, no new datums can be added to pg, so
the datum u can never be dequeued. Therefore, whenever an EndPOEnq p
step occurs for an operation that enqueued a datum w , if w is in elts (so it
hasn’t been dequeued) and is not in pg, then that EndPOEnq p step must
append w to qBar .
To recapitulate, here is how we add the history variable qBar to IPOFifo p
to obtain the program IPOFifo pq . These rules imply that, at any point in the
behavior, qBar will equal pg ◦ eb where pg is the state function of IPOFifo p
defined above and eb is a sequence of datums in elts that are not in pg.
Initially, pg and eb equal h i.
• An EndPODeq p step can occur only if pg 6= h i. Such a step satisfies
pg 0 = Tail (pg) and qBar 0 = Tail (qBar ).
• An EndPOEnq p step that removes from beingAdded a datum w thatis in elts but not in pg appends w to eb and hence to qBar .
• A BeginPOEnq p step that occurs when eb = h i (so qBar = pg) sets
qBar 0 equal to pg 0 .
These rules imply that a datum can never be removed from eb, so once eb
is nonempty no new datums can be added to pg and only datums currentlyin pg can ever be dequeued.
Observe that the sequence pg and the set of datums in eb can be definedin terms of the variables of IPOFifo p . A history variable is needed only
to remember the order in which datums have been appended to eb. ThisCHAPTER 6. AUXILIARY VARIABLES

214

suggests that it’s a little simpler to make eb the history variable and define
qbar to be the state expression pg ◦ eb. However, I could not have discovered
this without first understanding how qBar should be defined.
Writing a complete definition of IPOFifo pq is straightforward, once wehave solved the problem of writing a precise mathematical definition of thestate function qBar in terms of the variables of IPOFifo p . (It took me a few
tries to get that definition right, using a model checker to find my mistakes.)That definition is omitted.
6.5.3.3

Stuttering and the Refinement Mapping

Having defined qBar for IPOFifo pq , adding a stuttering variable s and defining the refinement mapping under which the resulting program IPOFifo pqs
implements IFifo are comparatively straightforward. First, s has to add
stuttering steps that allow us to define queueBar . Recall that qBar is defined so it is changed by interface actions (the only ones that IPOFifo pqhas) the way internal Do . . . actions of IFifo change the value of the internal variable queue of IFifo. Since queueBar should implement queue under
the refinement mapping (except that queueBar contains datums not just thedata values), it needs to be changed by stuttering steps added to IPOFifo pq .
We define the program IPOFifo pqs by adding a stuttering variable s that
adds steps in the following three cases. We define queueBar to be the state
expression that equals qBar except as noted below.
1. s adds a single stuttering step before each EndPODeq pq step. The
value of queueBar equals Tail (qBar ) immediately after that stutteringstep.
2. s adds a stuttering step before each EndPOEnq pq step that appends
an element w to eb (and hence to qBar ). Immediately after thatstuttering step, queueBar equals qBar ◦ hw i.
3. Following each BeginPOEnq pq step such that Len(pg 0 ) > Len(pg)(which implies eb = h i), s adds Len(pg 0 ) − Len(pg) stuttering steps.
While there are k more of those stuttering steps left to be executed,
queueBar equals the sequence obtained by removing the last k elements of qBar .
Encoding in the value of the stuttering variable s for which of the threecases the variable is being added, and in case 2 for which enqueuer e thestep is an EndPOEnq pq (e) step, allows the value of queueBar to be definedin terms of the values of s, qBar , and (for case 2) adding.

CHAPTER 6. AUXILIARY VARIABLES

215

We still have to define the state functions enqInnerBar and deqInnerBarthat are substituted for enqInner and deqInner in the refinement mapping
under which IPOFifo pqs implements IFifo. The value of enqInnerBar (e) foran enqueuer e should equal Done except when adding(e) equals the datum
that e is enqueueing, and that datum is not yet in queueBar . This meansthat enqInnerBar can be defined in terms of adding and queueBar .
The value of deqInnerBar (d ) for a dequeuer d should equal the value ofdeq(d ) except between when d has removed the first element of queueBar(by executing the stuttering step added in case 1) and before the subsequent EndPODeq pqs (d ) step has occurred. In that case, deq(d ) should
equal qBar (1). It’s therefore easy to define deqInnerBar as a state function of IPOFifo pqs if the value of the stuttering variable s added in case 1
contains the value of d for which the following EndPODeq pqs (d ) step is tobe performed.
This completes the sketch of how auxiliary variables are added to IPOFifo
to define a refinement mapping under which it implies IFifo, showing that
POFifo refines Fifo. The intellectually challenging part was discovering how
to define qBar . It took me quite a bit of thinking to find the definition. This
was not surprising. The example of the fifo had been studied for at least
15 years before Herlihy and Wing discovered that it could be implemented
without maintaining a totally ordered queue. Given the definition of qBar ,constructing the refinement mapping required the ability to write abstract
programs mathematically—an ability that comes with practice.

6.6

Prophecy Constants

We have seen examples of showing |= T ⇒ S , where S equals ∃ . . . : IS , byadding an auxiliary variable a to T and showing T a implies IS under arefinement mapping. In these examples, IS and S were safety properties.
Liveness was shown by showing that T a conjoined with the lower-level program’s liveness property implies the higher-level program’s liveness property.
Let’s return to an example we considered in Section 6.1.3. Define IS and
T to be the two formulas defined in (6.7) in (6.8):∆

IS = ∧ (x = 0) ∧ (y ∈ N)
∧ 2 [(y > 0) ∧ (x 0 = x + 1) ∧ (y 0 = y − 1)]hx ,y i
T = (x = 0) ∧ 2[x 0 = x + 1]x ∧ 32[x 0 = x ]x∆CHAPTER 6. AUXILIARY VARIABLES

216

and let S equal ∃ y : IS . We observed that formulas S and T are equivalent, so |= T ⇒ S is true. To define a refinement mapping under which T
implies IS , we have to add one or more auxiliary variables to T to obtainan expression to substitute for y.
The liveness property 32[x 0 = x ]x implies that a behavior of T eventually stops incrementing x and terminates. To define the refinement mapping,
we need a variable that can predict the value of x when the behavior terminates. So, we need a prophecy variable.
Because we have to predict something that is implied by a liveness property, it appears that the only kind of prophecy variable that will work is one
that predicts the entire future—namely an infinite prophecy variable thatpredicts all the future values of x . This means adding auxiliary variables,
including a prophecy variable, the way it is done in the completeness proof
of Section 6.4.4. This is disturbingly complicated for such a simple example.
Fortunately, there is a simple way to construct the refinement mapping
under which T implies IS without using a prophecy variable. We firstobserve that T implies that eventually x is forever equal to some natural
number—more precisely:(6.17) |= T ⇒ ∃ n ∈ N : 32(x = n)This implies:|= T ≡ ∃ n ∈ N : T ∧ 32(x = n)
For any formulas F and G and constants c and C , to prove (∃ c ∈ C : F ) ⇒ G
it suffices to prove (c ∈ C ) ∧ F ⇒ G. Therefore, to prove T ⇒ IS , it suffices
to prove(6.18) |= (n ∈ N) ∧ 32(x = n) ∧ T ⇒ IS
We can do this by adding the history variable h as follows to obtain T h :∆T h = ∧ (n ∈ N) ∧ (x = 0) ∧ (h = n)
∧ 2[(x 0 = x + 1) ∧ (h 0 = h − 1)]hx ,h i
∧ 32[x 0 = x ]x ∧ 32(x = n)
We can then use the refinement mapping that substitutes h for y, and weshow:|= T h ⇒ (IS with y ← h)
The key step in what we’ve done is the use of (6.17) to reduce showing|= T ⇒ IS to showing (6.18). This procedure is called adding the prophecy

CHAPTER 6. AUXILIARY VARIABLES

217

constant n to T . This is perhaps a silly name, since n is just an ordinary
bound constant. However, it serves to predict something that is eventually
going to happen—in this case, the final value x will have.
In general, we add a prophecy constant c to a program T by showing|= T ⇒ ∃ c ∈ C : L , where the constant c does not occur in T , which implies|= T ≡ ∃ c ∈ C : T ∧ L
and showing |= T ⇒ IS by showing|= (c ∈ C ) ∧ T ∧ L ⇒ IC
It can be shown that prophecy constants are in principle as powerful asprophecy variables. In particular, Theorem 6.6 of Section 6.4.4 is true withthe prophecy variable replaced by a prophecy constant. This is proved bymodifying the proof of Theorem 6.6 as described in Appendix Section B.12,
after the proof of that theorem.
Although in theory equivalent, prophecy variables and prophecy constants are quite different in practice. It appears that a prophecy variable
is best for predicting what a safety property implies may happen, while a
prophecy constant is best for predicting what a liveness property implies
must eventually happen.
Prophecy constants were introduced by Wim Hesselink, who called them“eternity variables” [19]. He did not represent programs mathematically, so
he had to invent a rule for adding them to programs.

Chapter 7

Loose Ends
This chapter covers two topics that, to my knowledge, have not yet seen any
industrial application. However, they might in the future become useful.
The first topic is reduction, which is about verifying that a program satisfies
a property by verifying that a coarser-grained version of the program satisfies
it. Even if you never use it, understanding the principles behind reduction
can help you choose the appropriate grain of atomicity for abstract programs.
For that purpose, skimming through sections 7.1.1–7.1.3 should suffice.
The second topic is about representing a program as the composition ofcomponent programs. We have been representing the components that makeup a program, such as the individual processes in a multiprocess program, as
disjuncts of the next-state action. Section 7.2 explains how the componentsthat form a program can be described as programs. How this is done depends
on why it is done. Two reasons for doing it and the methods they lead toare presented.

7.1

Reduction

7.1.1

Introduction

7.1.1.1

What Reduction Is

When writing an abstract program to describe some aspect of a concrete
one, we must decide what constitutes a single step of a behavior. Statedanother way, we must describe what the grain of atomicity of the next-state
action should be. The only advice provided thus far is that we should use
the coarsest grain of atomicity (the fewest steps) that is a sufficiently accurate representation of that aspect of the concrete program. “Sufficiently
218

CHAPTER 7. LOOSE ENDS

219

accurate” means that either we believe it is easy to make the concrete program implement that grain of atomicity, or we are deferring the problem of
how those atomic actions are implemented.
Some work has addressed the problem of formalizing what makes an abstract program “sufficiently accurate”, starting with a 1975 paper by Richard
Lipton [40]. This work used the approach called reduction, which replaces
a program S with an “equivalent” coarser-grained program S R called the
reduced version of S . Certain properties of S are verified by showing thatS R satisfies them. The program S R is obtained from S by replacing certain
nonatomic operations with atomic actions, each atomic action producing
the same effect as executing all the steps of the nonatomic operation it replaces one after another, with no intervening steps of other operations. The
reduced program S R is therefore simpler and easier to reason about thanprogram S .
It was never clear in exactly what sense S R was equivalent to S , and theresults were restricted to particular classes of programs and of the properties that could be verified. TLA enabled a new way of viewing reduction.
In that view, the variables of S are replaced in S R by “virtual” variables,
and S implements S R under a refinement mapping. The refinement mapping is not made explicit, but the relation between the values of the actualand the virtual variables is described by an invariant. This mathematicalview encompasses much of the previous work on reduction for concurrent
programs.
Our basic approach to writing a correct concrete program is showingthat it refines an abstract program. There are two aspects to refining one
program with another: data refinement and step refinement. Modern coding
languages have made data refinement easier by providing higher-level, more
abstract data structures. It is now almost as easy to write a program thatmanipulates integers as one that manipulates bit strings representing a finite
set of integers. There has been much less progress in making step refinement
easier. As explained in Section 6.5.1, a linearizable object allows a coarse
grain of atomicity in descriptions of the code that executes operations on
the object. However, the only general method of implementing a linearizable
object still seems to be the one invented by Dijkstra in the 1960s: putting
the code that reads and/or modifies the state of the object in a criticalsection.
I believe that better ways of describing the grain of atomicity will beneeded if rigorous verification that concrete concurrent programs implement
abstract ones is to become common practice. Reduction may provide thekey to doing this. Section 7.1 provides a mathematical foundation for under-CHAPTER 7. LOOSE ENDS

220

standing reduction. The theorems presented here are not the most generalones possible; some generalizations can be found elsewhere [8]. Also omitted are rigorous proofs. I know of no industrial use of reduction or of tools
to support it; and I have no experience using the results described here inpractice. The problem it addresses is real, but I don’t know if reduction is
the solution.
7.1.1.2

The TLA Approach

Here is how reduction can be described in TLA. Let x be the variables x 1 ,. . . , x n of S . Reduction is usually described by letting x also be the variablesof S R . However, I find that reduction is easier to understand by letting thevariables of S R be different from those of S . We will let those variables be
the list X of variables X 1 , . . . , X n . The goal is then to verify that S satisfies
a property P by verifying that S R satisfies the property P with x ← X .
To deduce |= S ⇒ P , where S and P contain the variables x, from|= S R ⇒ (P with x ← X), we need a relation between the variables x
and the variables X. That relation is expressed by a state predicate I R
containing the variables x and X. We then deduce that S satisfies P fromthe following three conditions. The formula T will be explained later; ignore
it for the moment.
R1. |= S ∧ T ⇒ ∃ X : S R ∧ 2I R
R2. |= S R ⇒ (P with x ← X)
R3. |= (P with x ← X) ∧ 2I R ⇒ P
Condition R1 is implied by theorems whose hypotheses are the conditions
necessary for reduction to be possible. Condition R2 asserts that P with
its variables x replaced by X is satisfied by the reduced program S R , whichshould be easier to verify than that P is satisfied by the finer-grained program S .
Throughout this section on reduction, we abbreviate F with x ← X as
F , for any formula F . Thus R2 and R3 can be written as|= S R ⇒ P

and|= P ∧ 2I R ⇒ P

We first consider the case in which S is the usual TLA safety property
Init ∧ 2[Next]hxi for an abstract program. We then consider the program
described by S ∧ F , where F is the conjunction of fairness properties for S .
Conditions R1–R3 will then have S replaced by S ∧ F , the reduced program(S ∧ F )R being defined to equal S R ∧ F R where F R is obtained by replacing

CHAPTER 7. LOOSE ENDS

221

each fairness condition for an action A of S with fairness of a corresponding
action AR of S R .
The formula T in the hypothesis of R1 is a liveness assumption thatwill be defined below. It turns out that even when S is a safety property,
so S R is also safety property, R1 requires a liveness assumption about S .
For a program with a fairness property F , we expect S ∧ F to imply T . If
the program describes only safety, then it can satisfy only safety properties,
so it would be strange if we required S to satisfy a liveness property to use
reduction. We will see that, to show S satisfies a safety property P , showingthat S satisfies a possibility condition allows us to assume that T is satisfied.
To prove the theorem that asserts R1, we construct an abstract programS ⊗S R , with variables x and X, that describes the programs S and S R
running simultaneously in parallel. (S ⊗S R is just an identifier that names
a formula, not an expression with formulas S and S R and an operator ⊗.
This unusual identifier is meant to remind us what the formula means.) We
then show:
R1a. |= S ⇒ ∃ X : S ⊗S R
R1b. |= S ⊗S R ∧ T ⇒ S R ∧ 2I R
R1b implies |= (∃ X : S ⊗S R ∧ T ) ⇒ (∃ X : S R ∧ 2I R ); and the variables X
don’t appear in T , so ∃ X : S ⊗S R ∧ T equals (∃ X : S ⊗S R ) ∧ T . Therefore,
R1a and R1b imply R1.
One property asserted by I R is that, if the values of x describe a state inwhich none of the nonatomic operations of S being reduced is currently being
executed, then x = X. The values of x and X are synchronized like this,despite the reduced program taking fewer steps than the original program,by having S ⊗S R take X-stuttering steps—steps that leave the values ofthe variables X unchanged. R1b is satisfied because these X-stuttering
steps implement stuttering steps of S R . R3 was satisfied in Lipton’s original
paper because he considered terminating programs and properties P that
depend only on the initial and final states of the program. In those states,
none of the nonatomic operations of S being reduced are being executed, so
x = X. In what may have been the second paper published on reduction,
Doeppner [10] satisfied R3 by proving only that an invariant is true whennone of the reduced operations are being executed.

7.1.2

An Example

To explain reduction, we start by examining this commonly assumed rule:
When reasoning about a multiprocess program in which interprocess com-

CHAPTER 7. LOOSE ENDS

222
rk:
r 1:

.
.
.
R1 ;
.
.
.

rk:
c:
l 1:

Rk ;
C;
L1 ;
.
.
.

lm
o:

Lm ;
...
.
.
.

Figure 7.1: The nonatomic operation RCL.
munication is performed by atomic operations to shared data objects, theprogram can be represented with any grain of atomicity in which each atomic
action accesses at most one shared data object.1 The following is a statement of the rule in our science and the argument generally used to justifyit.
Suppose S is a multiprocess program with a process that executes a
nonatomic operation, which we call RCL, described by the statements shownin Figure 7.1. We assume this is “straight line” code, so an execution of RCL
consists of k +1+m steps. For now, we let S be the safety property describedby the code; liveness is discussed later. We assume statements Ri and Lj
can access only data local to the process, while statement C can also accessshared data. The rule asserts that we can replace S with its reduced version
S R obtained by removing all the labels between (but not including) r 1 ando, so those k + 1 + m statements are executed as a single step, and replacing
the variables x with the variables X. It is usually claimed that we can dothis because other processes can’t observe when the statements Ri and Lj
are executed, so we can pretend that they are executed in the same step asstatement C.
We can reduce other operations of the same form to atomic actions as
well, reducing the operations one at a time. So, it suffices to see how it’sdone for just this single operation RCL, which may be executed multiple
times.
1
The rule was stated in print independently by Owicki and Gries [43] and by me [28],but I think it was well known at the time.

CHAPTER 7. LOOSE ENDS
7.1.2.1

223

The Reduced Behaviors

Let R i , C , and Lj be the TLA actions described by statements Ri , C, and
Lj . An execution of RCL consists of a sequence of R i steps, for i ∈ 1 . . k ,followed by a C step, followed by a sequence of Lj steps, for j ∈ 1 . . m. In
an execution of the operation during a behavior of the program, interleaved
between those steps may be steps performed by other processes. (There canalso be stuttering steps that leave the values of variables x unchanged, butthey are irrelevant and we can ignore them.) A reduced execution of theoperation execution is one in which all the steps of RCL occur one after theother, with no interleaved steps executed by other processes.
We transform a behavior to a reduced behavior, in which only reduced
executions of RCL occur, by a procedure illustrated with the following portion of a behavior containing an execution of RCL, where RCL has one R istatement (k = 1) and two Lj statements (m = 2). We show the name of
the action that each step satisfies, where E 1 , E 2 , and E 3 are actions of otherprocesses.
R

E

C

E

E

L

L

1
1
2
3
1
2
s 42 −→s 43 −→ s 44 −→s 45 −→s 46 −→
s 47 −→(7.1) · · · s 41 −→s 48 · · ·Define R to be the state predicate that is true of a state iff that state occurs
during an execution of RCL before the C action. In the part of a behavior
shown in (7.1), R is true only in states s 42 and s 43 . Define L to be the statepredicate asserting that the process is currently executing operation RCL
after the C action, so in (7.1) it is true in states s 44 –s 47 . In general, if p is theprocess executing RCL of Figure 7.1, then R equals pc(p) ∈ {r 2, . . . , r k , c}and L equals pc(p) ∈ {l 1 , . . . , l m }. The behavior is currently executing
RCL iff the state predicate R ∨ L is true. Thus, the operation is not being
executed iff ¬(R ∨ L) is true.
Because R i and Lj actions access only process-local state, they commute
with actions from other processes, where two actions commute iff executing
them in either order has the same effect. Recall that A · B is defined in
Section 3.4.1.4 to be the action that is satisfied by a step s → t iff there
is a state u such that s → u is an A step and u → t is a B step. Actions
A and B commute iff A · B equals B · A. If A and B commute, then forAB
any states s, t, and u such that s −→ u −→ t, there exists a state v such
B
A
that s −→ v −→ t. By commuting R i and Lj actions with actions of otherprocesses, moving R i actions to the right and Lj actions to the left, we
obtain a behavior in which every execution of RCL is reduced, with no stepsof other processes interleaved. For example, commuting actions in this way

CHAPTER 7. LOOSE ENDS

224

converts the original behavior into the reduced behavior in which the portionof the original behavior shown in (7.1) is converted to:
E

R

C

L

L

E

E

1
1
1
2
2
3
(7.2) · · · s 41 −→u 42 −→s 43 −→ s 44 −→u 45 −→
u 46 −→
u 47 −→
s 48 · · ·A state s i is changed to a possibly different state u i if commutativity wasABused to commute actions A and B in · · · −→ s i −→ · · ·. For example, states 46 had to be (possibly) changed twice to arrive at u 46 because both the E 2
and E 3 actions had to be “moved across” state number 46 of the behavior
to get from (7.1) to (7.2). If σ is the original behavior (7.1), we define Φ(σ)
to be its reduced version (7.2), obtained by transforming all executions of
RCL in this way.
Note that the states s 41 and s 48 are the same in σ and Φ(σ) because
RCL is not being executed in those states. States s 43 and s 44 , which form
the C step, are also the same in the original and reduced behaviors because
the C action is not commuted with any action. The reduced behavior (7.2)
is also a behavior of program S because it has the same initial state as (7.1),
which satisfies Init, and every step satisfies a subaction of the next-state
action Next.
7.1.2.2

The Program S ⊗S R

We define S ⊗S R in terms of a mapping φ from states in the original behavior
σ to states in the reduced behavior Φ(σ)—in our example, from states of(7.1) to states of (7.2). First, we define φ(s) for all states except the ones ina C step, which in (7.1) are all states except for s 43 and s 44 . We call those
two states “C states” and the other states “non-C states”.
We transform a behavior containing executions of RCL to a reduced behavior by a sequence of action interchanges based on commutativity. There
are two kinds of interchange, both involving an E h action of a different process: one that moves an R i step to the right of an E h step, and one thatmoves an Lj step to the left of an E h step. To go from behavior (7.1) tobehavior (7.2) requires five interchanges. Figure 7.2 shows the sequence of
behaviors created by performing these interchanges, where each behavior is
obtained from the preceding one by interchanging the left-most R i or Lj
action that can be moved closer to the C action. The top behavior is theoriginal behavior (7.1) and the bottom one is the reduced behavior (7.2).
Observe that every state in one behavior equals the corresponding statein the next behavior except for the one state across which the actions areinterchanged.

CHAPTER 7. LOOSE ENDS

225

R

E

C

E

E

L

L

E

R

C

E

E

L

L

2
1
3
2
1
1
s48 · · ·s 47 −→s 46 −→
s 45 −→s 43 −→ s 44 −→s 42 −→· · · s41 −→? 1 u? 3 s? 1 s? 2 s?
21
s 45
s 43 −→ s 44 −→· · · s41−→ 46 −→ 47 −→ 48 · · ·−→ 42 −→@
R ? L2 ?
E@
L1?
3@s 47 −→ s48 · · ·· · · 41 −→ 42 −→ 43 −→ s 44 −→ s 45 −→ r46 −→
@
@
R
@
L1
R1
E1
C
?
?
u E2 r ? E3 s ? L2 s ?
ssuss ? E1 u ? R1 s

···

41 −→
E

42 −→
R

C

E2

43 −→

44 −→

45 −→ 46 −→47 −→ 48

L

C

L

E

C

L1

u ? L2 u

···

@
R ?
E@
3@

? 1 u? 1 s? 2 r? 2 u1u45· · · s41−→ 46 −→ 47 −→ s48 · · ·−→ 42 −→ 43 −→ s 44 −→@···s ? E1 u ? R1 s
41 −→

42 −→

43 −→ s 44 −→45 −→R ? E3 ?
@E@
246 −→ u47 −→ s48 · · ·Figure 7.2: Constructing (7.2) from (7.1).
The arrows in the picture are drawn according to the following rules.
There is a (thin) downward pointing arrow from each non-C state that is
unchanged by the interchange that yields the next behavior. From the one
state in each behavior that is changed by the interchange, there is a (thick)diagonal arrow. If that state satisfies R (is before the C action), then thearrow points one state to the left of the changed state. If the state satisfies
L, then the arrow points one state to the right.
These arrows define a unique path from every non-C state s i of theoriginal behavior to a state in the reduced behavior. Define φ(s i ) to be thatstate in the reduced behavior. For the example in Figure 7.2, φ(s 45 ) = u 47
because the sequence of states in the path from s 45 in the top behavior to
the bottom behavior is:(7.3) s 45 → s 45 → s 45 → r 46 → r 46 → u 47
Figure 7.3 contains an arrow pointing from each non-C state s i in the original behavior to the state φ(s i ) in the reduced behavior. Observe that forevery non-C state s i , the state φ(s i ) is a state in which operation RCL is
not being executed—that is, a state satisfying ¬(R ∨ L).
C
We define φ(s) for the C states so that if the C step is s i −→ s i+1 , thenφ(s i ) is the first state to the left of s i for which ¬(R∨L) is true, and φ(s i+1 )is the first state to the right of s i+1 for which ¬(R ∨ L) is true. In otherwords, φ(s i ) and φ(s i+1 ) are the states of the reduced behavior in which theexecution of RCL begins and ends, respectively. The complete mapping φCHAPTER 7. LOOSE ENDS

226

R

E

C

E

E

L

L

?E

R

C

L

L

Ej

R?
Ej

2
1
3
2
1
1
s48 · · ·s 47 −→s 46 −→
s 45 −→s 43 −→ s 44 −→s 42 −→· · · s41 −→

3
2
2
1
1
1
s48 · · ·u47 −→
u46 −→
u45 −→s 43 −→ s 44 −→u42 −→· · · s41 −→Figure 7.3: The mapping si → φ(si ) for non-C states.
R

E

C

E

E

L

L

?E

R

C

L

L j

Ej

R?
Ej

2
1
3
2
1
1
s48 · · ·s 47 −→s 46 −→
s 45 −→s 43 −→ s 44 −→s 42 −→· · · s41 −→

3
2
2
1
1
1
s48 · · ·u47 −→
u46 −→
u45 −→s 43 −→ s 44 −→u42 −→· · · s41 −→Figure 7.4: The complete mapping si → φ(si ).
for our example is shown in Figure 7.4, where the mapping for non-C statesis in gray.
Formula S ⊗S R is defined so that it is satisfied by a behavior σ iff σsatisfies S (which describes the values of variables x) and the values of thevariables X in any state s k of σ equal the values of the variables x in the stateφ(s k ) of the reduced behavior Φ(σ). Since this assigns values of variables X
to every state of every behavior σ so that the behavior satisfies S ⊗S R , we
see that |= S ⇒ ∃ X : S ⊗S R is true, so R1a is satisfied.
From Figure 7.4, we see that for any k :φ1. If s k → s k +1 is an E h step (so E h is an action of another process)then φ(s k ) → φ(s k +1 ) is also an E h step.
φ2. If s k → s k +1 is an R i or Lj step, then φ(s k ) = φ(s k +1 ).
φ3. If s k → s k +1 is a C step, then φ(s k ) and φ(s k +1 ) are the first andlast states of an execution of operation RCL in the reduced behavior
Φ(σ), which is an execution with no interleaved steps of other processactions.
Recall that G equals G with x ← X for any formula G. A step ofis either an Eh step, a D step, where D is an action that performs
an execution of operation RCL as a single step, or a stuttering step thatleaves the variables X unchanged. From φ1–φ3, we see that if behavior(7.1) satisfies S ⊗S R (as well as S ), then each step of that behavior is either
an Eh step (by φ1), a D step (by φ3) or leaves the variables X unchanged(by φ2). Hence each step of S ⊗S R satisfies the next-state action of S R .
The initial-state predicate of S R is Init (remember that Init is the initialstate predicate of S ). Since operation RCL is not being executed in theSRCHAPTER 7. LOOSE ENDS

227

initial state s 0 of (7.1), φ(s 0 ) equals s 0 , which implies that s 0 satisfies Init.
Thus, if (7.1) satisfies S ⊗S R , then it satisfies S R . Therefore, S ⊗S R ⇒ S R
is satisfied—or so it seems.
The reasoning works in this example because the behavior (7.1) contains
a complete execution of operation RCL. However, S is a safety property,
which means that the process can stop executing actions at any point during
the execution of the operation. The general definition of the reduced version
of a behavior, which includes a possibly incomplete execution of RCL, is that
actions performing steps of an RCL execution are made to occur together
by commuting R i actions to the right, Lj actions to the left, and leaving a
C action unmoved. (If there is no C step, then the last R i action can beleft unmoved.) If s is the last state of a C step, φ(s) is defined to be thestate after the last step of the RCL operation being executed. That state
will satisfy ¬(R ∨ L) iff the behavior contains a complete execution of theoperation.
The one part of what we’ve done that’s not correct in the presence ofa partial execution is φ3. Statement φ3 is vacuously true if the partial
execution doesn’t contain a C step. In that case there are only R i steps
which correspond to stuttering steps of S R , so the behavior of S ⊗S R is abehavior of S R in which that RCL action doesn’t occur. The problem in φ3arises in our example if the execution contains a C step but doesn’t containboth the L1 and L2 steps.
The solution is to rule out such behaviors. That’s what the hypothesis
T in R1 and R1b does. Formula T must assert that any execution of RCL
that includes the C step must complete. The operation has performed the C
step but has not completed iff L is true. So we want to allow only behaviors
in which it is not the case that L eventually becomes true and remains true
forever. Such behaviors are ones satisfying ¬32L, which is equivalent to
23¬L. So, we can restate R1b as this assumption:|= S ⊗S R ∧ (23¬L) ⇒ S R ∧ 2I R
The argument showing S ⊗S R implies S R for the behavior (7.1) applies toall behaviors of the program of Figure 7.1 satisfying 23¬L. That is, wehave shown:|= S ⊗S R ∧ (23¬L) ⇒ S R
is satisfied by this program S . To complete the proof of R1b, we must define
I R and show that it is an invariant of S ⊗S R . Since we have seen that S
satisfies R1a, this will show that it satisfies R1 with T equal to 23¬L. The
assumption 23¬L is discussed in Section 7.1.4.

CHAPTER 7. LOOSE ENDS
7.1.2.3

228

The Invariant I R

The invariant I R of S ⊗S R that relates the values of the variables x to thoseof the variables X follows from three additional properties of the mapping
φ. We can see why those properties hold from Figures 7.2–7.4.
The most obvious of these properties follows from the observation thatif ¬(R ∨ L) is true in a state s, then only downward pointing arrows are
drawn from it in the figures. This shows:
φ4. For any state s in which ¬(R ∨ L) is true, φ(s) = s.
For the next property, look at the path (7.3) from the state s 45 to the stateφ(s 45 ), which equals u 47 . Follow that path in Figure 7.2. Observe that eachstep in the path either leaves the state unchanged (is a stuttering step) or
else is an L1 or L2 step. (To see this, look at the horizontal arrows justabove the diagonal arrows.) We can see from the figure that this is trueof the path from state s to state φ(s) for the states s 46 and s 47 as well.
The rule for drawing the arrows implies that this is true in general, for all
executions of the program of Figure 7.1. The path from every non-C states for which L is true to φ(s) consists of a sequence of steps each of which iseither a stuttering step or an Lj step for some j . From Figure 7.4, it’s clearthat this is also true for the C state for which L is true.
Let’s define L to equal L1 ∨ . . . ∨ Lm , so any Lj step is an L step. We haveseen that we can get from a state s in which L is true to the state φ(s) bya sequence of stuttering steps and/or L steps. Recall that in Section 4.3.2,
for any action A we defined A+ to equal A ∨ (A · A) ∨ (A · A · A) ∨ . . . .
Therefore, a step s → t satisfies ([L]hxi )+ , which we abbreviate [L]+hxi , iff
we can get from state s to state t by a sequence of L steps or steps thatleave the variables x unchanged. Let’s write the subscript hxi as simply x,
so [A]x and hAix mean [A]hxi and hAihxi for any action A.
We have thus seen:
φ5. For any state s in which L is true, s → φ(s) is an [L]+x step.
Following the path from s to φ(s) backwards for states s in which R is true
similarly leads to the following, where R equals R 1 ∨ . . . ∨ R k .2
φ6. For any state s in which R is true, φ(s) → s is an [R]+x step.
2

The action R bears no relation to the superscript R in S R . It is traditional to namethe action R for Right-mover because of the way the reduced behavior is constructed; andthere seems to be no better superscript than R to signify reduced.

CHAPTER 7. LOOSE ENDS

229

Finally, Figure 7.4 shows that for any state s of the original behavior, φ(s)is always a state in the reduced behavior in which the RCL operation is not
being executed, so ¬(R ∨ L) is true for φ(s). Because the rule for drawing
the arrows in Figure 7.2 creates a leftward pointing arrow whenever an R
step is moved to the right and a rightward pointing arrow whenever an L
step is moved to the left, this is true in general. Therefore, we have:
φ7. For any state s, the state predicate ¬(R ∨ L) is true in state φ(s).
Statements φ4–φ7 give us relations between s and φ(s) for all states s of abehavior of our example program. We now have to turn them into relations
between the values of the variables x and the variables X in any state s ina behavior of S ⊗S R .
It’s easy to do this for φ4. The values of the variables X in state s are
the values of x in φ(s). Since φ(s) = s if s satisfies ¬(R ∨ L), this meansthat x = X is true for any reachable state of S ⊗S R satisfying ¬(R ∨ L). In
other words:(7.4) ¬(R ∨ L) ⇒ (X = x)

is an invariant of S ⊗S R

To express the relations between x and X implied by φ5 and φ6, we needa bit of notation. For any action A containing only the variables x, a steps → t satisfies A iff formula A is true when we substitute for the variables x
their values in state s and for x0 their values in state t. Therefore, φ(s) → s+
is an [R]+x step iff [R]x is true when we substitute the values of x in φ(s) for
the variables x and the values of x in s for the primed variables x0 . But thevalues of x in φ(s) are by definition the values of X in state s. So φ(s) → s
is an [R]+x step iff s satisfies the formula we get by substituting X for x andx for x0 in [R]+x . Using the construct awith defined in Section 5.4.4.1, we
write the formula produced by these substitutions as:
0[R]+
x awith x ← X, x ← x

so formula φ6 implies:0(7.5) R ⇒ ([R]+x awith x ← X, x ← x)

is an invariant of S ⊗S R

Remember that in this formula, the definition of [R]+x must be fully expanded
before the awith substitution is performed.
We can obtain a similar relation between x and X from φ5. The statement that s → φ(s) is an [L]+x step is equivalent to the statement that states is satisfied by the formula obtained from [L]+x by substituting for variables
x their values in state s and substituting for x0 the values of x in stateCHAPTER 7. LOOSE ENDS

230

φ(s), the latter being the values of X in state s. Therefore, φ5 implies thefollowing, where x ← x has been eliminated from the awith formula, since
it just states that x is substituted for itself:0(7.6) L ⇒ ([L]+x awith x ← X)

is an invariant of S ⊗S R

Finally, since the values of X in state s equal the values of x in state φ(s),from φ7 we obtain:(7.7) ¬(R ∨ L) with x ← X

is an invariant of S ⊗S R

The invariant I R of S ⊗S R relating the values of x and X is the conjunction of the invariants (7.4)–(7.7):∆

I R = ∧ ¬(R ∨ L) ⇒ (X = x)0
∧ R ⇒ ([R]+x awith x ← X, x ← x)0+
∧ L ⇒ ([L]x awith x ← X)
∧ ¬(R ∨ L) with x ← X

7.1.3

Reduction In General

So far, we have been considering reduction of an operation RCL of one
process of a multiprocess program having the form shown in Figure 7.1. We
now extend this to a more general situation. First, some observations about
reducing RCL.
The invariant I R is described in terms of the actions R and L, which are
the disjunction of the actions R i and Lj , respectively. The fact that R and
L were defined in this particular way was irrelevant. All we required wasthat an execution of the operation RCL consists of a sequence of R steps
followed by a C step followed by a sequence of L steps. We didn’t needactions E h of other processes to commute with each of the actions R i and
Lj . In drawing the diagrams illustrated by Figures 7.2 and 7.4, we didn’t
have to identify the subactions of R and L that are involved. We could have
replaced each R i by R and each Li by L. We only needed to assume thateach action of another process commutes with R and L, not with each R i
and Lj individually. (For example, an E h · L1 step could be an L2 · E h step.)
Similarly, we didn’t have to require that R and L commute with particularactions of other processes. We just required R and L to commute with the
disjunction of the next-state relations of all the other processes—an action
we will call E .
Furthermore, we didn’t need to require that R and L commute with E .
To move R steps to the right, we just required that for any pair of steps

CHAPTER 7. LOOSE ENDS
R

E

231
E

R

s −→ u −→ t there is a pair of steps s −→ v −→ t for some state v . Thiscondition can be stated as the requirement R ·E ⇒ E ·R. When this formula
holds, we say that R right-commutes with E , and that E left-commutes with
R. Similarly, to move L steps to the left, we don’t need E · L to equal L · E ;we need only require E · L ⇒ L · E , which asserts that L left-commutes withE (and E right-commutes with L).
Finally, suppose that A is another action of the same process containing
the RCL operation, so A does not allow steps that implement the RCL
operation. Since the next step of the process after an R step can only be
an R step or a C step, an A step cannot follow an R step. This implies
that R · A must equal false, which means that R · A ⇒ A · R is triviallytrue. Similarly, the only step of the process that can immediately precedean L step is an L step or a C step. Therefore, A · L must equal false,
so A · L ⇒ L · A must be true. Therefore, other actions of the processcontaining RCL satisfy the same commutativity requirements as actions ofother processes. This implies that we can completely forget about processes.
We just assume that the program’s next-state action equals E ∨ R ∨ C ∨ L,
where R right-commutes with E and L left-commutes with E . If we represent
the program as a collection of processes, there is no need for R, C , and L
steps to all be steps of the same process.
What we need to require is that execution of an RCL operation consistsof a sequence of R steps followed by a C step followed by a sequence of L
steps. To express this requirement, we generalize R and L from assertions
about a process’s control state to arbitrary state predicates satisfying certain
conditions. We take as primitives the state predicates R and L and theactions E and M such that the program’s next state relation equals E ∨ M ,where M describes the operation to be reduced. The actions R, C , and L
will be defined in terms of R, L, and M . We therefore assume the original
program S is defined by:
S = Init ∧ 2[E ∨ M ]x∆

As in our example, we assume that R is true when execution of the operation described by M is in its first phase, where execution has begun but theC action has not yet been executed; and L is true when execution is in its
second phase, where the C action has been executed but the operation execution has not yet terminated. This is implied by the following assumptions
on executions of an operation described by the action M :M1. In the initial state, M is not in the middle of an execution, expressedby Init ⇒ ¬(R ∨ L).

CHAPTER 7. LOOSE ENDS

232

M2. An E step can’t change the current phase of an execution of M , expressed by E ⇒ (R0 ≡ R) ∧ (L0 ≡ L).
M3. An M step can’t go from the second phase to the first phase, expressedby ¬(L ∧ M ∧ R0 ).
M4. The two phases are disjoint, expressed by ¬(R ∧ L).
We can define the actions R, L, and C in terms of M , R, and L by:
R = M ∧ R0∆∆

L = L∧M

C = (¬L) ∧ M ∧ (¬R0 )∆A complete execution of the operation described by M consists of a sequenceof M steps beginning and ending in a state in which the M operation is not
being executed—in other words, in a state satisfying ¬(R ∨ L). Therefore,
the action M R that executes the complete operation as a single step for thevariables X is:
M R = (¬(R ∨ L) ∧ M + ∧ ¬(R ∨ L)0 ) with x ← X∆

We can therefore define S R as follows, where Init R and E R are Init and E
with the variables x replaced by the variables X:
S R = Init R ∧ 2[E R ∨ M R ]X∆

If R always equals false, then R equals false so there is no R action.
Similarly, there is no L action if L always equals false. If there is neither
an R nor an L action, then M equals C and S R equals (S with x ← X) so
reduction accomplishes nothing.
Ignoring liveness, reduction is described in TLA by a theorem assertingthat R1 (with T equal to 23¬L) is implied by the definitions of S , R, L,
M , and S R above, assumptions M1–M4, and the commutativity relations
assumed of R, L, and E .
M1–M4 and the commutativity relations are action formulas. (Remember that a state predicate is an action whose value depends only on the firststate of a step.) Those action formulas don’t have to be true of all possible
steps, just on steps in behaviors satisfying S . (The action formulas are usually meaningless for states not satisfying some type-correctness predicate.)
If x is the list of all variables that can appear in S and A, then the assertion
that an action formula A is true for all steps of behaviors satisfying S canbe written as |= S ⇒ 2[A]x . Here is reduction, without liveness, expressed
as a theorem.

CHAPTER 7. LOOSE ENDS

233

Theorem 7.1 Assume Init, L, and R are state predicates, M and E are
actions, x is a list of all variables appearing in these formulas, and X is alist of the same number of variables different from the variables x. Define
S = Init ∧ 2[E ∨ M ]x∆∆

R = M ∧ R0∆∆

L = L∧M∆

Init R = Init with x ← X
E R = E with x ← X∆
M R = (¬(R ∨ L) ∧ M + ∧ ¬(R ∨ L)0 ) with x ← X
S R = Init R ∧ 2[E R ∨ M R ]X∆∆

I R = ∧ ¬(R ∨ L) ⇒ (X = x)0
∧ R ⇒ ([R]+x awith x ← X, x ← x)+0
∧ L ⇒ ([L]x awith x ← X)
∧ ¬(R ∨ L) with x ← X
and assume:(1) |= Init ⇒ ¬(R ∨ L)(2) |= S ⇒ 2 [ ∧ E ⇒ (R0 ≡ R) ∧ (L0 ≡ L)
∧ ¬(L ∧ M ∧ R0 )∧ ¬(R ∧ L)
∧ R·E ⇒E ·R∧ E · L ⇒ L · E ]x
Then |= S ∧ 23¬L ⇒ ∃ X : S R ∧ 2I R .
Assumption (1) and the first three conjuncts in the action of assumption(2) are the conditions M1–M4, which assert that an execution of the operation described by the action M consists of a sequence of L steps followed bya C step followed by a sequence of R steps. The final two conjuncts in theaction of assumption (2) are the assumptions that R right-commutes with
E and L left-commutes with E .
In practice, R, L, and E will be defined to be the disjunction of subactions. This allows us to decompose the proofs of those commutativity
conditions by using the following theorem that is proved in the Appendix.
Theorem 7.2 If A ≡ ∃ i ∈ I : Ai and B ≡ ∃ j ∈ J : B j for actions Ai and
B j , then:|= (∀ i ∈ I , j ∈ J : Ai · B j ⇒ B j · Ai ) ⇒ (A · B ⇒ B · A)
By this theorem, to show that R right-commutes with E , it suffices to showthat each subaction in the definition of R right-commutes with each subaction in the definition of E . Similarly, L left-commutes with E if eachsubaction of L left-commutes with each subaction of E .

CHAPTER 7. LOOSE ENDS

7.1.4

234

The Hypothesis 23¬L

Formula 23¬L is a liveness property. When we add liveness conditions to
S and hope to use reduction to prove that it satisfies a liveness property
P , we would expect S to imply 23¬L. But we wouldn’t expect to haveto add a liveness property to S in order to verify that it satisfies a safety
property. In fact, to verify a safety property, we don’t have to prove that
¬L is always eventually true. The following theorem implies that, to verify
S satisfies a safety property, we can simply assume that 23¬L is true if
it is always possible for ¬L to eventually become true. To understand thetheorem, recall that Section 4.3.2 defines what it means for it to be always
possible for a state predicate Q to eventually become true—namely, that0
the program Init ∧ 2[Next]x implies 2 E([Next]+x ∧ Q ). (See (4.27).) This
theorem is proved in the Appendix:
Theorem 7.3 If S equals Init ∧ 2[Next]x , P is a safety property, and Q is a0state predicate such that |= S ⇒ 2 E([Next]+x ∧ Q ), then |= S ∧ 23Q ⇒ P
implies |= S ⇒ P .
The theorem allows us to replace the formula T in R1b (which we later0
defined to equal 23¬L) with 2 E([Next]+x ∧ ¬L ). Section 4.3.2 explainsthat we can verify this possibility condition by finding a fairness condition
F for S and verifying |= S ∧ F ⇒ 23¬L. This is the only case I know of inwhich a possibility condition is used to verify a correctness property.

7.1.5

Adding Liveness

Theorem 7.1 allows us to deduce safety properties of the program S fromsafety properties of the coarser-grain program S R . We also want to deduce
liveness properties of S from liveness properties of S R . We deduce livenessproperties of a program from fairness properties of program actions. To
deduce liveness properties of S by proving liveness properties of S R , weextend Theorem 7.1 so its conclusion is(7.8) |= S ∧ F ∧ 23¬L ⇒ ∃ X : S R ∧ 2I R ∧ F R
where F is the conjunction of fairness properties of subactions of the nextstate action E ∨ M of S and F R is the conjunction of fairness properties of
subactions of the next-state action E R ∨ M R of S R .
To understand how this is done, it helps to think in terms of the programS ⊗S R, a behavior of which is a behavior both of S (described by the valuesof variables x) and of S R (described by the values of variables X) whose

CHAPTER 7. LOOSE ENDS

235

existence is asserted by (7.8). We expect S to satisfy (7.8) because S ⊗S R
satisfies:(7.9) |= S ⊗S R ∧ F ∧ 23¬L ⇒ S R ∧ 2I R ∧ F R
Formula F R should assert fairness of subactions AR of E R ∨ M R . For simplicity, we consider only actions AR that are subactions of either E R or
M R , which I expect will usually be the case. When it is not the case, therequirements for deducing fairness of AR include requirements for deducing
fairness of both AR ∧ E R and AR ∧ M R [8].
7.1.5.1

Fairness of Subactions of E R

We defined S R so that E R equals E . (Recall that we defined G to equal
G with x ← X for any formula G.) Property φ1 of Section 7.1.2.2 for our
example generalizes to show that, in any behavior of S ⊗S R, an E step isalso an E step.
Because each E R step corresponds to a single E step in a behavior of
S ⊗S R , we expect fairness of a subaction AR of E R to be implied by fairnessof a single subaction A of E . In other words, we expect this to be true:(7.10) |= S ⊗S R ∧ XFx (A) ⇒ XFX (AR )where XF is either WF or SF. By (4.14) and (4.23) we have
XFx (A)
XFX

(AR )

≡ (2
32
3 EhAix ⇒ 23hAix )≡ (232
3 EhAR iX ⇒ 23hAR iX )where 232
3 means 32 if XF is WF and 23 if XF is SF. These formulas anda little temporal logic imply that to prove (7.10) it suffices to prove these
two theorems:(7.11) |= S ⊗S R ⇒ (23hAix ⇒ 23hAR iX )(7.12) |= S ⊗S R ⇒ 2( EhAR iX ⇒ EhAix )We make (7.11) true by requiring every hAix step in a behavior of S ⊗S R
to be an hAR iX step. Every E step in a behavior of S ⊗S R is an E R step
because E R equals E . This suggests that we want AR to equal A. (Notethat hAix equals hAiX because x equals X.)
Every E step in a behavior of S ⊗S R is an E R step because of property
φ1, and that property holds because of the commutativity assumptions ofCHAPTER 7. LOOSE ENDS

236

action E with respect to actions R and L. Therefore, we must require thathAix satisfies the same commutativity relation as E , namely:(7.13) |= S ⇒ 2[ (R · hAix ⇒ hAix · R) ∧ (hAix · L ⇒ L · hAix ) ]x
With this assumption, defining AR to equal A will make (7.11) true.
The commutativity relations satisfied by E were used to define the mapping φ, which in turn was used to define S R . For example, in Figures 7.2–
7.4, the state u 42 , which equals φ(s 43 ), was chosen when right-commuting
R 1 with E 1 so that s 41 → u 42 is an E 1 step and u 42 → s 43 is an R 1 step.
Suppose that A is a subaction of E 1 and s 41 → s 42 is an hAix step. Nothing in the construction in those figures, which describes the choice of φ used
to define S R in Theorem 7.1, ensures that the E 1 step s 41 → u 42 is also
an hAix step. However, the assumption (7.13) ensures that we could havechosen u 42 to make s 41 → u 43 an hAix step.
In general, we can use (7.13) to ensure that every E step in the original
behavior that is an hAix step remains an hAix step whenever that step iscommuted with an R or L step, so it remains an hAix step in the reduced
behavior. We can therefore define S R so that (7.12) is true, so this is not
a problem when we want to ensure that (7.10) holds for a single action A.
However, we may want (7.10) to hold for multiple subactions A of E , and asingle E step can be an hAix step for more than one of those subactions A.
We will return to this problem in Section 7.1.5.3. Now, we consider making(7.12) true.
We can deduce (7.12) from these two theorems:(7.14) (a) |= S ⊗S R ⇒ 2( EhAR iX ⇒ EhAix )(b) |= S ⊗S R ⇒ 2( EhAix ⇒ EhAix )Since hAR iX equals hAix and formulas EhAix and EhAix contain only thevariables X, (7.14a) is equivalent to:(7.15) |= S R ⇒ 2( EhAix ⇒ EhAix )If E were not a weird operator (see Section 5.4.4.3), EhAix would be equivalent to EhAix ; and we expect that equivalence to be true for most actions
hAix . However, because it is not always true, we have to add (7.15) as an
assumption.
To see what is required to make (7.14b) true, we consider what assumption is required to ensure that P ⇒ P is true for an arbitrary state predicate
P with free variables x. The free variables of P are X, and the relation between the values of x and X is described by the invariant I R of S ⊗S R .

CHAPTER 7. LOOSE ENDS

237

There are three cases, depending on whether R is true, L is true, or neither
is true:
R true: The conjunct0R ⇒ ([R]+x awith x ← X, x ← x)of I R asserts that, in this case, we can arrive at the values of x in thecurrent state by starting in a state in which the values of x equal thecurrent values of X and executing a sequence of R steps. This meansthat P ⇒ P is true if, starting in a state satisfying P and executing
a sequence of R steps, we reach a state in which P is true. Thisis true iff, starting in a state satisfying P and repeatedly executing
single R steps, we keep reaching states satisfying P . In other words, if
P ∧ R ⇒ P 0 is true in any state satisfying R of a behavior of S ⊗S R ,then P ⇒ P is true.
L true: A similar argument based on the conjunct0L ⇒ ([L]+x awith x ← X)

of I R shows that if L ∧ P 0 ⇒ P is true in any state satisfying L in a
behavior of S ⊗S R , then P ⇒ P is true.
Neither R nor L true: The conjunct ¬(R ∨ L) ⇒ (X = x) of I R showsthat P ≡ P is true for any state satisfying ¬(R ∨ L) in a behavior of
S ⊗S R
Let’s review what we have shown. We can deduce (7.10) from (7.11) and(7.12). If (7.13) is true, then we can choose S R of Theorem 7.1 to make(7.11) true for a single subaction A of E . We can deduce (7.12) from (7.14a)and (7.14b). We can deduce (7.14a) from (7.15). And finally, we can deduce(7.14b) from the conditions obtained above for proving P ⇒ P , substituting
EhAix for P . Putting all this together, we have shown that the program
S R of Theorem 7.1 can be chosen to make (7.10) true, for a single subaction
A of E , if the following two conditions are satisfied:(7.16) |= S ⇒ 2 [ ∧ (R · hAix ⇒ hAix · R) ∧ (hAix · L ⇒ L · hAix )∧ EhAix ∧ R ⇒ ( EhAix )0∧ L ∧ ( EhAix )0 ⇒ EhAix ]x|= S R ⇒ 2 ( EhAix ⇒ EhAix )CHAPTER 7. LOOSE ENDS
7.1.5.2

238

Fairness of Subactions of M R

Deducing fairness properties of subactions of M R from fairness properties ofactions of S is more complicated than for subactions of E R because an M R
step is the result of executing multiple actions of S as a single step. The
simplest and probably most common case is when we want the reduced program to satisfy fairness of the M R action itself. So, we begin by examining
this case.
Action M R is the action obtained by executing the entire operation consisting of a sequence of R steps, followed by a C step, followed by a completesequence of L steps, with the variables X substituted for the variables x.
For our example program of Figure 7.1, where the values of variables X instate s were defined to be the values of x in state φ(s), condition φ3 implies
that M R equals C . This means that in any behavior of S ⊗S R, a C step isan M R step. It suggests that we should be able to deduce fairness of the
M R action of S R from fairness of the C action of S .
Now suppose A is a subaction of C and AR is the action obtained byexecuting the entire operation consisting of a sequence of R steps, followedby an A step, followed by a complete sequence of L steps, with the variables
X substituted for the variables x. The same argument shows that AR equalsA, and that in any behavior of S ⊗S R, an A step is an AR step. Moreover,any AR step is also an M R step, so AR is a subaction of M R . So, it isreasonable to consider deriving fairness of a subaction AR of M R when AR
is obtained in this way from a subaction A of C . Since our goal is not to
obtain the most general results, we consider only this case.
First, we must define AR precisely for a subaction A of C . An AR step isobtained by combining a sequence of R steps followed by an A step followed
by a sequence of L steps into a single step, and then substituting X for x.
The definitions of R, C , and L in terms of R and L and assumptions M1–M4
imply that AR equals Aρ where Aρ is defined by+0(7.17) Aρ = ¬(R ∨ L) ∧ ([R]+x · A · [L]x ) ∧ ¬(R ∨ L)∆

We want condition (7.10) to be true for this choice of A and AR . As before,
we do this by making (7.11) and (7.12) true, starting with (7.11). In a
behavior satisfying S ⊗S R , every A step is an AR step. However, (7.11)
requires every hAix step to be an hAR iX step. This is not true for A anarbitrary subaction of C . It’s not even necessarily true for A = C , for thefollowing reason.
Recall that Figure 7.4 shows two behaviors that satisfy S , the bottom
one being the reduced version of the top one. The action labels describe theCHAPTER 7. LOOSE ENDS

239

changes of the values of the variables x. The top behavior satisfies S ⊗S R ,where the values of variables X in a state s i of that behavior are the valuesof x in the corresponding state φ(s i ) of the bottom sequence. The steps 43 → s 44 of the top behavior is a C step iff u 42 → u 46 is a C step. If one ofthe variables x has different values in states s 43 and s 44 , there is no reason
why its value should differ in states u 42 and u 46 . Step s 43 → s 44 would be
a hC ix step but not a hC iX step if the values of all the variables x are thesame in states u 42 and u 46 . To be able to deduce (7.11) when A is C and
AR is M R , we need the assumption that if s 43 → s 44 is a hC ix step, thenx0 6= x is true of step u 42 → u 46 .
Since every A step in a behavior of S ⊗S R is an AR step, we can deducethat every hAix step is an hAR iX step from this assumption:|= S ⇒ 2[ (hAix )ρ ⇒ (x0 6= x) ]xThere is seldom any reason for a program’s next-state action to allow stuttering steps, and modifying it to disallow stuttering steps does not change
the program. An A step of the program will usually be an hAix step; andif it isn’t, A can be replaced by hAix . So for simplicity, we strengthen thisassumption to:(7.18) |= S ⇒ 2[Aρ ⇒ (x0 6= x)]x
We have shown that (7.18) implies that in a behavior of S ⊗S R , every hAix
step is an hAR iX step. In other words, we have shown that it implies:(7.19) |= S ⊗S R ⇒ 2[ hAix ⇒ hAR iX ]x,X
This assertion implies (7.11).
The assumption (7.18) makes (7.11) true, so we now have to make (7.12)
true. But we can’t expect (7.12) to hold in general for the following reason.
Since AR equals Aρ , we expect EhAR iX to imply EhAρ ix . By (7.17),
EhAρ ix equals Eh¬(R ∨ L) ∧ [R]+x · A · . . .ix , which implies E(¬(R ∨ L) ∧(R ∨ A)) (since E(U · V ) implies E(U ) for any actions U and V ). We cantherefore expect EhAR iX to imply EhAix , as required by (7.12), only when
there is no R action.
A sequence of R steps may have to occur between when Aρ becomesenabled and when A becomes enabled, so fairness assumptions for R as well
as a fairness assumption for A may be required to imply fairness of Aρ . Instead of assuming a fairness condition on L actions to ensure that operation
M completes after a C step occurs, we simply assumed that the operation
completes by adding the assumption 23¬L. Similarly, instead of assuming

CHAPTER 7. LOOSE ENDS

240

a fairness condition on R actions to ensure that the necessary enabling condition of C occurs, we simply assume that the enabling condition eventuallyoccurs.
As an example, suppose we want to deduce weak fairness of AR fromstrong fairness of A. (Because fairness of AR requires fairness of more thanjust A, there’s no reason not to have different kinds of fairness for the two
actions.) By (7.19) and the definition (4.12) of WF, to prove WFX (AR ) it
suffices to prove 32 EhAR iX ; hAix . Just as we split the proof of (7.12)
into the two conditions of (7.14), we split the proof of 32 EhAR iX ; hAix
into proving:(7.20) (a) 2( EhAR iX ⇒ EhAρ ix )(b) 32 EhAρ ix ; hAix
This may seem wrong because we have EhAρ ix in (7.20a) and EhAρ ix
in (7.20b) when the two formulas should be equal. However, the following
reasoning shows that they are equal. The definition of Aρ and conditions E3
and E4 of Section 5.4.4.2 imply that EhAρ ix equals ¬(R ∨ L) ∧ EhAρ ix .
The invariant I R implies that ¬(R ∨ L) ⇒ (x = X) and ¬(R ∨ L) aretrue, so S ⊗S R implies that EhAρ ix always equals EhAρ ix . We make S R
implying (7.20a) one of our requirements for deducing that WFX (AR ) issatisfied. We now consider (7.20b).
By (3.32b) of Section 3.4.2.8 and the tautology |= ¬hAix ≡ [¬A]x , toprove (7.20b) it suffices to prove:(7.21) 32 EhAρ ix ∧ 2[¬A]x ; hAix
By the definition (4.22) of SF and transitivity of ;, to deduce (7.21) from
SFx (A), it suffices to prove that S implies:(7.22) 32 EhAρ ix ∧ 2[¬A]x ; 23 EhAix
We have seen that to deduce WFX (AR ) from SFx (A), it suffices to show
(7.18) and:(7.23) (a) |= S R ⇒ 2( EhAR iX ⇒ EhAρ ix )(b) |= S ⇒ (32 EhAρ ix ∧ 2[¬A]x ; 23 EhAix )For the other three possible pairs of fairness conditions on AR and A, thesame argument shows that we can deduce SFX (AR ) instead of WFX (AR )by replacing 32 with 23 in (7.23b); and we can assume WFx (A) insteadof SFx (A) by replacing 23 with 32 in (7.23b).

CHAPTER 7. LOOSE ENDS
7.1.5.3

241

The Reduction Theorem with Fairness

We have described the assumption needed to infer that the reduced programsatisfies a fairness condition on a single action AR if the original programsatisfies a fairness condition on a single action A. We now combine this intoa theorem for inferring that the reduced program satisfies the conjunctionof countably many fairness conditions AR
i . This is simple, except for one
problem mentioned above for the case in which AR is a subaction of E R .
Recall that to satisfy (7.11), we constrained the construction of the function φ illustrated in Figures 7.2–7.4 so that if an E step is an A step in theoriginal behavior, then the corresponding E step in the reduced behavior
is also an A step. With multiple actions Ai , if the E step in the original
behavior is both an Ai and an Aj step for j 6= i , it might be impossible to
make the E step in the transformed behavior both an Ai and an Aj step.
However, to satisfy (7.11), it’s not necessary for every E step that’s an
A step in the original behavior to remain an A step in the reduced behavior.
It’s only necessary to ensure that if there are infinitely many A steps in theoriginal behavior, then infinitely many of them are A steps in the reduced
behavior. With countably many such actions Ai , it’s possible to construct
the reduced behavior so that for every i for which there are infinitely many
Ai steps in the original behavior, there are infinitely many Ai steps in the
reduced behavior. This is done using Theorem 4.1 of Math V the same way
it is used in the proof of Theorem 4.7 in the Appendix..
We can now put together the assumptions we derived above for deducing
fairness of an action AR from fairness of an action A for individual actions
A into a theorem for deducing fairness of a countable number of actions
ARi from fairness of actions Ai . The requirements for Ai a subaction of E
R
(and ARi a subaction of E ) come from (7.16). The requirements for Ai a
R
subaction of C (and Ai a subaction of M R ) come from (7.18) and (7.23) plus
the modification of (7.23) for additional fairness conditions of A and AR .
Theorem 7.4 With the definitions and assumptions (1) and (2) of Theo∆rem 7.1, let C = (¬L) ∧ M ∧ (¬R0 ) and let∆|= F ⇒ ∀ i ∈ I : YFix (Ai )F R = ∀ i ∈ I : ZFiX (ARi )where I is a countable set and YFi and ZFi are WF or SF for each i ∈ I ;and assume either:∆ii• Ai is a subaction of E , AR
i = Ai , YF equals ZF ,CHAPTER 7. LOOSE ENDS

242|= S ⇒ 2 [ ∧ (R · hAi ix ⇒ hAi ix · R) ∧ (hAi ix · L ⇒ L · hAi ix )∧ EhAi ix ∧ R ⇒ ( EhAi ix )0∧ L ∧ ( EhAi ix )0 ⇒ EhAi ix ]x , and|= S R ⇒ 2 ( EhAi ix ⇒ EhAi ix )or
• Ai is a subaction of C ,+0Aρi = ¬(R ∨ L) ∧ ([R]+x · Ai · [L]x ) ∧ ¬(R ∨ L) ,∆AR
= Aρi ,i∆|= S ⇒ 2[Aρi ⇒ (x0 6= x)]x ,ρ|= S R ⇒ 2( EhAR
i iX ⇒ EhAi ix ) , and|= S ∧ F ⇒ (232
3 Z EhAρi ix ∧ 2[¬Ai ]x ; 232
3 Y EhAi ix )where for Q either Y or Z, 232
3 Q is 32 if QF is WF, and3
it is 23 if QF is SF.
Then |= S ∧ F ∧ 23¬L ⇒ ∃ X : S R ∧ 2I R ∧ F R .

7.1.6

An Example: Making Critical Sections Atomic

A standard concurrent coding practice is to “protect” accesses to shareddata by putting them in critical sections. Recall that Section 4.2.2.1 defineda critical section to be a piece of code in a process such that no two processes
can be executing their critical sections at the same time. We can consider
this coding practice to be an application of reduction in which the reduced
program executes the entire critical section, including its waiting and exiting
code, as a single action.
We assume that critical sections are implemented with the trivial mutual
exclusion algorithm LM described in Figure 4.6 of Section 4.2.6.1 that uses
Dijkstra’s P and V semaphore operations. (Correctness of a mutual exclusion algorithm can be expressed as the requirement that it implements LM
under a suitable refinement mapping.) We assume the program is describedwith pseudocode, using a semaphore variable sem and a variable pc to describe the control state. The variable sem initially equals 0 and is accessedby a process p only by P p and V p actions that execute the P (sem) andV (sem) operations. These actions are written in TLA as follows, where the3iR
For example, if YFix (Ai ) is SFix (Ai ) and ZFiX (ARi ) is WFX (Ai ), this condition is:|= S ∧ F ⇒ (32 EhAρi ix ∧ 2[¬Ai ]x ; 23 EhAi ix )

CHAPTER 7. LOOSE ENDS

243

unchanged formulas assert that all program variables other than sem andpc are left unchanged:∆

P p = ∧ pc(p) = . . .
∧ (sem = 1) ∧ (sem 0 = 0)
∧ pc 0 = (pc except p 7→ . . .)∧ unchanged . . .
∆V p = ∧ pc(p) = . . .
∧ sem 0 = 1∧ pc 0 = (pc except p 7→ . . .)∧ unchanged . . .
The value of sem is therefore always either 0 or 1. An execution of a critical section by process p consists of a P p step, followed by steps satisfying
actions CS p,1 , . . . , CS p,k p that represent executions of statements in thecritical section, followed by a V p step. The assumption that shared data isaccessed only within a critical section means that if an action E q describes
a statement of process q outside a critical section (meaning not a P q , CS q,j ,or V q action), then each action CS p,i commutes with E q if p 6= q.
We can reduce a program using critical sections in this way by making
execution of each critical section a single step. This is done by a sequence of
applications of our reduction theorems, each one reducing one critical sectionof a single process. When doing multiple reductions, it would get confusing
if we introduced new variables for each reduction. We therefore consider the
reduced version S R of a program S to be the program S R described in ourtheorems, except with x substituted for X. In our theorems, the M R that
executes the operation described by action M as a single step is defined toequal M ρ with x ← X . When we use the variables x instead of X for the
reduced program, M R becomes M ρ .
To apply the theorems to a critical section of a process p, we let M pequal P p ∨ CS p,1 ∨ . . . ∨ CS p,k p ∨ V p , so M p is replaced in the reduced
program by M ρp . We could let any of those actions be the action C , but it
is most convenient to let C be the P p action, so there is no action R andaction L is CS p,1 ∨ . . . ∨ CS p,k p ∨ V p . By Theorem 7.2, it suffices to showthat V p and each CS p,i left-commutes with every action of every process
q 6= p. (Action L trivially left-commutes with any action of process p not
a subaction of M p .) The possible actions of process q are P q , V q , CS q,jfor some j , an action E q not in a critical section, and M ρq if the operation
described by M q has already been reduced. Here is why V p and CS p,icommute with each of those actions of process q 6= p:

CHAPTER 7. LOOSE ENDS

244

Pq : V p left-commutes with P q because the mutual exclusion algorithm implies that V p is not enabled when a process q 6= p is in its criticalsection, so P q · V p equals false; CS p,i commutes with P q because it
does not access sem or pc(q) (meaning that it does not depend on or
modify sem or pc(q)).
Vq : V p commutes with V q because any two V (sem) operations commute;CS p,i commutes with V p because it does not access sem or pc(q).
CSq,j : CS q,j · V p and CS q,j · CS p,i both equal false because a CS q,j step
leaves process q inside its critical section, which by the mutual exclusion algorithm implies process q is outside its critical section so neither
CS p,i nor V p is enabled.
Eq : V p commutes with E q because E q does not access sem or pc(p); andCS p,i commutes with E q because of the assumption that actions describing a statement inside a critical section commute with all actions
describing statements not in another process’s critical section.
Mqρ : Both M ρq · V p and M ρq · CS p,i equal false because an M ρq step leaves
sem = 1, while the mutual exclusion algorithm implies that V p andCS p,i are enabled only when sem = 0.
This shows that S implies E · L ⇒ L · E , so since there is no R action, we
can apply Theorem 7.1. There is still the formula 23¬L to deal with. If
the program has fairness assumptions, then we expect 23¬L to be implied
by fairness assumptions of the L actions. If not, then by Theorem 7.3 wecan verify safety properties by showing that, after executing process p’s
P p statement, it is always possible for execution of the critical section tocomplete. It’s hard to imagine an application of mutual exclusion that would
allow a behavior in which it is impossible for some process ever to exit its
critical section.
We now consider deducing fairness properties of the reduced program.
First, let action A describe a statement outside any critical section. If thestatement is in process p, then Aρ equals A so fairness of Aρ is equivalent tofairness of A. If A is an action of a process other than p, the argument aboveshows that L commutes with hAix . If hAix is a subaction of the next-state
action of S , then an L ∧ ( EhAix )0 step ends in a state in which an hAix
step can occur, which by commutativity of L and hAix implies it begins ina state in which an hAix step can occur, so S implies 2(L ∧ ( EhAix )0 ⇒EhAix ). We expect 2 ( EhAi ix ⇒ EhAi ix ) to be true, since substitution
has been found to distribute over E for most actions. (However, there is

CHAPTER 7. LOOSE ENDS

245

little experience with the substitution x ← X that occurs in reduction.) If
this formula is true, then by Theorem 7.4 we can deduce fairness of Aρ fromfairness of A.
We expect the most common fairness property for a subaction of M ρp to
be fairness of M ρp itself. In this case C is P p , and we expect to deduce afairness condition of M ρp from the same fairness condition of the P p action.
There is no R action, so the definitions of P p and M ρp imply M ρp ⇒ (x0 6= x)
and EhM ρp ix ⇒ EhP p ix . (In the unlikely case that process p does nothing
but repeatedly execute the critical section, so M ρp leaves pc(p) unchanged,
we need to add the assumption that M ρp changes some other variable.) The
only remaining requirement to deduce from Theorem 7.4 that fairness of P p
implies fairness of M ρp is:|= S R ⇒ 2( EhM R iX ⇒ EhM ρ ix )Since hM R ix equals hM ρ ix , this is true if substitution distributes over E
for the action hM ρ ix .
We have described the mathematics underlying the use of mutual exclusion to implement atomic operations. We have ignored the question of whatthat achieves. We use mutual exclusion to view execution of the critical section as a single step, but is that a correct view? The answer lies in condition
R3 of Section 7.1.1.2, which tells us when we can deduce that the original
program satisfies a property that the reduced program satisfies. The only
part of the invariant I R that seems useful in condition R3 is the conjunct¬(R ∨ L) ⇒ (X = x), which asserts that the variables of the original program and the reduced one have equal values when no process is executing
its critical section.

7.1.7

Another Example: Pipelining

Here is a sketch of a simple example of reduction that is interesting in part
because each operation being reduced contains actions performed by two
different processes. The example is a very abstract view of one stage in apipelined computation—a view that tells us nothing about what is being
computed.
The program S performs a sequence of computations. Each computation
presumably obtains some input, does some computation, and then producessome output—but that is irrelevant. What concerns us is that the computations are pipelined as follows so they can be performed concurrently
by two processes. Process 1 performs the first part of the computation toCHAPTER 7. LOOSE ENDS

246

obtain a partial result that it appends to the end of a fifo queue. Process 2
removes the partial result from the head of the queue and completes thecomputation. Process 1 can therefore get ahead of process 2, performing
its part of the i th computation while process 2 is still performing its partof the j th computation, for i > j . The reduced program S R replaces thesetwo processes with a single process that performs each computation as asingle atomic action. The property we want to prove by reduction presumably involves how the computed values are used after they are computed,
when they have the same values in the original and reduced programs, so
condition R3 is satisfied.
We describe steps of process 1 by an action Cmp1 ∨ Send , where thatprocess’s part of a computation consists of a finite sequence of Cmp1 steps
followed by a single Send step that appends the partial result to the tailof the queue. Steps of process 2 are described by an action Rcv ∨ Cmp2,
where that process’s part of the computation consists of a single Rcv stepthat removes the partial result from the head of the queue followed by afinite sequence of Cmp2 steps. The contents of the queue are described by
the variable qBar , which is accessed only by the Send and Rcv actions. We
assume that the two processes communicate only through the fifo qBar ,an assumption expressed by these conditions: Cmp1 commutes with theprocess 2 actions Rcv and Cmp2, and Cmp2 commutes with the process 1
actions Cmp1 and Send . Since qBar is the only shared variable accessedby Rcv and Send , it doesn’t matter in which order these two actions are
executed in a state where the queue is nonempty. Thus, we have:(7.24) |= (qBar 6= h i) ⇒ (Send · Rcv ≡ Rcv · Send )The program may contain other processes that can interact in some way
with processes 1 and 2. For example, process 1 may obtain its input from athird process and process 2 may send its output to a fourth process.
The program’s next-state action is M ∨ O, where M describes processes
1 and 2 and O describes any other processes. We rewrite M in the form
∃ n ∈ N+ : M n , where N+ is the set of positive integers and M n is an action whose steps describe a complete execution of the n th computation. To
do this, we assume state functions snum and rnum whose values are thenumbers of Send and Rcv actions, respectively, that have been executed.
Initially, snum = rnum = 0. The Send action increments snum by 1 andthe Rcv action increments rnum by 1. We can then define:∆(7.25) M n = ∨ (snum = n − 1) ∧ (Cmp1 ∨ Send )∨ ((rnum = n − 1) ∧ Rcv ) ∨ ((rnum = n) ∧ Cmp2)

CHAPTER 7. LOOSE ENDS

247

We recursively define the n th reduction of the program to be the one obtainedby reducing the operations M 1 , . . . , M n in that order. To define the n th
reduction, define:
Cmp1n
Send n
Rcv n
Cmp2n

∆

=
∆
=
∆
=
∆
=

(snum = n − 1) ∧ Cmp1
(snum = n − 1) ∧ Send
(rnum = n − 1) ∧ Rcv(rnum = n) ∧ Cmp2

so M n equals Cmp1n ∨ Send n ∨ Rcv n ∨ Cmp2n . The actions R, C , and L
for the n th reduction are:∆R n = Cmp1n∆

C n = Send n∆

Ln = Rcv n ∨ Cmp2n

Again, with multiple reductions we let the reduced program have the same
variables as the original program, so the n th reduction replaces the action
M n with M ρn .
The remaining action E for this reduction is the disjunction of theseactions: the action O describing the other processes, the already reduced
actions M ρk for k < n, and the subactions of M k for k > n. To apply
Theorem 7.1, we must show that R n right-commutes with these actions andLn left-commutes with them.
That R n right-commutes and Ln left-commutes with O must be assumed. The commutativity relations hold for M ρk with k < n because an
R n step is enabled only after an M ρk step, which implies R n · M ρk equals
false (so R n right commutes with M ρk ), and which also implies that Ln
cannot be enabled immediately after an M ρk step, so M ρk · Ln also equals
false.
What remains to be shown is that Cmp1n (the action R n ) right commutes with M k , and that Rcv n and Cmp2n (whose disjunction equals Ln )left commutes with M k , for k > n. For that, we have to show that eachof the four actions whose disjunction equals M k satisfy those commutativity conditions. We will use the commutativity relations we assumed above:that Cmp1 commutes with Cmp2 and Rcv , and that Cmp2 commutes with
Send . The assumption that Cmp2 commutes with Send implies that Cmp2i
commutes with Send j for all i and j . This follows from the definitions of
Cmp2i and Send j , because Cmp2 does not depend on or modify snum and
Send j does not depend on or modify rnum. Similarly, Cmp1i commuteswith Rcv j and Cmp2j for all i and j . These assumptions are called thecommutativity assumptions in the following proof sketches of the required
commutativity relations. Recall that we are assuming k > n.

CHAPTER 7. LOOSE ENDS

248

Cmp1n right-commutes with Cmp1k and Sendk
Cmp1n ·Cmp1k and Cmp1n ·Send k equal false because snum = n −1
after a Cmp1n step; Cmp1k and Send k are enabled iff snum = k − 1;and k > n.
Cmp1n right-commutes with Rcvk and Cmp2k
By the commutativity assumptions.
Rcvn left-commutes with Cmp1k
By the commutativity assumptions.
Rcvn left-commutes with Sendk
A Send k step is enabled only if snum = k − 1; the step leaves rnum
unchanged; and Rcv n is enabled only if rnum = n − 1. Therefore,
Send k · Rcv n enabled implies snum = k − 1 and rnum = n − 1, sok > n implies snum > rnum which implies qBar 6= h i. By (7.24), this
implies Send k · Rcv n ≡ Rcv n · Send k .
Rcvn left-commutes with Rcvk and Cmp2k
Rcv k · Rcv n and Cmp2k · Rcv n equal false because a Rcv k or Cmp2k
step ends in a state with rnum = k which by k > n implies rnum 6=
n − 1, so Rcv n is not enabled in that state.
Cmp2n left-commutes with Cmp1k and Sendk
By the commutativity assumptions.
Cmp2n left-commutes with Rcvk and Cmp2k
A Rcv k or Cmp2k step ends with rnum = k , and Cmp2n is enabled
only if rnum = n, which is false because k > n. Therefore a Cmp2n
step cannot follow a Rcv k or Cmp2k step, so Rcv k ·Cmp2n and Cmp2k ·Cmp2n equal false.
This handles the commutativity assumptions of Theorem 7.1. We still havethe hypothesis 23¬L in the theorem’s conclusion to deal with. By Theorem 7.3, to use reduction for verifying safety properties, we don’t need that
hypothesis. We only have to show that any finite behavior satisfying thesafety property S can be extended to a behavior that completes each M noperation in which the C n action has occurred. This means showing that
Process 2 cannot deadlock. This should be easy to show unless process 2
may have to wait for another process to do something—for example, until
another process is ready to receive process 2’s output.
For reasoning about liveness, we would expect the hypothesis 23¬L to
be satisfied by adding fairness conditions to process 2 actions, and perhaps toCHAPTER 7. LOOSE ENDS

249

other processes, to ensure that the operation will complete once process 1’s
Send action occurs. The obvious fairness condition we want the reduced
program to satisfy is fairness of M ρ . If an M ρn action is enabled, then no
M ρi action with i 6= n can be enabled until an M ρn step occurs. This implies
that (weak or strong) fairness of M ρ is equivalent to fairness of M ρn for alln. For each n, ensuring fairness of M ρn is the second case in Theorem 7.4,
with Ai equal to C n , which equals Send n . The assumption |= S ∧ F ⇒ . . .
in that case of the theorem will have to be implied by fairness conditions on
subactions of Cmp1.

7.2

Decomposing and Composing Programs

We think of a program as consisting of multiple components. Most often
those components are processes. However, a process of an abstract program
need not correspond to a process (or thread) in a coding language. As
we saw in Section 1.5, Euclid’s algorithm can be viewed as a multiprocessprogram. In general, any disjunct of a program’s next-state action can bethought of as a process, and we may be able to write the next-state action
in more than one way as the disjunction of subactions. We now use theterm component instead of process for what is described by a disjunct of the
program’s next-state action.
In this section, we describe a program as the conjunction of separate
programs, each describing one of the program’s components. There are two
reasons for doing this. The first is that we have the program and want todecompose the problem of verifying its correctness into the simpler tasksof verifying correctness of each of its components. We call this procedure
decomposition and consider it in Section 7.2.1. The second reason is because
the program is implemented using existing components whose correctness
has been verified. We want to deduce correctness of the program fromcorrectness of the components, without knowing how the components are
implemented. This procedure is called composition and is considered in
Section 7.2.2.
There is little reason to decompose a program if we are proving its correctness. Decomposition structures the proof in three parts: (1) showingthat the program is equivalent to the conjunction of programs describing thecomponents, (2) showing that each of those programs satisfies a property,and (3) showing that the conjunction of those properties implies correctnessof the original program. Such a proof can be rewritten as an ordinary correctness proof of the original algorithm by a simple rearrangement of theCHAPTER 7. LOOSE ENDS

250

steps of those three parts. But math provides many ways to structure a
proof, and deciding in advance to structure it by decomposition might ruleout better proofs.
The one good reason to decompose the verification of a program in thisway is that it may make it easier to use a tool to verify correctness. For
example, a model checker might be able to verify correctness of individualcomponents but not correctness of the complete program. Decomposition
would allow using model checking to perform part of the verification, andthen using the results presented here to prove that correctness of the components implies correctness of the entire program. This approach has been
applied to a nontrivial example [24], but I don’t know of any case in which
it has been used in industry.
Composition is useful if an engineer wants to verify correctness of a program that describes a system built using an existing component whose behavior is specified by an abstract program. Up until now, we have describeda program by a formula that is satisfied by behaviors in which the program
to be implemented, which I will here call the actual program, and its environment are both acting correctly. There was no need for the mathematicaldescription to separate the actual program and its environment, since itmakes no difference if an execution is incorrect because the programmer
didn’t understand what the code would do or what the environment would
do. However, if a program is implemented using a component purchased
elsewhere, it is important to know if an incorrect behavior is due to an incorrect implementation of the actual program or of the component, whichis part of the environment.
For composition, we therefore describe a program with two formulas,
formula M describing the correct behavior of the actual program and aformula E describing correct behavior of its environment. These formulas+
are combined into a single formula, written E −.
M , that can be thought ofas being true of a behavior iff M is true as long as E is (so M is always true+
if E is always true). Formula E −.
M is what is called a rely/guarantee
description of the program [22].
Currently, implementing actual programs with precisely specified existing components seems likely to arise in practice only for components thatare traditional programs that perform a computation and stop; and where
execution of the component can be considered to be a single step of thecomplete program. In that case, there is no need for TLA. As explained inAppendix Section A.5, the safety property of the component can be specified by a Hoare triple; and termination is the only required liveness property.
Composition in TLA is needed only if the existing component interacts with

CHAPTER 7. LOOSE ENDS

251

its environment in a more complex way that must be described with a moregeneral abstract program. Such reusable, precisely specified components do
not seem to exist now. Perhaps someday they will.
The results presented here come from a single paper [2]. The reader isreferred to that paper for the proofs. To make reading it easier, much of
the notation used here—including the identifiers in formulas—is taken fromthat paper.

7.2.1

Decomposing Programs

7.2.1.1

Writing a Program as a Conjunction

As an example, we take Euclid’s algorithm, described in Section 1.5. Insteadof x and y, let’s name the variables a and b. Also, instead of having thealgorithm compute the GCD of two particular numbers, we’ll let it nondeterministically choose the initial values of a and b and compute their GCD.
To write the algorithm in TLA, let’s first define formulas that describe
the initial values of each of the variables, how they are changed in the nextstate action, and fairness of the actions that change them, where N+ is theset of positive integers. Here are those formulas for the variable a:∆Init a = a ∈ N+∆
Next a = (a > b) ∧ (a 0 = a − b) ∧ (b 0 = b)∆La
= WFha i (Next a )The formulas Init b , Next b , and Lb are obtained from these formulas byinterchanging a and b. Note that La is equivalent to WFha,b i (Next a ) because
Next a implies b 0 = b, and similarly, Lb is equivalent to WFha,b i (Next b ).
We can describe Euclid’s algorithm with the following TLA formula M :M = Init M ∧ 2[Next M ]ha,b i∆∆

Init M = Init a ∧ Init b∆

Next M = Next a ∨ Next b∆

LM = La ∧ Lb
Formula M is equivalent to the conjunction of M a and M b , defined by:
M a = Init a ∧ 2[Next a ]a ∧ La∆

M b = Init b ∧ 2[Next b ]b ∧ Lb∆

The equivalence of M and M a ∧ M b follows by simple logic from:|= 2[Next a ]a ∧ 2[Next b ]b ≡ 2[Next a ∨ Next b ]ha,b i

CHAPTER 7. LOOSE ENDS

252

This result follows from the equivalence of 2(F ∧ G) and 2F ∧ 2G, for any
formulas F and G, and from
[Next a ]a ∧ [Next b ]b ≡ [Next a ∨ Next b ]ha,b iwhich follows from the definition of [. . .]... , the equivalence of (a 0 = a)∧(b 0 =b) and ha, b i0 = ha, b i, and:(7.26) |= Next a ⇒ (b 0 = b)|= Next b ⇒ (a 0 = a)That M is equivalent to M a ∧ M b depends only on (7.26), not on any otherproperties of Next a and Next b , and not on the definitions of Init a , Init b ,La , or Lb . Moreover, it remains true if each variable a and b is replaced
by a tuple of variables, as long as those two tuples have no variable incommon and (7.26) is satisfied. In other words, if a program consists of
two components, each modifying different variables than the other, thenthe program can be decomposed as the conjunction of two programs, each
describing one of the components.
The following theorem generalizes this example from two to n components. It replaces M a and M b by processes M i for i ∈ 1 . . n, replaces a andb by the lists m i of variables modified by each component i , and replaces(7.26) by the requirement that for each i , the next-state action Next i of M i
implies hm j i0 = hm j i for j 6= i .4
Theorem 7.5 If m 1 , . . . , m n are each lists of variables, with all the vari∆ables in all the lists distinct, N = 1 . . n, and∆m = m 1, . . . , m n∆
M i = Init i ∧ 2[Next i ]hm i i ∧ Li∆
M = ∀i ∈ N :Mi|= M ⇒ 2 [ ∀ i , j ∈ N : Next i ∧ (i 6= j ) ⇒ (hm j i0 = hm j i) ]mthen|= M ≡ (∀ i ∈ N : Init i ) ∧ 2[∃ i ∈ N : Next i ]hm i ∧ (∀ i ∈ N : Li )We can further generalize this theorem to allow hiding of variables local
to components. Suppose that for each component i , we might want to hide4
We are abandoning our convention of naming a list of variables with a boldface letterand adopting the notation of [2], where each mi is a list of variables that we could write
mi,1 , . . . , mi,ni but won’t.

CHAPTER 7. LOOSE ENDS

253

a sublist y i of the variable list m i , where the variables y i do not appear in
any M j with j 6= i . We can then define M byM∆=

∀ i ∈ N : (∃ y i : M i )where if y i is the empty tuple, then ∃ y i : M i equals M i . We must modify
the hypothesis |= M ⇒ 2[. . .]m by replacing m j with the variables of m j
not in y j , and make this the conclusion:|= M ≡ ∃ y 1 , . . . , y n :d i](∀ i ∈ N : Init i ) ∧ 2[∃ i ∈ N : Next
hm i ∧ (∀ i ∈ N : Li )∆d i = Next i ∧ ∀ j ∈ N \ {i } : y 0 = y j .
where NextjAnother generalization is to require only that different components modify different parts of the state, not necessarily different variables. For example, suppose the components are processes and process i modifies pc(i ),where the value of the variable pc is always a function whose domain is theset N . In the hypothesis |= M ⇒ 2[. . .]m , we can replace the expression
hm j i0 = hm j i by a state predicate ν j , where the predicates ν i must satisfy
only the additional hypothesis:|= M ⇒ 2[(∀ i ∈ N : ν i ) ⇒ (m 0 = m)]hm i
For the example in which process i modifies pc(i ), we can define ν i so it
implies (∃ S : pc ∈ (N → S )) ∧ (pc 0 (i ) = pc(i )).
For simplicity, we consider only decomposing programs as described by
Theorem 7.5. The rest of what we say about program decomposition canbe generalized to these more general ways to decompose programs.
7.2.1.2

Decomposing Proofs

We now consider decomposing the verification that a program is correct into
the verification that its components are correct. Let’s start with a programwith two variables c and d and two components, each component modifying
one of the variables. Let’s suppose we have decomposed the program into
the conjunction M lc ∧ M ld , and we have decomposed its correctness property
into M c ∧ M d , where M c and M d are correctness conditions for the twocomponents. We have to verify:(7.27) |= M lc ∧ M ld ⇒ M c ∧ M d
and we’d like to do this by verifying that M lc satisfies M c and that M ld
satisfies M d . We can obviously do that if we can verify|= M lc ⇒ M c

and|= M ld ⇒ M d

CHAPTER 7. LOOSE ENDS

254

However, those conditions are unlikely to be true. The component program
M lc is unlikely to satisfy M c when used as a component of an arbitraryprogram. Its correctness will depend upon some property of its environment
M ld . Similarly, correctness of M ld will depend upon some property of M lc .
We can obviously reduce verification of (7.27) to verifying|= M lc ∧ M ld ⇒ M c|= M lc ∧ M ld ⇒ M d

andbut that doesn’t reduce the amount of work involved. However, suppose that
correctness of M lc doesn’t depend on its environment being the component
M ld , but just requires its environment to satisfy the correctness condition
M d of that component, and similarly correctness of M ld just requires thatthe other component satisfies M c . We would then like to reduce verificationof (7.27) to verifying:(7.28) |= M d ∧ M lc ⇒ M c

and|= M c ∧ M ld ⇒ M dThis would reduce the amount of work because M c and M d are probably
significantly simpler than M lc and M ld . Can we do that?
Let’s consider the following trivial example, where each component initializes its variable to 0 and keeps setting its variable’s value to the value ofthe other component’s variable.
(7.29) M lc = (c = 0) ∧ 2[(c 0 = d ) ∧ (d 0 = d )]c∧ WFc ((c 0 = d ) ∧ (d 0 = d ))∆M ld = (d = 0) ∧ 2[(d 0 = c) ∧ (c 0 = c)]d
∧ WFd ((d 0 = c) ∧ (c 0 = c))∆

We take as the correctness condition of each component that its variable
always equals 0:
M c = 2(c = 0)∆

and M d = 2(d = 0)∆

Condition (7.28) is satisfied because each component’s variable keeps setting
its variable to 0 (that is, it can take nothing but stuttering steps) if the othercomponent’s variable always equals 0. As we would hope, the correctness
condition (7.27) is also satisfied because the program consisting of those twocomponents keeps both c and d always equal to 0.
Now let’s replace M c and M d by the properties asserting that c and deventually equal 1:
M c = 3(c = 1)∆

M d = 3(d = 1)∆

CHAPTER 7. LOOSE ENDS

255

while keeping M lc and M ld the same. Condition (7.28) is still satisfied because each component eventually sets its variable to 1 if the other component
sets its variable to 1. However, (7.27) is not satisfied. Changing the correctness conditions doesn’t change the behavior of the program, which is totake nothing but stuttering steps.
We might ask why we can’t deduce (7.27) from (7.28) in this example.
However, the real question is why we can deduce it in the first example. Deducing (7.27) from (7.28) is deducing, from the assumption that correctnessof each component implies correctness of the other, that both components
are correct. This is circular reasoning, and letting M c = M d = false showsthat it allows us to deduce that any program implies false, from which we
can deduce that the program satisfies any property.
So, why does (7.28) imply (7.27) in the first case? Why can we deducethat both components leave their variables equal to 0 from the assumptionthat each component leaves its variable equal to 0 if the other process leaves
its variable equal to 0? The reason is that neither process can set its variable
to a value other than 0 until the other one does. Stated more generally,
we can deduce that both components in a two-component program satisfy
their correctness properties if neither component can violate its correctness
property until after the other does. So we want to replace (7.28) by:(7.30) |= ∀ k ∈ N :(M d true through state k − 1)
∧ (M lc true through state k ) ⇒ (M c true through state k )plus the same condition with c and d interchanged, where F true throughstate −1 is taken to be true for any property F .
To express (7.30) precisely, we have to say what it means for a property
F to be true through state k . If F is a safety property, it means that F istrue of the finite behavior σ(0) → . . . → σ(k ), which means it’s true of the(infinite) behavior obtained by repeating the state σ(k ) forever. It follows
from Theorems 4.4 and 4.5 that any property F equals C(F ) ∧ L where L isa liveness property such that hC(F ), Li is machine closed. By the definitionof machine closure (in Section 4.2.2.2), any finite behavior that satisfies
C(F ) can be completed to a behavior satisfying C(F ) ∧ L, which equals F .
Therefore, the only way a behavior can fail to satisfy F through state k is
for it not to satisfy C(F ) through state k , so F is true through state k meansthat C(F ) is true through state k . We should therefore replace M d , M lc ,and M c by C(Md ), C(Mcl ), and C(Mc ) in (7.30). For a safety property, true
through state k means true if all states i with i > k equal state k , so weCHAPTER 7. LOOSE ENDS

256

can rewrite the resulting condition as:(7.31) |= ∀ k ∈ N :(every state after state k equals state k ) ⇒( (C(M d ) true through state k − 1) ∧ C(M lc ) ⇒ C(M c ) )Next, let v be the tuple of all variables in these formulas. We can thenreplace the assertion “every state . . . state k ” in (7.31) with “v 0 = v fromstate k on”. By predicate logic, if k does not appear in R or S , then(∀ k : P ⇒ (Q ∧ R ⇒ S )) ≡ ((∃ k : P ∧ Q) ∧ R ⇒ S )We can therefore rewrite (7.31) as follows, abbreviating “true through state”
as “tts”:(7.32) (∃ k ∈ N : (v 0 = v from state k on) ∧ (C(M d ) tts k − 1))∧ C(M lc ) ⇒ C(M c )If we define F+v to equal∃ k ∈ N : (v 0 = v from state k on) ∧ (C(F ) tts k − 1)
we can then write (7.32) and the condition obtained from it by interchanging
c and d as:(7.33) |= C(M d )+v ∧ C(M lc ) ⇒ C(M c )|= C(M c )+v ∧ C(M ld ) ⇒ C(M d )From (7.33), we can infer:(7.34) |= C(M lc ) ∧ C(M ld ) ⇒ C(M c ) ∧ C(M d )The theorems to be stated require a slightly weaker definition of F+v , whicholdmakes the conditions (7.33) stronger (so they still imply (7.34)). Let F+v
be the formula that we have been calling F+v . We now define F+v to equalold ∨ F . With this definition, (7.33) implies its two conditions also holdF+vwith the “+v ” removed. If F is a safety property, then F v is a safety
old usually isn’t. In fact, if F is a safety property then F
property but F+v+v
oldequals C(F+v ). In practice, the change should seldom make a difference in(7.34) because we don’t expect liveness properties to be useful for proving
safety properties, so we wouldn’t expect F ∧ G ⇒ H to be true for safety
properties G and H without C(F ) ∧ G ⇒ H also being true.
The formula F+v has been defined semantically. However, to verify (7.33)
directly, we have to write C(F )+v as a formula for a given formula F . It’s

CHAPTER 7. LOOSE ENDS

257

easy to write C(F ) if F has the usual form Init ∧ 2[Next]w ∧ L , where w is
the tuple of variables in the formulas and L is the conjunction of fairness
properties of subactions of Next. In that case, the definition of machineclosure (Section 4.2.2.2) and Theorem 4.7 (Section 4.2.7) imply C(F ) equals
Init ∧ 2[Next]w . We can then write F+v as follows:∆d ∧ [Next]dF+v = ∃ h : Initw ◦v ◦hh idwhere Init∆

= (Init ∧ (h = 0)) ∨ (h = 1)∆d = ∨ (h = 0) ∧ ∨ (h 0 = 0) ∧ [Next]w
Next∨ h0 = 1∨ (h = 1) ∧ (h 0 = h) ∧ (v 0 = v )While writing F+v is easy enough, we usually don’t have to for the same
reason that we didn’t have to use the +v subscripts in (7.27). Our example
has one feature that we didn’t use in our generalization—namely, that no
single program step can make both M c and M d false. Here’s how to use thatfeature in general. For safety properties F and G, define F ⊥ G to be true ofa behavior σ iff for every k ∈ N, if F ∧ G is true of σ(0) → . . . → σ(k ) thenF ∨ G is true of σ(0) → . . . → σ(k + 1). Understanding why the following
theorem is true is a good test that you understand the definition of F+v .
Theorem 7.6 If F , G, and H are safety properties, v is a tuple of variables
containing all variables of F , and |= H ⇒ (F ⊥ G), then |= F ∧ H ⇒ G
implies |= F+v ∧ H ⇒ G.
For our example, in which M c and M d are safety properties, |= C(M lc ) ⇒(M c ⊥ M d ) and |= C(M ld ) ⇒ (M c ⊥ M d ) are true and allow us to remove +v from the conditions (7.33). These properties are true because theexample satisfies these two conditions:• We can express correctness of the program as M c ∧ M d , where only
a step of component c can violate M c and only a step of component
d can violate M d . This seems to be a requirement for decomposing
verification of the program into verification of its components to makesense. For example, mutual exclusion can’t be expressed as the conjunction of invariance properties that can each be violated by only one
process. I therefore expect that attempting to decompose verificationof a mutual exclusion algorithm in this way would complicate the task.
• No step is both a c step and a d step. This condition means that a stepin a behavior of the program consists of a step of a single component.

CHAPTER 7. LOOSE ENDS

258

It is the case if the components are processes in a program written in
the kind of pseudocode we have been using, which is modeled after
the most popular coding languages. I believe that all the engineers
I have worked with find this to be the most natural way to describe
concurrent programs.
We have obtained the assumptions we need to deduce (7.34). But wewant to verify (7.27), which is (7.34) with the C operators removed. Since F
implies C(F ) for any property F , we can remove the Cs from the left-handside of the implication (7.34). But we need additional assumptions to beable to infer that M lc ∧ M ld implies the liveness parts of M c and M d . Since
we know that M lc ∧ M ld implies C(M c ) ∧ C(M d ), we can use the following
assumptions to deduce (7.27).
(7.35) |= C(M d ) ∧ M lc ⇒ M c

and|= C(M c ) ∧ M ld ⇒ M d

Condition (7.33) allows us to assume that other components satisfy theirsafety conditions when showing that a component satisfies its safety condition. However, (7.35) allows us to use the liveness property of only thatcomponent when showing that the component satisfies its liveness requirement. It would be circular reasoning to assume M d when verifying M c andassume M c when verifying M d . However, we can do it for one of the components. For example, if we show that C(M c )∧M ld implies M d , we can thenassume M d when showing that M lc implies M c . We can therefore replaceC(M d ) by M d in (7.35), since C(M d ) ∧ M d equals M d . (But we then can’t
also replace C(M c ) by M c .)For any decomposition of a program into two components M lc and M ld
with correctness properties M c and M d , we have deduced (7.27) from (7.33)
and (7.35). The following theorem, which is Theorem 1 of [2], generalizes
this to a program with n components M li , each with correctness property
M i . The theorem is first stated, then explained.
Theorem 7.7 (Decomposition Theorem) If for all i ∈ 1 . . n:
1. |= ∀ j ∈ 1 . . n : C(M j ) ⇒ E i
2. (a) |= C(E i )+v ∧ C(M li ) ⇒ C(M i )(b) |= E i ∧ M li ∧ (∀ j ∈ 1 . . (i − 1) : M j ) ⇒ M ithen |= (∀ i ∈ 1 . . n : M li ) ⇒ (∀ i ∈ 1 . . n : M i )CHAPTER 7. LOOSE ENDS259

The theorem’s conclusion is the obvious generalization of (7.27). There are
two hypotheses for each component i . Let’s first ignore hypothesis 1 andtake E i to be the conjunction of all the C(M j ) for j 6= i . Hypothesis 2(a) forcomponent M li then generalizes the first condition of (7.33) for component
M lc , replacing the correctness condition C(M d ) of the other component withthe conjunction C(M j ) of all the other components. Hypothesis 2(b) makes
the similar generalization of (7.35), where allowing the use of all M j withj < i in the proof of M i generalizes the observation we made about being
able to weaken one of the conditions of (7.35). Hypothesis 1 generalizes
what we did for two components in two ways:• It allows E i to be the conjunction of all formulas C(M j ), including
j = i . This can obviously be done for hypothesis 2(b). It might seemto turn hypothesis 2(a) into a tautology by conjoining the right-handside C(M i ) of the implication to the left-hand side, resulting in circularreasoning. However, the subscript +v turns it from circular reasoning
into induction on the number of steps in a finite behavior.
• Instead of using the conjunction of the closures of all the components’correctness properties in hypothesis 2, it allows E i to be any property
implied by that conjunction that is strong enough to satisfy hypothesis 2. I expect E i will always be a safety property, but it’s conceivablethat it might not be.
The theorem does not make any assumption about v . That’s because if w
is the tuple of all variables appearing in the formulas (including in v ), thenF+w implies F+v . Thus, if hypothesis 2(a) is satisfied for any state functionv , then it’s satisfied with v equal to the tuple of all variables in the formulas.
Letting v equal that tuple produces the weakest (hence easiest to satisfy)
hypothesis.

7.2.2

Composing Components

In Section 7.2.1, we decomposed a given program as the conjunction ofcomponents. We now assume we are given a collection of components anddefine the program to be the conjunction of those components. As a tiny
example, assume we want to write a program that satisfies the property2(c = 0) ∧ 2(d = 0), and we want to do it by conjoining a c component
that implements 2(c = 0) and a d component that implements 2(d = 0).
We find that someone has written a program M lx that satisfies 2(x = 0)

CHAPTER 7. LOOSE ENDS

260

when run in an environment that satisfies 2(y = 0). So, we decide to write
our program as M lc ∧ M ld where:∆

M lc = (M lx with x ← c, y ← d )∆M ld = (M lx with x ← d , y ← c)
This silly example captures the most important aspect of specifying components: No real device will satisfy a specification such as 2(c = 0) when
executed in an arbitrary environment. For example, a process will not beable to compute the GCD of two numbers if other processes can at any timearbitrarily change the values of its variables.
We want to deduce that M lc ∧ M ld implies 2(c = 0) ∧ 2(d = 0)
from the properties that components c and d satisfy, without knowing
what M lc and M ld are. The property that the c component satisfies isthat if its environment satisfies 2(d = 0) then the component satisfies
2(c = 0); and d satisfies the same condition with d and c interchanged.
The obvious way to express these two properties is 2(d = 0) ⇒ 2(c = 0)
and 2(c = 0) ⇒ 2(d = 0), but those two properties obviously don’t imply
2(c = 0) ∧ 2(d = 0). We need to find the right way to express mathematically the condition that a component satisfies the property M if its environment satisfies the property E . We do this by assuming that the condition is++expressed by a formula E −.
M and figuring out what the definition of −.
should be, given the assumption that the definition should make this true:++(7.36) |= 2(d = 0) −.
2(c = 0) and |= 2(c = 0) −.
2(d = 0)implies |= 2(c = 0) ∧ 2(d = 0)

We first ask when we can deduce this:+(7.37) |= E 1 −.
M1

and

+
|= E 2 −.
M2implies|= M 1 ∧ M 2

The answer lies in Theorem 7.7. Since (7.37) doesn’t mention the programs
M l1 and M l2 , it should be true if we let those programs equal true. Substituting true for them, the conclusion of Theorem 7.7 for n = 2 is M 1 ∧ M 2 .
++We define −.
so that hypotheses 2(a) and 2(b) are equivalent to E i −.
M i.
The definition is:
∆

+
E −.
M = (C(E )+v ⇒ C(M )) ∧ (E ⇒ M )where v is the tuple of all variables in E and M . The theorem then implies
that (7.37) is true if hypothesis 1 is satisfied, that hypothesis asserting:(7.38) |= C(M 1 ) ∧ C(M 2 ) ⇒ E 1

and|= C(M 1 ) ∧ C(M 2 ) ⇒ E 2

CHAPTER 7. LOOSE ENDS

261

These conditions are true for our example, so (7.36) is true.
The conclusion of Theorem 7.7 is |= M 1 ∧ M 2 , which asserts that thecomposition of the components satisfies M 1 and M 2 assuming nothing about
its environment. We need a more general theorem whose conclusion is+|= E −.
M 1 ∧ M 2 , asserting that the composition satisfies M 1 ∧M 2 if its environment satisfies E . There is actually a stronger result, asserting that the+composition satisfies |= E −.
M for any property M implied by E ∧M 1 ∧M 2 .
Here is the theorem, generalized from two to n components. It is Theorem 3of [2].
Theorem 7.8 (Composition Theorem) If
1. |= ∀ i ∈ 1 . . n : C(E ) ∧ (∀ j ∈ 1 . . n : C(M j )) ⇒ E i
2. (a) |= C(E )+v ∧ (∀ j ∈ 1 . . n : C(M j )) ⇒ C(M )(b) |= E ∧ (∀ j ∈ 1 . . n : M j ) ⇒ M++
then |= (∀ j ∈ 1 . . n : E j −.
M j ) ⇒ (E −.
M)

It’s instructive to compare Theorems 7.7 and 7.8. They both make noassumption about v , since letting it equal the tuple of all variables in theformulas yields the weakest hypothesis 2(a). Hypothesis 1 differs only in
Theorem 7.8 having the additional conjunct C(E ). This conjunct (which
weakens the hypothesis) is expected because, if M is the conjunction of theM i , then the M in the conclusion of Theorem 7.7 is replaced in Theorem 7.8+
by E −.
M.
As we observed for Theorem 7.7, hypothesis 1 of Theorem 7.8 prettymuch requires the E i to be safety properties. However, when applying Theorem 7.8, we can choose to make them safety properties by moving the
liveness property of E i into the liveness property of M i . More precisely,
suppose we write E i as E Si ∧ E Li , where E Si is a safety property and E Li
a liveness property such that hE Si , E Li i is machine closed; and we similarly write M i as M Si ∧ M Li . We can then replace E i by E Si and M i by+
M Si ∧ (E Li ⇒ M Li ).5 This replaces the property E i −.
M i by the stronger
property:+(7.39) E Si −.
(M Si ∧ (E Li ⇒ M Li ))It is stronger because if the environment doesn’t satisfy its liveness property+
E Li , then E i −.
M i is satisfied no matter what the component does; but in5
By definition of machine closure, hMiS , MiL i machine closed implies hMiS , EiL ⇒ MiL i
is also machine closed, because MiL implies EiL ⇒ MiL .

CHAPTER 7. LOOSE ENDS

262

that case, (7.39) still requires the component to satisfy its safety property
M Si if the environment satisfies its safety property E Si . The two formulas
should be equivalent in practice because machine closure of hE Si , E Li i implies
that, as long as the environment satisfies its safety property, the component
can’t know that the environment’s entire infinite behavior will violate its
liveness property.
Theorem 7.8 has been explained in terms of M i being the property satisfied by a component whose description M li we don’t know, with M aproperty we want the composition of the components to satisfy. It can also
be applied by letting M i be the actual component M li and letting M be
the composition ∀ i ∈ 1 . . n : M li of those components. The theorem thentells us under what environment assumption E the composition will behave
properly if each M li behaves properly under the environment assumption
E i . However, there is a problem when using it in this way. To explain
the problem, we return to our two components c and d whose composition
satisfies 2(c = 0) ∧ 2(d = 0).
The definitions M lc and M ld in (7.29) were written for components c andd intended to be composed with one another. They were not written to describe a component that satisfies its desired property only if the environment
satisfies its property. We now want to define them and their environment
assumptions E c and E d so that:+|= (E c −.
M lc ) ⇒ 2(c = 0)+|= (E d −.
M ld ) ⇒ 2(d = 0)

The definition of M lc asserts that the value of d cannot change when thevalue of c changes (because of the conjunct d 0 = d in the next-state relation)and d cannot change when c doesn’t change (because of the subscript hc, d i).
That’s a property of its environment. If we want d to satisfy that property,
we should state it in E c , not inside the definition of M lc . So, the definitionof M lc should be
M lc = (c = 0) ∧ 2[c 0 = d ]c ∧ WFc (c 0 = d )∆and the definition of M ld should be similarly changed.
If you recall how we decomposed programs in Section 7.2.1.1, expressedin Theorem 7.5, you will realize that the conjuncts d 0 = d and c 0 = c in theoriginal definitions of M lc and M ld were there so that the next-state action of
the conjunction of M lc and M ld would be the disjunction of their next-stateCHAPTER 7. LOOSE ENDS

263

actions. With these new definitions, the next-state action of M lc ∧M ld equals[ ∨ (c 0 = d ) ∧ (d 0 = d )∨ (d 0 = c) ∧ (c 0 = c)
∨ (c 0 = d ) ∧ (d 0 = c) ]hc,d i
The additional disjunct (c 0 = d )∧(d 0 = c) describes a step that is performed
jointly by the two components. If we want the composition of the two components to allow such steps, then there is no problem. However, components
are often processes, and in all the examples we’ve considered, each step isa step of exactly one process. Program descriptions in which each step isperformed by a single component are called interleaving descriptions.6
Suppose we want to consider only interleaving program descriptions. We
would take the approach used in Theorem 7.5 that for each i , there is a listm i of variables that can be modified only by component M li . It would benice to let E i assert that any step that changes a variable other than one ofthe variables of m i must leave all the variables of m i unchanged. However,this is impossible because there are infinitely many variables other than theones in m i , and a formula E i can mention only finitely many of them.
Instead, we modify Theorem 7.8 so its conclusion is:++(7.40) |= G ∧ (∀ j ∈ 1 . . n : E j −.
M j ) ⇒ (E −.
G ∧ M)

for a property G. We can then apply the theorem with M i equal to M li , M
equal to ∀ i ∈ 1 . . n : M li , and G the property asserting that if i 6= j , then astep can’t change both hm i i and hm j i. Formula G ∧ M is the interleaving
description that is presumably what we intended the composition of thecomponents M li to mean.
In the same way as we could generalize Theorem 7.5, we can replacehm j i0 = hm j i in the definition of G by a step predicate ν j and have G
assert that every step must satisfy ν i ∨ ν j for i 6= j .
You can write the theorem whose conclusion is (7.40) by yourself. All you
have to do is apply Theorem 7.8 substituting n + 1 for n, letting E n+1 equal
true, letting M n+1 equal G, and replacing M with G ∧ M . The hypothesesof Theorem 7.8 after making these substitutions are the hypotheses of thetheorem.

6

An interleaving description is often taken to mean any description of a program’s
executions as sequences of states and/or events, so by that meaning all TLA program
descriptions are interleaving descriptions.

Appendix A

Miscellany
A.1

Ordinary Math Summary

This is a summary of all the ordinary math introduced in the main textof the book. Each subsection indicates in [square brackets] the sections
where the operators it describes were introduced. Section A.1.5 introduces
an operator not described earlier that is used in the appendix.

A.1.1

Arithmetic [Math I]

Ordinary Operators +, −, ∗ (multiplication), / (real-number division),>, ≥, <, ≤ .
The Operator % For integers m and n, if n > 0 then m % n is the uniqueinteger r satisfying 0 ≤ r < n and m = d ∗ n + r , for some integer d .

A.1.2

Propositional Logic [Sections 2.4 and 2.9.2]

Booleans true and false
Operators For any Boolean values A and B :¬A

Equals true iff A equals false .

A∧B

Equals true iff both A and B equal true .

A∨B

Equals true iff A or B or both equal true .

A⇒B

Equals false iff A equals true and B Equals false .

A≡B

Equals true iff A equals B .

264

APPENDIX A. MISCELLANY

265

Conjunction/Disjunction Lists An aligned list of formulas A1 , . . . , An“bulleted” by ∧ like this:
∧ A1
..
.
∧ An
equals (A1 ) ∧ . . . ∧ (An ). The analogous notation is also used for ∨ .

A.1.3

Predicate Logic [Section 2.7, Math IX]∀v :F

Equals true iff F equals true for all values of the variable v .

∃v :FEquals true iff F equals true for some value of the variable v .

∀v ∈ S :F

Equals ∀ v : (v ∈ S ) ⇒ F .

∃v ∈ S :F

Equals ∃ v : (v ∈ S ) ∧ F .

|= F

A metaformula that is true iff formula F is true for any
assignment of values to its variables.

∃ Introduction Rule |= (F with v ← exp) ⇒ (∃ v : F )∃ Elimination Rule

A.1.4|= F ⇒ G

implies|= (∃ v : F ) ⇒ (∃ v : G)

Sets [Section 2.5, Math II, Math V, Math VI, Math XI]v ∈ S Equals true iff v is an element of the set S .
{exp1 , . . . , expn } The set for which v ∈ S equals true iff v equals one (ormore) of the expressions exp i .
Sets of Numbers
R

The set of all real numbers.

I

The set of all integers.

N

The set of all non-negative integers (natural numbers).

m . . n The set of all integers i satisfying m ≤ i ≤ n.
#(S ) The number of elements in S , if S is a finite set.
S ⊆ T Equals true iff every element of set S is an element of set T .
S ∩ T The set of all elements in both S and T .
S ∪ T The set of all elements in S or T or both.

APPENDIX A. MISCELLANY

266

S \ T The set of all elements in S that are not elements of T .
{v ∈ S : F } The set of all values of the variable v for which (v ∈ S ) ∧ F
equals true .
{exp : v ∈ S } The set of all values of exp obtained by substituting an element of S for v .
Countable Set A set S is countable iff there is a mapping M such that
this formula equals true: ∀ s ∈ S : ∃ n ∈ N : M (n) = s .

A.1.5

The choose Operator

Mathematicians often define something in terms of its properties. For ex√
ample, they might define r for a real number r to be the non-negative√ 2
real number such that ( r ) = r . We can express such a definition using
an operator invented by the mathematician David Hilbert in the 1920s. I
didn’t learn about this operator until some 25 years after I completed mystudies; I suspect it’s still unknown to most mathematicians. Hilbert calledit ε , but I think it’s better to call it choose. We can use this operator todefine the square root as follows:√ ∆r = choose s ∈ R : (s ≥ 0) ∧ (s 2 = r )The choose operator is much like ∃ in that choose v ∈ S : F is defined toequal choose v : (v ∈ S ) ∧ F , where the scope of the bound variable v does
not include S . The expression choose v : F is defined to equal a value ethat makes F true when e is substituted for v . If there is no such e, thenthe value of the expression is unspecified. If there is more than one suchvalue e, then the expression can equal any one of those values. For example,
define the mapping ASqrt by:∆

ASqrt(r ) = choose s ∈ R : s 2 = r
Then ASqrt(4) might equal 2 and ASqrt(9) might equal −3. Since this is
math, |= ASqrt(4) = ASqrt(4) is true. The value of ASqrt(4) may be 2 or
−2. But whichever value it equals, like every mathematical expression withno free variable, it always equals the same value.
Formally, choose is defined by the following rules:(A.1) (a) |= (∃ v : F ) ⇒ (F with v ← (choose v : F ))(b) |= (∀ v : F ≡ G) ⇒ ((choose v : F ) = (choose v : G))APPENDIX A. MISCELLANY

267

If there is more than one value of x for which F equals true, thenchoose x : F can equal any of those values. But it always equals the samevalue.
No matter how often I repeat that the choose operator always chooses
the same value, there are engineers who think that choose is nondeterministic, possibly choosing a different value each time it’s evaluated; andthey try to use it to describe nondeterminism in a program. I’ve also heard
computer scientists talk about “nondeterministic functions”.1 There’s nosuch thing. There’s no nondeterminism in mathematics. Nondeterminism
is important in concurrent programs, and Section 3.3 show’s that it’s easy
to describe mathematically. Adding nondeterminism to math for describing
nondeterminism in a program makes as much sense as adding water to mathfor describing fluid dynamics.
An expression choose v : F is most often used when there is only a√single choice of v that makes F true, as in the definition of r above.
Sometimes, it appears within an expression whose value doesn’t depend on
which value of v satisfying F is chosen.

A.1.6

Functions [Section 2.8.2, Math II]

A function f is a mapping that is a value such that f (e) is defined only on
its domain, which is a set.
domain(f ) The domain of f , if f is a function.
v ∈ S 7→ exp The function f with domain S such that f (v ) = exp for all
values of the variable v in the set S .
D → S The set of all functions f with domain D such that ∀ v ∈ D : f (v ) ∈ S
equals true .
f except exp1 7→ exp2 If f is a function, this equals the function:v ∈ domain(f ) 7→ if v = exp 1 then exp 2 else f (v )A.1.7

Sequences [Section 2.8.3, Math VII]A finite ordinal sequence σ of length n, also called an n-tuple, is a function
σ with domain 1 . . n. We can write such a function σ as hσ(1), . . . , σ(n)i .
An infinite ordinal sequence is a function with domain the set of all positive
integers.
1

I must confess that, many years ago, I used that term in a paper [28].

APPENDIX A. MISCELLANY

268

A finite cardinal sequence σ of length n is a function σ with domain
0 . . (n − 1). We can write such a function σ as σ(1) → . . . → σ(n − 1) , if
n > 0. An infinite cardinal sequence is a function with domain the set N of
all natural numbers.
Except for Append , all the following operators that take sequences asarguments are defined for both ordinal and cardinal sequences.
Len(σ) The length of the sequence σ.
σ ◦ τ The concatenation of the finite sequence σ and the finite or infinite
sequence τ , where the sequences are both ordinal or both cardinal.
Head (σ) The first element (σ(1) or σ(0)) of the nonempty (positive-length)
sequence σ.
Tail (σ) The sequence obtained by removing the first element of the nonempty
sequence σ.
Append (σ, exp) The sequence σ ◦ hexp i for an ordinal sequence σ.
Seq(S ) The set of all ordinal sequences σ such that σ(i ) ∈ S for all i ∈domain(σ).
S1 × . . . × Sn The set of all n-tuples σ such that σ(i ) ∈ S i for all i in 1 . . n,
for any integer n > 1.

A.1.8

Notation [Section 2.9.1, Chapter 5 introduction]

if P then exp1 else exp2
Equals exp 1 if P equals true and exp 2 if P equals false .
E with v1 ← exp1 , . . . , vm ← expm
The expression obtained by simultaneously substituting every expression exp i for the variable v i in expression E .

A.1.9

Recursive Definitions [Math IV, Math XI]

Recursive function definitions are defined using the choose operator introduced in Section A.1.5 above. For example, the recursive definition of thefactorial function ! in Math IV is an abbreviation for∆! = choose f :f = (n ∈ N 7→ if n = 0 then 1 else n ∗ f (n − 1))

APPENDIX A. MISCELLANY

269

In general, any recursive definition with no definition parameters can be
expressed this way in terms of choose. Such a definition has the form∆g = M (g) for some mapping M . This definition is an abbreviation for∆g = choose f : f = M (f )The rule (A.1a) implies |= (∃ f : M (f )) ⇒ (g = M (g)) .
Sometimes we want to write a recursive definition of a mapping thattakes an argument and isn’t a function. For example here is a definitionof the operator #, where #(S ) is defined in Math II to equal the numberof elements in S , for any finite set S . This operator can’t be a function
because its domain would have to be the collection of all finite sets, which is
too big to be a set. (The one-to-one correspondence S ↔ {S } implies thatthe collection of finite sets is as big as the collection of all sets.) However,it’s intuitively clear that the following recursive definition of # defines #(S )for any finite set S :∆#(S ) = if S = {} then 0
else 1 + #(S \ {choose e : e ∈ S })In general, a recursive definition of a mapping M has the form:∆(A.2) M (v ) = Def (v , M )where Def is called a higher-order mapping because it takes a mapping as
its second argument. Allowing recursive definitions of mappings in ZF without introducing logical inconsistency is tricky. A method of doing this bytranslating a recursive definition to a non-recursive one was apparently firstgiven in this century [16]. That work essentially showed that for any value
v such that the recursive computation of M (v ) defined by (A.2) terminates,
M (v ) equals Def (v , M ).

A.2

Structured Proofs

To understand structured proofs, we need to understand what a completely
rigorous proof would be. We therefore pretend that our proofs appear in acompletely rigorous book of ordinary math, written for a reader who knows
ZF. The book consists of a sequence of global definitions, theorems, and theproofs of some of the theorems. (Theorems without proofs are axioms.) A
proof is either a terminal proof (corresponding to a paragraph proof in an
informal proof) or a sequence of proof steps, each with a proof. Mathglish

APPENDIX A. MISCELLANY

270

can appear only in comments, which would not be needed by sufficiently
brilliant mathematicians (or computers).
A context consists of a collection of definitions, formulas that can beassumed to be true, and variable declarations. Every definition, theorem,
proof, and proof step occurs in a context. The context of a global definition
or a theorem consists of all previous global definitions and theorems. A
proof step and a proof also have associated with it a formula called its
current goal. The contexts and current goals of proofs and proof steps aredescribed below. We state here only that the context and current goal of
the first step of a proof are the same as for the proof.
The statement of a theorem or proof step asserts a formula. That formula should be provable using the formulas and definitions of the context ofthe theorem or step. A theorem’s context contains no declarations, so theformula it asserts can have no free variables.2 (The assertion of a theorem
stated informally with free variables is stated formally with those variables
universally quantified with ∀ .)The statement of a theorem and of most proof steps has the form
(A.3) Assume: F 1 , . . . , F n
Prove: G
where G is a formula called the statement’s goal and each F i is an assumption that is either a formula or a new declaration. (When n = 0, so there
is no assumption, the statement is written simply as G.) If there is no new
declaration, statement (A.3) asserts the formula(A.4) F 1 ∧ . . . ∧ F n ⇒ G.
By propositional logic, (P ∧ Q) ⇒ R is equivalent to P ⇒ (Q ⇒ R), so (A.4)
is equivalent to:(A.5) F 1 ⇒ (F 2 ⇒ ( . . . ⇒ (F n ⇒ G ) . . . ))A new declaration has the form new v ∈ S for a variable v and an expression S . For every such new assumption F i in (A.3), the “F i ⇒” in (A.5)
is replaced by “ ∀ v ∈ S :”. For example, the statement
Assume: P , new v ∈ S , Q
Prove: G
2Here, variable means a variable of ordinary math, which is a constant of temporal
logic. In a temporal logic book, (program) variables would be declared and could appear
free in a theorem.

APPENDIX A. MISCELLANY

271

asserts the formula P ⇒ (∀ v ∈ S : (Q ⇒ G)) . The scope of the bound variable v is the assumption Q and the goal G; it does not include P or S . The
Safe Scoping Rule implies that no variable named v is declared in the context
of the theorem or step.
The context of the proof of (A.3) contains everything in the context ofthat statement, plus the additional formulas assumed to be true consistingof all the assumptions F i that are formulas and all the assumptions v ∈ Sfrom assumptions new v ∈ S , plus declarations of all the variables introduced by new assumptions. The scope of such a declaration consists of all
subsequent assumptions in the Assume clause, the goal G, and the proof ofthe statement. The current goal of the proof of (A.3) is G.
If (A.3) is a proof step, then the context of the next proof step (if there
is one) contains everything in that step plus the formula (A.5) assertedby (A.3).
There are two abbreviations for a step of the form (A.3). The statementcase P is an abbreviation for P ⇒ G (an Assume/Prove statement withno assumptions), where G is the step’s current goal. The other abbreviationis Q.E.D., which must be the statement of the last step of a proof. It is anabbreviation for the formula that is the step’s current goal.
A definition step makes one or more definitions that are local to thecurrent proof. It consists of Define followed by one or more definitions.
Such a step has no proof. The context of the next step is the same as thedefinition step’s context with those definitions added to it. The goal of thenext step is the same as that of the definition step.
The only other kind of step is a suffices step whose statement is:(A.6) Suffices: Assume: F 1 , . . . , F n
Prove: G(If there are no assumptions F i , then the “Assume:” and “Prove:” areomitted.) Suppose that the current goal of this statement is H . Statement(A.6) asserts that to prove H , it suffices to prove G under the additional
assumptions F 1 , . . . F n . In other words, the statement asserts the formulaA ⇒ H where A is the assertion made by the Assume/Prove. The context
of the proof of (A.6) is the same as for the statement:
Assume: A Prove: H
The context of the following step consists of the context of the Suffices
step with the added assumptions F i . This means that F i is assumed true
if it is a formula, and if it is new v ∈ S then the context contains the

APPENDIX A. MISCELLANY

272

declaration of v and the assumption that v ∈ S is true. The current goal of
the following step is G.
Finally, there is a terminal proof. It specifies which formulas and definitions in the proof’s context are used to prove its current goal. A formulain the context that comes from a previous theorem or step is identified by
its name. Steps are named like sections in this book, so the 4th step of theproof of the 5th step of the proof of the 2nd step of a theorem is step 2.5.4.
(It can be abbreviated as h3i4, meaning it is step 4 of a depth-3 proof.) The
other formulas in a context come from Assume clause assumptions, and forour purpose there is no need to consider how they are identified. Definitions
are identified by the name of the defined symbol, so definition steps need nonumber.
Of course, this is not a completely formal book. Our proofs containmany formulas written in Mathglish, and the terminal proofs attempt to
explain why the current goal follows from the assertions and definitions in
the current context. But you should now understand what that context isand what the proof has to prove.

A.3

Why Not All Mappings Are Sets

Section 2.8.2 states that a function is a special kind of mapping that isassumed to be a value—meaning that it’s a set, although we don’t knowwhat its elements are. This raises the question of why we can’t simply
assume that all mappings are sets. The answer is provided by the following
theorem, whose proof is due to Stephan Merz. It asserts that there has to bea mapping that is not a set. Although we could assume that some mappings
other than functions are sets, the theorem means that we can’t assume all
mappings are sets. For simplicity, we let functions be the only mappingsthat we assume to be sets.
Theorem There exists a mapping that is not a set.
1. Suffices: Assume: Every mapping is a set.
Prove: false
Proof: Obvious.
Define M to be the mapping such that M (S ) = S if S is a set that is amapping.
2. M (S )(U ) = S (U ) for every mapping S and every set U .

APPENDIX A. MISCELLANY

273

Proof: Since we are assuming that every mapping S is a set, M is amapping on the collection of all mappings, and by definition M (S ) = S
for every mapping S , so M (S )(U ) = S (U ) for every set U .
Define Russell to be the mapping on the collection of all sets that are∆
mappings such that Russell (S ) = choose U : U 6= M (S )(S ).
3. Russell is a mapping such that Russell (S ) 6= M (S )(S ) for all sets S thatare mappings.
Proof: The value of any syntactically correct formula is a set, even if its
elements are unspecified. Therefore, M (S )(S ) is a set, and for any set T
there exists a set U such that U 6= T . Thus, Russell is a mapping suchthat Russell (S ) 6= M (S )(S ) for every mapping S .
4. Russell (S ) 6= S (S ) for all sets S that are mappings.
Proof: Substituting S for U in step 2 shows S (S ) equals M (S )(S ), whichby step 3 is unequal to Russell (S ).
5. Q.E.D.
Proof: Since Russell is a mapping, and all mappings are assumed to
be sets, substituting Russell for S in step 4 proves Russell (Russell ) 6=
Russell (Russell ), which equals false.

A.4

How Not to Write x 000

Here is an amusing paradox. It’s illegal to prime a primed expression, so it’s
illegal to write x 00 or x 000 if x is a variable. However, consider this definition:∆(A.7) F (n) = if n = 0 then x else F (n − 1)0
It apparently defines F (3) to equal x 000 . It doesn’t. To see why not, let’s
simplify things by defining F to be a function with domain N:∆

F = choose f : f = (n ∈ N 7→ if n = 0 then x else f (n − 1)0 )In this definition f and n are bound constants, so f (n − 1) is a constant
expression; and exp 0 = exp for any constant expression exp. Therefore, thisdefinition of F is equivalent to∆

F = choose f : f = (n ∈ N 7→ if n = 0 then x else f (n − 1))which defines f (n) to equal x for all n ∈ N.

APPENDIX A. MISCELLANY

274

If we defined F as a mapping by (A.7), using the meaning of thatdefinition described in [16], we would see that F (n) equals an expression(choose f : . . . ) (n) where the primed expression in “. . . ” is a constant.
Again, we would obtain F (n) = x for all n ∈ N.
This example illustrates why we should not write a recursive definition that contains an expression that isn’t a constant or a state expression.
There’s no problem applying a recursively defined mapping to a step expression. It should also be all right to apply one to a temporal logic formula,though I can’t imagine why we would want to do that. Recursively defined
mappings are used to define the meaning of temporal logic operators, but
those are mappings of ordinary math whose definitions contain no primes
or temporal operators.

A.5

Hoare Logic

Hoare logic is a science of traditional programs developed by C. A. R. (Tony)
Hoare [21]. Programs are described in a coding language, and the logic’s
goal is to prove properties of concrete programs. However, Hoare intended it
also to be applied to abstract programs written in code and used in verifying
a concrete program.
In Hoare logic, a program is viewed as a relation between the initial
and the final states of its execution. A formula of the logic has the form
{P }S {Q}, where S is a program (written in code) and P and Q are statepredicates. This formula asserts that if program S is executed starting in astate in which P is true and the execution terminates, then Q is true in the
final state of the execution. The formula {P }S {Q} is called a Hoare triple,
P is called its precondition, and Q is called its postcondition. Hoare logic
provides a way of showing that a program S satisfies a Hoare triple.
The following is the Hoare logic rule for a program consisting of thesingle assignment statement x : = exp, where x is a variable and exp is anexpression:(A.8) |= (P with x ← exp) ⇒ Q implies {P } x : = exp {Q}
There are also rules for deriving a Hoare triple for a program from Hoare
triples of its components. Here are three such rules:(A.9) {P }S {R} and {R}T {Q} imply {P } S ;T {Q}(A.10) {P ∧ R}S {Q} and {P ∧ ¬R}T {Q} imply{P } if R then S else T end if {Q}APPENDIX A. MISCELLANY

275(A.11) |= P ⇒ I and {I ∧ R}S {I } and |= I ∧ ¬R ⇒ Q imply{P } while R do S end while {Q}Such rules decompose the proof of a Hoare triple for any program to proofs ofHoare triples for elementary statements of the language, such as assignment
statements.
It was quickly realized that pre- and postconditions are not adequate todescribe what a program should do. For example, suppose S is a program
to sort an array x of numbers. The obvious Hoare triple for it to satisfy has
a precondition asserting that x is an array of numbers and a postcondition
asserting that x is sorted. But this Hoare triple is true of a program that
simply sets all the elements of the array x to 0. A postcondition needs tobe able to state a relation between the final values of the variables and theirinitial values. Various ways were proposed for doing this, one of them being
to allow formulas P and Q to contain constants whose values are the samein the initial and final states. For example, the precondition for a sorting
program could assert that the constant x 0 equals x , and the postcondition
could assert that the elements of the array x are a sorted permutation of
the elements of x 0.
Viewing a program as a relation between initial and final states meansthat it can be described mathematically as a formula of the Logic of Actions.
If we represent the program S as an LA formula, then {P }S {Q} is theassertion |= P ∧ S ⇒ Q 0 ; and the Hoare logic rules follow from rules of LA.
For example, when programs are described in LA, S ; T is S · T , where “·” isthe action composition operator defined in Section 3.4.1.4. The Hoare Logicrule (A.9) is equivalent to this LA rule:|= P ∧ S ⇒ R 0 and |= R ∧ T ⇒ Q 0 imply |= P ∧ (S · T ) ⇒ Q 0
The program if R then S else T end if is represented by the LA formula(R∧S )∨(¬R∧T ), and rule (A.10) becomes the propositional-logic tautology:|= (P ∧ R ∧ S ⇒ Q 0 ) ∧ (P ∧ ¬R ∧ S ⇒ Q 0 ) ⇒(P ∧ ((R ∧ S ) ∨ (¬R ∧ S )) ⇒ Q 0 )Hoare’s rule (A.8) for assignment statements is obtained from LA by representing the statement x := exp as (x 0 = exp) ∧ ((v x̃ )0 = v x̃ ) , wherev x̃ is the tuple of all program variables other than x . It is valid because|= P ∧ (x 0 = exp) ∧ ((v x̃ )0 = v x̃ ) ⇒ Q 0 equals |= (P with x ← exp) ⇒ Q
if v x̃ is a tuple containing all variables other than x that appear in P or exp.

APPENDIX A. MISCELLANY

276

Rule (A.11) is a bit tricky because, when executed in a state in which R
equals false, the while statement leaves all variables unchanged. We canrepresent that while statement by((R ∧ S )+ ∧ ¬R 0 ) ∨ (¬R ∧ (v 0 = v ))where v is the tuple of all program variables and (. . .)+ is defined in Section 3.4.1.4. With this representation of the while statement, (A.11) canbe derived from the following rule of LA, where I is any state predicate andA any action:(A.12) |= I ∧ A ⇒ I 0 implies |= I ∧ A+ ⇒ I 0
The LA definition of a Hoare triple implies that the validity of rule (A.11)
is proved by the following theorem:
Theorem A.1 Assume: 1. |= P ⇒ I
2. |= I ∧ R ∧ S ⇒ I 0
3. |= I ∧ ¬R ⇒ Q
4. v is the tuple of all variables occurring in Q.
Prove: |= P ∧ ((R ∧ S )+ ∧ ¬R 0 ) ∨ (¬R ∧ (v 0 = v )) ⇒ Q 0
1. Suffices: Assume: P ∧ ((R ∧ S )+ ∧ ¬R 0 ) ∨ (¬R ∧ (v 0 = v ))Prove: Q 0
Proof: Because assumptions 1–3 have the form |= . . . , proving that they
imply a formula F ⇒ G proves that they imply |= (F ⇒ G), and F ⇒ G
is proved by assuming F and proving G.
2. Case: P ∧ (R ∧ S )+ ∧ ¬R 0
2.1. I ∧ (R ∧ S )+ ⇒ I 0
Proof: By assumption 2 and (A.12), with R ∧ S substituted for A.
2.2. P ∧ (R ∧ S )+ ⇒ I 0
Proof: By 2.1 and assumption 1.
2.3. I 0
Proof: By 2.2 and the step 2 case assumption
2.4. ¬R 0
Proof: By the step 2 case assumption
2.5. Q.E.D.
Proof: By 2.3, 2.4, and assumption 3 (since |= F implies |= F 0 for any
state predicate F ).

APPENDIX A. MISCELLANY

277

3. Case: P ∧ ¬R ∧ (v 0 = v )Proof: By assumptions 1 and 3, P ∧ ¬R implies Q, which by v 0 = v andassumption 4 implies Q 0 .
4. Q.E.D.
Proof: By the step 1 assumption, steps 2 and 3 cover all possibilities.

A.6

Another Way to Look at Safety and LivenessThis section provides a different view of safety and liveness based on viewing
behavior predicates as sets of behaviors. This view was first recognized byGordon Plotkin. I find that it helps me understand safety and liveness. To
understand it, we first need some more math.

A.6.1

Metric Spaces

A metric space M is a set with a distance function δ that assigns a nonnegative real number δ(p, q), called the distance between p and q, to allelements p and q of M . The function δ must satisfy these conditions for all
elements p, q, and r of M :M1. δ(p, q) = 0 iff p = q.
M2. δ(p, q) = δ(q, p)
M3. δ(p, q) ≤ δ(p, r ) + δ(r , q)
Do you see why these conditions imply δ(p, q) ≥ 0 for all p and q in M ?
The set R of real numbers is a metric space with δ(p, q) equal to |p − q|,
where |r | is the absolute value of the number r , defined by∆|r | = if r ≥ 0 then r else − r
An infinite plane, represented as in analytic geometry by the set R × R ofpairs ofp real numbers, is a metric space with δ(hx 1 , y 1 i, hx 2 , y 2 i) defined toequal (x 1 − x 2 )2 + (y 1 − y 2 )2 . I find that thinking of a metric space M as
the set of points in a plane is a good way to visualize the concepts presented
here.
b S ) from p ∈ M to a nonempty
For a metric space M , the distance δ(p,subset S of M is defined to be the largest number r such that r ≤ δ(p, q)

APPENDIX A. MISCELLANY

278

for all q ∈ S .3 For example, if S is the set of all points hx , y i in the planebbsuch that x < 3, then δ(h4,7i, S ) equals 1 because δ(h4,7i, S ) > 1 for all q
in S and there are elements q of S such that δ(h4, 7i, q) is arbitrarily close
to 1.
b S) = 0
For any metric spaces M and subset S of M , if p ∈ S then δ(p,bbecause condition M1 implies δ(p, p) = 0. In general, δ(p, S ) = 0 for p ∈ M
iff for every e > 0 there exists q ∈ S such that δ(p, q) < e.
The closure operation C on subsets of a metric space M is defined byb S ) = 0} of all elements M that are aletting C(S ) be the set {p ∈ M : δ(p,distance 0 from S . For example, if M is the plane, let OD and CD be theopen and closed disks of radius 1 centered at the origin, defined by:∆

OD = {p ∈ M : δ(p, h0, 0i) < 1}∆

CD = {p ∈ M : δ(p, h0, 0i) ≤ 1}
Both C(OD) and C(CD) equal CD.
Theorem A.2 For any subset S of a metric space, S ⊆ C(S ) and C(S ) =C(C(S )).
Proof: The definition of C and property M1 imply S ⊆ C(S ) for any set S ,which implies C(S ) ⊆ C(C(S )) for any S . Therefore, to show C(S ) = C(C(S )),it suffices to assume p ∈ C(C(S )) and show p ∈ C(S ). By definition of Cb we do this by assuming e > 0 and showing there exists q ∈ S withand δ,
δ(q, p) < e. Because p ∈ C(C(S )), there exists u ∈ C(S ) with δ(p, u) < e/2;
and u ∈ C(S ) implies there exists q ∈ S with δ(q, u) < e/2. By M2 and M3,
this implies δ(p, q) < e. End Proof
As you will have guessed by its name, the operator C on behavior predicatesis a special case of the closure operator C on metric spaces. But for now,
forget about behavior predicates and just think about metric spaces.
A set S that, like CD, equals its closure is said to be closed. The following
result shows that for any set S , its closure C(S ) is the smallest closed set
that contains S .
Theorem A.3 For any subsets S and T of a metric space, if T is a closed
set and S ⊆ T then C(S ) ⊆ T .
Proof: It follows from the definition of C that S ⊆ T implies C(S ) ⊆ C(T ),and the definition of a closed set implies T = C(T ). End Proof
3
To handle the uninteresting case of the empty set, we can define bδ (p, {}) to equal ∞,which is a value satisfying r < ∞ for all r ∈ R.

APPENDIX A. MISCELLANY

279

For any subset S of a metric space M , the boundary of S is defined to beb S ) = 0 and δ(p,b M \ S ) = 0. The boundary
the set of all p ∈ M with δ(p,of both disks OD and CD is {p ∈ M : δ(p, h0, 0i) = 1}, the circle of radius
1 centered at the origin. For any metric space M and S ⊆ M , any elementb S ) = 0 that is not in S must be in M \ S and therefore
p of M with δ(p,bmust satisfy δ(p, M \ S ) = 0. This shows that the closure of any set S is theunion of S and the boundary of S .
A subset S of a metric space M is said to be dense iff C(S ) = M . A
dense set is one that, for any element p of M , contains p or elements of M
arbitrarily close to p. As an example, let’s call a finite-digit real number one
that can be written in decimal notation with a finite number of digits—for
example, 123.5432. The set of all pairs of finite-digit numbers is dense in
the plane because any real number can be approximated arbitrarily closelywith a finite-digit number. Thus, for any pair of real numbers hx , y i andany e > 0, we can find a pair of finite-digit numbers hp, q i within a distancee of hx ,√y i by choosing p and q such that |x − p| and |y − q| are both lessthan e/ 2.
Theorem A.4 Any subset S of a metric space equals C(S ) ∩ D for a dense
set D.
Proof: Let M be the metric space and let D equal S ∪ (M \ C(S )). The set
D consists of all elements of M except those elements in the boundary of S
that are not in S . It follows from this that C(S ) ∩ D = S . Since elementsin the boundary of S are a distance 0 from S , which is a subset of D, they
are a distance 0 from D. Therefore all elements in M are a distance 0 fromD, so D is dense. End Proof
What we’re interested in is not the distance function δ, but the closure operator C. Imagine that the plane was an infinite sheet of rubber that wasthen stretched and shrunk unevenly in some way. Define the distance between two points on the original plane to be the distance between themafter the plane was deformed. For example, if the plane was stretchedto make everything twice as far apart in the y direction but the same
distance
apart in the x direction, then δ(hx 1 , y 1 i, hx 2 , y 2 i) would equalp(x 1 − x 2 )2 + (2 ∗ (y 1 − y 2 ))2 . As long as the stretching and shrinking iscontinuous, meaning that the rubber sheet is not torn, the boundary of aset S in the plane after it is deformed is the set obtained by deforming theboundary of S . This implies that the new distance function produces thesame closure operator as the ordinary distance function on the plane.

APPENDIX A. MISCELLANY

280

Topology is the study of properties of objects that depend only on a
closure operation, which need not be generated by a metric space. But weare interested in a closure operator that is generated by a particular kind of
metric space, and it helps me to think in terms of its distance function.

A.6.2

The Metric Space of Behaviors

Safey and liveness will be explained by viewing behaviors as elements of a
metric space. In particular, we will see that:• The operator C on behavior predicates corresponds to the closure operator C on sets of behaviors.
• Safety predicates correspond to closed sets of behaviors.
• Liveness predicates correspond to dense sets of behaviors.
Doing this poses two problems. The first is that mathematicians describe
metric spaces as sets, and the collection of all behaviors isn’t a set. I believethat all the results about metric spaces that we need would remain true
if metric spaces were arbitrary collections rather than sets, but I haven’t
checked this. So for the rest of this section, we assume that the collection of
all behaviors is a set, which we call B. For example, we can let a behavior
here mean an infinite sequence of states in which each variable satisfies some
type invariant. Since our purpose is an intuitive understanding of safety andliveness, there’s no need to be very rigorous.
The second problem is that we are relating properties, which are temporallogic formulas, to sets of behaviors. Recall that the meaning [[F ]] of a property F is a Boolean-valued mapping on behaviors. There’s a standard way ofidentifying predicates on a set with subsets of that set: we identify the predicate P with the subset consisting of all elements e such that P (e) equals
true. (This is the basis of Venn diagrams, which you have probably seen.)
We can therefore identify the property F with the subset F of B definedby:∆

F = {b ∈ B : [[F ]](b)}Under this identification, the propositional logic operators ∧, ∨, ⇒, and ≡correspond to the set-theoretic operators ∩, ∪, ⊆, and =. That is, for any
properties F and G :|= F ∨ G = (F ∪ G)|= F ⇒ G = (F ⊆ G)|= F ∧ G = (F ∩ G)|= F ≡ G = (F = G)APPENDIX A. MISCELLANY

281

We’re interested in the closure operator on sets of behaviors, which can be
the same for many different distance functions. The property of the distancefunction that provides the closure operator we want is that behaviors witha long prefix in common are close together. More precisely, for two different
behaviors σ and τ , define o(σ, τ ) to be the largest n such that σ and τ
have the same prefix of length n − 1—that is, the largest value n such that∀ i ∈ 0 . . (n − 1) : σ(i ) = τ (i ). Thus, o(σ, τ ) equals 1 iff σ(0) = τ (0) andσ(1) 6= τ (1). (There is no such n iff σ = τ , in which case we let o(σ, τ ) = ∞,where ∞ > i for all i ∈ N.) We get the right closure operator on sets of
behaviors if δ satisfies this property:
For any e > 0, there is an n ∈ N such that o(σ, τ ) > n implies
δ(σ, τ ) < e, for any behaviors σ and τ .
The simplest choice of δ satisfying this and the properties of a distance∆function for a metric space is δ(σ, τ ) = 1/(1 + o(σ, τ )) for σ 6= τ . (Ofcourse, δ(σ, τ ) = 0 if σ = τ .)With the correspondence between the operator C on behavior predicates
and the closure operator on this metric space, Theorems 4.3 and 4.4 of Section 4.1.3 are immediate consequences of Theorems A.2–A.4 of Section A.6.1.
I find it more elegant to deduce the results about behavior predicates fromthe corresponding results about metric spaces than to prove them directly.
But that might be because I was educated as a mathematician. Whichever
you prefer, I hope that having an alternative way of thinking about safety
and liveness helps you understand those concepts.

Appendix B

ProofsMost of the proofs here are structured proofs. To understand them, you
should first read Appendix Section A.2.

B.1

Invariance Proof of Increment

Figure 3.5 in Section 3.4.1.1 defines the initial predicate Init and next-state
action Next for the RTLA formula describing a program having the inductive
invariant Inv . As described in Section 3.4.1.3, to prove the invariance of Inv
we had to prove the two conditions of (3.10). As with most programs, theproof of the first condition is simple. Here, we describe the proof of thesecond condition, which is:
Theorem Next ∧ Inv ⇒ Inv 0
If the program were described in TLA instead of RTLA, the disjunct Stutter
would be removed from the definition of Next; and Next in the theorem
would be replaced by [Next]v , where v is the tuple hx , t, pc i of variables.
The proof of the theorem would be essentially the same, the only difference
being that the action Stutter would be replaced everywhere by its second
conjunct, which is v 0 = v .
The proof of the theorem is decomposed hierarchically. The first twolevels are determined by the logical structure of the theorem. There are twostandard ways to decompose the proof of a formula of the form F ⇒ G:
• Write F in the form F 1 ∨ . . . ∨ F m and prove F i ⇒ G for all i .
• Write G in the form G 1 ∧ . . . ∧ G n and prove F ⇒ G j for all j .

282

APPENDIX B. PROOFS

283

In this case, we can do both, proving F ⇒ G by proving F i ⇒ G j for all iand j , performing the two decompositions in either order. We can do the firstdecomposition by writing Next as a disjunction (since (P ∨ Q ∨ . . . ) ∧ Inv
equals (P ∧ Inv ) ∨ (Q ∧ Inv ) ∨ . . . ), and we can do the second decomposition
because Inv is defined to be the conjunction of three formulas. We do thefirst decomposition first.
Expanding the definitions of Next and PgmStep, using this rule of predicate logic:|= (∃ v ∈ S : F ∨ G) ≡ (∃ v ∈ S : F ) ∨ (∃ v ∈ S : G)
we see that Next is equivalent to:(∀ p ∈ Procs : aStep(p) ∧ Inv ) ∨ (∀ p ∈ Procs : bStep(p) ∧ Inv )∨ (Stutter ∧ Inv )Writing each ∀ assertion as an Assume/Prove, the top level of the proofis:
1. Assume: new p ∈ Procs, aStep(p), Inv
Prove: Inv 0
2. Assume: new p ∈ Procs, bStep(p), Inv
Prove: Inv 0
3. Assume: Stutter , Inv
Prove: Inv 0
Proof: By the definitions of Stutter , Inv , TypeOK , and NumberDone, since a stutter Stutter step leaves the three variables unchanged, which by definition of Inv implies that the value of Inv isunchanged.
4. Q.E.D.
Proof: By steps 1–3 and the definition of Next.
Steps 3 and 4 are simple enough that there is no need to decompose their
proofs. You should try to understand why these steps, and the others whose
proofs are given here, follow from the facts and definitions mentioned intheir proofs. To help you, a little bit of explanation has been added to someof the proofs.
We now have to prove steps 1 and 2. They can both be decomposed using
the definition of Inv as a conjunction. We consider the proof of step 1. Hereis the first level of its decomposition.

APPENDIX B. PROOFS

284

1.1. TypeOK 0
1.2. ∀ i ∈ Procs : (pc 0 (i ) = b) ⇒ (t 0 (i ) ≤ NumberDone 0 )1.3. x 0 ≤ NumberDone 0
1.4. Q.E.D.
Proof: By steps 1.1–1.3 and the definition of Inv .
Step 1.2 is the most difficult one to prove, so we examine its proof. The
standard way to prove a formula of this form is to assume i ∈ Procs andpc 0 (i ) = b and prove t 0 (i ) ≤ NumberDone 0 . So, the first step of the proof
should be a Suffices step asserting that it suffices to make those assumptions and prove t 0 (i ) ≤ NumberDone 0 . Thus far, we have used only the
logical structure of the formulas, without thinking about what the formulasmean. We can go no further that way. To write the rest of the proof ofstep 1.2, we have to ask ourselves why an aStep(p) step starting in a statewith Inv true produces a state with t 0 (i ) ≤ NumberDone 0 true.
When I asked myself that question, I realized that the answer depends
on whether or not i is the process p executing the step. That suggested
proving the two cases i 6= p and i = p separately, asserting them as Casestatements. In figuring out how to write those two proofs, I found that bothof them required proving NumberDone 0 = NumberDone. Moreover, this wastrue for the same reason in both cases—namely, that an aStep step of any
process leaves NumberDone unchanged. Therefore, I could prove it once ina single step that precedes the two Case statements. This produced thefollowing level-3 proof:
1.2.1. Suffices: Assume: new i ∈ Procs, pc 0 (i ) = b
Prove: t 0 (i ) ≤ NumberDone 0
Proof: Obvious.
1.2.2. NumberDone 0 = NumberDone
1.2.3. Case: i = p
1.2.4. Case: i 6= p
1.2.5. Q.E.D.
Proof: By steps 1.2.3 and 1.2.4.

APPENDIX B. PROOFS

285

This leaves three steps to prove. Here is the proof of step 1.2.4, which I
think is the most interesting one.
1.2.4.1. (t 0 (i ) = t(i )) ∧ (pc 0 (i ) = pc(i ))Proof: By step 1 (which implies aStep(p) and Inv ), the step 1.2.4
case assumption, and the definitions of aStep, Inv , and TypeOK ,which together imply that the values of t(i ) and pc(i ) are unchanged.
(The definition of TypeOK is needed because type correctness isrequired to deduce this.)
1.2.4.2. pc(i ) = b
Proof: By step 1.2.4.1 and the step 1.2.1 assumption pc 0 (i ) = b.
1.2.4.3. t(i ) ≤ NumberDone
Proof: By step 1.2.4.2, the step 1 assumption (which implies Inv ),and the second conjunct in the definition of Inv .
1.2.4.4. Q.E.D.
Proof: Steps 1.2.4.1, 1.2.4.3, and 1.2.2 imply t 0 (i ) ≤ NumberDone 0 ,which is the current goal (introduced in step 1.2.1).
The purpose of this example is to illustrate the science of proving correctness of concurrent programs. The program and its proof are very simple.1
The example shows how proving that a program satisfies a property canbe hierarchically decomposed into proving simple mathematical assertions
whose proofs require no understanding of why the program works or what
it’s supposed to do. How this can be done for real abstract programs is anengineering problem that is outside the scope of this book.

B.2

Proof of Theorem 4.3

Theorem 4.3 If F is a property, then C(F ) is a safety property suchthat |= F ⇒ C(F ) and, for any safety property G, if |= F ⇒ G then|= C(F ) ⇒ G.
Proof: Let F be a property. Extend the definition of \ in Section 3.5.3
in the obvious way to finite behaviors ρ so that \ρ equals ρ with stuttering
1
To check the level-1 proof, the TLA+ proof checker requires only that step 2 bedecomposed to a two-step proof, and that it be told to use two simple facts about the
cardinality of finite sets that it easily deduces from a standard library of such facts.

APPENDIX B. PROOFS

286

steps removed.
1. Assume: F is a property
Prove: C(F ) is a property
1.1. Suffices: Assume: σ is a behavior
Prove: σ satisfies C(F ) iff \σ does
Proof: By definition of a property, it suffices to show that C(F ) is SI.
By definition of SI, it suffices to assume σ is a behavior and show σsatisfies C(F ) iff \σ does.
1.2. Assume: σ satisfies C(F )Prove: \σ satisfies C(F )Proof: By definition of C, it suffices to assume ρ is a nonempty finite
prefix of \σ and show it is a prefix of a behavior satisfying F . Sinceρ is a prefix of \σ, it equals \τ for some prefix τ of σ, so σ satisfies F
implies τ ◦ ν satisfies F for some behavior ν. Since F is SI and ρ is
obtained from τ by removing stuttering steps, ρ ◦ ν also satisfies F , so
ρ is a prefix of a behavior satisfying F .
1.3. Assume: \σ satisfies C(F )Prove: σ satisfies C(F )Proof: By definition of C, it suffices to show that any finite nonempty
prefix ρ of σ satisfies F , which means showing that ρ is the prefix of abehavior satisfying F . Since \ρ is a prefix of \σ, by hypothesis there isa behavior τ such that (\ρ) ◦ τ satisfies F . Since F is SI and ρ ◦ τ differsfrom (\ρ) ◦ τ only by stuttering steps, ρ ◦ τ too satisfies F . Thus ρ isthe prefix of a behavior satisfying F .
1.4. Q.E.D.
Proof: By steps 1.1–1.3.
2. C(F ) is a safety predicate.
2.1. Suffices: Assume: ρ is a prefix of a behavior that satisfies C(F ).
Prove: ρ↑ satisfies C(F )Proof: By definition of safety.
2.2. Let σ be a behavior such that ρ ◦ σ satisfies F , and let φ(n) be thesequence of states consisting of n “copies” of the final state of ρ, for
any n ∈ N, and let τ (n) equal ρ ◦ φ(n) ◦ σ. Then τ (n) satisfies F for
all n ∈ N.
Proof: A behavior σ such that ρ ◦ σ satisfies F exists by the step 2.1
assumption and the definition of C. That τ (n) satisfies F follows from:APPENDIX B. PROOFS

287(i) \τ (n) equals \(ρ ◦ σ) by definition of φ(n) and τ (n), (ii) ρ ◦ σ satisfies
F , and (iii) F is SI.
2.3. Every finite prefix of ρ↑ is a finite prefix of τ (n), for some n.
Proof: By the definitions of τ (n) and of ρ↑ .
2.4. Q.E.D.
Proof: By steps 2.2 and 2.3, every finite prefix of ρ↑ is a prefix of abehavior satisfying F . By definition of C, this implies ρ satisfies C(F ),which by step 2.1 is what we had to prove.
3. Assume: G a safety property and |= F ⇒ G
Prove: |= C(F ) ⇒ G
Proof: It suffices to assume σ is a behavior satisfying C(F ) and prove it
satisfies G. Since G is a safety property, it suffices to show that any finite
prefix ρ of σ satisfies G. By definition of C, ρ is a prefix of a behavior
satisfying F , and therefore by hypothesis satisfying G. Since G is a safety
property, this implies ρ satisfies G.
4. Q.E.D.
Proof: Steps 1–3 are the assertions of the theorem.

B.3

Proof of Theorem 4.4

Theorem 4.4 Every property F is equivalent to C(F ) ∧ L for a livenessproperty L.
∆

Define L = F ∨ ¬C(F )1. F is equivalent to C(F ) ∧ L .
Proof: By |= (F ⇒ C(F )) (from Theorem 4.3) and propositional logic.
2. L is a liveness property.
2.1. Suffices: Assume: ρ is a finite behavior.
Prove: ρ is a prefix of a behavior τ satisfying L.
Proof: By definition of liveness, since L is a property because theoperators of propositional logic preserve stuttering insensitivity, andC(F ) is a property by Theorem 4.3.
2.2. Case: ρ is the prefix of a behavior τ satisfying F .
Proof: By definition of L, if τ satisfies F then it satisfies L.
2.3. Case: ρ is not the prefix of any behavior satisfying F .

APPENDIX B. PROOFS

288

Proof: By definition of C(F ), if ρ were the prefix of a behavior satisfying C(F ), then it would be the prefix of a behavior satisfying F . The
case assumption therefore implies that any behavior τ having ρ as aprefix does not satisfy C(F ), so it satisfies ¬C(F ) and therefore satisfies
L by definition of L.
2.4. Q.E.D.
Proof: Steps 2.2 and 2.3 cover all possibilities.
3. Q.E.D.
Proof: By steps 1 and 2.

B.4

Proof of Theorem 4.5

Theorem 4.5 Assume: S a safety property and L a liveness property.
Prove: hS , Li is machine closed iff C(S ∧ L) ≡ S .
1. Assume: hS , Li is machine closed.
Prove: C(S ∧ L) ≡ S
1.1. C(S ∧ L) ⇒ S
Proof: Theorem 4.3 implies |= S ⇒ C(S ), so |= S ∧ L ⇒ C(S ).
That theorem also implies C(S ) is a safety property and therefore|= C(S ∧ L) ⇒ C(S ). Since S is a safety property, it equals C(S ), so|= C(S ∧ L) ⇒ C(S ) implies C(S ∧ L) ⇒ S .
1.2. S ⇒ C(S ∧ L)
Proof: It suffices to assume a behavior σ satisfies S and prove σ satisfies C(S ∧ L). By definition of machine closure, every finite prefix of σcan be completed to a behavior of S ∧ L. By definition of C, this implies
σ satisfies C(S ∧ L).
1.3. Q.E.D.
Proof: By steps 1.1 and 1.2.
2. Assume: C(S ∧ L) ≡ S
Prove: hS , Li is machine closed.
Proof: By definition of machine closure, it suffices to assume ρ is a
finite behavior satisfying S and prove ρ can be completed to a behavior
satisfying S ∧ L. By definition of what it means for a finite behavior
to satisfy a property, ρ↑ satisfies S . Since S ≡ C(S ∧ L), behavior ρ↑
satisfies C(S ∧ L). By definition of C, this implies every prefix of ρ↑ can

APPENDIX B. PROOFS

289

be completed to a behavior satisfying S ∧ L, and ρ is a prefix of ρ↑ .
3. Q.E.D.
Proof: By steps 1 and 2.

B.5

Proof of Theorem 4.6

Theorem 4.6 Assume: |= (E U P ) ≡ (3P ∧ E U P ) ∨ (¬3P ∧ 2E )Prove: |= ((E U P ) ; P ) ≡ (2E ; P ).
1. Suffices: |= ((E U P ) ⇒ 3P ) ≡ (2E ⇒ 3P )Proof: F ; G is defined to equal 2(F ⇒ 3G).
2. |= ((E U P ) ⇒ 3P ) ≡ ∧ (3P ∧ E U P ) ⇒ 3P
∧ (¬3P ∧ 2E ) ⇒ 3P
Proof: By the theorem’s assumption and the propositional logic tautology |= ((F ∨ G) ⇒ H ) ≡ (F ⇒ H ) ∧ (G ⇒ H ).
3. Q.E.D.
Proof: |= 3P ∧ E U P ⇒ 3P is a propositional logic tautology, whichby step 2 implies |= ((E U P ) ⇒ 3P ) ≡ (¬3P ∧2E ⇒ 3P ), which withthe propositional logic tautology |= (¬3P ∧ 2E ⇒ 3P ) ≡ (2E ⇒ 3P )proves the step 1 goal.

B.6

Proof of Theorem 4.7

Theorem 4.7 Let Init be a state predicate, Next an action, and v a tupleof all variables occurring in Init and Next. If Ai is a subaction of Next for
all i in a countable set I , then the pairh Init ∧ 2[Next]v , ∀ i ∈ I : XFiv (Ai ) i
is machine closed, where each XFiv may be either WF or SF.
Define S = Init ∧ 2[Next]v∆

1. Suffices: Assume: ρ is a finite behavior satisfying S .
Prove: There exists a behavior σ having ρ as a prefix thatsatisfies S and SFv (Ai ), for all i ∈ I .
Proof: By definition of machine closure, it suffices to show that any
finite behavior ρ satisfying S is the prefix of a behavior σ satisfying

APPENDIX B. PROOFS

290

S ∧ ∀ i ∈ I : XFiv (Ai ). Since SFv (Ai ) implies WFv (Ai ), it suffices to showthat σ satisfies SFv (Ai ) for all i ∈ I .
2. Choose f ∈ ( N → I ) such that each i ∈ I equals f (n) for infinitely manyn ∈ N. Define τ j for each j ∈ N as follows. Let τ 0 = ρ, and for j > 0,
define τ j such that:if τ j −1 is a prefix of a finite behavior µ satisfying S and ending in astate in which hAf (j −1) iv is enabled.
then τ j equals the finite behavior obtained by appending to µ astate that makes the last step of τ j an hAf (j −1) iv step.
else τ j is obtained from τ j −1 by adding a stuttering step.
For all j ∈ N, τ j is a prefix of and shorter than τ j +1 , and τ j satisfies S .
Proof: Theorem 4.1 of Math V shows the existence of f . By construction
each τ j is a prefix of and shorter than τ j +1 . We must just show that τ jsatisfies S . The proof is by induction. It is true for j = 0 since τ 0 equals
ρ, which satisfies S by the step 1 assumption. So we complete the proof
by assuming j > 0 and τ j −1 satisfies S and proving as follows that τ jsatisfies S .
If the if condition in the definition of τ j is true, then τ j satisfies S
because τ j −1 does and τ j is obtained by appending to τ j −1 an hAf (j −1) iv
step, which is a Next step by the hypothesis that |= Ai ⇒ Next for alli ∈ I . If the if condition is false, then τ j satisfies S because S is stuttering
insensitive, τ j −1 satisfies S , and τ j is obtained by adding a stuttering stepto τ j −1 .
3. Let σ be the behavior having every τ j as a prefix. Then σ is a behavior
satisfying S having the prefix ρ.
Proof: The behavior σ exists (and is unique) because each τ j is a prefixof and shorter than τ j +1 . Since ρ equals τ 0 , it is a prefix of σ. Step 2
asserts that every prefix τ j of σ satisfies S . By definition of S , this implies
σ satisfies S .
4. σ satisfies SFi (A) for all i ∈ I .
Proof: Step 2 asserts that for any i ∈ I , there are infinitely many j ∈ Nsuch that i = f (j − 1). If the if condition in the definition of τ j is true
for all of those values of j , then σ contains an hAi iv step for each of thosevalues of j , so σ satisfies 23hAi iv . If the if condition is false for any
such j , then τ j −1 cannot be extended to any finite behavior containing
an hAi iv step. Hence, 2¬ EhAi iv is true for the suffix of σ obtained

APPENDIX B. PROOFS

291

by removing the prefix τ j −1 . Therefore, σ satisfies 32¬ EhAi iv , whichequals ¬23 EhAi iv . By (4.14), in either case σ satisfies SFv (Ai ).
5. Q.E.D.
Proof: The theorem follows from steps 1, 3, and 4.

B.7

Proof of Theorem 4.8∆

Theorem 4.8 Let Ai be an action for each i ∈ I , let Q = ∃ i ∈ I : Ai ,and let XF be either WF or SF. Then|= ( ∀ i ∈ I : 2( EhAi iv ∧ 2[¬Ai ]v ⇒2[¬Q]v ∧ 2( EhQ iv ⇒ EhAi iv ) )⇒ ( XFv (Q) ≡ ∀ i ∈ I : XFv (Ai ) )Define 232
3 to equal 32 if XF is WF, and 23 if XF is SF.
1. Suffices: Assume: ∀ i ∈ I : 2( EhAi iv ∧ 2[¬Ai ]v ⇒2[¬Q]v ∧ 2( EhQ iv ⇒ EhAi iv ))Prove: XFv (Q) ≡ ∀ i ∈ I : XFv (Ai )Proof: Obvious.
2. XFv (Q) ⇒ ∀ i ∈ I : XFv (Ai )2.1. Suffices: Assume: XFv (Q), new i ∈ I , 2
32
3 EhAi iv ∧ 32[¬Ai ]v
Prove: false
Proof: By (4.14) and (4.23), since F ⇒ G is equivalent to F ∧ ¬G ⇒false and ¬23hAi iv equals 32[¬Ai ]v .
2.2. 3 ( 2[¬Q]v ∧ 2( EhQ iv ⇒ EhAi iv ) )Proof: 232
3 EhAi iv implies 23 EhAi iv , and 23 EhAi iv ∧ 32[¬Ai ]v
implies 3( EhAi iv ∧ 2[¬Ai ]v ) by temporal reasoning. Therefore, thestep 2.1 assumption implies 3( EhAi iv ∧ 2[¬Ai ]v ), which by the step 1
assumption implies 2.2.
2.3. 32[¬Q]v ∧ 32( EhQ iv ≡ EhAi iv )Proof: By step 2.2, because 3(2F ∧ 2G) equals 32F ∧ 32G for any
F and G, and 2( EhQ iv ⇒ EhAi iv ) implies 2( EhQ iv ≡ EhAi iv )because the definition of Q implies |= Ai ⇒ Q, which by the definitionof E in Section 4.2.1 implies |= EhAi iv ⇒ EhQ iv .
2.4. 23hQ iv
Proof: 232
3 F and 32(F ≡ G) imply 2
32
3 G, for any F and G.
Therefore step 2.3 and the step 2.1 assumption 232
3 EhAi iv imply

APPENDIX B. PROOFS

292

32
3 EhQ iv . By definition of XF, the step 2.1 assumption XFv (Q)
2
and 2
32
3 EhQ iv imply 23hQ iv .
2.5. Q.E.D.
Proof: Since 32[¬Q]v is equivalent to ¬23hQ iv , steps 2.3 and 2.4
imply false, the goal introduced in step 2.1.
3. (∀ i ∈ I : XFv (Ai )) ⇒ XFv (Q)3.1. Suffices: Assume: (∀ i ∈ I : XFv (Ai )) ∧ 2
32
3 EhQ iv
Prove: 23hQ iv
Proof: By (4.14) and (4.23).
3.2. EhQiv ⇒ 3hQiv
3.2.1. Suffices: Assume: (i ∈ I ) ∧ EhAi iv
Prove: 3hQ iv
Proof: By predicate logic (the ∃ Elimination rule), since Q equals∃ i ∈ I : Ai , so EhQ iv equals ∃ i ∈ I : EhAi iv by rule E2 of Section 5.4.4.2.
3.2.2. Case: 3hAi iv
Proof: 3hQ iv follows from the case assumption and |= Ai ⇒ Q.
3.2.3. Case: 2[¬Ai ]v
Proof: Assumption EhAi iv from step 3.2.1, the case assumption,and the step 1 assumption imply 2( EhQ iv ⇒ EhAi iv ). This, thetemporal logic tautology |= 2(F ⇒ G) ⇒ (232
3F ⇒ 232
3 G), and thestep 3.1 assumption 232
3 EhQ iv imply 2
32
3 EhAi iv . Since i ∈ I by
the step 3.2.1 assumption, the step 3.1 assumption implies XFv (Ai ),which by 232
3 EhAi iv and the definition of XF implies 3hAi iv , whichby |= Ai ⇒ Q implies 3hQ iv .
3.3. Q.E.D.
Proof: All assumptions in effect at step 3.2 are 2 formulas so, as explained in Section 4.2.4, we can deduce 2( EhQ iv ⇒ 3hQ iv ) from 3.2.
This and the temporal logic tautology|= 2(F ⇒ 3G) ⇒ (232
3 F ⇒ 23G)
imply 232
3 EhQ iv ⇒ 23Q, which by the step 3.1 assumption 232
3 EhQ iv
implies the step 3.1 goal 23Q.
4. Q.E.D.
Proof: By steps 1–3.

APPENDIX B. PROOFS

B.8

293

Proof Sketch of Theorem 4.9

Theorem 4.9 Let x be the list x 1 , . . . , x n of variables and let F be aproperty such that F (σ) depends only on the values of the variables x in σ,
for any behavior σ. There exists a formula S equal to Init ∧ 2[Next]hx,y i ∧WFhx,y i (Next), where Init and Next are defined in terms of F , y is a variable
not among the variables x, and the variables of S are x and y, such that|= F ⇒ [[G]] iff |= S ⇒ G, for any property G. If F is a safety property,
then the conjunct WFhx,y i (Next) is not needed.
Proof sketch: For any behavior σ, let σ|x be the infinite sequence of ntuples of values such that σ|x (i ) equals the value of hxi in state σ(i ). The
basic idea is to define S so that the value of y in any state i of a behaviorof S always equals (σ|x )+i for some behavior σ satisfying F , and x always
equals y(0). (Remember that τ is the infinite sequence τ (0) → τ (1) → · · · ,and τ +i equals τ (i ) → τ (i + 1) → · · · .)To do this, for any infinite sequence τ of n-tuples of values, we definee (τ ) to equal F (σ) for any behavior σ such that σ|x equals τ . This uniquelyFe because, by hypothesis, the value of F (σ) depends only on thedefines F
values of the variables x in the behavior σ. Define IsTupleSeq to be themapping such that IsTupleSeq(τ ) is true iff τ is an infinite cardinal sequenceof n-tuples of arbitrary values. We then define S by letting:Init∆e (τ )= ∃ τ : ∧ IsTupleSeq(τ ) ∧ F∧ (y = τ ) ∧ (hxi = τ (0))∆

Next = (y 0 = Tail (y)) ∧ (hxi0 = y 0 (0))
With this definition, F (σ) equals true for a behavior σ iff there is a behavior
satisfying S in which the initial value of y is σ|x . Notice that σ is a halting
behavior iff τ ends with an infinite sequence of identical n-tuples. Wheny equals that value Tail (y) = y, so hNext ihx,y i equals false and S allows
only stuttering steps from that point on.
Eliminating the conjunct WFhx,y i (Next) allows S to halt even if the
behavior y initially equals σ|x for a non-halting behavior σ that satisfies F .
That makes no difference if F is a safety property, since in that case every
finite prefix of σ also satisfies F . End Proof Sketch

B.9

Proof of Formula (5.4)

For any variable p and any state s, let s p be the value of p in state s. For
any S -behavior σ:

APPENDIX B. PROOFS

294[[(z 0 = x + y) with . . . ]](σ)≡ [[w 0 = u + v ]](σ)

By definition of with . . . .

≡ σ(1)w = σ(0)u + σ(0)v

By definition of [[. . .]].

[[z 0 = x + y]](fb(σ))≡ fb(σ)(1)z = fb(σ)(0)x + fb(σ)(0)y By definition of [[. . .]].
≡ f (σ(1))z = f (σ(0))x + f (σ(0))y By definition of bf .
≡ σ(1)w = σ(0)u + σ(0)v

B.10

By definition of f .

Proof of Theorem 6.2

Theorem 6.2 With the assumptions of Theorem 6.1, for all i ∈ I let B i
be a subaction of Ai such that(*) T ∧ (i 6= j ) ⇒ 2[¬(B i ∧ Aj )]v∆

for all j in I ; and let B hi = hB i iv ∧ (h 0 = exp i ). ThenT ∧ (∀ i ∈ I : XFiv (Bi )) ≡ ∃ h : T h ∧ (∀ i ∈ I : XFivh (Bih ))where each XFi is either WF or SF.
1. Assume: i ∈ I
Prove: hB hi ivh ≡ hB i ∧ (h 0 = exp i )iv
1.1. hB hi ivh ≡ B i ∧ (v 0 6= v ) ∧ (h 0 = exp i ) ∧ (vh 0 6= vh)
Proof: By the definitions of B hi , Next i , and h. . .i... .
1.2. hB hi ivh ≡ B i ∧ (v 0 6= v ) ∧ (h 0 = exp i )Proof: By step 1.1, since vh = v ◦ hh i implies (v 0 6= v ) ∧ (vh 0 6= vh) ≡(v 0 6= v ).
1.3. Q.E.D.
Proof: By step 1.2 and the definition of h. . .iv .
2. Assume: i ∈ I
Prove: EhB hi ivh ≡ EhB i iv
Proof: By step 1 because exp is assumed not to contain h 0 , so rules E3
and E5 of Section 5.4.4.2 imply EhB i ∧ (h 0 = exp i )iv equals EhB i iv .
Define 232
3 i to equal 32 if XFi is WF and to equal 23 if XFi is SF.
3. Assume: T h ∧ ∀ i ∈ I : XFivh (B hi )

APPENDIX B. PROOFS
Prove:

295

T ∧ ∀ i ∈ I : XFiv (B i )3.1. Suffices: Assume: (i ∈ I )Prove: XFiv (B i )Proof: By Theorem 6.1, T h implies T . Therefore, if suffices to prove∀ i ∈ I : XFiv (B i ) to prove step 3
3.2. Suffices: Assume: 232
3 i EhB i iv
Prove: 23hB i iv
Proof: By (4.14) and (4.23)
3.3. 232
3 i EhB hi ivh
Proof: By the step 3.2 assumption and step 2. (Since step 2 is not in
the scope of any assumptions, it implies 2( EhB hi ivh ≡ EhB i iv ) .)3.4. 23hB hi ivh
Proof: The step 3 assumption implies XFivh (Bih ), which by step 3.3,
(4.14), and (4.23) implies 23hB hi ivh .
3.5. Q.E.D.
Proof: Step 3.4 and step 1 imply 23hB i ∧(h 0 = exp i )iv , which implies
the goal introduced in step 3.2.
4. Assume: T ∧ ∀ i ∈ I : XFiv (B i )Prove: ∃ h : T h ∧ ∀ i ∈ I : XFivh (B hi )4.1. Suffices: Assume: T h ∧ (i ∈ I )Prove: XFivh (B hi )Proof: Theorem 6.1 shows that T implies ∃ h : T h . This implies thatto prove T ∧ F implies ∃ h : (T h ∧ G) for any F and G, it suffices
to prove that T ∧ F ∧ T h implies G. Thus, the step 4 assumption
shows that to prove the step 4 goal, it suffices to prove T h implies∀ i ∈ I : XFivh (B hi ), which is asserted by this step’s Assume/Prove.
4.2. Suffices: Assume: 232
3 i EhB hi ivh
Prove: 23hB hi ivh
Proof: By (4.14) and (4.23).
4.3. 232
3 i EhB i iv
Proof: By the step 4.2 assumption and step 2.
4.4. 23hB i iv
Proof: The step 4 assumption implies XFiv (Bi ), which by step 4.3,
(4.14), and (4.23) implies 23hB i iv .
4.5. Q.E.D.

APPENDIX B. PROOFS

296

Proof: By hypothesis, B i is a subaction of Ai . By hypothesis (∗) andthe step 4 assumption (which implies T ), B i ∧ Aj equals false if i 6= j .
Hence a B i step must be an Ahi step. By definition of Ahi and the step
4.1 assumption (which implies T h ), every B i step is a B i ∧ (h 0 = exp i )step. Therefore, step 4.4 and step 1 imply 23hB hi ivh , which is the goal
introduced by step 4.2.
5. Q.E.D.
Proof: Steps 3 and 4 imply that T ∧ (∀ i ∈ I : XFiv (Bi )) is equivalentto ∃ h : T h ∧ (∀ i ∈ I : XFivh (Bih )) .

B.11

Proof Sketch of Theorem 6.3

Theorem 6.3 Let T equal Init ∧ 2[Next]hxi where x is the list of all
variables of S ; let F be a safety property such that F (σ) depends only on
the values of the variables x in σ, for any behavior σ; and let h be a variable
not one of the variables x. We can add h as a history variable to T to obtainT h and define a state predicate IF in terms of F such that |= [[T ]] ⇒ F istrue iff IF is an invariant of T h .
Proof sketch: Define T h as follows:Th= Init h ∧ 2[Next h ]hx,h i

Init h= Init ∧ (h = hxi)

∆

∆

∆

Next h = Next ∧ (h 0 = Append (h, hxi0 ))Since h is a history variable, so ∃ h : T h is equivalent to T , to every behavior
σ satisfying T there is a corresponding behavior satisfying T h that has thesame values of the variables of x as σ. Since F does not depend on h, thismeans that |= [[T ]] ⇒ F iff |= [[T h ]] ⇒ F .
e to be the same as in the proof of Theorem 4.9,
We now define ρ|x and F
except for finite behaviors ρ. We define ρ|x to be the finite cardinal sequenceof n-tuples of the same length as ρ such that ρ|x (i ) equals the value of hxi
e to be the predicate on finite sequences ofin state ρ(i ); and we define Fe (ρ|x ) equals F (ρ) (which by definition equals
n-tuples of values such that F↑e (h).
F (ρ )). We then define IF to equal F
Much as in the proof of Theorem 4.9, for any behavior τ , a finite prefixe (ρ|x ) is true, which is true iff Fe (h) is true of the lastρ of τ satisfies F iff F
state of ρ. Every state of τ is the last state of some finite prefix of τ , andthe safety property F is true of τ iff it is true of every finite prefix of τ , so

APPENDIX B. PROOFS

297

F is true of τ iff IF is true of every state of τ . This proves that IF is aninvariant of T h iff T h satisfies F ; and T satisfies F iff T h does, because F
depends only on the variables x. End Proof Sketch

B.12

Proof Sketch of Theorem 6.6

Theorem 6.6 Let x, y, and z be lists of variables, all distinct from one
another; let the variables of T be x and z and the variables of IS be x and y;and let T equal Init ∧ 2[Next]hx,zi ∧ L. Let the operator Φ map behaviors
satisfying T to behaviors satisfying IS such that Φ(σ) ∼y σ. By adding
history, stuttering, and prophecy variables to T , we can define a formulaT a such that ∃ a : T a is equivalent to T and a tuple exp of expressions
defined in terms of Φ and the variables of T a such that|= T a ⇒ (IS with y ← exp)
Proof sketch: We first add an infinite stuttering insensitivity t to T ,defining T t to equal∧ Init ∧ 2[(Next ∧ (v 0 6= v )) ∨ ((t 0 6= t) ∧ (hx, zi0 = hx, zi))]hx,z,t i∧ L ∧ 23ht 0 6= t it
In addition to handling the weird case described in Section 6.3.5, this simplifies the proof by not having to consider terminating behaviors, since T tdoesn’t allow them.
Let m be the number of variables in x, z, and t. We next define T th byadding to T t a history variable h whose value in any state is a cardinal sequence of m-tuples. The initial value of h is the one-element sequence whose
single element is the value of hx, z, t i in the initial state. Each step that
does not leave hx, z, t i unchanged appends to h the new value of hx, z, t i.
For a behavior σ satisfying T th that has no stuttering steps (steps leaving
x, z, and t unchanged), the value of variable h always equals the sequenceh(0), . . . , h(Len(h) − 1) of m-tuples such that each h(i ) equals the value ofhx, z, t i in state σ(i ) for all i < Len(h).
We now add to T th a prophecy variable p that always makes an infinite
sequence of prophecies. The value of p in state σ(i ) of a behavior σ satisfying
T thp is the infinite sequence of m-tuples such that in state σ(i ), the value ofp(0), the next prediction made by p, is the m-tuple that equals the next valueof hx, z, t i different from its current value. This is a generalized prophecy
variable with predictions in the collection (not a set) of m-tuple of values.

APPENDIX B. PROOFS

298

It is defined by writing the next-state action Next th as ∃ i : Ai , where
Ai = (i = hx, z, t i0 ) ∧ Next th∆and defining the next-state action Next thp of T thp by
Next thp = Ap(0) ∧ Next th ∧ (p 0 = Tail (p))∆

A Next thp step removes the first element from p and appends that element
to the end of h. Therefore, the value of h ◦ p remains unchanged throughout
any behavior that satisfies T thp . The value of h ◦ p during a behavior σsatisfying T thp equals the sequence of values of hx, z, t i in the entire behavior
σ, except that σ may have additional (stuttering) steps that leave hx, z, t iunchanged.
In any state of a behavior satisfying T thp , the value of (h ◦p)(Len(h)−1)(the last element in the sequence h of m-tuples of values) is the current valueof hx, z, t i. The variables h and p, together with the mapping Φ contain all
the information needed to define a refinement mapping under which T thp
implements IS . To see how this is done, we need some notation.
For any behavior σ and state expression exp, define σ|exp to be the infinite
sequence of values such that (σ|exp )(i ) equals the value of exp in state σ(i ),for all i ∈ N. Thus σ|hx,z,t i is the sequence of m-tuples of values of hx, z, t ie from m-tuples of values to behaviors
in the states of σ. Define the mapping Φeso that Φ(ρ) equals Φ(σ) for some behavior σ such that σ|hx,z,t i = ρ. (Itdoesn’t matter what values the states of σ assign to variables other thanthose in x, z, and t since they don’t affect whether or not σ satisfies T .)We are assuming that Φ(σ) satisfies IS and Φ(σ) ∼ y σ. Therefore, forany behavior satisfying T thp , for the value of h ◦ p in any state of thate ◦ p) satisfies IS and Φ(he ◦ p) ∼y σ for some behavior σ such
behavior, Φ(hthat σ|hx,zi = h ◦ p.
To understand how to construct the needed refinement mapping, we consider a simpler version of the theorem that would be true if we were using
RTLA rather than TLA, so we didn’t have the complication introduced bye ◦ p) would satisfy Φ(he ◦ p) ' y σ
stuttering insensitivity In that case, Φ(he ◦ p) ∼y σ. This means that the behavior Φ(σ) satisfying IS isinstead of Φ(hconstructed from a behavior σ with σ|hx,z,t i equal to h ◦ p by just changing
the value of the variables y in each state of σ (without adding or removing
stuttering steps). For any state s, let s y be the values of the variables yin that state. For σ to satisfy IS , the values of y in any state σ(i ) of the
behavior σ should equal the values of Φ(σ)(i )y , the values of y in the corre-

APPENDIX B. PROOFS

299

sponding state of Φ(σ).2 Remember that state number i of σ corresponds
to the m-tuple (h ◦ p)(i ) with i = Len(h) − 1. Therefore, the values assigned
to y by the refinement mapping under which T thp implements IS should ine ◦ p). In
each state equal the values of y in state number Len(h) − 1 of Φ(hother words, we have:e ◦ p)(Len(h) − 1))y )(B.1) |= T thp ⇒ (IS with y ← (Φ(he ◦ p) ∼ y σ (rather
Let’s now return to the actual situation in which Φ(he ◦ p) 'y σ). The behavior Φ(he ◦ p) is constructed from the behavior
than Φ(hσ, where σ|hx,z,t i equals the value of h ◦ p in every state of σ, by possibly
adding stuttering steps to σ and then modifying the values of y in its states.
(There are no stuttering steps to remove from σ because we defined T t andthe history variable h so that h is a sequence of m-tuples no two successive
elements of which are equal.)
To fix (B.1) to handle these stuttering steps, we have to add a stuttering
variable s to T thp to obtain the program T thps that adds to the behavior
σ satisfying T thp the stuttering steps needed to produce a behavior τ suche ◦ p)(i ) for every i ∈ N. The
that the state τ (i ) corresponds to the state Φ(hebehavior Φ(h ◦ p) tells us where those stuttering steps must be added: eache ◦p)(i ) → Φ(he ◦p)(i +1) that leaves the value of hx, z, t i unchanged
step Φ(hcorresponds to a stuttering step added to the behavior σ satisfying T thp toform τ .
Define the function f in ( N → N) in terms of h ◦ p as follows. Let
f (0) = 0, and for all i ∈ N, let f (i + 1) be the smallest number greater thane ◦p)(f (i +1)) is different fromf (i ) such that the value of hx, z, t i in state Φ(heits value in state Φ(h ◦ p)(i ). (Such a number f (i + 1) exists for the valueof h ◦ p in any reachable state of T thp because adding the infinite-stuttering
variable t ensured that 23(t 0 6= t) is true for every behavior of T thp .)e ◦ p) from a behavior σ with σ|
To construct Φ(hhx,z,t i = h ◦ p, we haveto add stuttering steps to make each state number i of σ correspond toestate number f (i ) of Φ(h◦ p). The stuttering variable s added to T thp
thps
to define T
has to add f (i + 1) − f (i ) − 1 stuttering steps between
states number i and i + 1 of a behavior of T thp . That means addingf (Len(h)) − f (Len(h) − 1) − 1 stuttering steps after every step of the nextstate action of T thp . (Of course no stuttering step is added if f (Len(h)) −f (Len(h) − 1) = 1.) We then define k to be a state expression whose value
in any behavior satisfying T thps is the number of steps of the next-state2This means that for each variable yj of y, the value of yj in any state σ(i) should
equal the value of yj in Φ(σ)(i).

APPENDIX B. PROOFS

300

action of T thps that have occurred so far. We can define k in terms of thevalues of f and s, or we can simply add k as a history variable to T thps .
However we define it, we can express the corrected version of (B.1) that
handles stuttering insensitivity by:e ◦ p)(k ))y )|= T thps ⇒ (IS with y ← (Φ(hwhich completes the proof. End Proof Sketch
Replacing the Prophecy Variable with a Prophecy Constant
Theorem 6.6 is true if we use a prophecy constant, as defined in Section 6.6,
instead of a prophecy variable. This is proved by modifying the proof sketchof Theorem 6.6 as follows. After adding the auxiliary variables t and h, we
add to T th a prophecy constant c whose value is the infinite sequence ofm-tuples that are the values of hx, z, t i in the entire behavior. In otherwords,∆

T thc = ∃ c : P (h, c) ∧ T th
where P (h, c) asserts that c is an infinite sequence of m-tuples such that,in every state, h equals the sequence of the first Len(h) elements of c. We
then define p to be the state function such that, in any state, h ◦ p equalsc. The proof is then the same as the rest of the proof of Theorem 6.6, using
this as the definition of p.

B.13

Proof of Theorem 7.2

The proof uses the following assertion, which the definition of the action
composition operator “·” implies is true for all actions Ai and B j :(B.2) |= (∃ i ∈ I : Ai ) · (∃ j ∈ J : B j ) ≡ (∃ i ∈ I , j ∈ J : Ai · B j )Theorem 7.2 If A ≡ ∃ i ∈ I : Ai and B ≡ ∃ j ∈ J : B j for actions Ai and
B j , then:|= (∀ i ∈ I , j ∈ J : Ai · B j ⇒ B j · Ai ) ⇒ (A · B ⇒ B · A)
Proof: It suffices to assume Ai · B j ⇒ B j · Ai for all i ∈ I and j ∈ J andprove A · B ⇒ B · A. Here is the proof:

APPENDIX B. PROOFS

301

A · B ≡ (∃ i ∈ I , j ∈ J : Ai · B j ) by (B.2)⇒ (∃ i ∈ I , j ∈ J : B j · Ai ) we assume Ai · B j ⇒ B j · Ai for all i and j≡ B ·Aby (B.2), substituting I ← J , J ← I ,Ai ← B j , and B j ← Ai .

End Proof

B.14

Proof of Theorem 7.3

Theorem 7.3 If S equals Init ∧ 2[Next]x , P is a safety property, and Q is a0state predicate such that |= S ⇒ 2 E([Next]+x ∧ Q ), then |= S ∧ 23Q ⇒ P
implies |= S ⇒ P .
1. hS , 23Q i is machine closed.
1.1. Suffices: Assume: ρ a finite behavior satisfying S
Prove: ρ is a prefix of a behavior satisfying S ∧ L
Proof: By definition of machine closure.
1.2. There is a mapping Φ such that if µ is any finite behavior satisfying
S , then Φ(µ) is a finite behavior ending in a state satisfying Q suchthat µ ◦ Φ(µ) satisfies S .
0
Proof: The hypothesis |= S ⇒ 2 E([Next]+x ∧ Q ) implies that the ac0tion [Next]+x ∧ Q is enabled in the last state of µ. Therefore, there isa finite behavior ψ beginning with the last state of µ and containing atleast two states such that the last state of ψ satisfies Q and every stepof ψ satisfies [Next]+
x . Let Φ(µ) equal Tail (ψ). Then µ ◦ Φ(µ) satisfies
S by definition of S , because µ satisfies Init and 2[Next]x and every
step of ψ is a [Next]+
x step; and the last state of µ ◦ Φ(µ) satisfies Q.
∆

Define τ i for i ∈ N by: τ 0 = ρ∆τ i+1 = τ i ◦ Φ(τ i ) for all i ∈ N
1.3. Q.E.D.
Proof: Let σ be the (unique) behavior such that each τ i is a prefix ofσ, so ρ (which equals τ 0 ) is a prefix of σ. Each finite prefix of σ is aprefix of some τ i and therefore satisfies S . Since S is a safety property,
this implies σ satisfies S . For all i ∈ N, τ i+1 has at least one morestate satisfying Q than τ i does, so σ satisfies 23Q.
2. S = C(S ∧ 23Q)
Proof: By step 1 and Theorem 4.5.

APPENDIX B. PROOFS

302

3. Q.E.D.
Proof: By step 2, the assumption that P is a safety property, and Theorem 4.3.

Bibliography[1] Martı́n Abadi and Leslie Lamport. An old-fashioned recipe for realtime. ACM Transactions on Programming Languages and Systems,
16(5):1543–1571, September 1994. This paper has an appendix published by ACM only online that contains proofs. Other online versionsof the paper might not contain the appendix.
[2] Martı́n Abadi and Leslie Lamport. Conjoining specifications. ACM
Transactions on Programming Languages and Systems, 17(3):507–534,
May 1995. This paper has an appendix published by ACM only onlinethat contains proofs. Online versions of the paper might not containthe appendix.
[3] Bowen Alpern and Fred B. Schneider. Defining liveness. Information
Processing Letters, 21(4):181–185, October 1985.
[4] E. A. Ashcroft. Proving assertions about parallel programs. Journal ofComputer and System Sciences, 10:110–135, February 1975.
[5] Selma Azaiez, Damien Doligez, Matthieu Lemerre, Tomer Libal, andStephan Merz. Proving determinacy of the PharOS real-time operating
system. In Michael Butler, Klaus-Dieter Schewe, Atif Mashkoor, andMiklós Biró, editors, 5th Intl. Conf. Abstract State Machines, Alloy, B,
TLA, VDM, and Z (ABZ 2016), volume 9675 of LNCS, pages 70–85.
Springer, 2016.
[6] Arthur Bernstein and Paul K. Harter, Jr. Proving real time properties ofprograms with temporal logic. In Proceedings of the Eighth Symposium
on Operating Systems Principles, pages 1–11, New York, 1981. ACM.
Operating Systems Review 15, 5.
[7] James E. Burns and Nancy A. Lynch. Bounds on shared memory formutual exclusion. Inf. Comput., 107(2):171–184, 1993.
303

BIBLIOGRAPHY

304[8] Ernie Cohen and Leslie Lamport. Reduction in TLA. In David Sangiorgi and Robert de Simone, editors, CONCUR’98 Concurrency Theory, volume 1466 of Lecture Notes in Computer Science, pages 317–331.
Springer-Verlag, 1998.
[9] E. W. Dijkstra. Solution of a problem in concurrent programming
control. Communications of the ACM, 8(9):569, September 1965.
[10] Thomas W. Doeppner, Jr. Parallel program correctness through refinement. In Fourth Annual ACM Symposium on Principles of Programming Languages, pages 155–169. ACM, January 1977.
[11] Laurent Doyen, Goran Frehse, George J. Pappas, and André Platzer.
Verification of hybrid systems. In Edmund M. Clarke, Thomas A. Henzinger, Helmut Veith, and Roderick Bloem, editors, Handbook of Model
Checking, pages 1047–1110. Springer, 2018.
[12] Michael Fischer. Re: Where are you? Email message to Leslie Lamport. Arpanet message sent on June 25, 1985 18:56:29 EDT, number 8506252257.AA07636@YALE-BULLDOG.YALE.ARPA (47 lines),
1985.
[13] Michael J. Fischer, Nancy Lynch, and Michael S. Paterson. Impossibility of distributed consensus with one faulty process. Journal of theACM, 32(2):374–382, April 1985.
[14] R. W. Floyd. Assigning meanings to programs. In Proceedings of the
Symposium on Applied Math., Vol. 19, pages 19–32. American Mathematical Society, 1967.
[15] Aman Goel, Stephan Merz, and Karem A. Sakallah. Towards an automatic proof of the bakery algorithm. In Marieke Huisman and António
Ravara, editors, Formal Techniques for Distributed Objects, Components, and Systems, volume 13910 of Lecture Notes in Computer Science, pages 21–28. Springer, 2023.
[16] George Gonthier and Leslie Lamport. Recursive operator definitions.
Research Report RR-9341, Inria Saclay Ile de France, 2020. https://inria.hal.science/hal-02598330/file/RR-9341.pdf.
[17] Thomas A. Henzinger, Zohar Manna, and Amir Pnueli. What goodare digital clocks? In Werner Kuich, editor, Automata, Languages
and Programming, 19th International Colloquium, ICALP92, Vienna,

BIBLIOGRAPHY305

Austria, July 13-17, 1992, Proceedings, volume 623 of Lecture Notes in
Computer Science, pages 545–558. Springer, 1992.
[18] Maurice P. Herlihy and Jeannette M. Wing. Linearizability: A correctness condition for concurrent objects. ACM Transactions on Programming Languages and Systems, 12(3):463–492, January 1990.
[19] Wim H. Hesselink. Eternity variables to prove simulation of specifications. ACM Trans. Comput. Log., 6(1):175–201, 2005.
[20] C. A. R. Hoare. Proof of correctness of data representations. Acta
Informatica, 1:271–281, 1972.
[21] C.A.R. Hoare. An axiomatic basis for computer programming. Communications of the ACM, 12(10):576–583, October 1969.
[22] Cliff B. Jones. Specification and design of (parallel) programs. In
R. E. A. Mason, editor, Information Processing 83: Proceedings of the
IFIP 9th World Congress, pages 321–332, Amsterdam, September 1983.
IFIP, North-Holland.
[23] R. M. Keller. Formal verification of parallel programs. Communicationsof the ACM, 19(7):371–384, July 1976.
[24] R. P. Kurshan and Leslie Lamport. Verification of a multiplier: 64 bits
and beyond. In Costas Courcoubetis, editor, Computer-Aided Verification, volume 697 of Lecture Notes in Computer Science, pages 166–179,
Berlin, June 1993. Springer-Verlag. Proceedings of the Fifth International Conference, CAV’93.
[25] Peter Ladkin, Leslie Lamport, Bryan Olivier, and Denis Roegel. Lazycaching in TLA. Distributed Computing, 12(2/3):151–174, 1999.
[26] Leslie Lamport.
The paxos algorithm or how to win a turing award. Web page. https://lamport.azurewebsites.net/tla/paxos-algorithm.html.
[27] Leslie Lamport. TLA—temporal logic of actions. A web page at https://lamport.azurewebsites.net/tla/tla.html.
[28] Leslie Lamport. Proving the correctness of multiprocess programs.
IEEE Transactions on Software Engineering, SE-3(2):125–143, March
1977.

BIBLIOGRAPHY

306[29] Leslie Lamport. The mutual exclusion problem—part ii: Statement
and solutions. Journal of the ACM, 32(1):327–348, January 1986.
[30] Leslie Lamport. Hybrid systems in TLA+ . In Robert L. Grossman, Anil
Nerode, Anders P. Ravn, and Hans Rischel, editors, Hybrid Systems,
volume 736 of Lecture Notes in Computer Science, pages 77–102, Berlin,
Heidelberg, 1993. Springer-Verlag.
[31] Leslie Lamport. The temporal logic of actions. ACM Transactions on
Programming Languages and Systems, 16(3):872–923, May 1994.
[32] Leslie Lamport. Proving possibility properties. Theoretical Computer
Science, 206(1–2):341–352, October 1998.
[33] Leslie Lamport. Fairness and hyperfairness. Distributed Computing,13(4):239–245, November 2000.
[34] Leslie Lamport. Specifying Systems. Addison-Wesley, Boston, 2003.
[35] Leslie Lamport. Real-time model checking is really simple. In Dominique Borrione and Wolfgang Paul, editors, Correct Hardware Design and Verification Methods, 13th IFIP WG 10.5 Advanced ResearchWorking Conference, CHARME 2005, Saarbrücken, Germany, October 3-6, 2005, Proceedings, volume 3725 of Lecture Notes in Computer
Science, pages 162–175. Springer, 2005.
[36] Leslie Lamport. The PlusCal algorithm language. In Martin Leucker
and Carroll Morgan, editors, Theoretical Aspects of Computing, ICTAC
2009, volume 5684 of Lecture Notes in Computer Science, pages 36–60.
Springer-Verlag, 2009.
[37] Leslie Lamport. How to write a 21st century proof. Journal of Fixed
Point Theory and Applications, March 2012. DOI: 10.1007/s11784-0120071-6.
[38] Leslie Lamport and Stephan Merz. Auxiliary variables in TLA+.
arXiv:1703.05121 (https://arxiv.org/abs/1703.05121) Also available, together with TLA+ specifications, at http://lamport.
azurewebsites.net/tla/auxiliary/auxiliary.html.
[39] Mark H. Liffiton and Karem A. Sakallah. Algorithms for computing minimal unsatisfiable subsets of constraints. J. Autom. Reason.,40(1):1–33, 2008.

BIBLIOGRAPHY

307[40] Richard J. Lipton. Reduction: A method of proving properties of parallel programs. Communications of the ACM, 18(12):717–721, December
1975.
[41] Chris Newcombe, Tim Rath, Fan Zhang, Bogdan Munteanu, Marc
Brooker, and Michael Deardeuff. How amazon web services uses formal
methods. Communications of the ACM, 58(4):66–73, April 2015.
[42] Brian M. Oki and Barbara H. Liskov. Viewstamped replication: A new
primary copy method to support highly-available distributed systems.
In Proceedings of the Seventh Annual ACM Symposium on Principles
of Distributed Computing, pages 8–17. ACM Press, August 1988.
[43] S. Owicki and D. Gries. An axiomatic proof technique for parallel
programs I. Acta Informatica, 6(4):319–340, 1976.
[44] Susan Owicki and David Gries. Verifying properties of parallel
programs: An axiomatic approach. Communications of the ACM,
19(5):279–284, May 1976.
[45] Susan Owicki and Leslie Lamport. Proving liveness properties of concurrent programs. ACM Transactions on Programming Languages andSystems, 4(3):455–495, July 1982.
[46] Marshall Pease, Robert Shostak, and Leslie Lamport. Reaching agreement in the presence of faults. Journal of the ACM, 27(2):228–234,
April 1980.
[47] Amir Pnueli. The temporal logic of programs. In Proceedings of the 18th
Annual Symposium on the Foundations of Computer Science, pages 46–
57. IEEE, November 1977.
[48] Eric Verhulst, Raymond T. Boute, José Miguel Sampaio Faria, Bernard
H. C. Sputh, and Vitaliy Mezhuyev. Formal Development of a NetworkCentric RTOS. Springer, New York, 2011.
[49] Hagen Völzer and Daniele Varacca. Defining fairness in reactive andconcurrent systems. J. ACM, 59(3):13:1–13:37, 2012.

IndexThe index obviously needs to be added.

308