To save content items to your account,
please confirm that you agree to abide by our usage policies.
If this is the first time you use this feature, you will be asked to authorise Cambridge Core to connect with your account.
Find out more about saving content to .
To save content items to your Kindle, first ensure no-reply@cambridge.org
is added to your Approved Personal Document E-mail List under your Personal Document Settings
on the Manage Your Content and Devices page of your Amazon account. Then enter the ‘name’ part
of your Kindle email address below.
Find out more about saving to your Kindle.
Note you can select to save to either the @free.kindle.com or @kindle.com variations.
‘@free.kindle.com’ emails are free but can only be saved to your device when it is connected to wi-fi.
‘@kindle.com’ emails can be delivered even when you are not connected to wi-fi, but note that service fees apply.
This chapter shows how to use schemas to define new data types. It also explains the mathematical meaning or semantics of schemas. This will help you use schemas expressively and reason about Z texts.
Schema types
So far we have treated schemas as nothing more than macros that we can use to abbreviate blocks of mathematical text. In this view, schemas and the schema calculus are just conveniences: They save us a lot of writing, but they don't introduce any new concepts. This modest view provides practical benefits — but it isn't very ambitious.
Schemas are more than just abbreviations. They are objects in their own right. Schema definitions declare new data types called schema types. The instances of schema types are objects called bindings. Schema references denote sets of bindings. Schema types and bindings are new kinds of mathematical objects.
So far we have defined only three kinds of fundamental data types — all of the others are built up from these: basic types, declared as in [X], whose instances are individuals; set types, declared as in ℙ X, whose instances are sets; and Cartesian product types, declared as in X × Y, whose instances are tuples. Schema types and their instances, bindings, are the fourth (and last) kind of data type in Z.
A binding is the formal realization, in Z, of what we have been calling a situation or a state: an assignment of particular values to a collection of named variables.
The state machine model did not specify the initial state. The only reasonable choice is the PATIENTS state.
From Chapter 10
beam = on ↔ door = closed means the beam is on when the door is closed and the beam is off when the door is open. This is a bad requirement because the beam will turn on the moment the door is closed.
beam = on ∧ door = closed means the beam is always on and the door is always closed. Obviously useless.
beam = on ∨ door = open means the beam is on or the door is open, or both. This is a bad requirement because it allows the beam to be on when the door is open.
beam = off ∨ door = closed means the beam is off or the door is closed, or both. This is a good requirement, and means exactly the same thing as beam = on ⇒ door = closed, according to the law p ⇒ q ⇔ ¬ p ∨ q.
x ∈ dom f ⇒ f x = y is true when x ∈ dom f is false, otherwise it has the same truth value as f x = y.
From Chapter 11
Represent each triangle as a tuple whose components are the lengths of its three sides. These tuples are called Pythagorean triples because their components are related by the Pythagorean theorem; (3, 4, 5) is a Pythagorean triple because 32 + 42 = 52.
In this chapter we pursue the safety issues introduced in the therapy machine study from Chapter 6. To ensure that patients are treated as directed by their prescriptions, many machine settings must be set properly. The radiation beam should only be allowed to turn on when the correct settings have been achieved. This chapter presents a formal specification for the control software that permits the beam to turn on. It is an example of a safety-critical protection system because it prevents some potentially hazardous action from occurring unless particular safety requirements are satisfied.
This study also illustrates how Z can express two important design strategies: partitioning a complex system into largely independent subsystems or modules and refining from an abstract model to a detailed design.
Partition
First we develop a more detailed model of the therapy machine system Machine that we introduced in Chapter 21. Much of the apparent complexity of the therapy machine arises from the interaction of several subsystems which, by themselves, are simpler. We partition the system into subsystems and describe simple operations on each. For each operation on the system as a whole, we define a separate operation on each affected subsystem. The complex behaviors of the whole system emerge when we compose these simpler operations together.
The advantages of this approach arise because many operations involve only a few of the subsystems, and many complex operations can emerge when simpler operations appear together in different combinations.
We have described a universe that is richly populated with individuals, sets, tuples, relations, functions, and sequences. We can extend our univetse indefinitely by using operators to build up ever more complex structures. But we need something more.
We need a way to classify the profusion of structures we can create. We need to divide the wheat from the chaff, the sheep from the goats, the bogus from the bona fide. We will make an essentially binary distinction between the answer we are looking for — the objects we wish to model — and everything else. Our tool for distinguishing the two is called logic. The concept of a purely binary classification may seem crude, but with logic we can express distinctions that are exceedingly fine.
Basic predicates
The textual unit of logic is the predicate. There are just a few kinds of basic predicates. All the others are built up from these.
The simplest predicates are true and false. We say true and false are the two logical constants or truth values. In fact, every predicate has one value or the other, true or false. There are many rules for simplifying predicates or otherwise inferring whether any predicate, no matter how complicated, is true or false.
The next basic predicate is equals, =. The predicate e1 = e2 is true when the two expressions e1 and e2 have the same value, and is false otherwise.
These selections from the tool-kit are based on the Reference Manual. They include all the operators used in this book and a few more that are needed to define them.
The definitions in the tool-kit require some Z constructs we have not used elsewhere. It uses generic definitions very heavily: X, Y, and Z stand for any type, S and T are sets of any type, and Q and R are binary relations between any two types. The tool-kit also makes extensive use of patterns in abbreviation definitions, for example it defines the binary relation symbol by X ↔ Y == ℙ(X × Y).
In a few places I've used English paraphrases for predicates, where the formal definition uses constructs or concepts not discussed in this book.
Formal methods apply logic and simple mathematics to programming. They work best where traditional programming methods don't work very well: problems that are too difficult to solve by intuition or too novel to solve by modifying some existing program or design. They can help you create new programs, or analyze and document programs that are already written. Using formal methods requires creativity and judgment, but once you have created or analyzed a program formally, you can document your work as a sequence of steps that you or anyone else can check. You must be able to do this if you need to convince yourself or others that a program meets requirements for safety, accuracy, security, or any other critical property. It is also worth doing if you simply want to understand how the program works.
What are formal methods?
Formal methods are methods that use formulas.
A formula is a text or diagram constructed from predefined symbols combined according to explicit rules. A good working definition of formula is anything whose appearance or syntax can be checked by a computer. According to this definition, every computer program is a formula.
It's a little odd for programmers to speak of formal methods as if they were something special – as if formality were an option. If you want to program a computer, you really don't have any choice. Computation is formula evaluation.
All of our examples so far have been small: They have only a few state variables. In this chapter we tackle a large system that has hundreds of state variables. Z provides several structuring techniques that make this feasible. The system is large but the Z description is concise. It is built up from components, subsystems, conditions, and modes that are developed separately, but also accounts for behaviors that emerge at the system level. The description illustrates several useful idioms of the Z notation, including one called promotion.
The case study in this chapter is the control system for a cyclotron, a type of particle accelerator. A radiation therapy machine includes an accelerator that produces a radiation beam and therapy equipment that uses the beam. In Chapters 6, 21, and 22 we described some of the controls for the therapy equipment. Now we turn to the controls for the accelerator.
Our system is built up from many components, and most of its size derives from repetition of similar components. We can make our specification much shorter and easier to grasp by identifying the components, describing them separately, and then combining them. We will define a schema type for each kind of component. The system contains multiple copies of most kinds of components, so the system model contains multiple bindings of those schema types. Many features are common to several kinds of components, and these can be concisely represented by schemas that are included elsewhere.
I learned Z (pronounced zed) when I got tired of programming by trial and error.
I write large programs for a serious purpose. I work in a clinical department in a research hospital. My first project here was a program that assists in planning radiation therapy treatments for cancer, by performing physics simulations – radiation dose calculations – with 3-D interactive graphics. Our planning system took more than two years to develop and comprised 40,000 lines of code. We spent plenty of time on design, coded carefully, and ran lots of tests.
Like most software, our system usually worked. It did most of what the users asked for – and some things that they didn't. It handled most cases correctly – then every so often it did the wrong thing, locked up, or crashed. We, the developers, were as surprised by the bizarre behavior as anyone else. Fortunately, the computations were done before patients' treatments began and every result was reviewed thoroughly. We could detect and work around the problems. We could live with it – though it wasn't always convenient.
We had to do better. Our next project was the computer control system for a unique radiation therapy machine at our clinic. Typical software quality wasn't good enough. We had recently learned of another therapy control system that had killed people!
I surveyed every development method I could find, including many packaged as software products with nice facilities for drawing diagrams and producing documents.
So far we have been using Z to name objects, describe their structure, and state some of their properties. For each property of an object, we added another formula to the description. But this is not always necessary. We don't have to spell out each property explicitly. Once we have stated a few properties, we can infer many more by using formal reasoning. This ability to infer new facts by applying simple rules is one of the distinguishing features of a formal method.
Reasoning enables us to use a formal model as a nonexecutable prototype or oracle. Formal reasoning plays somewhat the same role for mathematical models that testing does for code. Just as you can experiment with code by running it, you can investigate the behavior of a nonexecutable prototype by reasoning. You can check important system properties before you write a single line of code. Moreover, an exercise in formal reasoning often establishes the behavior for a whole class of situations, not just a single test case.
We can use formal reasoning to validate a mathematical model against requirements. A model is valid if its properties satisfy the intent of the requirements. Requirements are usually not expressed formally, but we can translate almost any reasonable requirement to a predicate. We can then attempt to determine whether this predicate follows from the predicates in our model. If it does, the model is valid with respect to that requirement.